/// <summary> /// Create an order book listener using user-provided data /// structures for the full and delta order books. It is an error /// for the deltaBook to be NULL. If the fullBook is NULL, then /// there will be no cached order book (and therefore nothing to /// apply the delta order books to); this may be useful in some /// circumstances. /// </summary> /// <param name="fullBook"></param> /// <param name="deltaBook"></param> public MamdaOrderBookListener( MamdaOrderBook fullBook, MamdaOrderBook deltaBook) { mFullBook = fullBook; mDeltaBook = deltaBook; }
/// <summary> /// Set this order book to be a delta that would, when applied, be /// the difference between to other books. /// </summary> /// <param name="lhs">An order book.</param> /// <param name="rhs">An order book.</param> public void setAsDeltaDifference( MamdaOrderBook lhs, MamdaOrderBook rhs) { clear(); determineDiffs(mBidLevels, lhs.mBidLevels, rhs.mBidLevels, false); determineDiffs(mAskLevels, lhs.mAskLevels, rhs.mAskLevels, true); }
/// <summary> /// Order book equality verification. A MamdaOrderBookException is /// thrown if the books are not equal, along with the reason for /// the inequality. /// </summary> /// <param name="rhs">The order book to compare to the current book.</param> /// <exception cref="MamdaOrderBookException">Throws MamdaOrderBookException /// if the two books are not equal.</exception> public void assertEqual(MamdaOrderBook rhs) { if (mSymbol != rhs.mSymbol) { throw new MamdaOrderBookException( "different symbols: " + mSymbol + "/" + rhs.mSymbol); } assertEqual(mBidLevels, rhs.mBidLevels); assertEqual(mAskLevels, rhs.mAskLevels); }
internal void OnBookRecapCallback( MamdaSubscription subscription, MamdaOrderBookListener listener, MamaMsg msg, MamdaOrderBookDelta delta, MamdaOrderBookRecap recap) { long snappedSeqNum = listener.getSeqNum(); long realTimeSeqNum = mRealTimeListener.getSeqNum(); MamdaOrderBook fullBook = recap.getFullOrderBook(); if (snappedSeqNum != realTimeSeqNum) { mInconclusiveCount++; if (mHandler != null) { string reason = "sequence numbers differ (" + snappedSeqNum + "!=" + realTimeSeqNum; mHandler.onInconclusive(MamdaOrderBookCheckType.SNAPSHOT, reason); } } else { try { fullBook.assertEqual(mRealTimeListener.getFullOrderBook()); mSuccessCount++; if (mHandler != null) { mHandler.onSuccess(MamdaOrderBookCheckType.APPLY_DELTA); } } catch (MamdaOrderBookException e) { mFailureCount++; if (mHandler != null) { mHandler.onFailure(MamdaOrderBookCheckType.SNAPSHOT, e.ToString(), msg, mRealTimeListener.getFullOrderBook(), fullBook); } } } //Deactivate the subscription mSnapShotListener.clear(); mSnapShotSubsc.deactivate(); }
/// <summary> /// Returns a shallow copy of the underlying order book. /// As such this method should not be called from a separate thread. /// The recommended use of this method is to use a timer on the same queue /// as data for this book is being dispatched and grab the snapshot at /// regular intervals. /// </summary> /// <returns>A snapshot of the current Order Book</returns> public MamdaOrderBook getBookSnapshot() { MamdaOrderBook mSnapshot = null; if (mFullBook != null) { mSnapshot = new MamdaOrderBook(); // aquire lock lock (mFullBook) { mSnapshot.copy(mFullBook); mSnapshot.setSymbol(mFullBook.getSymbol()); mSnapshot.setIsConsistent(mFullBook.getIsConsistent()); } } return(mSnapshot); }
/// <summary> /// Returns a deep copy of the underlying order book. /// </summary> /// <returns>A deep snapshot of the current Order Book</returns> public MamdaOrderBook getDeepBookSnapshot() { MamdaOrderBook mSnapshot = null; if (null != mFullBook) { mSnapshot = new MamdaOrderBook(); // aquire lock lock (mFullBook) { mSnapshot.deepCopy(mFullBook); mSnapshot.setSymbol(mFullBook.getSymbol()); // strings are immutable, hence safe for assignment mSnapshot.setIsConsistent(mFullBook.getIsConsistent()); } } return(mSnapshot); }
private void getLevelInfo( MamdaOrderBookPriceLevel level, MamaMsg plMsg, MamdaOrderBook deltaBook) { level.setPrice(plMsg.getPrice(MamdaOrderBookFields.PL_PRICE)); level.setSize((long)plMsg.getF64(MamdaOrderBookFields.PL_SIZE, 0)); level.setNumEntries((int)plMsg.getF64(MamdaOrderBookFields.PL_NUM_ENTRIES, 1)); level.setAction((MamdaOrderBookPriceLevel.Actions)plMsg.getChar( MamdaOrderBookFields.PL_ACTION, 'A')); level.setSide((MamdaOrderBookPriceLevel.Sides)plMsg.getChar( MamdaOrderBookFields.PL_SIDE, 'B')); /* Optional order book fields: */ level.setSizeChange((long)plMsg.getF64(MamdaOrderBookFields.PL_SIZE_CHANGE, 0)); //default 0 level.setTime(plMsg.getDateTime(MamdaOrderBookFields.PL_TIME, deltaBook.getBookTime())); }
private void createDeltaFromMamaMsgWithVectorFields( MamdaOrderBook delta, MamaMsg[] msgLevels) { /* * Books with vector fields always come in a single MamaMsg. */ delta.clear(); for (int i = 0; i < msgLevels.Length; i++) { MamaMsg plMsg = msgLevels[i]; MamdaOrderBookPriceLevel level = new MamdaOrderBookPriceLevel(); getLevelInfo(level, plMsg, delta); getEntries(level, plMsg); delta.addLevel(level); } }
/// <summary> /// createDeltaFromMamaMsg processes a MamaMsg containing a partial /// or full order book and returns whether processing is complete /// </summary> /// <param name="delta"></param> /// <param name="msg"></param> /// <returns></returns> private bool createDeltaFromMamaMsg( MamdaOrderBook delta, MamaMsg msg) { // Note: the following test checks whether vector fields are part // of the data dictionary. However, the vector fields may indeed // be part of the data dictionary, but the message may still // contain the non-vector style order book data. if (MamdaOrderBookFields.getHasVectorFields()) { /* null is passed as default value otherwise * getVectorMsg throws an exception if not found*/ MamaMsg[] msgLevels = msg.getVectorMsg(MamdaOrderBookFields.PRICE_LEVELS, null); if (msgLevels != null) { createDeltaFromMamaMsgWithVectorFields(delta, msgLevels); return(true); } } return(createDeltaFromMamaMsgWithoutVectorFields(delta, msg)); }
/// <summary> /// Make a shallow copy of a book. /// </summary> /// <param name="book">The order book to copy.</param> public void copy(MamdaOrderBook book) { clear(); apply(book); }
/// <summary> /// Set this order book to be a delta that would, when applied, /// delete all of the fields in the bookToDelete. /// </summary> /// <param name="bookToDelete">The book to be deleted.</param> public void setAsDeltaDeleted(MamdaOrderBook bookToDelete) { copy(bookToDelete); markAllDeleted(mBidLevels); markAllDeleted(mAskLevels); }
/// <summary> /// Make a deep copy of a book. /// </summary> /// <param name="book">The order book to copy.</param> public void deepCopy(MamdaOrderBook book) { clear(); deepCopy(book.getBidLevels()); deepCopy(book.getAskLevels()); }
/// <summary> /// Apply a delta to this (presumably) full book. /// </summary> /// <param name="deltaBook">The delta to apply to the order book.</param> public void apply(MamdaOrderBook deltaBook) { apply(deltaBook.getBidLevels()); apply(deltaBook.getAskLevels()); }
/// <summary> /// Returns whether a complete book delta was received. /// /// Books without vector fields (i.e. fixed field layout) might /// come in multiple MamaMsgs. The MdMsgNum and MdTotalNum /// fields can be used to determine which message is which. /// /// When a single price level is present, it may or may not be /// encapsulated in a nested message field. Similarly, with single /// entries in a price level. /// </summary> /// <param name="delta"></param> /// <param name="msg"></param> /// <returns></returns> private bool createDeltaFromMamaMsgWithoutVectorFields( MamdaOrderBook delta, MamaMsg msg) { int msgNum = 1; int msgTotal = 1; if (msg.tryI32(MamaReservedFields.MsgNum, ref mMsgNum)) { msgNum = mMsgNum.Value; } if (msg.tryI32(MamaReservedFields.MsgTotal, ref mMsgTotal)) { msgTotal = mMsgTotal.Value; } if (msgNum == 1) { // Only clear the book if this is the first message in the // set of updates. delta.clear(); } if (!mHaveSanityCheckedBookDict) { mHaveSanityCheckedBookDict = true; if (MamdaOrderBookFields.PRICE_LEVEL.Length == 0) { throw new MamdaOrderBookException ( "data dictionary error: cannot find price level fields"); } } //for optimised feed date, wNumLevels should be assumed = 1 if not sent int numLevelFieldInMsg = 1; if (msg.tryI32(MamdaOrderBookFields.NUM_LEVELS, ref mNumLevelFields)) { numLevelFieldInMsg = mNumLevelFields.Value; } int maxLevelFields = MamdaOrderBookFields.PRICE_LEVEL.Length; if (numLevelFieldInMsg < maxLevelFields) { maxLevelFields = numLevelFieldInMsg; } for (int i = 1; i <= maxLevelFields; i++) { MamaMsg plMsg = msg.getMsg(MamdaOrderBookFields.PRICE_LEVEL[i], null); if (plMsg == null) { if (numLevelFieldInMsg == 1) { /* Price level fields are probably be in the main * message. */ plMsg = msg; } else { throw new MamdaDataException ( "cannot find price level fields in MamaMsg"); } } MamdaOrderBookPriceLevel level = new MamdaOrderBookPriceLevel(); getLevelInfo(level, plMsg, delta); getEntries(level, plMsg); delta.addLevel (level); } return msgNum == msgTotal; }
/// <summary> /// Returns a deep copy of the underlying order book. /// </summary> /// <returns>A deep snapshot of the current Order Book</returns> public MamdaOrderBook getDeepBookSnapshot() { MamdaOrderBook mSnapshot = null; if (null != mFullBook) { mSnapshot = new MamdaOrderBook(); // aquire lock lock (mFullBook) { mSnapshot.deepCopy(mFullBook); mSnapshot.setSymbol(mFullBook.getSymbol()); // strings are immutable, hence safe for assignment mSnapshot.setIsConsistent(mFullBook.getIsConsistent()); } } return mSnapshot; }
/// <summary> /// Create an order book listener using internally created data /// structures for the full and delta order books. /// </summary> public MamdaOrderBookListener() { mFullBook = new MamdaOrderBook(); mDeltaBook = new MamdaOrderBook(); }
/// <summary> /// Returns whether a complete book delta was received. /// /// Books without vector fields (i.e. fixed field layout) might /// come in multiple MamaMsgs. The MdMsgNum and MdTotalNum /// fields can be used to determine which message is which. /// /// When a single price level is present, it may or may not be /// encapsulated in a nested message field. Similarly, with single /// entries in a price level. /// </summary> /// <param name="delta"></param> /// <param name="msg"></param> /// <returns></returns> private bool createDeltaFromMamaMsgWithoutVectorFields( MamdaOrderBook delta, MamaMsg msg) { int msgNum = 1; int msgTotal = 1; if (msg.tryI32(MamaReservedFields.MsgNum, ref mMsgNum)) { msgNum = mMsgNum.Value; } if (msg.tryI32(MamaReservedFields.MsgTotal, ref mMsgTotal)) { msgTotal = mMsgTotal.Value; } if (msgNum == 1) { // Only clear the book if this is the first message in the // set of updates. delta.clear(); } if (!mHaveSanityCheckedBookDict) { mHaveSanityCheckedBookDict = true; if (MamdaOrderBookFields.PRICE_LEVEL.Length == 0) { throw new MamdaOrderBookException( "data dictionary error: cannot find price level fields"); } } //for optimised feed date, wNumLevels should be assumed = 1 if not sent int numLevelFieldInMsg = 1; if (msg.tryI32(MamdaOrderBookFields.NUM_LEVELS, ref mNumLevelFields)) { numLevelFieldInMsg = mNumLevelFields.Value; } int maxLevelFields = MamdaOrderBookFields.PRICE_LEVEL.Length; if (numLevelFieldInMsg < maxLevelFields) { maxLevelFields = numLevelFieldInMsg; } for (int i = 1; i <= maxLevelFields; i++) { MamaMsg plMsg = msg.getMsg(MamdaOrderBookFields.PRICE_LEVEL[i], null); if (plMsg == null) { if (numLevelFieldInMsg == 1) { /* Price level fields are probably be in the main * message. */ plMsg = msg; } else { throw new MamdaDataException( "cannot find price level fields in MamaMsg"); } } MamdaOrderBookPriceLevel level = new MamdaOrderBookPriceLevel(); getLevelInfo(level, plMsg, delta); getEntries(level, plMsg); delta.addLevel(level); } return(msgNum == msgTotal); }
/// <summary> /// Returns a shallow copy of the underlying order book. /// As such this method should not be called from a separate thread. /// The recommended use of this method is to use a timer on the same queue /// as data for this book is being dispatched and grab the snapshot at /// regular intervals. /// </summary> /// <returns>A snapshot of the current Order Book</returns> public MamdaOrderBook getBookSnapshot() { MamdaOrderBook mSnapshot = null; if (mFullBook != null) { mSnapshot = new MamdaOrderBook(); // aquire lock lock (mFullBook) { mSnapshot.copy(mFullBook); mSnapshot.setSymbol(mFullBook.getSymbol()); mSnapshot.setIsConsistent(mFullBook.getIsConsistent()); } } return mSnapshot; }
/// <summary> /// createDeltaFromMamaMsg processes a MamaMsg containing a partial /// or full order book and returns whether processing is complete /// </summary> /// <param name="delta"></param> /// <param name="msg"></param> /// <returns></returns> private bool createDeltaFromMamaMsg( MamdaOrderBook delta, MamaMsg msg) { // Note: the following test checks whether vector fields are part // of the data dictionary. However, the vector fields may indeed // be part of the data dictionary, but the message may still // contain the non-vector style order book data. if (MamdaOrderBookFields.getHasVectorFields()) { /* null is passed as default value otherwise getVectorMsg throws an exception if not found*/ MamaMsg[] msgLevels = msg.getVectorMsg(MamdaOrderBookFields.PRICE_LEVELS, null); if (msgLevels != null) { createDeltaFromMamaMsgWithVectorFields(delta, msgLevels); return true; } } return createDeltaFromMamaMsgWithoutVectorFields(delta, msg); }