private bool AddOrder(OrderTracker tracker, double price) { bool matched = false; Order order = tracker.Order; if (order.IsBuy) { matched = MatchBidOrder(tracker, price, Asks); } else { matched = MatchAskOrder(tracker, price, Bids); } if (tracker.Open != 0 && !tracker.IsImmediate) { if (order.IsBuy) { Bids.Add(price, tracker); } else { Asks.Add(price, tracker); } } return(matched); }
protected virtual bool Matches(OrderTracker inbound, double inboundPrice, int inboundOpen, OrderTracker current, double currentPrice, bool isInboundBuy) { if (isInboundBuy) { if (inboundPrice < currentPrice) { return(false); } } else { if (inboundPrice > currentPrice) { return(false); } } if (current.IsInseparable) { if (current.Open > inboundOpen) { return(false); } } return(true); }
protected virtual bool ValidateReplace(OrderTracker order, int deltaSize, double price) { bool sizeDecreased = deltaSize < 0; if (sizeDecreased && (order.Open < Math.Abs(deltaSize))) { OnReplaceRejected(order.Order, "Insufficient open quantity", Transaction); return(false); } return(true); }
protected void CrossOrders(OrderTracker inbound, OrderTracker current) { int fillQuantity = Math.Min(inbound.Open, current.Open); double crossPrice = current.Order.Price; if (MarketOrderPrice == crossPrice) { crossPrice = inbound.Order.Price; } inbound.Fill(fillQuantity); current.Fill(fillQuantity); bool inboundFilled = inbound.IsFilled; bool matchedFilled = current.IsFilled; OnFilled(inbound.Order, current.Order, fillQuantity, crossPrice, inboundFilled, matchedFilled, Transaction); }
public virtual bool Add(Order order, OrderConditions conditions = OrderConditions.None) { ++Transaction; bool matched = false; if (!ValidateOrder(order, conditions)) { // rejected } else { double price = SortPrice(order); OrderTracker tracker = new OrderTracker(order, conditions); matched = AddOrder(tracker, price); if (matched) { // add tracker.Filled to OnAccepted OnAccepted(order, Transaction, tracker.Filled); } else { OnAccepted(order, Transaction, 0); } if (tracker.IsImmediate && !tracker.IsFilled) { // cancel order, transaction OnCanceled(order, 0, Transaction); } // update this, transaction OnBookUpdated(Transaction); } return(matched); }
public virtual void Replace(Order order, int deltaSize, double newPrice) { ++Transaction; bool matched = false; bool found = false; bool priceChanged = newPrice != 0 && newPrice != order.Price; double price = (newPrice == PriceUnchanged) ? order.Price : newPrice; if (order.IsBuy) { int index = FindBid(order); if (index != -1) { found = true; if (ValidateReplace(Bids.Values[index], deltaSize, price)) { OrderTracker tracker = Bids.Values[index]; OnReplaced(order, tracker.Open, deltaSize, price, Transaction); OnBookUpdated(Transaction); int newOpen = tracker.Open + deltaSize; tracker.ChangeQuantity(newOpen); if (newOpen == 0) { OnCanceled(order, 0, Transaction); Bids.RemoveAt(index); } else { matched = AddOrder(tracker, price); Bids.RemoveAt(index); } } } } else { int index = FindAsk(order); if (index != -1) { found = true; if (ValidateReplace(Asks.Values[index], deltaSize, price)) { OrderTracker tracker = Asks.Values[index]; OnReplaced(order, tracker.Open, deltaSize, price, Transaction); OnBookUpdated(Transaction); int newOpen = tracker.Open + deltaSize; tracker.ChangeQuantity(newOpen); if (newOpen == 0) { OnCanceled(order, 0, Transaction); Asks.RemoveAt(index); } else { matched = AddOrder(tracker, price); Asks.RemoveAt(index); } } } } if (!found) { OnReplaceRejected(order, "Order not found.", Transaction); } }
/// <summary> /// Matches a new bid order to current asks. /// </summary> /// <param name="order"></param> /// <param name="price"></param> /// <param name="asks"></param> /// <returns></returns> protected virtual bool MatchBidOrder(OrderTracker order, double price, OrderList asks) { bool matched = false; int matchedQuantity = 0; int orderQuantity = order.Open; for (int i = 0; i < asks.Count; i++) { if (Matches(order, price, order.Open - matchedQuantity, asks.Values[i], asks.Keys[i], true)) { if (order.IsInseparable) { matchedQuantity += asks.Values[i].Open; if (matchedQuantity >= orderQuantity) { matched = true; // unwind deferred crosses int adjustment = 0; for (int j = 0; j < DeferredAskCrosses.Count; j++) { int index = DeferredAskCrosses[j] - adjustment; CrossOrders(order, asks.Values[index]); if (asks.Values[index].IsFilled) { asks.RemoveAt(index); ++adjustment; DeferredAskCrosses.RemoveAt(j--); } else { DeferredAskCrosses[j] = index; } } } else { DeferredAskCrosses.Add(i); } } else { matched = true; } if (matched) { CrossOrders(order, asks.Values[i]); if (asks.Values[i].IsFilled) { asks.RemoveAt(i--); } if (order.IsFilled) { break; } } } else if (asks.Keys[i] > price) { break; } } return(matched); }