// NOTE: In the context of the CME's data platform, a DELETE OrderAction means the deletion of an entire price level // from the book, not simply the deletion of a single order. Deletions of single // orders (while the price level remains intact) will be communicated via the // CHANGE OrderAction. /// <summary> /// Removes a price level from the limit order book. /// </summary> /// <param name="header"></param> /// <param name="update"></param> private void Delete(Header header, MarketDataIncrementalRefresh.RepeatingGroup update) { int level = update.MDPriceLevel; if (update.MDEntryType == MDEntryType.Bid) { // TO DO: Find a better way to implement below. //if (Bid[level].Price != update.MDEntryPx) //{ // throw new InvalidOperationException("Rebuild operation is attempting to delete a price level (" + update.MDEntryPx + ") that does not exist in the order book!"); //} ShiftDepthLevelsUp(Bid, header.SendingTime, from: level, to: Depth); if (level != Depth) return; Bid[level].Delete(header.SendingTime); } else if (update.MDEntryType == MDEntryType.Offer) { // TO DO: Find a better way to implement below. //if (Ask[level].Price != update.MDEntryPx) //{ // throw new InvalidOperationException("Rebuild operation is attempting to delete a price level (" + update.MDEntryPx + ") that does not exist in the order book!"); //} ShiftDepthLevelsUp(Ask, header.SendingTime, from: level, to: Depth); if (level != Depth) return; Ask[level].Delete(header.SendingTime); } }
/// <summary> /// Applies the current update to the limit order book. /// </summary> /// <param name="header"></param> /// <param name="update"></param> public void Build(Header header, MarketDataIncrementalRefresh.RepeatingGroup update) { if (update.MDUpdateAction == MDUpdateAction.New) { New(header, update); } else if (update.MDUpdateAction == MDUpdateAction.Change) { Change(header, update); } else if (update.MDUpdateAction == MDUpdateAction.Delete) { Delete(header, update); } UpdateTime = header.SendingTime; }
// NOTE: In the context of the CME's data platform, a CHANGE OrderAction means a change to the aggregate size // of a pre-existing level. It DOES NOT mean a change to the price of a resting order. // A change to the price of a resting order would be communicated via a DELETE OrderAction // at the old price, followed immediately by a NEW OrderAction at the new price. /// <summary> /// Modifies a price level which is already displayed in the limit order book. /// </summary> /// <param name="header"></param> /// <param name="update"></param> private void Change(Header header, MarketDataIncrementalRefresh.RepeatingGroup update) { int level = update.MDPriceLevel; if (update.MDEntryType == MDEntryType.Bid) { if (Bid[level].Price == null) { New(header, update); return; } Bid[level].Size = update.MDEntrySize; Bid[level].UpdateTime = header.SendingTime; Bid[level].NumberOfOrders = update.NumberOfOrders; } else if (update.MDEntryType == MDEntryType.Offer) { if (Ask[level].Price == null) { New(header, update); return; } Ask[level].Size = update.MDEntrySize; Ask[level].UpdateTime = header.SendingTime; Ask[level].NumberOfOrders = update.NumberOfOrders; } }
// NOTE: In the context of the CME's data platform, a NEW OrderAction means the addition of an entire price level // to the book, not simply the addition of a single order. Additions of single // orders (to a pre-existing price level) will be communicated via the // CHANGE OrderAction. /// <summary> /// Inserts a new price level into the limit order book. /// </summary> /// <param name="header"></param> /// <param name="update"></param> private void New(Header header, MarketDataIncrementalRefresh.RepeatingGroup update) { int level = update.MDPriceLevel; if (update.MDEntryType == MDEntryType.Bid) { ShiftDepthLevelsDown(Bid, from: Depth, to: level); Bid[level].Price = update.MDEntryPx; Bid[level].Size = update.MDEntrySize; Bid[level].UpdateTime = header.SendingTime; Bid[level].NumberOfOrders = update.NumberOfOrders; } else if (update.MDEntryType == MDEntryType.Offer) { ShiftDepthLevelsDown(Ask, from: Depth, to: level); Ask[level].Price = update.MDEntryPx; Ask[level].Size = update.MDEntrySize; Ask[level].UpdateTime = header.SendingTime; Ask[level].NumberOfOrders = update.NumberOfOrders; } }
public event HeaderEventHandler HeaderParsed = delegate { }; // Initializing to the empty anonymous method will ensure that the event is never null, even if no methods are subscribed to it. /// <summary> /// Wrapper around the 'HeaderParsed' event, called when the header of a message has been parsed. /// </summary> internal void OnHeaderParsed(Header header) { HeaderEventHandler invoker = HeaderParsed; invoker(header); }
public event DecodeStatusEventHandler DecodeStarted = delegate { }; // Initializing to the empty anonymous method will ensure that the event is never null, even if no methods are subscribed to it. /// <summary> /// Provides methods and properties for decoding FIX messages. /// </summary> public Decoder() { trailer = new Trailer(); header = new Header(tag, value, trailer, this); xupdate = new MarketDataIncrementalRefresh(tag, value, trailer, this); logout = new Logout(tag, value, trailer); logon = new Logon(tag, value, trailer); vupdate = new MarketDataRequest(tag, value, trailer); fupdate = new SecurityStatus(tag, value, trailer); dupdate = new SecurityDefinition(tag, value, trailer); rupdate = new QuoteRequest(tag, value, trailer); wupdate = new MarketDataSnapshotFullRefresh(tag, value, trailer); message = new Message(); }
/// <summary> /// Called when the header of a FIX message has been decoded. /// </summary> /// <param name="header"></param> protected virtual void OnHeaderParsed(Header header) { this.header = header; currentTime = header.SendingTime; RollOrderBooks(currentTime); messageContainsValidTrade = false; messageContainsValidQuote = false; }