@Override public OrderResult Execute(Order order, IUserBalance balanceService, IStockInfo stockService) { OrderResult result = new OrderResult(order); Date submitted = order.getDateSubmitted(); if (today.equals(submitted)) { StockInfo info = stockService.requestCurrentStockData(order.getStock().getStockSymbol()); if (info != null) { attemptTrade( result, balanceService, stockService, today, info.getDayLow(), info.getDayHigh(), info.getVolume()); } } else // SELL { Date lastEvaluated = order.getLastEvaluated(); if (order .getDateSubmitted() .equals( lastEvaluated)) { // do not try to evaluate again the first day the Limit order was // submitted lastEvaluated = getDateOneDayInTheFuture(lastEvaluated); } List<HistoricalStockInfo> infos = stockService.requestDailyHistoricalStockData( order.getStock().getStockSymbol(), lastEvaluated); if (infos != null && infos.size() > 0) { HistoricalStockInfo info; for (int i = infos.size() - 1; i >= 0; --i) { info = infos.get(i); attemptTrade( result, balanceService, stockService, info.getDate(), info.getDayLow(), info.getDayHigh(), info.getVolume()); if (result.getCompleted() || result.getCancelled()) { break; } } } } return result; }
private void attemptTrade( OrderResult result, IUserBalance balanceService, IStockInfo stockService, Date date, double dayLow, double dayHigh, int volume) { Order order = result.getOrder(); float quantity = order.getQuantity(); if (quantity > volume) { return; } try { if (order.getAction() == OrderAction.BUY) { if (order.getLimitPrice() < dayLow) { // price was too high to buy today return; } double orderTotal = quantity * dayLow; double accountBalance = balanceService.getBalance(order.getUserName()); if (accountBalance <= orderTotal) { quantity = (int) (accountBalance / dayLow); orderTotal = quantity * dayLow; result.setNote("Reduced quantity from " + order.getQuantity() + " to " + quantity); } if (quantity > 0 && accountBalance >= orderTotal) { try { balanceService.updateBalance(order.getUserName(), accountBalance - orderTotal); result.setCompleted(true); result.setQuantity(quantity); result.setSharePrice(dayLow); result.setDateTime(date); } catch (Exception ex) { // ignore } } else { // account balance is zero or not enough to purchase even one share result.setCancelled(true); result.setDateTime(date); result.setNote("Insufficient funds"); } } else { if (order.getLimitPrice() > dayHigh) { // price was too low to sell today return; } double orderTotal = quantity * dayHigh; double accountBalance = balanceService.getBalance(order.getUserName()); try { balanceService.updateBalance(order.getUserName(), accountBalance + orderTotal); result.setCompleted(true); result.setQuantity(quantity); result.setSharePrice(dayHigh); result.setDateTime(date); } catch (Exception ex) { // ignore } } } finally { // these apply on the first historical trade attempt (should be the same day the order was // submitted) if (!result.getCompleted() && !result.getCancelled()) { if ((order.getTimeInForce() == TimeInForce.DAY || order.getTimeInForce() == TimeInForce.FILLORKILL) && (today.after(date) || (today.equals(date) && !stockService.isWithinTradingHours()))) { // Cancel order result.setCancelled(true); result.setDateTime(date); result.setNote("Market closed"); } if (order.getTimeInForce() == TimeInForce.IMMEDIATEORCANCEL) { // Cancel order result.setCancelled(true); result.setDateTime(date); result.setNote("Unable to fill immediately"); } if (order.getTimeInForce() == TimeInForce.GOODUNTILCANCELED) { long diffInDays = (date.getTime() - order.getDateSubmitted().getTime()) / (1000 * 60 * 60 * 24); if (diffInDays > 120) { result.setCancelled(true); result.setDateTime(date); result.setNote("120 day limit reached"); } } } } }