Esempio n. 1
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";
    }
Esempio n. 2
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);
    }
Esempio n. 3
0
    /*
     * 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;
    }
    void prettyPrint (const MamdaOrderBookBasicDelta&  delta)
    {
        char timeStr[32];
        MamdaOrderBookEntry* entry = delta.getEntry();
        
        MamdaOrderBookPriceLevel*        level  = delta.getPriceLevel ();
        mama_quantity_t                  size   = delta.getPlDeltaSize ();
        MamdaOrderBookPriceLevel::Action action = delta.getPlDeltaAction();

        if (MamdaOrderBookPriceLevel::MAMDA_BOOK_LEVEL_LIMIT
            == level->getOrderType())
        {            
            double price = level->getPrice ();
            printf (" %7g %7.*f  %c \n", size, mPrecision, price, action);
        }
        else
        {
            printf (" %7g MARKET %c \n",size, action);

        }
    }
Esempio n. 5
0
    /**
     * 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 onBookAtomicLevelEntryRecap (
        MamdaSubscription*                  subscription,
        MamdaBookAtomicListener&            listener,
        const MamaMsg&                      msg,
        const MamdaBookAtomicLevelEntry&    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);
    }
Esempio n. 6
0
    /**
     * Helper function to store a MamdaBookAtomicLevel in
     *  the resuabale MamdaOrderBookPriceLevel
     */
    void storeLevel(const MamdaBookAtomicLevel&  level)
    {
        mReusablePriceLevel.clear();
        mReusablePriceLevel.setPrice (level.getPriceLevelPrice());
        mReusablePriceLevel.setSide ((MamdaOrderBookPriceLevel::Side)level.getPriceLevelSide());
        mReusablePriceLevel.setTime (level.getPriceLevelTime());

        /**
         * As per the MAMDA Developers Guide, the following three accessors on a MamdaBookAtomicLevel
         *  object should not be used for V5 entry updates. Here, these calls are used and
         *  the resulting MamdaOrderBookPriceLevel is only used when the callbacks received
         *  indicate that the update was not a V5 entry update.
         */
        mReusablePriceLevel.setSize (level.getPriceLevelSize());
        mReusablePriceLevel.setAction ((MamdaOrderBookPriceLevel::Action) level.getPriceLevelAction());
        mReusablePriceLevel.setNumEntries ((mama_u32_t)level.getPriceLevelNumEntries());
    }
Esempio n. 7
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);
    }
Esempio n. 8
0
    /**
     * 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 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 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());
    }
void BookPublisher::processOrder () 
{   
    MamdaOrderBookPriceLevel* level = NULL;
    MamdaOrderBookEntry*      entry = NULL;
    order thisOrder = orderArray[mOrderCount];
    mBookTime.setToNow();

    if (mProcessEntries)
    {          
        switch (thisOrder.entAction)
        {
            case ENTDELETE:
            {
                level = mBook->getLevelAtPrice (thisOrder.price, thisOrder.side);
                
                if (level)
                    entry = level->findEntry (thisOrder.entId);
                if (entry)
                    mBook->deleteEntry (entry, mBookTime, NULL);
                break;
            }
            case ENTADD:
            {
                mBook->addEntry (thisOrder.entId, thisOrder.entSize,
                                 thisOrder.price, thisOrder.side,
                                 mBookTime, NULL, NULL);
                break;
            }
            case ENTUPDATE:
            {
                entry = level->findEntry (thisOrder.entId);
                mBook->updateEntry (entry, thisOrder.entSize,
                                    mBookTime, NULL);
                break;
            }
        }
    }
    else
    {
        level = mBook->getLevelAtPrice(thisOrder.price, thisOrder.side);
        if (level)
        {
            level->setSizeChange (thisOrder.sizeChange);
            level->setPrice      (thisOrder.price);
            level->setSize       (thisOrder.volume);
            level->setNumEntries (thisOrder.numEntries);           
            level->setTime       (mBookTime);
            level->setAction     (thisOrder.plAction);
        }
        else
        {
            level = new MamdaOrderBookPriceLevel();
            level->setSide       (thisOrder.side);
            level->setSizeChange (thisOrder.sizeChange);
            level->setPrice      (thisOrder.price);
            level->setSize       (thisOrder.volume);
            level->setNumEntries (thisOrder.numEntries);           
            level->setTime       (mBookTime);
            level->setAction     (thisOrder.plAction);                
        }
        
        switch (thisOrder.plAction)
        {
            case PLDELETE:
                mBook->deleteLevel(*level);
                break;
            case PLADD:
                mBook->addLevel(*level);
                break;
            case PLUPDATE:
                mBook->updateLevel(*level);
                break;
        }
    }
    mOrderCount++;
}
Esempio n. 12
0
    /**
     * Helper function to apply a MamdaBookAtomicLevelEntry to
     * a MamdaOrderBook
     */
    void applyEntry (const MamdaBookAtomicLevelEntry& levelEntry)
    {
        MamdaOrderBookEntry::Action entryAction;

        if(mOrderBook.getQuality() == MAMA_QUALITY_OK)
        {
            entryAction = (MamdaOrderBookEntry::Action) levelEntry.getPriceLevelEntryAction();

            switch(entryAction)
            {
            case MamdaOrderBookEntry::MAMDA_BOOK_ACTION_UPDATE :
                try
                {
                    //get the price level by price
                    mLevelPtr = mOrderBook.findLevel(
                                    levelEntry.getPriceLevelPrice(),
                                    (MamdaOrderBookPriceLevel::Side) levelEntry.getPriceLevelSide());
                    if(mLevelPtr != NULL)
                    {
                        //get the entry by id
                        mEntryPtr = mLevelPtr->findEntry(levelEntry.getPriceLevelEntryId());

                        if(mEntryPtr != NULL)
                        {
                            mOrderBook.updateEntry(
                                mEntryPtr,
                                levelEntry.getPriceLevelEntrySize(),
                                levelEntry.getPriceLevelEntryTime(),
                                (MamdaOrderBookBasicDelta*) NULL);
                            break;
                        }
                    }
                    /*
                     * intentional fall through to add the entry if
                     * the entry or level cannot be found to update it
                     */
                }
                catch ( MamdaOrderBookInvalidEntry &e)
                {
                    cout<< "atomicbookbuilder: could not update entry.\n";
                    cout << "Caught MamdaOrderBookInvalidEntry [" << e.what() << "]\n";
                }
                catch (MamdaOrderBookException &e)
                {
                    cout<< "atomicbookbuilder: could not update entry.\n";
                    cout<< "Caught MamdaOrderBookException [" << e.what() << "[\n";
                }
            case MamdaOrderBookEntry::MAMDA_BOOK_ACTION_ADD :
                mEntryPtr = mOrderBook.addEntry(
                                levelEntry.getPriceLevelEntryId(),
                                levelEntry.getPriceLevelEntrySize(),
                                levelEntry.getPriceLevelPrice(),
                                (MamdaOrderBookPriceLevel::Side) levelEntry.getPriceLevelSide(),
                                levelEntry.getPriceLevelEntryTime(),
                                (const MamaSourceDerivative*) NULL,
                                (MamdaOrderBookBasicDelta*) NULL);

                mEntryPtr->setReason(
                    (MamdaOrderBookTypes::Reason)levelEntry.getPriceLevelEntryReason());
                break;
            case MamdaOrderBookEntry::MAMDA_BOOK_ACTION_DELETE :
                try
                {
                    //get the price level by price
                    mLevelPtr = mOrderBook.findLevel(
                                    levelEntry.getPriceLevelPrice(),
                                    (MamdaOrderBookPriceLevel::Side) levelEntry.getPriceLevelSide());
                    if(mLevelPtr != NULL)
                    {
                        //get the entry by id
                        mEntryPtr = mLevelPtr->findEntry(levelEntry.getPriceLevelEntryId());

                        if(mEntryPtr != NULL)
                            mOrderBook.deleteEntry(
                                mEntryPtr,
                                levelEntry.getPriceLevelEntryTime(),
                                (MamdaOrderBookBasicDelta*) NULL);
                    }
                }
                catch ( MamdaOrderBookInvalidEntry &e)
                {
                    cout<< "atomicbookbuilder: could not delete entry.\n";
                    cout << "Caught MamdaOrderBookInvalidEntry [" << e.what() << "]\n";
                }
                catch (MamdaOrderBookException &e)
                {
                    cout<< "atomicbookbuilder: could not delete entry.\n";
                    cout<< "Caught MamdaOrderBookException [" << e.what() << "[\n";
                }
                break;
            default:
                cout << "atomicbookbuilder: Unknown entry action ["
                     << (char)entryAction << "]\n";
                break;
            }

            mEntryPtr = NULL;
            mLevelPtr = NULL;
        }
    }
Esempio n. 13
0
    /**
     * Helper function to apply a MamdaOrderBookPriceLevel to
     * a MamdaOrderBook
     */
    void applyLevel (MamdaOrderBookPriceLevel& level)
    {
        if(mOrderBook.getQuality() == MAMA_QUALITY_OK)
        {
            switch(level.getAction())
            {
            case MamdaOrderBookPriceLevel::MAMDA_BOOK_ACTION_UPDATE :
                try
                {
                    /*
                     * When in the order book the only Action which makes sense is
                     * ADD
                     */
                    level.setAction(MamdaOrderBookPriceLevel::MAMDA_BOOK_ACTION_ADD);

                    mOrderBook.updateLevel(level);
                }
                catch ( MamdaOrderBookException &e)
                {
                    //Exception is thrown when updating level which does not exist
                    //level will be added so handled internally
                }
                break;
            case MamdaOrderBookPriceLevel::MAMDA_BOOK_ACTION_ADD :
                try
                {
                    mLevelPtr = new MamdaOrderBookPriceLevel(level);
                    /*
                     * When in the order book the only Action which makes sense is
                     * ADD
                     */
                    mLevelPtr->setAction(MamdaOrderBookPriceLevel::MAMDA_BOOK_ACTION_ADD);

                    mOrderBook.addLevel(*mLevelPtr);
                    //ownership of ptr passed to MamdaOrderBook
                }
                catch ( MamdaOrderBookException &e)
                {
                    //Exception is thrown if adding a level already in book
                    //handled internally by updating level
                    delete mLevelPtr;
                }
                break;
            case MamdaOrderBookPriceLevel::MAMDA_BOOK_ACTION_DELETE :
                try
                {
                    mOrderBook.deleteLevel(mReusablePriceLevel);
                }
                catch (MamdaOrderBookException &e)
                {
                    //Thrown if the level cannot be found in the book
                    //No need for handling as level is deleted
                }
                break;
            default:
                cout << "atomicbookbuilder: Unknown price level ["
                     << level.getAction() << "]\n";
                break;
            }

            mLevelPtr = NULL;
        }
    }