/// <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="IOrderProvider"/> 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> /// <param name="allowFailedSubmission">Allow failed order submission</param> /// <returns>The same order that was submitted.</returns> protected Order PlaceOrderWaitForStatus(Order order, OrderStatus expectedStatus = OrderStatus.Filled, double secondsTimeout = 10.0, bool allowFailedSubmission = false) { 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; OrderProvider.Add(order); if (!Brokerage.PlaceOrder(order) && !allowFailedSubmission) { Assert.Fail("Brokerage failed to place the order: " + order); } // This is due to IB simulating stop orders https://www.interactivebrokers.com/en/trading/orders/stop.php // which causes the Status.Submitted order event to never be set bool assertOrderEventStatus = !(Brokerage.Name == "Interactive Brokers Brokerage" && new[] { OrderType.StopMarket, OrderType.StopLimit }.Contains(order.Type)); if (assertOrderEventStatus) { 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. Order Id:" + order.Id); } else { requiredStatusEvent.WaitOne((int)(1000 * secondsTimeout)); } Brokerage.OrderStatusChanged -= brokerageOnOrderStatusChanged; return(order); }
/// <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, -holding.Quantity, DateTime.UtcNow); _orderProvider.Add(order); PlaceOrderWaitForStatus(order, OrderStatus.Filled); } }
public void PartialFills() { var manualResetEvent = new ManualResetEvent(false); var qty = 1000000m; var remaining = qty; var sync = new object(); Brokerage.OrderStatusChanged += (sender, orderEvent) => { lock (sync) { remaining -= orderEvent.FillQuantity; Console.WriteLine("Remaining: " + remaining + " FillQuantity: " + orderEvent.FillQuantity); if (orderEvent.Status == OrderStatus.Filled) { manualResetEvent.Set(); } } }; // pick a security with low, but some, volume var symbol = Symbols.EURUSD; var order = new MarketOrder(symbol, qty, DateTime.UtcNow) { Id = 1 }; OrderProvider.Add(order); Brokerage.PlaceOrder(order); // pause for a while to wait for fills to come in manualResetEvent.WaitOne(2500); manualResetEvent.WaitOne(2500); manualResetEvent.WaitOne(2500); Console.WriteLine("Remaining: " + remaining); Assert.AreEqual(0, remaining); }
/// <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="IOrderProvider"/> 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, bool allowFailedSubmission = false) { 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; OrderProvider.Add(order); if (!Brokerage.PlaceOrder(order) && !allowFailedSubmission) { 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(OrderProvider, 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()) { OrderProvider.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 = _orderProvider.GetOrderById(args.OrderId); order.Status = args.Status; } }; return(brokerage); }
private IBrokerage InitializeBrokerage() { Log.Trace(""); Log.Trace("- INITIALIZING BROKERAGE -"); Log.Trace(""); var brokerage = CreateBrokerage(OrderProvider, SecurityProvider); brokerage.Connect(); if (!brokerage.IsConnected) { Assert.Fail("Failed to connect to brokerage"); } //gdax does not have a user data stream. Instead, we need to symbol subscribe and monitor for our orders. if (brokerage.Name == "GDAX") { ((QuantConnect.Brokerages.GDAX.GDAXBrokerage)brokerage).Subscribe(new[] { Symbol }); } Log.Trace(""); Log.Trace("GET OPEN ORDERS"); Log.Trace(""); foreach (var openOrder in brokerage.GetOpenOrders()) { OrderProvider.Add(openOrder); } Log.Trace(""); Log.Trace("GET ACCOUNT HOLDINGS"); Log.Trace(""); foreach (var accountHolding in brokerage.GetAccountHoldings()) { // these securities don't need to be real, just used for the ISecurityProvider impl, required // by brokerages to track holdings SecurityProvider[accountHolding.Symbol] = CreateSecurity(accountHolding.Symbol); } 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.ToString()); Security security; if (_securityProvider.TryGetValue(args.Symbol, out security)) { var holding = _securityProvider[args.Symbol].Holdings; holding.SetHoldings(args.FillPrice, holding.Quantity + args.FillQuantity); } else { _securityProvider[args.Symbol] = CreateSecurity(args.Symbol); _securityProvider[args.Symbol].Holdings.SetHoldings(args.FillPrice, args.FillQuantity); } Log.Trace("--HOLDINGS: " + _securityProvider[args.Symbol]); // update order mapping var order = _orderProvider.GetOrderById(args.OrderId); order.Status = args.Status; } }; return(brokerage); }
private IBrokerage InitializeBrokerage() { Log.Trace(""); Log.Trace("- INITIALIZING BROKERAGE -"); Log.Trace(""); var brokerage = CreateBrokerage(OrderProvider, SecurityProvider); 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()) { OrderProvider.Add(openOrder); } Log.Trace(""); Log.Trace("GET ACCOUNT HOLDINGS"); Log.Trace(""); foreach (var accountHolding in brokerage.GetAccountHoldings()) { // these securities don't need to be real, just used for the ISecurityProvider impl, required // by brokerages to track holdings SecurityProvider[accountHolding.Symbol] = new Security(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), new SubscriptionDataConfig(typeof(TradeBar), accountHolding.Symbol, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork, false, false, false)); } 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.ToString()); Security security; if (_securityProvider.TryGetValue(args.Symbol, out security)) { var holding = _securityProvider[args.Symbol].Holdings; holding.SetHoldings(args.FillPrice, holding.Quantity + args.FillQuantity); } else { var accountHoldings = brokerage.GetAccountHoldings().ToDictionary(x => x.Symbol); if (accountHoldings.ContainsKey(args.Symbol)) { _securityProvider[args.Symbol].Holdings.SetHoldings(args.FillPrice, args.FillQuantity); } else { _securityProvider[args.Symbol] = new Security(SecurityExchangeHours.AlwaysOpen(TimeZones.NewYork), new SubscriptionDataConfig(typeof(TradeBar), args.Symbol, Resolution.Minute, TimeZones.NewYork, TimeZones.NewYork, false, false, false)); _securityProvider[args.Symbol].Holdings.SetHoldings(args.FillPrice, args.FillQuantity); } } Log.Trace("--HOLDINGS: " + _securityProvider[args.Symbol]); // update order mapping var order = _orderProvider.GetOrderById(args.OrderId); order.Status = args.Status; } }; return(brokerage); }