public void Fill() { // market should fill on trade but not on quote OrderImpl o = new OrderImpl(security, Direction.Long, 100); Assert.True(o.Fill(TickImpl.NewTrade(security.Name, 9, 100), trans) == StatusType.ORDER_FILLED); Assert.True(o.Fill(TickImpl.NewBid(security.Name, 8, 100), trans) == StatusType.OK); // buy limit // limit should fill if order price is inside market o = new OrderImpl(security, Direction.Long, 100, 10m); Assert.True(o.Fill(TickImpl.NewTrade(security.Name, 9, 100), trans) == StatusType.ORDER_FILLED); // shouldn't fill outside market o = new OrderImpl(security, Direction.Long, 100, 10m); Assert.True(o.Fill(TickImpl.NewTrade(security.Name, 11, 100), trans) == StatusType.OK); // sell limit // limit should fill if order price is inside market o = new OrderImpl(security, Direction.Short, 100, 10m); Assert.True(o.Fill(TickImpl.NewTrade(security.Name, 11, 100), trans) == StatusType.ORDER_FILLED); // shouldn't fill outside market o = new OrderImpl(security, Direction.Short, 100, 10m); Assert.True(o.Fill(TickImpl.NewTrade(security.Name, 9, 100), trans) == StatusType.OK); // buy stop o = new OrderImpl(security, Direction.Long, 100, 0, 10m); Assert.True(o.Fill(TickImpl.NewTrade(security.Name, 11, 100), trans) == StatusType.ORDER_FILLED); // shouldn't fill outside market o = new OrderImpl(security, Direction.Long, 100, 0, 10m); Assert.True(o.Fill(TickImpl.NewTrade(security.Name, 9, 100), trans) == StatusType.OK); // sell stop o = new OrderImpl(security, Direction.Short, 100, 0, 10m); Assert.True(o.Fill(TickImpl.NewTrade(security.Name, 9, 100), trans) == StatusType.ORDER_FILLED); // shouldn't fill outside market o = new OrderImpl(security, Direction.Short, 100, 0, 10m); Assert.True(o.Fill(TickImpl.NewTrade(security.Name, 11, 100), trans) == StatusType.OK); // always fail filling an invalid tick o = new OrderImpl(security, Direction.Long, 100); Assert.False(o.Fill(TickImpl.NewTrade(security.Name, 0, 0), trans) == StatusType.ORDER_FILLED); // always fail filling invalid order o = new OrderImpl(security, Direction.Long, 100, 10); OrderImpl x = new OrderImpl(); Assert.False(o.Fill(x) == StatusType.ORDER_FILLED); // always fail filling an order that doesn't cross market x = new OrderImpl(security, Direction.Long, 100); Assert.False(o.Fill(x) == StatusType.ORDER_FILLED); const string t2 = "agent2"; // succeed on crossing market x = new OrderImpl(security, Direction.Short, 100); x.AccountName = t2; Assert.True(o.Fill(x) == StatusType.ORDER_FILLED); // fail when accounts are the same x = new OrderImpl(security, Direction.Short, 100); x.AccountName = o.AccountName; Assert.False(o.Fill(x) == StatusType.OK); // fail on match outside of market x = new OrderImpl(security, Direction.Long, 100, 11); x.AccountName = t2; Assert.False(o.Fill(x) == StatusType.OK); // succeed on limit cross o = new OrderImpl(security, Direction.Long, 100, 10); x = new OrderImpl(security, Direction.Short, 100, 10); x.AccountName = t2; Assert.True(o.Fill(x) == StatusType.ORDER_FILLED); // make sure we can stop cross o = new OrderImpl(security, Direction.Short, 100, 0, 10); x = new OrderImpl(security, Direction.Long, 100); x.AccountName = t2; Assert.True(o.Fill(x) == StatusType.ORDER_FILLED); }
/// <summary> /// Executes any open orders allowed by the specified tick. /// </summary> /// <param name="tick">The tick.</param> /// <returns>the number of orders executed using the tick.</returns> public int Execute(TickImpl tick) { //TODO: in order to calculate the floating PnL ticks are send to the account for calculations. //Also this location is incorrect! Default.OnTick(tick); BrokerCostCalculation(tick); if (_pendorders == 0) { return(0); } //Check if we need to process the order as a trade or use the bid ask fills UseBidAskFills = tick.HasAsk && tick.HasBid; int filledorders = 0; SimAccount[] accts = new SimAccount[MasterOrders.Count]; MasterOrders.Keys.CopyTo(accts, 0); for (int idx = 0; idx < accts.Length; idx++) { // go through each account SimAccount a = accts[idx]; // if account has requested no executions, skip it if (!a.Execute) { continue; } //Check for a margin call by the broker if (a.MarginLevel <= BrokerModel.StopOutLevel()) { //cancel this order MasterOrders[a].ForEach(x => { ((PendingOrderImpl)x).OrderStatus = StatusType.INSUFFICIENT_CAPITAL; x.Cancel(); }); } // make sure we have a record for this account if (!MasterTrades.ContainsKey(a.Id)) { MasterTrades.Add(a.Id, new List <Trade>()); } // track orders being removed and trades that need notification List <int> notifytrade = new List <int>(); List <int> remove = new List <int>(); // go through each order in the account for (int i = 0; i < MasterOrders[a].Count; i++) { //Get the order object PendingOrderImpl po = (PendingOrderImpl)MasterOrders[a][i]; OrderImpl o = (OrderImpl)po.Order; //make sure tick is for the right stock, and right exchange if (tick.Symbol != o.Symbol) { continue; } //Check if order is in a correct state if (po.OrderStatus != StatusType.OK) { remove.Add(i); // count the trade filledorders++; continue; } if (UseHighLiquidityFillsEod) { po.OrderStatus = o.Fill(tick, BrokerModel, UseBidAskFills, false, true); } else if (o.ValidInstruct <= OrderInstructionType.GTC) { po.OrderStatus = o.Fill(tick, BrokerModel, UseBidAskFills, false); // fill our trade } else if (o.ValidInstruct == OrderInstructionType.OPG) { // if it's already opened, we missed our shot if (_hasopened.Contains(o.Symbol)) { continue; } // otherwise make sure it's really the opening if (tick.Source == Opgex) { // it's the opening tick, so fill it as an opg po.OrderStatus = o.Fill(tick, BrokerModel, UseBidAskFills, true); // mark this symbol as already being open _hasopened.Add(tick.Symbol); } } // other orders fill normally, except MOC orders which are at 4:00PM else if (o.ValidInstruct == OrderInstructionType.MOC) { if (tick.Time >= 160000000) { po.OrderStatus = o.Fill(tick, BrokerModel, UseBidAskFills, false); // fill our trade } } else { po.OrderStatus = o.Fill(tick, BrokerModel, UseBidAskFills, false); // fill our trade } if (po.OrderStatus == StatusType.ORDER_FILLED) { // remove filled size from size available in trade tick.Size -= o.UnsignedSize; // get copy of trade for recording TradeImpl trade = new TradeImpl(o); // if trade represents entire requested order, mark order for removal if (trade.UnsignedSize == o.UnsignedSize) { remove.Add(i); } else // otherwise reflect order's remaining size { o.Size = (o.UnsignedSize - trade.UnsignedSize) * (o.Direction == Direction.Long ? 1 : -1); } // record trade MasterTrades[a.Id].Add(trade); // mark it for notification notifytrade.Add(MasterTrades[a.Id].Count - 1); // count the trade filledorders++; } } // notify subscribers of trade if ((GotFill != null) && a.Notify) { for (int tradeidx = 0; tradeidx < notifytrade.Count; tradeidx++) { TradeImpl t = (TradeImpl)MasterTrades[a.Id][notifytrade[tradeidx]]; var account = Acctlist[Accounts[0]]; t.Account = account; t.AccountName = t.Account.Id; account.OnFill(t); GotFill(t, MasterOrders[a][remove[tradeidx]]); } } int rmcount = remove.Count; // remove the filled orders for (int i = remove.Count - 1; i >= 0; i--) { MasterOrders[a].RemoveAt(remove[i]); } // unmark filled orders as pending _pendorders -= rmcount; if (_pendorders < 0) { _pendorders = 0; } } return(filledorders); }