/** * Method invoked when an order book delta is reported. */ void onBookAtomicLevelDelta ( MamdaSubscription* subscription, MamdaBookAtomicListener& listener, const MamaMsg& msg, const MamdaBookAtomicLevel& level) { /** * The level should only be processed when entires are not received * i.e. for level only based feeds * If an entry was received on the previous level, then the level will * have been marked with an UNKNOWN side and should not be applied to * the book */ if(mReusablePriceLevel.getSide() != MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_UNKNOWN) { if (gExampleLogLevel == EXAMPLE_LOG_LEVEL_NORMAL && mOrderBook.getQuality() == MAMA_QUALITY_OK) { prettyPrint(subscription, mReusablePriceLevel); } applyLevel(mReusablePriceLevel); } /** * Store the current level */ storeLevel(level); }
/** * Method invoked when we stop processing the last level in a message. We * invoke this method after the last entry for the level gets processed. * The subscription may be destroyed from this callback. */ void onBookAtomicEndBook ( MamdaSubscription* subscription, MamdaBookAtomicListener& listener) { /** * When level recap/delta is received, it is stored in a MamdaOrderBookPriceLevel. * If no entry deltas/recaps are received, then the price level should be applied * to the book. * The entry delta/recap callback will mark the price level with an UNKNOWN side to * show that it does not need to be applied to the book */ if(mReusablePriceLevel.getSide() != MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_UNKNOWN) { if (gExampleLogLevel == EXAMPLE_LOG_LEVEL_NORMAL && mOrderBook.getQuality() == MAMA_QUALITY_OK) { prettyPrint(subscription, mReusablePriceLevel); } applyLevel(mReusablePriceLevel); mReusablePriceLevel.setSide(MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_UNKNOWN); } if(mOrderBook.getQuality() == MAMA_QUALITY_OK && gExampleLogLevel == EXAMPLE_LOG_LEVEL_NORMAL) { prettyPrint(mOrderBook); } cout<< "BOOK END\n"; }
/* * Helper function to print a MamdaOrderBookPriceLevel */ void prettyPrint( MamdaSubscription* subscription, const MamdaOrderBookPriceLevel& level) { // Print Entry Level Info const char* symbol = subscription->getSymbol (); const char* time = level.getTime().getTimeAsString(); double price = level.getPrice (); char side = level.getSide(); char action = level.getAction (); double size = level.getSize (); cout << "LEVEL " << symbol << " " << time << " " << action << " " << price << " " << side << " " << size << endl; }
/** * Method invoked when a full refresh of the order book for the * security is available. The reason for the invocation may be * any of the following: * - Initial image. * - Recap update (e.g., after server fault tolerant event or data * quality event.) * - After stale status removed. */ void onBookAtomicLevelRecap ( MamdaSubscription* subscription, MamdaBookAtomicListener& listener, const MamaMsg& msg, const MamdaBookAtomicLevel& level) { /** * The level should only be processed when entires are not received * i.e. for level only based feeds * If an entry was received on the previous level, then the level will * have been marked with an UNKNOWN side and should not be applied to * the book */ if(mReusablePriceLevel.getSide() != MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_UNKNOWN) { applyLevel (mReusablePriceLevel); } /** * Store the current level */ storeLevel(level); }
void MamdaOrderBookPriceLevel::setAsDifference ( const MamdaOrderBookPriceLevel& lhs, const MamdaOrderBookPriceLevel& rhs) { assert (lhs.getPrice() == rhs.getPrice()); MamdaOrderBookPriceLevel::iterator lhsEnd = end(); MamdaOrderBookPriceLevel::iterator lhsIter = begin(); MamdaOrderBookPriceLevel::iterator rhsEnd = end(); MamdaOrderBookPriceLevel::iterator rhsIter = begin(); while ((lhsIter != lhsEnd) && (rhsIter != rhsEnd)) { const char* lhsId = NULL; const char* rhsId = NULL; mama_quantity_t lhsSize = 0.0; mama_quantity_t rhsSize = 0.0; if (lhsIter != lhsEnd) { const MamdaOrderBookEntry* entry = *lhsIter; lhsId = entry->getId(); lhsSize = entry->getSize(); } if (rhsIter != rhsEnd) { const MamdaOrderBookEntry* entry = *rhsIter; rhsId = entry->getId(); rhsSize = entry->getSize(); } if (lhsId && rhsId) { if (strcmp(lhsId,rhsId)==0) { // Same ID, maybe different size. if (mama_isQuantityEqual (lhsSize, rhsSize)) { MamdaOrderBookEntry* updateEntry = new MamdaOrderBookEntry (**rhsIter); updateEntry->setAction( MamdaOrderBookEntry::MAMDA_BOOK_ACTION_UPDATE); addEntry (updateEntry); } ++lhsIter; ++rhsIter; continue; } else { // Different ID (either something exists on the LHS // and not on RHS or vice versa). MamdaOrderBookPriceLevel::const_iterator rhsFound = findEntryAfter (rhsIter, lhsId); if (rhsFound != rhsEnd) { // The ID from the LHS was found on the RHS, so // there must have been additional entries on the // RHS, which we now need to add. do { MamdaOrderBookEntry* entry = new MamdaOrderBookEntry(**rhsIter); addEntry (entry); ++rhsIter; } while (rhsIter != rhsFound); } else { // The ID from the LHS was not present on the RHS, // so add the LHS entry. Note: it would probably // be faster to iterate over the LHS side rather // than begin the loop again. MamdaOrderBookEntry* entry = new MamdaOrderBookEntry(**lhsIter); addEntry (entry); ++lhsIter; } } } } setPrice (rhs.getPrice()); setSizeChange (rhs.getSize() - lhs.getSize()); setSize (rhs.getSize()); setNumEntries (rhs.getNumEntries()); setAction (MamdaOrderBookPriceLevel::MAMDA_BOOK_ACTION_UPDATE); setTime (rhs.getTime()); setSide (rhs.getSide()); }