bool database::apply_order(const limit_order_object& new_order_object, bool allow_black_swan) { auto order_id = new_order_object.id; const asset_object& sell_asset = get(new_order_object.amount_for_sale().asset_id); const asset_object& receive_asset = get(new_order_object.amount_to_receive().asset_id); // Possible optimization: We only need to check calls if both are true: // - The new order is at the front of the book // - The new order is below the call limit price bool called_some = check_call_orders(sell_asset, allow_black_swan); called_some |= check_call_orders(receive_asset, allow_black_swan); if( called_some && !find_object(order_id) ) // then we were filled by call order return true; const auto& limit_price_idx = get_index_type<limit_order_index>().indices().get<by_price>(); // TODO: it should be possible to simply check the NEXT/PREV iterator after new_order_object to // determine whether or not this order has "changed the book" in a way that requires us to // check orders. For now I just lookup the lower bound and check for equality... this is log(n) vs // constant time check. Potential optimization. auto max_price = ~new_order_object.sell_price; auto limit_itr = limit_price_idx.lower_bound(max_price.max()); auto limit_end = limit_price_idx.upper_bound(max_price); bool finished = false; while( !finished && limit_itr != limit_end ) { auto old_limit_itr = limit_itr; ++limit_itr; // match returns 2 when only the old order was fully filled. In this case, we keep matching; otherwise, we stop. finished = (match(new_order_object, *old_limit_itr, old_limit_itr->sell_price) != 2); } //Possible optimization: only check calls if the new order completely filled some old order //Do I need to check both assets? check_call_orders(sell_asset, allow_black_swan); check_call_orders(receive_asset, allow_black_swan); const limit_order_object* updated_order_object = find< limit_order_object >( order_id ); if( updated_order_object == nullptr ) return true; if( head_block_time() <= HARDFORK_555_TIME ) return false; // before #555 we would have done maybe_cull_small_order() logic as a result of fill_order() being called by match() above // however after #555 we need to get rid of small orders -- #555 hardfork defers logic that was done too eagerly before, and // this is the point it's deferred to. return maybe_cull_small_order( *this, *updated_order_object ); }
bool database::apply_order(const limit_order_object& new_order_object, bool allow_black_swan) { auto order_id = new_order_object.id; const asset_object& sell_asset = get(new_order_object.amount_for_sale().asset_id); const asset_object& receive_asset = get(new_order_object.amount_to_receive().asset_id); // Possible optimization: We only need to check calls if both are true: // - The new order is at the front of the book // - The new order is below the call limit price bool called_some = check_call_orders(sell_asset, allow_black_swan); called_some |= check_call_orders(receive_asset, allow_black_swan); if( called_some && !find_object(order_id) ) // then we were filled by call order return true; const auto& limit_price_idx = get_index_type<limit_order_index>().indices().get<by_price>(); // TODO: it should be possible to simply check the NEXT/PREV iterator after new_order_object to // determine whether or not this order has "changed the book" in a way that requires us to // check orders. For now I just lookup the lower bound and check for equality... this is log(n) vs // constant time check. Potential optimization. auto max_price = ~new_order_object.sell_price; auto limit_itr = limit_price_idx.lower_bound(max_price.max()); auto limit_end = limit_price_idx.upper_bound(max_price); bool finished = false; while( !finished && limit_itr != limit_end ) { auto old_limit_itr = limit_itr; ++limit_itr; // match returns 2 when only the old order was fully filled. In this case, we keep matching; otherwise, we stop. finished = (match(new_order_object, *old_limit_itr, old_limit_itr->sell_price) != 2); } //Possible optimization: only check calls if the new order completely filled some old order //Do I need to check both assets? check_call_orders(sell_asset, allow_black_swan); check_call_orders(receive_asset, allow_black_swan); return find_object(order_id) == nullptr; }
void database::update_expired_feeds() { auto& asset_idx = get_index_type<asset_index>().indices(); for( const asset_object& a : asset_idx ) { if( !a.is_market_issued() ) continue; const asset_bitasset_data_object& b = a.bitasset_data(*this); if( b.feed_is_expired(head_block_time()) ) { modify(b, [this](asset_bitasset_data_object& a) { a.update_median_feeds(head_block_time()); }); check_call_orders(b.current_feed.settlement_price.base.asset_id(*this)); } if( !b.current_feed.core_exchange_rate.is_null() && a.options.core_exchange_rate != b.current_feed.core_exchange_rate ) modify(a, [&b](asset_object& a) { a.options.core_exchange_rate = b.current_feed.core_exchange_rate; }); } }