Creating a National Best Bid/Offer Engine (cont.)
Well... it took me a little bit, and I had to re-arrange the code slightly, but in the end, I have the logic I need for the NBBO engine that works when you remove the one NBBO component. It's a little more complex, but it's still very clean.
The previous code was slick, and this is nearly as slick, but it's a little more complex because of the different cases I had to deal with in the change of the 'best values'. Still... it's straight-through code with only the one lock to control it's updating, and I think it's going to be plenty fast enough. But we'll have to see how long it takes in real loading conditions.
if ((bidExch != '\0') && (bidPrice > 0.0) && (bidSize > 0)) { // get the exchange as an index into the arrays uint8_t idx = bidExch - 'A'; if (bidPrice > myExchData->nbboBidPrice) { // with a new leading bid, we are all there is to consider myExchData->nbboBidPrice = bidPrice; myExchData->nbboBidSize = bidSize; newNBBO = true; } else if (bidPrice == myExchData->nbboBidPrice) { // if we had something in the old NBBO, remove it now if (myExchData->bidPrice[idx] == myExchData->nbboBidPrice) { myExchData->nbboBidSize -= myExchData->bidSize[idx]; } // ...and we know we need to add in our contribution now myExchData->nbboBidSize += bidSize; newNBBO = ((myExchData->bidPrice[idx] != bidPrice) || (myExchData->bidSize[idx] != bidSize)); } else if (myExchData->bidPrice[idx] == myExchData->nbboBidPrice) { // we had something in the old NBBO, remove it now myExchData->nbboBidSize -= myExchData->bidSize[idx]; newNBBO = (myExchData->bidSize[idx] > 0); // see if this was the only one in the NBBO if (myExchData->bboBidSize == 0) { // reset the bid part of the NBBO newBidPrice = 0.0; newBidSize = 0; // save what we have now for the scan myExchData->bidPrice[idx] = bidPrice; myExchData->bidSize[idx] = bidSize; // ...and scan all the data (skipping this guy) for (uint8_t e = 0; e < 26; ++e) { if (myExchData->bidPrice[e] > newBidPrice) { newBidPrice = myExchData->bidPrice[e]; newBidSize = myExchData->bidSize[e]; } else if (myExchData->bidPrice[e] == newBidPrice) { newBidSize += myExchData->bidSize[e]; } } // make sure we have something if (newBidSize > 0) { myExchData->nbboBidPrice = newBidPrice; myExchData->nbboBidSize = newBidSize; // we KNOW this is a new one newNBBO = true; } } } // no matter what, save the bid for the next time myExchData->bidPrice[idx] = bidPrice; myExchData->bidSize[idx] = bidSize; }
There are a few neat things in this guy. First off, we look for the obvious winners - if we have a brand new best bid, or an addition to the size on the existing best bid. We needed to be careful when looking at adding the value in (line 11), and especially careful about sending out a new NBBO message out (line 16).
But the really new part is the scanning of the existing exchange data (line 31). This is done only when there was a single component to the best bid, and he's just taken himself out of the mix. For those cases, we have no choice but to start all over and see what we can come up with. The wrinkle was that we need to add back in our current data so it too was included in the scan. It's possible, after all, that it's still part of the best bid, just ad a different price. And maybe with some friends.
All told, I really liked this code. It's fun, and the test frame for exercising it was a blast to write. I have the ability to throw any number of sequences of ticks to the engine and test each subsequent value. It's nice. Good, fun, work.