/// <summary> /// This is used to ensure each test starts with a clean, known state. /// </summary> protected void LiquidateHoldings() { Log.Trace(""); Log.Trace("LIQUIDATE HOLDINGS"); Log.Trace(""); var holdings = Brokerage.GetAccountHoldings(); foreach (var holding in holdings) { if (holding.Quantity == 0) { continue; } Log.Trace("Liquidating: " + holding); var order = new MarketOrder(holding.Symbol, (int)-holding.Quantity, DateTime.Now, type: holding.Type); _orderMapping.Add(order); PlaceOrderWaitForStatus(order, OrderStatus.Filled); } }
/// <summary> /// Places the specified order with the brokerage and wait until we get the <paramref name="expectedStatus"/> back via an OrderStatusChanged event. /// This function handles adding the order to the <see cref="IOrderMapping"/> instance as well as incrementing the order ID. /// </summary> /// <param name="order">The order to be submitted</param> /// <param name="expectedStatus">The status to wait for</param> /// <param name="secondsTimeout">Maximum amount of time to wait for <paramref name="expectedStatus"/></param> /// <returns>The same order that was submitted.</returns> protected Order PlaceOrderWaitForStatus(Order order, OrderStatus expectedStatus = OrderStatus.Filled, double secondsTimeout = 10.0) { var requiredStatusEvent = new ManualResetEvent(false); var desiredStatusEvent = new ManualResetEvent(false); EventHandler <OrderEvent> brokerageOnOrderStatusChanged = (sender, args) => { // no matter what, every order should fire at least one of these if (args.Status == OrderStatus.Submitted || args.Status == OrderStatus.Invalid) { Log.Trace(""); Log.Trace("SUBMITTED: " + args); Log.Trace(""); requiredStatusEvent.Set(); } // make sure we fire the status we're expecting if (args.Status == expectedStatus) { Log.Trace(""); Log.Trace("EXPECTED: " + args); Log.Trace(""); desiredStatusEvent.Set(); } }; Brokerage.OrderStatusChanged += brokerageOnOrderStatusChanged; OrderMapping.Add(order); if (!Brokerage.PlaceOrder(order)) { Assert.Fail("Brokerage failed to place the order: " + order); } requiredStatusEvent.WaitOneAssertFail((int)(1000 * secondsTimeout), "Expected every order to fire a submitted or invalid status event"); desiredStatusEvent.WaitOneAssertFail((int)(1000 * secondsTimeout), "OrderStatus " + expectedStatus + " was not encountered within the timeout."); Brokerage.OrderStatusChanged -= brokerageOnOrderStatusChanged; return(order); }
private IBrokerage InitializeBrokerage() { Log.Trace(""); Log.Trace("- INITIALIZING BROKERAGE -"); Log.Trace(""); var brokerage = CreateBrokerage(OrderMapping, HoldingsProvider); brokerage.Connect(); if (!brokerage.IsConnected) { Assert.Fail("Failed to connect to brokerage"); } Log.Trace(""); Log.Trace("GET OPEN ORDERS"); Log.Trace(""); foreach (var openOrder in brokerage.GetOpenOrders()) { OrderMapping.Add(openOrder); } Log.Trace(""); Log.Trace("GET ACCOUNT HOLDINGS"); Log.Trace(""); foreach (var accountHolding in brokerage.GetAccountHoldings()) { HoldingsProvider[accountHolding.Symbol] = accountHolding; } brokerage.OrderStatusChanged += (sender, args) => { Log.Trace(""); Log.Trace("ORDER STATUS CHANGED: " + args); Log.Trace(""); // we need to keep this maintained properly if (args.Status == OrderStatus.Filled || args.Status == OrderStatus.PartiallyFilled) { Log.Trace("FILL EVENT: " + args.FillQuantity + " units of " + args.Symbol); Holding holding; if (_holdingsProvider.TryGetValue(args.Symbol, out holding)) { _holdingsProvider[args.Symbol].Quantity += args.FillQuantity; } else { var accountHoldings = brokerage.GetAccountHoldings().ToDictionary(x => x.Symbol); if (accountHoldings.ContainsKey(args.Symbol)) { _holdingsProvider[args.Symbol] = accountHoldings[args.Symbol]; } else { _holdingsProvider[args.Symbol] = new Holding { Symbol = args.Symbol }; } } Log.Trace("--HOLDINGS: " + _holdingsProvider[args.Symbol]); // update order mapping var order = _orderMapping.GetOrderById(args.OrderId); order.Status = args.Status; } }; return(brokerage); }