public void CanSubmitBuyLimitOrder() { ILimitOrderBook lob = new LimitOrderBook.StandardLimitOrderBook(); Assert.IsNotNull(lob); Assert.AreEqual(0, lob.Bids.Count); Assert.IsInstanceOfType(lob, typeof(ILimitOrderBook)); var testOrder = new Order() { Price = 100, Quantity = 10, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" }; var testOrderGuid = testOrder.ID.ToString(); var result = lob.ProcessLimitOrder(testOrder,true); Assert.IsNotNull(result); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); Assert.AreEqual("Test", result.First().Order.UserID); Assert.AreEqual(testOrderGuid, result.First().Order.ID.ToString()); Assert.AreEqual(OrderSide.Buy, result.First().Order.Side); Assert.AreEqual(1, lob.Bids.Count); Assert.AreEqual(100, lob.BestBid.Price); Assert.AreEqual(10, lob.BestBid.Quantity); }
public virtual Order GetNextAction(LimitOrderBookSnapshot limitOrderBook) { var size = Math.Ceiling(_maxOrderSize * _rng.GetRandomDouble()); var priceDiff = _maxPriceDifferential * Math.Abs(_normal.Sample()); Order order; var randomNumber = _rng.GetRandomDouble(); if (randomNumber > (0.5 + (_doNothingProbability/2))) { //buylimitorder var price = Math.Round(limitOrderBook.BestAskPrice.Value - priceDiff, _decimals); order = new Order { Price = price, Quantity = size, Side = OrderSide.Buy,Type = OrderType.LimitOrder, Valid = true}; } else if (randomNumber < (0.5 - (_doNothingProbability/2))) { //selllimitorder var price = Math.Round(limitOrderBook.BestBidPrice.Value + priceDiff, _decimals); order = new Order { Price = price, Quantity = size, Side = OrderSide.Sell, Type = OrderType.LimitOrder, Valid = true }; } else { //donothing order = null; } return order; }
public Order[] GetNextActions(LimitOrderBookSnapshot limitOrderBook) { var order = base.GetNextAction(limitOrderBook); var orders = new List<Order>(); if (order != null) { if (_lastOrder != null) { //cancel previous var cancelOrder = new Order(); cancelOrder.Type = OrderType.Cancel; cancelOrder.ID = _lastOrder.ID; orders.Add(cancelOrder); } orders.Add(order); _lastOrder = order; } return orders.ToArray(); }
void _orderCommunicationsModule_OnOrder(Order order, string userID) { IEnumerable<OrderUpdate> orderUpdates = null; switch (order.Type) { case OrderType.LimitOrder: orderUpdates =_limitOrderBook.ProcessLimitOrder(order,true); break; case OrderType.MarketOrder: orderUpdates = _limitOrderBook.ProcessMarketOrder(order,true); break; case OrderType.StopLimitOrder: orderUpdates = _limitOrderBook.ProcessStopOrder(order); break; case OrderType.StopMarketOrder: orderUpdates = _limitOrderBook.ProcessStopOrder(order); break; case OrderType.Cancel: orderUpdates = _limitOrderBook.CancelOrder(order); break; case OrderType.Amend: orderUpdates = _limitOrderBook.AmendLimitOrder(order); break; default: throw new Exception("Unknown order type"); } if (orderUpdates != null) { foreach (var orderUpdate in orderUpdates) { _orderCommunicationsModule.PushOrderInstructionUpdate(orderUpdate, orderUpdate.Order.UserID); } } _dataCommunicationsModule.PushUpdate(_limitOrderBook); }
public Order GetNextAction(LimitOrderBookSnapshot limitOrderBook) { Order order; var size = Math.Ceiling(_maxOrderSize * _rng.GetRandomDouble()); var randomNumber = _rng.GetRandomDouble(); if (randomNumber < (0.5 - (_doNothingProbability / 2))) { //buymarketdorder order = new Order() {Quantity = size,Type = OrderType.MarketOrder, Side = OrderSide.Buy }; } else if (randomNumber > (0.5 + (_doNothingProbability / 2))) { order = new Order() { Quantity = size, Type = OrderType.MarketOrder, Side = OrderSide.Sell }; } else { //do nothing order = null; } return order; }
public IEnumerable<OrderUpdate> ProcessStopOrder(Order order) { switch (order.Side) { case OrderSide.Buy: if (BestAsk != null && BestAsk.Price <= order.StopPrice) { switch (order.Type) { case OrderType.StopLimitOrder: return ProcessLimitOrder(order,true); case OrderType.StopMarketOrder: return ProcessMarketOrder(order,true); default: break; } } else { if (!StopBids.ContainsKey(order.StopPrice.Value)) { StopBids.Add(order.StopPrice.Value, new Queue<Order>()); } StopBids[order.StopPrice.Value].Enqueue(order); } break; case OrderSide.Sell: if (BestBid != null && BestBid.Price >= order.StopPrice) { switch (order.Type) { case OrderType.StopLimitOrder: return ProcessLimitOrder(order,true); case OrderType.StopMarketOrder: return ProcessMarketOrder(order,true); default: break; } } else { if (!StopBids.ContainsKey(order.StopPrice.Value)) { StopBids.Add(order.StopPrice.Value, new Queue<Order>()); } StopBids[order.StopPrice.Value].Enqueue(order); } break; default: break; } return new OrderUpdate[] { new OrderUpdate() { Placed = true, Order = order, Message = "Stop order enqueued" }}; }
public IEnumerable<OrderUpdate> ProcessMarketOrder(Order order, bool checkStopOrders) { var results = new List<OrderUpdate>(); switch (order.Side) { case OrderSide.Buy: results.AddRange(ProcessBuyMarketOrder(order)); break; case OrderSide.Sell: results.AddRange(ProcessSellMarketOrder(order)); break; default: results.Add(new OrderUpdate() { Placed = false, Order = order, Message = "Order side not known" }); break; } if (checkStopOrders) results.AddRange(ClearStopOrders()); return results; }
public IEnumerable<OrderUpdate> CancelOrder(Order order) { return AmendLimitOrder(order, true); }
public void CanSubmitBuyMarketOrderSimple() { //ARRANGE ILimitOrderBook lob = new LimitOrderBook.StandardLimitOrderBook(); Assert.IsNotNull(lob); Assert.AreEqual(0, lob.Bids.Count); Assert.IsInstanceOfType(lob, typeof(ILimitOrderBook)); var setupOrder = new Order() { Price = 101, Quantity = 20, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" }; var result = lob.ProcessLimitOrder(setupOrder,true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); setupOrder = new Order() { Price = 101, Quantity = 10, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" }; result = lob.ProcessLimitOrder(setupOrder, true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); setupOrder = new Order() { Price = 103, Quantity = 30, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" }; result = lob.ProcessLimitOrder(setupOrder, true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); setupOrder = new Order() { Price = 104, Quantity = 15, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" }; result = lob.ProcessLimitOrder(setupOrder, true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); setupOrder = new Order() { Price = 104, Quantity = 5, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" }; result = lob.ProcessLimitOrder(setupOrder, true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); setupOrder = new Order() { Price = 105, Quantity = 50, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "Test" }; result = lob.ProcessLimitOrder(setupOrder, true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); setupOrder = new Order() { Price = 94, Quantity = 30, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" }; result = lob.ProcessLimitOrder(setupOrder, true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); setupOrder = new Order() { Price = 96, Quantity = 50, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" }; result = lob.ProcessLimitOrder(setupOrder, true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); setupOrder = new Order() { Price = 97, Quantity = 40, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" }; result = lob.ProcessLimitOrder(setupOrder, true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); setupOrder = new Order() { Price = 97, Quantity = 10, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" }; result = lob.ProcessLimitOrder(setupOrder, true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); setupOrder = new Order() { Price = 97, Quantity = 10, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "Test" }; result = lob.ProcessLimitOrder(setupOrder, true); Assert.AreEqual(1, result.Count()); Assert.AreEqual(true, result.First().Placed); //ACT var marketOrder = new Order() { Quantity = 15, Side = OrderSide.Buy, Type = OrderType.MarketOrder, UserID = "Test2" }; var testResult = lob.ProcessMarketOrder(marketOrder, true); Assert.AreEqual(1, result.Count()); //ASSERT Assert.AreEqual(2, lob.Asks[101].Count); Assert.AreEqual(5,lob.Asks[101].ElementAt(0).Quantity); Assert.AreEqual(10, lob.Asks[101].ElementAt(1).Quantity); Assert.AreEqual(1, lob.Asks[103].Count); Assert.AreEqual(30, lob.Asks[103].ElementAt(0).Quantity); Assert.AreEqual(2, lob.Asks[104].Count); Assert.AreEqual(15, lob.Asks[104].ElementAt(0).Quantity); Assert.AreEqual(5, lob.Asks[104].ElementAt(1).Quantity); Assert.AreEqual(1, lob.Asks[105].Count); Assert.AreEqual(50, lob.Asks[105].ElementAt(0).Quantity); Assert.AreEqual(3, lob.Bids[97].Count); Assert.AreEqual(40, lob.Bids[97].ElementAt(0).Quantity); Assert.AreEqual(10, lob.Bids[97].ElementAt(1).Quantity); Assert.AreEqual(10, lob.Bids[97].ElementAt(2).Quantity); Assert.AreEqual(1, lob.Bids[96].Count); Assert.AreEqual(50, lob.Bids[96].ElementAt(0).Quantity); Assert.AreEqual(1, lob.Bids[94].Count); Assert.AreEqual(30, lob.Bids[94].ElementAt(0).Quantity); }
public bool ProcessOrderInstruction(Order order, string userID) { RegisterUserID(userID, Context.ConnectionId); return _commsHandler.ProcessOrderInstruction(order,userID); }
public IEnumerable<OrderUpdate> AmendLimitOrder(Order order) { return AmendLimitOrder(order, false); }
public virtual Order FilterLimitOrders(Order order) { return order; }
public Order GetAction(int timeStep, double[] spotPrice, double[] fundamentalValue, double[] noise, double? bestBid, double? bestAsk) { var fundamentalTimeHorizon = _agentTimeHorizon; var lookBackTime = Math.Min(_agentTimeHorizon, timeStep)-1; var normalisationTerm = _fundamentalistWeighting + _chartistWeighting + _noiseWeighting; var fundamentalistTerm = (_fundamentalistWeighting * (decimal)Math.Log(fundamentalValue[timeStep - 1] / spotPrice[timeStep - 1])) / fundamentalTimeHorizon; //should the fundamental TH be added?? var averageReturn = CalculateAverageReturn(timeStep, spotPrice, lookBackTime); var chartistTerm = _chartistWeighting * averageReturn; var noiseTerm = _noiseWeighting * (decimal) noise[timeStep]; var expectedReturn = (fundamentalistTerm + chartistTerm + noiseTerm) / normalisationTerm; var expectedPrice = Math.Round(spotPrice[timeStep-1] * Math.Exp((double)(expectedReturn * _agentTimeHorizon)),4); var varianceOfPastReturns = CalculateVarianceOfPastReturns(timeStep, spotPrice, lookBackTime, averageReturn); var comfortPriceAtCurrentHolding = Math.Round(FindRoot(p => GetStocksToHold(p, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns) - StockHeld, expectedPrice, 0.0000001,0.01,expectedPrice), 4); var maxPrice = expectedPrice; var minPrice = FindRoot(p => p * (GetStocksToHold(p, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns) - StockHeld) - CashHeld, comfortPriceAtCurrentHolding, 0.0000001,0.1,expectedPrice); var drawnPrice = Math.Round(Math.Min(minPrice,maxPrice) + (Math.Abs(maxPrice-minPrice) * _randomGenerator.NextDouble()),4); var order = new Order(); if (drawnPrice < comfortPriceAtCurrentHolding) { //buy order.Side = OrderSide.Buy; if (bestAsk.HasValue && drawnPrice > bestAsk.Value) { //buy market order order.Quantity = GetStocksToHold(bestAsk.Value, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns) - StockHeld; order.Type = OrderType.MarketOrder; order.Price = bestAsk.Value; StockHeld += (int)order.Quantity; CashHeld -= order.Quantity * order.Price; } else { //buy limit order at drawnPrice order.Quantity = GetStocksToHold(drawnPrice, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns) - StockHeld; order.Type = OrderType.LimitOrder; order.Price = drawnPrice; } } else if (drawnPrice > comfortPriceAtCurrentHolding) { //sell order.Side = OrderSide.Sell; if (bestBid.HasValue && drawnPrice < bestBid.Value) { //sell market order order.Quantity = StockHeld - GetStocksToHold(bestBid.Value, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns); order.Type = OrderType.MarketOrder; order.Price = bestBid.Value; StockHeld -= (int)order.Quantity; CashHeld += order.Quantity * order.Price; } else { //sell limit order at drawnProce order.Quantity = StockHeld - GetStocksToHold(drawnPrice, expectedPrice, (double)_agentRiskAversionLevel, (double)varianceOfPastReturns); order.Type = OrderType.LimitOrder; order.Price = drawnPrice; } } else { //do nothing order = null; } return order; }
private IEnumerable<OrderUpdate> ProcessSellLimitOrder(Order order) { if (Bids.Any() && order.Price < Bids.Last().Key) { //cross order return new [] {new OrderUpdate() { Message = "Cross order", Order = order }}; } if (!Asks.Keys.Contains(order.Price)) { Asks.Add(order.Price, new Queue<Order>()); } Asks[order.Price].Enqueue(order); return new[] {new OrderUpdate() { Placed = true, Order = order }}; }
public MarketSimulator.Contracts.Order GetNextAction(MarketSimulator.Contracts.LimitOrderBookSnapshot limitOrderBookSnapshot, int day, int tradingPeriod) { if (!WillTradeInThisPeriod(day, tradingPeriod)) { return null; } var randomDraw = (ExpectedAssetLiquidationValue - ExpectedAssetLiquidationValueOrderRange) + (_random.NextDouble() * ExpectedAssetLiquidationValueOrderRange * 2); var orderQuantity = Math.Round(_random.NextDouble() * _maxOrderQuantity,0); Order order = new Order(); order.Price = randomDraw; order.Quantity = orderQuantity; order.UserID = _name; if (randomDraw > ExpectedAssetLiquidationValue) { //sell order.Side = OrderSide.Sell; if (limitOrderBookSnapshot != null && limitOrderBookSnapshot.BestBidPrice != null && randomDraw < limitOrderBookSnapshot.BestBidPrice) { //sell market order order.Type = OrderType.MarketOrder; } else { //sell limit order order.Type = OrderType.LimitOrder; } } else { //buy order.Side = OrderSide.Buy; if (limitOrderBookSnapshot != null && limitOrderBookSnapshot.BestAskPrice != null && randomDraw > limitOrderBookSnapshot.BestAskPrice) { //buy market order order.Type = OrderType.MarketOrder; } else { //buy limit order order.Type = OrderType.LimitOrder; } } order = FilterLimitOrders(order); return order; }
private IEnumerable<OrderUpdate> ProcessSellMarketOrder(Order order) { if (order.ExecutionValidity == OrderExecutionValidity.ForceOrKill) { if (order.Quantity > Bids.Sum(a => a.Value.Sum(l => l.Quantity))) { return new[] {new OrderUpdate() { Placed = false, Order = order, Message = "FOK validity and not enough depth" }}; } } var quantity = order.Quantity; var matches = new List<Match>(); var orderUpdates = new List<OrderUpdate>(); while (quantity > 0 && Bids.Count != 0) { var prices = Bids.Keys; for (int i = prices.Count - 1; i >= 0; i--) { var price = prices[i]; var orders = Bids[price]; while (orders.Any() && quantity > 0) { var nextOrder = orders.Peek(); if (!nextOrder.Valid) { orders.Dequeue(); continue; } if (nextOrder.Quantity > quantity) { nextOrder.Quantity -= quantity; matches.Add(new Match() { Price = price, Quantity = quantity }); orderUpdates.Add(new OrderUpdate() { Order = nextOrder, Matches = new List<Match> { new Match() { Price = price, Quantity = quantity } } }); quantity = 0; } if (nextOrder.Quantity <= quantity) { quantity -= nextOrder.Quantity; matches.Add(new Match() { Price = price, Quantity = nextOrder.Quantity }); orderUpdates.Add(new OrderUpdate() { Order = nextOrder, Matches = new List<Match> { new Match() { Price = price, Quantity = nextOrder.Quantity } } }); orders.Dequeue(); } } if (!orders.Any()) Bids.Remove(price); } } orderUpdates.Add(new OrderUpdate() { Placed = true, Order = order, Matches = matches }); return orderUpdates; }
static void Main(string[] args) { System.IO.File.WriteAllLines(@"c:\temp\test.csv", new string[] {"Time,BestBid,BestAsk"}); var providers = new List<LiquidityProvider>(); var rng = new CSharpRandomNumberGenerator() as IRandomNumberGenerator; var normalDist = new Normal(0, 0.01); var numLiquidityProviders = 10; var numLiquidityTakers = 10; for (int i = 0; i < numLiquidityProviders; i++) { providers.Add(new LiquidityProvider(rng,50,1,0.3,normalDist,4)); } var takers = new List<RandomLiquidityTaker>(); for (int i = 0; i < numLiquidityTakers; i++) { takers.Add(new RandomLiquidityTaker(rng, 5, 0.6)); } var connection = new HubConnection(@"http://localhost:8080/signalr"); var hub = connection.CreateHubProxy("market"); connection.Start().Wait(); System.Console.WriteLine("Connected"); hub.On<LimitOrderBookSnapshot>("Update", data => UpdateLimitOrderBook(data) ); var subscribeResult = hub.Invoke("SubscribeToDataFeed", "TestDriver"); subscribeResult.Wait(); var orders = new List<Order>(); orders.Add(new Order() { Price = 100, Quantity = 10, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "TestDriver" }); orders.Add(new Order() { Price = 99, Quantity = 10, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "TestDriver" }); orders.Add(new Order() { Price = 98, Quantity = 20, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "TestDriver" }); orders.Add(new Order() { Price = 99.5, Quantity = 3, Side = OrderSide.Buy, Type = OrderType.LimitOrder, UserID = "TestDriver" }); orders.Add(new Order() { Price = 102, Quantity = 10, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "TestDriver" }); orders.Add(new Order() { Price = 103, Quantity = 8, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "TestDriver" }); orders.Add(new Order() { Price = 102.5, Quantity = 19, Side = OrderSide.Sell, Type = OrderType.LimitOrder, UserID = "TestDriver" }); foreach (var order in orders) { var r = hub.Invoke<bool>("ProcessOrderInstruction", order, "TestDriver"); r.Wait(); } while (true) { Thread.Sleep(10); var rndLT = rng.GetRandomInt(0, numLiquidityTakers - 1); var rndLP = rng.GetRandomInt(0, numLiquidityProviders - 1); var rnd = rng.GetRandomInt(1, 100); Order[] orders2; if (rnd % 2 == 0) { orders2 = providers[rndLP].GetNextActions(_lob); } else { orders2 = new Order[] { takers[rndLT].GetNextAction(_lob) }; } foreach (var item in orders2) { if (item != null) { item.UserID = "TestDriver"; var r = hub.Invoke<bool>("ProcessOrderInstruction", item, "TestDriver"); r.Wait(); } } } }
public IEnumerable<OrderUpdate> AmendLimitOrder(Order order,bool cancel) { var amended = false; var remove = false; foreach (var bidGroup in Bids.Values) { foreach (var bid in bidGroup) { if (bid.ID == order.ID) { if (cancel) { bid.Valid = false; if (bidGroup.Count() <= 1) { remove = true; Bids.Remove(bid.Price); } return new[] {new OrderUpdate() { Amended = false,Message = "Order Canceled",Order = bid,Placed=false} }; } if (bid.Price != order.Price) { bid.Valid = false; if (bidGroup.Count() <= 1) { remove = true; Bids.Remove(bid.Price); } return ProcessLimitOrder(order,true); } else { bid.Quantity = order.Quantity; } return new[] {new OrderUpdate() { Amended = true,Message = "Order amended",Order = bid,Placed=true} }; } } } foreach (var askGroup in Asks.Values) { foreach (var ask in askGroup) { if (ask.ID == order.ID) { if (cancel) { ask.Valid = false; if (askGroup.Count() <= 1) { remove = true; Asks.Remove(ask.Price); } return new[] {new OrderUpdate() { Amended = false,Message = "Order Canceled",Order = ask,Placed=false} }; } if (ask.Price != order.Price) { ask.Valid = false; if (askGroup.Count() <= 1) { remove = true; Asks.Remove(ask.Price); } return ProcessLimitOrder(order,true); } else { ask.Quantity = order.Quantity; } return new[] {new OrderUpdate() { Amended = true,Message = "Order amended",Order = ask,Placed=true} }; } } } return new[] {new OrderUpdate() { Message = "Order not found", Order = order }}; }
public bool ProcessOrderInstruction(Order order, string userID) { OnOrder(order, userID); return true; }