@Override public void updateAccountValue(String key, String value, String currency, String accountName) { try { if (logger.isDebugEnabled()) logger.debug( "updateAccountValue: {} {} {} {}", new Object[] {key, value, currency, accountName}); if ("AccountCode".equals(key)) { synchronized (this) { this.accountCode = value; notifyAll(); } } else if ("AvailableFunds".equalsIgnoreCase(key) && isCurrencyCode(currency) && Util.isDouble(value)) { portfolio.setCash(currency, Double.parseDouble(value)); } else if ("BuyingPower".equalsIgnoreCase(key) && isCurrencyCode(currency) && Util.isDouble(value)) { portfolio.setBaseCurrency(currency); } else if ("ExchangeRate".equalsIgnoreCase(key) && isCurrencyCode(currency) && Util.isDouble(value)) { portfolio.setExchangeRate(currency, Double.parseDouble(value)); } } catch (Throwable t) { logger.error(t.getMessage(), t); } }
@Override public void openOrder(int orderId, Contract contract, Order order, OrderState orderState) { try { if (logger.isDebugEnabled()) logger.debug( "openOrder: {} {} {} {}", new Object[] { orderId, Util.toString(contract), Util.toString(order), Util.toString(orderState) }); OpenOrder openOrder = openOrdersById.get(orderId); if (openOrder != null) { if ((openOrder.isFilled() || (!openOrder.isOpen() && openOrder.getQuantityFilled() > 0)) && orderState.m_commission != Double.MAX_VALUE) { closeOpenOrder(openOrder, orderState.m_commission); } } else { if ("PendingSubmit".equals(orderState.m_status) || "PreSubmitted".equals(orderState.m_status) || "Submitted".equals(orderState.m_status)) { openOrder = toOpenOrder(contract, order); openOrdersById.put(orderId, openOrder); logger.info("Added {}", openOrder); } } } catch (Throwable t) { logger.error(t.getMessage(), t); } }
@Override public void execDetails(int reqId, Contract contract, Execution execution) { try { if (logger.isDebugEnabled()) logger.debug( "execDetails: {} {} {}", new Object[] {reqId, Util.toString(contract), Util.toString(execution)}); OpenOrder openOrder = openOrdersById.get(execution.m_orderId); DateTime dt = DateTimeFormat.forPattern("yyyyMMdd HH:mm:ss").parseDateTime(execution.m_time); if (openOrder != null) { int quantityChange = openOrder.isBuy() ? execution.m_shares : -execution.m_shares; openOrder.update(quantityChange, execution.m_price, dt); logExecution(openOrder, quantityChange); } else { logger.info( "Execution does not match any open order {} {}", Util.toString(contract), Util.toString(execution)); } } catch (Throwable t) { // Do not allow exceptions come back to the socket -- it will cause // disconnects logger.error(t.getMessage(), t); } }
@Test() public void testDummyTraderPlaceOrder() { DummyTrader trader = new DummyTrader(marketFeed); trader.connect(); final boolean[] listenerCalled = new boolean[4]; trader.addOrderListener( new OrderListener() { @Override public void onOrderPlaced(OpenOrder openOrder) { assertEquals(openOrder.getOrderId(), 1); listenerCalled[0] = true; } @Override public void onOrderFilled(OpenOrder openOrder, Position position) { assertEquals(openOrder.getOrderId(), 1); assertEquals(position.getQuantity(), 1); listenerCalled[1] = true; } @Override public void onOrderFailed(OpenOrder openOrder) {} @Override public void onOrderCancelled(OpenOrder openOrder) {} }); OpenOrder openOrder = trader.placeOrder(symbol, OrderType.MARKET, 1, -1.0, -1.0, "test"); assertEquals(trader.getOpenOrder(symbol, OrderType.MARKET) != null, true); assertEquals(trader.getOpenOrders().size(), 1); assertEquals(trader.getOpenOrders(symbol, OrderType.MARKET).size(), 1); assertEquals(openOrder.getAction(), OrderAction.BUY); assertEquals(openOrder.getType(), OrderType.MARKET); assertEquals(openOrder.getAvgFillPrice(), Double.NaN); assertEquals(openOrder.getCommission(), Double.NaN); assertEquals(openOrder.getLastFillPrice(), Double.NaN); assertEquals(openOrder.getOrderDate(), date); assertEquals(openOrder.getOrderId(), 1); assertEquals(openOrder.getPrice(), -1.0); assertEquals(openOrder.getStopPrice(), -1.0); assertEquals(openOrder.getTrailStopOffset(), -1.0); assertEquals(openOrder.getQuantity(), 1); assertEquals(openOrder.getQuantityFilled(), 0); assertEquals(openOrder.getReference(), "test"); assertEquals(listenerCalled[0], true); Util.callMethod(trader, "processOpenOrders", date); assertEquals(listenerCalled[1], true); }
protected void logTrade( OpenOrder openOrder, int position, double costBasis, double realized, double unrealized) { Object[] params = new Object[] { openOrder.getFillDate(), "TRADE", openOrder.getAction(), openOrder.getType(), openOrder.getQuantityFilled(), openOrder.getSymbol(), openOrder.getSymbol().getCurrency(), openOrder.getAvgFillPrice(), position, Util.round(costBasis, 4), Util.round(realized, 4), Util.round(unrealized, 4), Util.round(openOrder.getCommission(), 4), openOrder.getReference() != null ? openOrder.getReference() : "", accountCode }; blotter.info( MarkerFactory.getMarker("TRADE"), "{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}", params); }
@Override public void updatePortfolio( Contract contract, int qty, double marketPrice, double marketValue, double averageCost, double unrealizedPNL, double realizedPNL, String accountName) { try { if (logger.isDebugEnabled()) logger.debug( "updatePortfolio: {} {} {} {} {} {} {} {}", new Object[] { Util.toString(contract), qty, marketPrice, marketValue, averageCost, unrealizedPNL, realizedPNL, accountName }); if (qty != 0) { Symbol symbol = toSymbol(contract); double costBasis = averageCost / (contract.m_multiplier != null ? Integer.parseInt(contract.m_multiplier) : 1); Position position = new Position(symbol, qty, costBasis, 0.0); portfolio.setPosition(symbol, position); logger.info( "Updated {}, last: {}, unrealized pnl: {}", new Object[] {position, marketPrice, position.getProfitLoss(marketPrice)}); } } catch (Throwable t) { logger.error(t.getMessage(), t); } }
@Override public synchronized OpenOrder placeOrder( Symbol symbol, OrderType type, int quantity, double price, double stopPercent, String reference) { if (quantity == 0) { throw new IllegalArgumentException(String.format("Invalid quantity %s", quantity)); } if ((OrderType.LIMIT.equals(type) || OrderType.STOP_LIMIT.equals(type) || OrderType.TRAIL_LIMIT.equals(type)) && price <= 0) { throw new IllegalArgumentException(String.format("Invalid limit order price %s", price)); } if ((OrderType.STOP_MARKET.equals(type) || OrderType.STOP_LIMIT.equals(type) || OrderType.TRAIL_MARKET.equals(type) || OrderType.TRAIL_LIMIT.equals(type)) && stopPercent <= 0) { throw new IllegalArgumentException( String.format("Invalid stop order with stop percent %s", stopPercent)); } checkConnected(); OpenOrder openOrder = getOpenOrder(symbol, type); if (openOrder != null && !openOrder.isFilled() && !openOrder.isCancelled()) { throw new IllegalStateException( "OpenOrder for same strategy, symbol and type already exists: " + openOrder); } DateTime now = new DateTime(); double stopPrice = -1; double trailingStopOffset = -1; if (OrderType.STOP_MARKET.equals(type) || OrderType.STOP_LIMIT.equals(type) || OrderType.TRAIL_MARKET.equals(type) || OrderType.TRAIL_LIMIT.equals(type)) { Tick t = getLastTick(symbol); if (t == null) { t = getLastTick(symbol, now); if (t == null) { throw new IllegalStateException( String.format("Cannot set stop without tick data for symbol %s", symbol)); } } trailingStopOffset = Util.round(t.getMidPrice() * stopPercent, 10.0); if (quantity < 0) { stopPrice = t.getMidPrice() - trailingStopOffset; } else { stopPrice = t.getMidPrice() + trailingStopOffset; } stopPrice = Util.round(stopPrice, 2.0); } int orderId = nextValidOrderId.getAndIncrement(); openOrder = new OpenOrder( orderId, symbol, type, quantity, price, stopPrice, trailingStopOffset, new DateTime(), reference); openOrdersById.put(orderId, openOrder); Contract contract = makeContract(symbol); Order order = makeOrder(openOrder); logger.info("Placing order {}", openOrder); socket.placeOrder(orderId, contract, order); for (OrderListener listener : orderListeners) { try { listener.onOrderPlaced(openOrder); } catch (Throwable t) { logger.error(t.getMessage(), t); } } return openOrder; }