public void Fill_RegularLiquidity() { SimBroker broker = new SimBroker(); broker.BrokerModel = _trans; ForexSecurity tsec = new ForexSecurity(S); tsec.LotSize = 1; tsec.OrderStepSize = 1; OrderImpl limitBuy = new OrderImpl(tsec, Direction.Long, 1, 133m); OrderImpl limitSell = new OrderImpl(tsec, Direction.Short, 1, 133.5m); OrderImpl stopBuy = new OrderImpl(tsec, Direction.Long, 3, 0, 135.70m); OrderImpl stopSell = new OrderImpl(tsec, Direction.Short, 4, 0, 135.75m); PendingOrderImpl plimitBuy = new PendingOrderImpl(limitBuy); PendingOrderImpl plimitSell = new PendingOrderImpl(limitSell); PendingOrderImpl pstopBuy = new PendingOrderImpl(stopBuy); PendingOrderImpl pstopSell = new PendingOrderImpl(stopSell); broker.SendOrderStatus(plimitBuy); broker.SendOrderStatus(plimitSell); broker.SendOrderStatus(pstopBuy); broker.SendOrderStatus(pstopSell); // OHLC for 6/21/2012 on SPY TickImpl openingTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(9, 30, 00, 000), 135.67m, 10670270, "NYS"); TickImpl endMornTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(12, 00, 00, 000), 135.78m, 10670270, "NYS"); TickImpl endLunchTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(14, 15, 00, 000), 132.33m, 10670270, "NYS"); TickImpl closingTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(16, 00, 00, 000), 132.44m, 10670270, "NYS"); broker.Execute(openingTick); broker.Execute(endMornTick); broker.Execute(endLunchTick); broker.Execute(closingTick); List <Trade> trades = broker.GetTradeList(); Assert.True(trades.Count == 4); foreach (Trade trade in trades) { if (trade.Xsize == 1) { Assert.Equal(132.33m, trade.Xprice); } else if (trade.Xsize == 2) { Assert.Equal(132.33m, trade.Xprice); } else if (trade.Xsize == 3) { Assert.Equal(135.78m, trade.Xprice); } else if (trade.Xsize == 4) { Assert.Equal(135.78m, trade.Xprice); } } }
public void MOCs() { SimBroker broker = new SimBroker(); broker.BrokerModel = _trans; ForexSecurity tsec = new ForexSecurity(S); tsec.LotSize = 1; tsec.OrderStepSize = 1; OrderImpl moc = new OrderImpl(tsec, Direction.Long, 200); moc.ValidInstruct = OrderInstructionType.MOC; PendingOrderImpl pmoc = new PendingOrderImpl(moc); Assert.True(moc.ValidInstruct == OrderInstructionType.MOC, "unexpected order instruction: " + moc.ValidInstruct); Assert.Equal(0, broker.SendOrderStatus(pmoc)); TickImpl openingTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(9, 30, 00, 000), 9, 10000, "NYS"); TickImpl endMornTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(12, 00, 00, 000), 9, 10000, "NYS"); TickImpl endLunchTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(14, 15, 00, 000), 9, 10000, "NYS"); TickImpl closingTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(16, 00, 00, 000), 9, 10000, "NYS"); int c = 0; c = broker.Execute(openingTick); Assert.Equal(0, c); c = broker.Execute(endMornTick); Assert.Equal(0, c); c = broker.Execute(endLunchTick); Assert.Equal(0, c); c = broker.Execute(closingTick); Assert.Equal(1, c); // should execute on the first tick at/after 16:00:00 }
public void DayFill() { SimBroker broker = new SimBroker(); broker.BrokerModel = _trans; ForexSecurity tsec = new ForexSecurity(S); tsec.LotSize = 1; tsec.OrderStepSize = 1; OrderImpl day = new OrderImpl(tsec, Direction.Long, 200); PendingOrderImpl pday = new PendingOrderImpl(day); broker.SendOrderStatus(pday); TickImpl openingTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(9, 30, 00, 000), 9, 10000, "NYS"); TickImpl endMornTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(12, 00, 00, 000), 9, 10000, "NYS"); TickImpl endLunchTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(14, 15, 00, 000), 9, 10000, "NYS"); TickImpl closingTick = TickImpl.NewTrade(S, Util.ToQLDate(DateTime.Now), Util.QL2FT(16, 00, 00, 000), 9, 10000, "NYS"); int c; c = broker.Execute(openingTick); Assert.Equal(1, c); // should execute on first received tick c = broker.Execute(endMornTick); Assert.Equal(0, c); c = broker.Execute(endLunchTick); Assert.Equal(0, c); c = broker.Execute(closingTick); Assert.Equal(0, c); }
/// <summary> /// Process order update event /// </summary> /// <param name="pendingorder"></param> private void HandleOrderUpdate(PendingOrder pendingorder) { //Check if order exists PendingOrderImpl currentorder = null; PendingOrderImpl changedorder = (PendingOrderImpl)pendingorder; var account = pendingorder.Account ?? Default; if (account == null) { changedorder.OrderStatus = StatusType.INVALID_ACCOUNT; return; } var masterorders = MasterOrders[account]; foreach (var po in masterorders) { if (po.OrderId == pendingorder.OrderId) { currentorder = (PendingOrderImpl)po; } } //Check if we could find this order if (currentorder == null) { return; } //Check order integrity var result = CheckOrderIntegrity(currentorder); if (result != StatusType.OK) { currentorder.OrderStatus = result; currentorder.Cancel(); return; } //Check if we need to remove this order if (!pendingorder.Order.IsValid || pendingorder.IsCancelled) { pendingorder.Cancel(); } //Send updates to any modules if (GotOrderUpdate != null) { GotOrderUpdate(pendingorder); } }
public void OpGs() { SimBroker broker = new SimBroker(); broker.BrokerModel = _trans; const string s = "NYS"; ForexSecurity tsec = new ForexSecurity(s); tsec.LotSize = 1; tsec.OrderStepSize = 1; // build and send an OPG order OrderImpl opg = new OrderImpl(tsec, Direction.Long, 200, 10); PendingOrderImpl popg = new PendingOrderImpl(opg); Assert.Equal(0, broker.SendOrderStatus(popg)); // build a tick on another exchange TickImpl it = TickImpl.NewTrade(s, 9, 100); it.Exchange = "ISLD"; // fill order (should fail) int c = broker.Execute(it); Assert.Equal(0, c); // build opening price for desired exchange TickImpl nt = TickImpl.NewTrade(s, 9, 10000); nt.Exchange = "NYS"; // fill order (should work) c = broker.Execute(nt); Assert.Equal(1, c); // add another OPG, make sure it's not filled with another tick TickImpl next = TickImpl.NewTrade(s, 9, 2000); next.Exchange = "NYS"; OrderImpl late = new OrderImpl(tsec, Direction.Long, 200, 10); PendingOrderImpl plate = new PendingOrderImpl(late); broker.SendOrderStatus(plate); c = broker.Execute(next); Assert.Equal(0, c); }
public void Basics() { ForexSecurity tsec = new ForexSecurity(S); tsec.LotSize = 1; tsec.PipValue = 1; tsec.PipSize = 1; tsec.OrderStepSize = 1; SimAccount account = new SimAccount("TEST", "testing", 1000M, 100); account.Securities.AddSecurity(tsec); SimBroker broker = new SimBroker(account, _trans); broker.BrokerModel = _trans; broker.GotFill += broker_GotFill; broker.GotOrder += broker_GotOrder; OrderImpl o = new OrderImpl(); PendingOrderImpl po = new PendingOrderImpl(o); int error = broker.SendOrderStatus(po); Assert.NotEqual((int)StatusType.OK, error); Assert.True(_orders == 0); Assert.True(_fills == 0); o = new OrderImpl(tsec, Direction.Long, 100); po = new PendingOrderImpl(o); broker.SendOrderStatus(po); Assert.True(_orders == 1); Assert.True(_fills == 0); Assert.True(broker.Execute(TickImpl.NewTrade(S, 10, 200)) == 1); Assert.True(_fills == 1); // test that a limit order is not filled outside the market o = new OrderImpl(tsec, Direction.Long, 100, 9); po = new PendingOrderImpl(o); broker.SendOrderStatus(po); Assert.Equal(0, broker.Execute(TickImpl.NewTrade(S, 10, 100))); Assert.True(_fills == 1); // redundant but for counting // test that limit order is filled inside the market Assert.Equal(1, broker.Execute(TickImpl.NewTrade(S, 8, 100))); Assert.True(_fills == 2); }
private void execute_GotTick(Tick t) { tickcount++; // generate fills periodically if (fillcount >= desiredfills) { return; } if (tickcount % 50 == 0) { bool side = fillcount % 2 == 0; OrderImpl o = new OrderImpl(new ForexSecurity(t.Symbol), side ? Direction.Long : Direction.Short, 100); PendingOrderImpl po = new PendingOrderImpl(o); h.SimBroker.SendOrderStatus(po); } }
public void MultiAccount() { _broker.BrokerModel = _trans; const string sym = "TST"; ForexSecurity tsec = new ForexSecurity(sym); tsec.LotSize = 1; tsec.OrderStepSize = 1; const string me = "tester"; const string other = "anotherguy"; SimAccount a = new SimAccount(me); SimAccount b = new SimAccount(other); SimAccount c = new SimAccount("sleeper"); OrderImpl oa = new OrderImpl(tsec, Direction.Long, 100); OrderImpl ob = new OrderImpl(tsec, Direction.Long, 100); oa.AccountName = me; ob.AccountName = other; // send order to accounts PendingOrderImpl poa = new PendingOrderImpl(oa, a); PendingOrderImpl pob = new PendingOrderImpl(ob, b); _broker.SendOrderStatus(poa); _broker.SendOrderStatus(pob); TickImpl t = new TickImpl(sym) { Trade = 100m, Size = 200 }; Assert.Equal(2, _broker.Execute(t)); Position apos = _broker.GetOpenPosition(tsec, a); Position bpos = _broker.GetOpenPosition(tsec, b); Position cpos = _broker.GetOpenPosition(tsec, c); Assert.True(apos.IsLong); Assert.Equal(100, apos.Size); Assert.True(bpos.IsLong); Assert.Equal(100, bpos.Size); Assert.True(cpos.IsFlat); // make sure that default account doesn't register // any trades Assert.True(_broker.GetOpenPosition(tsec).IsFlat); }
/// <summary> /// Process order cancel events /// </summary> /// <param name="pendingorder"></param> private void HandleOrderCancel(PendingOrder pendingorder) { //Check if order exists PendingOrder currentorder = null; PendingOrderImpl changedorder = (PendingOrderImpl)pendingorder; var account = pendingorder.Account ?? Default; if (account == null) { changedorder.OrderStatus = StatusType.INVALID_ACCOUNT; return; } var masterorders = MasterOrders[account]; foreach (var po in masterorders) { if (po.OrderId == pendingorder.OrderId) { currentorder = po; } } //Check if we could find this order if (currentorder == null) { return; } //Send changes to the broker book masterorders.Remove(pendingorder); //Notify cancelation if (GotOrderCancel != null) { GotOrderCancel(pendingorder); } }
public void BBO() { SimBroker broker = new SimBroker(); broker.BrokerModel = _trans; ForexSecurity tsec = new ForexSecurity(S); tsec.LotSize = 1; tsec.OrderStepSize = 1; const decimal p1 = 10m; const decimal p2 = 11m; const int x = 100; Order bid, offer; // send bid, make sure it's BBO (since it's only order on any book) broker.SendOrderStatus(new PendingOrderImpl(new OrderImpl(tsec, Direction.Long, x, p1))); bid = broker.BestBid(S); offer = broker.BestOffer(S); Assert.True(bid.IsValid && (bid.LimitPrice == p1) && (bid.Quantity == x), bid.ToString()); Assert.True(!offer.IsValid, offer.ToString()); // add better bid, make sure it's BBO OrderImpl o; // Order#1... 100 shares buy at $11 o = new OrderImpl(tsec, Direction.Long, x, p2); PendingOrderImpl po = new PendingOrderImpl(o); broker.SendOrderStatus(po); bid = broker.BestBid(S); offer = broker.BestOffer(S); Assert.True(bid.IsValid); Assert.Equal(p2, bid.LimitPrice); Assert.Equal(x, bid.Size); Assert.True(!offer.IsValid, offer.ToString()); // add another bid at same price on another account, make sure it's additive //order #2... 100 shares buy at $11 o = new OrderImpl(tsec, Direction.Long, x, p2); po = new PendingOrderImpl(o, new SimAccount("ANOTHER_ACCOUNT")); o.AccountName = "ANOTHER_ACCOUNT"; broker.SendOrderStatus(po); bid = broker.BestBid(S); offer = broker.BestOffer(S); Assert.True(bid.IsValid); Assert.Equal(p2, bid.LimitPrice); Assert.Equal(x * 2, bid.Size); Assert.True(!offer.IsValid, offer.ToString()); // cancel order and make sure bbo returns po.Cancel(); bid = broker.BestBid(S); offer = broker.BestOffer(S); Assert.True(bid.IsValid); Assert.Equal(p2, bid.LimitPrice); Assert.Equal(x, bid.Size); Assert.True(!offer.IsValid, offer.ToString()); // other test ideas // replicate above tests for sell-side }
/// <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); }