void TradingEngine::enterBid(Bid bid) {
    auto &m_bidQueue = m_bidQueues[bid.instrument()];
    auto &m_askQueue = m_askQueues[bid.instrument()];

    if (m_bidQueue.contains(bid)) {
        qDebug() << "skipping duplicate bid with id : " << bid.id();
        return;
    }

    // find a seller for less than we're offering
    for (auto it = m_askQueue.begin(); it != m_askQueue.end(); ) {
        Ask ask = *it;
        if (ask.price() <= bid.price()) {

            // if we have to make a partial trade
            if (ask.volume() != bid.volume()) {

                // seller has more than we want
                // leaves sell in queue with smaller volume
                if (ask.volume() > bid.volume()) {
                    Ask a = ask.createPartial(bid.volume());
                    createTrade(a, bid);
                    ++it;

                // we want more from another seller
                // removes sell, as it's completed
                } else {
                    Bid b = bid.createPartial(ask.volume());
                    it = m_askQueue.erase(it);
                    createTrade(ask, b);
                }
            } else {
                it = m_askQueue.erase(it);
                createTrade(ask, bid);
            }
        } else {
            ++it;
        }

        // if we've completely gone through the bid, there's
        // no point in adding it to the orderbook
        if (bid.volume() == 0) {
            return;
        }
    }

    // if we're still here, we weren't able to fully
    // process the bid
    auto pos = std::lower_bound(m_bidQueue.begin(), m_bidQueue.end(), bid);
    m_bidQueue.insert(pos, bid);
}
void TradingEngine::modifyBid(Bid bid) {
    modifyOrder(m_bidQueues[bid.instrument()], bid);
}
void TradingEngine::removeBid(Bid bid) {
    m_bidQueues[bid.instrument()].removeOne(bid);
}