public void ClientCancelsLimitOrder() { var orderedResetEvent = new ManualResetEvent(false); var canceledResetEvent = new ManualResetEvent(false); var ib = _interactiveBrokersBrokerage; ib.OrderStatusChanged += (sender, orderEvent) => { if (orderEvent.Status == OrderStatus.Submitted) { orderedResetEvent.Set(); } if (orderEvent.Status == OrderStatus.Canceled) { canceledResetEvent.Set(); } }; // try to sell a single share at a ridiculous price, we'll cancel this later var order = new LimitOrder(Symbol, -buyQuantity, 100000, DateTime.UtcNow, null, Type); _orders.Add(order); ib.PlaceOrder(order); orderedResetEvent.WaitOneAssertFail(2500, "Limit order failed to be submitted."); Thread.Sleep(500); ib.CancelOrder(order); canceledResetEvent.WaitOneAssertFail(2500, "Canceled event did not fire."); var openOrders = ib.GetOpenOrders(); var cancelledOrder = openOrders.FirstOrDefault(x => x.BrokerId.Contains(order.BrokerId[0])); Assert.IsNull(cancelledOrder); }
/// <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; }
public void GetsCashBalanceAfterTrade() { var ib = _interactiveBrokersBrokerage; decimal balance = ib.GetCashBalance().Single(x => x.Symbol == "USD").Amount; // wait for our order to fill var manualResetEvent = new ManualResetEvent(false); ib.AccountChanged += (sender, orderEvent) => manualResetEvent.Set(); var order = new MarketOrder(Symbols.USDJPY, buyQuantity, DateTime.UtcNow); _orders.Add(order); ib.PlaceOrder(order); manualResetEvent.WaitOneAssertFail(1500, "Didn't receive account changed event"); decimal balanceAfterTrade = ib.GetCashBalance().Single(x => x.Symbol == "USD").Amount; Assert.AreNotEqual(balance, balanceAfterTrade); }
public void FiresMultipleAccountBalanceEvents() { var ib = _interactiveBrokersBrokerage; var orderEventFired = new ManualResetEvent(false); ib.OrderStatusChanged += (sender, args) => { if (args.Status == OrderStatus.Filled) { orderEventFired.Set(); } }; var cashBalanceUpdates = new List<decimal>(); var accountChangedFired = new ManualResetEvent(false); ib.AccountChanged += (sender, args) => { cashBalanceUpdates.Add(args.CashBalance); accountChangedFired.Set(); }; const int orderCount = 3; for (int i = 0; i < orderCount; i++) { var order = new MarketOrder(Symbols.USDJPY, buyQuantity*(i + 1), new DateTime()) {Id = i + 1}; _orders.Add(order); ib.PlaceOrder(order); orderEventFired.WaitOneAssertFail(1500, "Didnt receive order event #" + i); orderEventFired.Reset(); accountChangedFired.WaitOneAssertFail(1500, "Didnt receive account event #" + i); accountChangedFired.Reset(); } Assert.AreEqual(orderCount, cashBalanceUpdates.Count); }
public void GetsAccountHoldings() { var ib = _interactiveBrokersBrokerage; Thread.Sleep(500); var previousHoldings = ib.GetAccountHoldings().ToDictionary(x => x.Symbol); foreach (var holding in previousHoldings) { Console.WriteLine(holding.Value); } Log.Trace("Quantity: " + previousHoldings[Symbols.USDJPY].Quantity); bool hasSymbol = previousHoldings.ContainsKey(Symbols.USDJPY); // wait for order to complete before request account holdings var orderResetEvent = new ManualResetEvent(false); ib.OrderStatusChanged += (sender, fill) => { if (fill.Status == OrderStatus.Filled) orderResetEvent.Set(); }; // buy some currency const int quantity = -buyQuantity; var order = new MarketOrder(Symbols.USDJPY, quantity, DateTime.UtcNow); _orders.Add(order); ib.PlaceOrder(order); // wait for the order to go through orderResetEvent.WaitOneAssertFail(3000, "Didn't receive order event"); // ib is slow to update tws Thread.Sleep(5000); var newHoldings = ib.GetAccountHoldings().ToDictionary(x => x.Symbol); Log.Trace("New Quantity: " + newHoldings[Symbols.USDJPY].Quantity); if (hasSymbol) { Assert.AreEqual(previousHoldings[Symbols.USDJPY].Quantity, newHoldings[Symbols.USDJPY].Quantity - quantity); } else { Assert.IsTrue(newHoldings.ContainsKey(Symbols.USDJPY)); Assert.AreEqual(newHoldings[Symbols.USDJPY].Quantity, quantity); } }
public void ClientFiresSingleOrderFilledEvent() { var ib = _interactiveBrokersBrokerage; var order = new MarketOrder(Symbols.USDJPY, buyQuantity, new DateTime()) {Id = 1}; _orders.Add(order); int orderFilledEventCount = 0; var orderFilledResetEvent = new ManualResetEvent(false); ib.OrderStatusChanged += (sender, fill) => { if (fill.Status == OrderStatus.Filled) { orderFilledEventCount++; orderFilledResetEvent.Set(); } // mimic what the transaction handler would do order.Status = fill.Status; }; ib.PlaceOrder(order); orderFilledResetEvent.WaitOneAssertFail(2500, "Didnt fire order filled event"); // wait a little to see if we get multiple fill events Thread.Sleep(2000); Assert.AreEqual(1, orderFilledEventCount); }