void MamdaQuoteToBookListenerImpl::setQuality (
    MamdaSubscription*  sub,
    mamaQuality         quality)
{
    if (mFullBook->getQuality() == quality)
        return;  // no change

    mFullBook->setQuality (quality);
    switch (quality)
    {
    case MAMA_QUALITY_OK:
        break;
    case MAMA_QUALITY_STALE:
    case MAMA_QUALITY_MAYBE_STALE:
    case MAMA_QUALITY_PARTIAL_STALE:
    case MAMA_QUALITY_FORCED_STALE:
    case MAMA_QUALITY_UNKNOWN:
        if (mClearStaleBook)
        {
            acquireLock();
            clear();
            invokeClearHandlers (sub, NULL);
            releaseLock();
        }
    }
}
示例#2
0
int main (int argc, const char** argv)
{
    MamdaOrderBook  book;
    setbuf (stdout, NULL);
    book.setSymbol (symbol);

    // Populate an order book with N price levels ranging from 50.00
    // to 150.00, with M entries in each level.
    char uniqueId[32];
    for (int level = 0; level < N; level++)
    {
        MamdaOrderBookTypes::Side side = (level < N/2) ?
                                         MamdaOrderBookTypes::MAMDA_BOOK_SIDE_BID :
                                         MamdaOrderBookTypes::MAMDA_BOOK_SIDE_ASK;
        double price = 50.0 + (100.0 * level/(double)N);

        for (int entry = 0; entry < M; entry++)
        {
            mama_u64_t   size = 10 * entry;
            MamaDateTime now;
            now.setToNow();
            snprintf(uniqueId, 32, "%s%.4g%c", symbol, price, (char)side);
//            book.addUniqueEntry (uniqueId, price, size, side, now);
        }
    }

    return 0;
}
示例#3
0
    /**
     * 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";
    }
示例#4
0
void BookViewer::displayLevels (const MamdaOrderBook&  book)
{
    const char* symbol = book.getSymbol ();
    int symbolCol = sMidColumn - (strlen (symbol)/2);
    attron (A_BOLD);
    mvprintw (0, symbolCol, "%s", symbol);
    mvprintw (1, 0, "%s | %s",
             "        Time     Num    Size   Price",
             "Price   Size    Num       Time  ");
    attroff (A_BOLD);

    MamdaOrderBook::constBidIterator bidIter = book.bidBegin ();
    MamdaOrderBook::constBidIterator bidEnd  = book.bidEnd ();
    MamdaOrderBook::constAskIterator askIter = book.askBegin ();
    MamdaOrderBook::constAskIterator askEnd  = book.askEnd ();

    for (int i = 2; i < LINES-1; i++)
    {
        move (i, 0);
        if (i < 7)
            attron (COLOR_PAIR (i-1));
        if (bidIter != bidEnd)
        {
            const MamdaOrderBookPriceLevel* bidLevel = *bidIter;
            printw ("   %12s %4d %7d %7.4f ",
                    bidLevel->getTime ().getTimeAsString (),
                    bidLevel->getNumEntries (),
                    (long)bidLevel->getSize (),
                    bidLevel->getPrice ());
            ++bidIter;
        }
        else
        {
            printw ("                                     ");
        }

        printw ("|");

        if (askIter!= askEnd)
        {
            const MamdaOrderBookPriceLevel* askLevel = *askIter;
            printw (" %-7.4f %-7d %-6d %-12s   ",
                    askLevel->getPrice (),
                    (long)askLevel->getSize (),
                    askLevel->getNumEntries (),
                    askLevel->getTime ().getTimeAsString ());
            ++askIter;
        }
        else
        {
            printw ("                                     ");
        }
        if (i < 7)
            attroff (COLOR_PAIR (i-1));
    }
    refresh ();  // refresh the screen
}
示例#5
0
void BookViewer::displayEntries (const MamdaOrderBook&  book)
{
    const char* symbol = book.getSymbol ();
    int symbolCol = sMidColumn - (strlen (symbol)/2);
    attron (A_BOLD);
    mvprintw (0, symbolCol, "%s", symbol);
    attroff (A_BOLD);

    /* Bid entries */
    attron (A_BOLD);
    mvprintw (1, 0, "%s", sBidHeading);
    attroff (A_BOLD);
    MamdaOrderBook::constBidIterator bidIter = book.bidBegin ();
    MamdaOrderBook::constBidIterator bidEnd  = book.bidEnd ();
    int colorId = 1;
    for (int i = 2; i < LINES-1;)
    {
        if (bidIter != bidEnd)
        {
            const MamdaOrderBookPriceLevel* bidLevel = *bidIter;
            displayBidEntriesInLevel (bidLevel, i, colorId);
            ++bidIter;
            ++colorId;
        }
        else
        {
            mvprintw (i, 0, "                                              |");
            i++;
        }
    }

    /* Ask entries */
    attron (A_BOLD);
    mvprintw (1, sMidColumn+1, "%s", sAskHeading);
    attroff (A_BOLD);
    MamdaOrderBook::constAskIterator askIter = book.askBegin ();
    MamdaOrderBook::constAskIterator askEnd  = book.askEnd ();
    colorId = 1;
    for (int i = 2; i < LINES-1;)
    {
        if (askIter!= askEnd)
        {
            const MamdaOrderBookPriceLevel* askLevel = *askIter;
            displayAskEntriesInLevel (askLevel, i, colorId);
            ++askIter;
            ++colorId;
        }
        else
        {
            mvprintw (i, sMidColumn+1,
                     "                                              ");
            i++;
        }
    }

    refresh ();  // refresh the screen
}
示例#6
0
 AtomicBookBuilder (
     const char* symbol)
     : mShowEntries      (false)
     , mShowMarketOrders (false)
     , mEntryPtr         (NULL)
     , mLevelPtr         (NULL)
     , mSymbol           (strdup(symbol))
 {
     mOrderBook.setSymbol  (mSymbol);
     mOrderBook.setQuality (MAMA_QUALITY_OK);
 }
void BookPublisher::createBook (const char* symbol, const char* partId) 
{ 
    mBook = new MamdaOrderBook();
    // This turns on the generation of deltas at the order book 
    mBook->generateDeltaMsgs (true);
    if (symbol) mBook->setSymbol (symbol); 
    if (partId) mBook->setPartId (partId); 
    mBookTime.setToNow();
    mBook->setBookTime (mBookTime);
    mSymbolList.push_back (symbol);
}
void MamdaQuoteToBookListenerImpl::handleRecap (MamdaSubscription*  subscription,
                                const MamaMsg&      msg)
{
    // Clear the book
    mFullBook->clear();

    // Clear ask/bid 
    mQuoteCache.mBidPrice = 0.0;
    mQuoteCache.mBidSize  = 0.0;
    mQuoteCache.mAskPrice = 0.0;
    mQuoteCache.mAskSize  = 0.0;

    // get all the fields out of the message
    updateQuoteFields (msg);

    checkQuoteCount (subscription, msg);

    if (mFullBook->getIsConsistent()==false)
    {
        mama_log (MAMA_LOG_LEVEL_NORMAL,
            "Received Recap: Book now consistent for  %s\n",
            (subscription ? subscription->getSymbol() : "no symbol"));
    }

    MamdaOrderBookPriceLevel* level = NULL;
    if (mQuoteCache.mGotBidSize || mQuoteCache.mGotBidPrice)
    {
        addLevel (level, 
                  mQuoteCache.mBidPrice.getValue(), 
                  mQuoteCache.mBidSize, 
                  MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_BID,
                  mQuoteCache.mQuoteTime);
    }

    if (mQuoteCache.mGotAskSize || mQuoteCache.mGotAskPrice)
    {
        addLevel (level, 
                  mQuoteCache.mAskPrice.getValue(), 
                  mQuoteCache.mAskSize, 
                  MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_ASK,
                  mQuoteCache.mQuoteTime);
    }

    mFullBook->setIsConsistent (true);
    setQuality (subscription, MAMA_QUALITY_OK);
    invokeRecapHandlers (subscription, &msg);
    MamdaOrderBookComplexDelta::clear();
}
示例#9
0
 /**
  * Method invoked when an order book is cleared.
  */
 void onBookAtomicClear (
     MamdaSubscription*          subscription,
     MamdaBookAtomicListener&    listener,
     const MamaMsg&              msg)
 {
     mOrderBook.clear();
 }
示例#10
0
void BookPublisher::subscribeToSymbols () 
{ 

    for (vector<const char*>::const_iterator i = mSymbolList.begin ();
         i != mSymbolList.end ();
         ++i)
    {   
        const char* symbol = *i;
        mBook = new MamdaOrderBook();
        // Turn on delta generation
        mBook->generateDeltaMsgs(true);
        MamdaSubscription*      aSubscription = new MamdaSubscription;
        MamdaOrderBookListener* aBookListener = new MamdaOrderBookListener(mBook);
        aSubscription->addMsgListener (aBookListener);
        aBookListener->setProcessEntries (mProcessEntries);

        BookTicker* aTicker = new BookTicker;
        aBookListener->addHandler (aTicker);
       
        aSubscription->setType (MAMA_SUBSC_TYPE_BOOK);
        aSubscription->setMdDataType (MAMA_MD_DATA_TYPE_ORDER_BOOK);
        mSubscriptionList.push_back (aSubscription);

        aSubscription->create (Mama::getDefaultEventQueue (mBridge), mSubSource, symbol, NULL);

    }
}
const char* MamdaQuoteToBookListenerImpl::getSymbol() const
{
    if (mFullBook)
        return mFullBook->getSymbol();
    else
        return "unknown-symbol";
}
void MamdaQuoteToBookListenerImpl::invokeDeltaHandlers (
    MamdaSubscription*  subscription,
    const MamaMsg*      msg)
{
    if (mCurrentDeltaCount == 0)
    {
        // no deltas - no change to the top of book on this update.
        return;
    }
    deque<MamdaOrderBookHandler*>::iterator end = mHandlers.end();
    deque<MamdaOrderBookHandler*>::iterator i   = mHandlers.begin();
    for (; i != end; ++i)
    {
        MamdaOrderBookHandler* handler = *i;

        if (mCurrentDeltaCount == 1)
        {
            handler->onBookDelta (subscription, mListener, msg,
                                  *this, *mFullBook);
        }
        else
        {
            MamdaOrderBookComplexDelta::setOrderBook(mFullBook);
            handler->onBookComplexDelta (subscription, mListener, msg,
                                         *this, *mFullBook);
            MamdaOrderBookComplexDelta::clear();
        }
    }

    mFullBook->cleanupDetached();
    mCurrentDeltaCount =0;
}
示例#13
0
    /**
     * 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);
    }
void MamdaQuoteToBookListenerImpl::checkQuoteCount (
    MamdaSubscription*  subscription,
    const MamaMsg&      msg)
{
    // Check number of quotes for gaps
    mama_u32_t quoteCount = mQuoteCache.mTmpQuoteCount;
    mama_u16_t conflateCount = 0;
    if (!msg.tryU16 ("wConflateQuoteCount", 23, conflateCount))
    {
        conflateCount = 1;
    }

    if (quoteCount > 0)
    {
        if ((mQuoteCache.mQuoteCount > 0) &&
            (quoteCount > (mQuoteCache.mQuoteCount+conflateCount)))
        {
            mGapBegin = mQuoteCache.mQuoteCount+conflateCount;
            mGapEnd   = quoteCount-1;
            mQuoteCache.mQuoteCount = quoteCount;
            mFullBook->setIsConsistent (false);
            invokeGapHandlers (subscription, &msg);
        }
    }
    mQuoteCache.mQuoteCount = quoteCount;
}
 void onFailure (MamdaOrderBookCheckType  type,
                 const char*              reason,
                 const MamaMsg*           msg,
                 const MamdaOrderBook&    realTimeBook,
                 const MamdaOrderBook&    checkBook)
 {
     cout << "Failed check ("
          << mamdaOrderBookCheckTypeToString(type) << "): "
          << reason << "\n";
     if (gExampleLogLevel >= EXAMPLE_LOG_LEVEL_QUIET)
     {
         if (msg)
             cout << "Failed message: " << msg->toString() << "\n";
         cout << "Failed current book: ";  realTimeBook.dump(cout);
         cout << "Failed checking book: "; checkBook.dump(cout);
         cout << "\n";
     }
 }
示例#16
0
    void onQuality (MamdaSubscription* subscription, mamaQuality quality)
    {
        if (gExampleLogLevel == EXAMPLE_LOG_LEVEL_NORMAL)
        {
            cout << "atomicbookbuilder: QUALITY: " << quality << "\n";
        }

        mOrderBook.setQuality (quality);
    }
示例#17
0
 void onBookGap (
     MamdaSubscription*          subscription,
     MamdaOrderBookListener&     listener,
     const MamaMsg*              msg,
     const MamdaOrderBookGap&    event,
     const MamdaOrderBook&       book)
 {
     printf("\n Book Gap \n");
     book.dump(std::cout);
 }
void MamdaQuoteToBookListenerImpl::deleteLevel (
    MamdaOrderBookPriceLevel*         level,
    MamdaOrderBookPriceLevel::Side    plSide,
    const MamaDateTime&               plTime)
{
    mFullBook->detach (level); // remove level from book, but still use level for indicating change
    level->setTime (plTime);
    level->setSize (0); 
    addDelta (level, (0-level->getSize()), MamdaOrderBookPriceLevel::MAMDA_BOOK_ACTION_DELETE);
}
示例#19
0
 void onBookDelta (
     MamdaSubscription*                 subscription,
     MamdaOrderBookListener&            listener,
     const MamaMsg*                     msg,
     const MamdaOrderBookSimpleDelta&   delta,
     const MamdaOrderBook&              book)
 {
     printf("\n Book Delta \n");
     book.dump(std::cout);
 }
void MamdaQuoteToBookListenerImpl::clear()
{
    acquireLock();
    mQuoteCache.initialize();
    mEventSeqNum = 0;
    mGapBegin = 0;
    mGapEnd = 0;
    mFullBook->clear();
    releaseLock();
}
示例#21
0
 void onBookClear (
     MamdaSubscription*          subscription,
     MamdaOrderBookListener&     listener,
     const MamaMsg*              msg,
     const MamdaOrderBookClear&  clear,
     const MamdaOrderBook&       book)
 {
     printf("\n Book Clear \n");
     book.dump(std::cout);
 }
示例#22
0
 void onBookRecap (
     MamdaSubscription*                 subscription,
     MamdaOrderBookListener&            listener,
     const MamaMsg*                     msg,
     const MamdaOrderBookComplexDelta*  delta,
     const MamdaOrderBookRecap&         recap,
     const MamdaOrderBook&              book)
 {
     printf("\n Book Recap \n");
     book.dump(std::cout);
 }
void MamdaQuoteToBookListenerImpl::addLevel (
    MamdaOrderBookPriceLevel*&        level,
    double                            plPrice,
    mama_f64_t                        plSize,
    MamdaOrderBookPriceLevel::Side    plSide,
    const MamaDateTime&               plTime)
{
    level = mFullBook->findOrCreateLevel (plPrice, plSide);
    level->setTime (plTime);
    level->setSize (plSize);
    addDelta (level, plSize, MamdaOrderBookPriceLevel::MAMDA_BOOK_ACTION_ADD);
}
示例#24
0
    /**
     * Method invoked before we start processing the first level in a message.
     * The book should be cleared when isRecap == true.
     */
    void onBookAtomicBeginBook (
        MamdaSubscription*           subscription,
        MamdaBookAtomicListener&     listener,
        bool                         isRecap)

    {
        cout<< "BOOK BEGIN\n";
        if(isRecap)
            mOrderBook.clear();

        if(mOrderBook.getQuality() == MAMA_QUALITY_OK)
        {
            if(isRecap)
            {
                cout << "RECAP!!!\n";
            }
            else
            {
                cout << "DELTA!!!\n";
            }
        }
    }
void BookPublisher::onTimer (MamaTimer* timer)
{  
    if (!mPublishing) return;
    //  On every timer update we take the next order from the orderArray and processEntries

    // clear book when at end of orderArray
    // To avoid editing the book while publishing using multiple threads, we need to have a 
    // lock during the book editing functionality and also when sending initial/recap data.
    // We use the MamdaLock class for this functionality and have two functions called
    // acquireLock() and releaseLock() that implement this functionality. 
    acquireLock();
    bool publish = false;
    if (10 == mOrderCount)
    {
        mBook->clear(true);
        mOrderCount = 0;
        mPublishMsg.updateU8 (NULL, MamaFieldMsgType.mFid, MAMA_MSG_TYPE_BOOK_CLEAR);
        publish = true;
    }
    else
    { 
        // process multiple orders, alike a complex update
        processOrder();
        processOrder();
        // get changes to the book and publish
        if (mPublishRecaps)
        {
            mBook->populateRecap(mPublishMsg);
            publish=true;
        }
        else
        {
            publish = mBook->populateDelta(mPublishMsg);
        }
    }
    if (publish) publishMessage(NULL);    
    releaseLock();
}
示例#26
0
    /**
     * Method invoked when an order book delta is reported.
     */
    void onBookAtomicLevelEntryDelta (
        MamdaSubscription*                  subscription,
        MamdaBookAtomicListener&            listener,
        const MamaMsg&                      msg,
        const MamdaBookAtomicLevelEntry&    levelEntry)
    {
        if (gExampleLogLevel == EXAMPLE_LOG_LEVEL_NORMAL
                && mOrderBook.getQuality() == MAMA_QUALITY_OK)
        {
            prettyPrint (subscription, levelEntry);
        }
        applyEntry (levelEntry);

        /**
         * An entry has been processed on the level so mark the level with
         *  an unknown side so that it will not be applied to book
         */
        mReusablePriceLevel.setSide (MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_UNKNOWN);
    }
示例#27
0
void BookPublisher::onTimer (MamaTimer* timer)
{  
    // need to clear publishMsg after every update
    const char* symbol;
    for (vector<const char*>::const_iterator i = mSymbolList.begin ();
         i != mSymbolList.end ();
         ++i)
    {
        symbol = (const char*)*i;
        acquireLock (symbol);
        mPublishMsg.clear();
        if (mBook->populateDelta (mPublishMsg))
        {
            publishMessage (NULL, symbol);
            printf ("\n Publishing Message:- %s \n", mPublishMsg.toString());

        }       
        else printf ("\n Not publishing from Empty State \n");
        releaseLock (symbol);
    }

}
void MamdaQuoteToBookListenerImpl::handleQuote (MamdaSubscription*  subscription,
                                                const MamaMsg&      msg)
{
    checkQuoteCount (subscription, msg);

    MamdaOrderBookPriceLevel* level = NULL;
    if (mQuoteCache.mGotBidSize || mQuoteCache.mGotBidPrice)
    {
        // get current level
        MamdaOrderBook::bidIterator bidIter = mFullBook->bidBegin();
        if (bidIter == mFullBook->bidEnd())
            level = NULL;
        else
            level = *bidIter;
        if (level == NULL)
        {
            if (mQuoteCache.mBidSize == (mama_quantity_t)0 || mQuoteCache.mBidPrice.isZero())
            {
                if (mQuoteCache.mBidSize == (mama_quantity_t)0 && mQuoteCache.mBidPrice.isZero())
                {
                    mama_log (MAMA_LOG_LEVEL_WARN,
                              "MamdaQuoteToBookListener: Got bid update, but price and size are 0\n");
                }
            }
            else
            {
                addLevel (level, 
                          mQuoteCache.mBidPrice.getValue(), 
                          mQuoteCache.mBidSize, 
                          MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_BID, 
                          mQuoteCache.mQuoteTime);
            }
        }
        else
        {
            if ((mQuoteCache.mBidSize == 0) || (mQuoteCache.mBidPrice.isZero()))
            {
                deleteLevel (level, MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_BID, mQuoteCache.mQuoteTime);
            }
            else if (mQuoteCache.mBidPrice == level->getPrice())
            {
                updateLevel (level,  
                             mQuoteCache.mBidSize, 
                             mQuoteCache.mBidSize - level->getSize(), 
                             MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_BID, 
                             mQuoteCache.mQuoteTime);
            }
            else
            {
                deleteLevel (level, 
                             MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_BID, 
                             mQuoteCache.mQuoteTime);
                addLevel (level, 
                          mQuoteCache.mBidPrice.getValue(), 
                          mQuoteCache.mBidSize, 
                          MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_BID,
                          mQuoteCache.mQuoteTime);
            }
        }
    } 

    if (mQuoteCache.mGotAskSize || mQuoteCache.mGotAskPrice)
    {
        // get current level
        MamdaOrderBook::askIterator askIter = mFullBook->askBegin();
        if (askIter == mFullBook->askEnd())
            level = NULL;
        else
            level = *askIter;
        if (level == NULL)
        {
            if (mQuoteCache.mAskSize == (mama_quantity_t)0 || mQuoteCache.mAskPrice.isZero())
            {
                if (mQuoteCache.mAskSize == (mama_quantity_t)0 && mQuoteCache.mAskPrice.isZero())
                {
                    mama_log (MAMA_LOG_LEVEL_WARN,
                        "MamdaQuoteToBookListener: Got ask update, but price and size are 0\n");
                }
            }
            else
            {
                addLevel (level, 
                          mQuoteCache.mAskPrice.getValue(), 
                          mQuoteCache.mAskSize, 
                          MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_ASK, 
                          mQuoteCache.mQuoteTime);
            }
        }
        else
        {
            if ((mQuoteCache.mAskSize == 0) || (mQuoteCache.mAskPrice.isZero()))
            {
                deleteLevel (level, MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_ASK, mQuoteCache.mQuoteTime);
            }
            else if (mQuoteCache.mAskPrice == level->getPrice())
            {
                updateLevel (level, 
                             mQuoteCache.mAskSize, 
                             mQuoteCache.mAskSize - level->getSize(),
                             MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_ASK, 
                             mQuoteCache.mQuoteTime);
            }
            else
            {
                deleteLevel (level, 
                             MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_ASK, 
                             mQuoteCache.mQuoteTime);
                addLevel (level, 
                          mQuoteCache.mAskPrice.getValue(), 
                          mQuoteCache.mAskSize, 
                          MamdaOrderBookPriceLevel::MAMDA_BOOK_SIDE_ASK, 
                          mQuoteCache.mQuoteTime);
            }
        }
    }
    
    if (mUpdateInconsistentBook || mFullBook->getIsConsistent())
    {
        invokeDeltaHandlers (subscription, &msg);
    } 
}
    void prettyPrintEntries (const MamdaOrderBook&  book)
    {
        printf ("%s\n",
            "     ID/Num           Time       Size   Price");
        MamdaOrderBook::constBidIterator bidIter = book.bidBegin ();
        MamdaOrderBook::constBidIterator bidEnd  = book.bidEnd ();
        MamdaOrderBook::constAskIterator askIter = book.askBegin ();
        MamdaOrderBook::constAskIterator askEnd  = book.askEnd ();
        char timeStr[32];
        
        if (mShowMarketOrders)
        {
            const MamdaOrderBookPriceLevel* marketBidLevel =
                  book.getBidMarketOrders ();
            if (marketBidLevel)
            {
                marketBidLevel->getTime().getAsFormattedString (timeStr, 32, "%T%;");
                printf ("  Bid  %4d       %12s %7g  MARKET\n",
                        marketBidLevel->getNumEntries (),
                        timeStr,
                        marketBidLevel->getSize ());
                MamdaOrderBookPriceLevel::const_iterator end = marketBidLevel->end ();
                MamdaOrderBookPriceLevel::const_iterator i   = marketBidLevel->begin ();
                while (i != end)
                {
                    const MamdaOrderBookEntry* entry = *i;
                    const char*      id    = entry->getId ();
                    mama_quantity_t  size  = entry->getSize ();
                    entry->getTime().getAsFormattedString (timeStr, 32, "%T%;");
                    printf ("  %14s  %12s %7g  MARKET\n",
                            id, timeStr, size);
                    ++i;
                }
            }
        }

        if (mShowMarketOrders)
        {
            const MamdaOrderBookPriceLevel* marketAskLevel =
                book.getAskMarketOrders ();
            if (marketAskLevel)
            {
                marketAskLevel->getTime().getAsFormattedString (timeStr, 32, "%T%;");
                printf ("  Ask  %4d       %12s %7g  MARKET\n",
                        marketAskLevel->getNumEntries (),
                        timeStr,
                        marketAskLevel->getSize ());
                MamdaOrderBookPriceLevel::const_iterator end = marketAskLevel->end ();
                MamdaOrderBookPriceLevel::const_iterator i   = marketAskLevel->begin ();
                while (i != end)
                {
                    const MamdaOrderBookEntry* entry = *i;
                    const char*      id    = entry->getId ();
                    mama_quantity_t  size  = entry->getSize ();
                    entry->getTime().getAsFormattedString (timeStr, 32, "%T%;");
                    printf ("  %14s  %12s %7g  MARKET\n",
                            id, timeStr, size);
                    ++i;
                }   
            }
        }

        while (bidIter != bidEnd)
        {
            const MamdaOrderBookPriceLevel* bidLevel = *bidIter;
            bidLevel->getTime().getAsFormattedString (timeStr, 32, "%T%;");
            printf ("  Bid  %4d       %12s %7g %7.*f\n",
                    bidLevel->getNumEntries (),
                    timeStr,
                    bidLevel->getSize (),
                    mPrecision,
                    bidLevel->getPrice ());
            MamdaOrderBookPriceLevel::const_iterator end = bidLevel->end ();
            MamdaOrderBookPriceLevel::const_iterator i   = bidLevel->begin ();
            while (i != end)
            {
                const MamdaOrderBookEntry* entry = *i;
                const char*      id    = entry->getId ();
                mama_quantity_t  size  = entry->getSize ();
                double           price = bidLevel->getPrice ();
                entry->getTime().getAsFormattedString (timeStr, 32, "%T%;");
                printf ("  %14s  %12s %7g %7.*f\n", 
                        id, timeStr, size, mPrecision, price);
                ++i;
            }
            ++bidIter;
        }
        
        while (askIter != askEnd)
        {
            const MamdaOrderBookPriceLevel* askLevel = *askIter;
            askLevel->getTime().getAsFormattedString (timeStr, 32, "%T%;");
            printf ("  Ask  %4d       %12s %7g %7.*f\n",
                    askLevel->getNumEntries (),
                    timeStr,
                    askLevel->getSize (),
                    mPrecision,
                    askLevel->getPrice ());
            MamdaOrderBookPriceLevel::const_iterator end = askLevel->end ();
            MamdaOrderBookPriceLevel::const_iterator i   = askLevel->begin ();
            while (i != end)
            {
                const MamdaOrderBookEntry* entry = *i;
                const char*      id    = entry->getId ();
                mama_quantity_t  size  = entry->getSize ();
                double           price = askLevel->getPrice ();
                entry->getTime().getAsFormattedString (timeStr, 32, "%T%;");
                printf ("  %14s  %12s %7g %7.*f\n",
                        id, timeStr, size, mPrecision, price);
                ++i;
            }
            ++askIter;
        }
        
    }
    void prettyPrintLevels (const MamdaOrderBook&  book)
    {
        printf ("%s | %s\n",
                "        Time     Num    Size   Price Act",
                "Act Price   Size    Num       Time  ");
        MamdaOrderBook::constBidIterator bidIter = book.bidBegin ();
        MamdaOrderBook::constBidIterator bidEnd  = book.bidEnd ();
        MamdaOrderBook::constAskIterator askIter = book.askBegin ();
        MamdaOrderBook::constAskIterator askEnd  = book.askEnd ();
        char timeStr[32];

      
        if (mShowMarketOrders)
        {
            printf ("    MARKET ORDERS ---------------------------------------------------------------\n");
            const MamdaOrderBookPriceLevel* marketOrders = NULL;

            if (marketOrders = book.getBidMarketOrders())
            {
                marketOrders->getTime().getAsFormattedString (timeStr, 32, "%T%;");
                printf ("   %12s %4d %7g  MARKET  %c  ",
                        timeStr,
                        marketOrders->getNumEntries (),
                        marketOrders->getSize (),
                        marketOrders->getAction ());
            }
            else
            {
                printf ("                                         ");
            }
            printf ("|");
            if (marketOrders = book.getAskMarketOrders())
            {
                marketOrders->getTime().getAsFormattedString (timeStr, 32, "%T%;");
                printf ("  %c  MARKET  %-7g %-6d %-12s   ",
                        marketOrders->getAction (),
                        marketOrders->getSize (),
                        marketOrders->getNumEntries (),
                        timeStr);
            }
            else
            {
                printf ("                                         ");
            }
            printf ("\n");
            printf ("    LIMIT ORDERS  ---------------------------------------------------------------\n");
        }
      
        while ((bidIter != bidEnd) || (askIter != askEnd))
        {
            if (bidIter != bidEnd)
            {
                const MamdaOrderBookPriceLevel* bidLevel = *bidIter;
                bidLevel->getTime().getAsFormattedString (timeStr, 32, "%T%;");
                printf ("   %12s %4d %7g %7.*f  %c  ",
                        timeStr,
                        bidLevel->getNumEntries (),
                        bidLevel->getSize (),
                        mPrecision,
                        bidLevel->getPrice (),
                        bidLevel->getAction ());
                ++bidIter;
            }
            else
            {
                printf ("                                         ");
            }
            printf ("|");
            if (askIter != askEnd)
            {
                const MamdaOrderBookPriceLevel* askLevel = *askIter;
                askLevel->getTime().getAsFormattedString (timeStr, 32, "%T%;");
                printf ("  %c  %-7.*f %-7g %-6d %-12s   ",
                        askLevel->getAction (),
                        mPrecision,
                        askLevel->getPrice (),
                        askLevel->getSize (),
                        askLevel->getNumEntries (),
                        timeStr);
                ++askIter;
            }
            printf ("\n");
        }
        printf ("\n");
    }