Skip to content

Commit

Permalink
Ref bitshares#1604: Add matching logic
Browse files Browse the repository at this point in the history
Add logic to match an updated limit order if the price is changed to be
higher than the previous top-of-book price.

I believe this completes bitshares#1604
  • Loading branch information
nathanielhourt committed Feb 22, 2019
1 parent 328f2aa commit 8da1f72
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ namespace graphene { namespace chain {
void_result do_apply(const limit_order_update_operation& o);

const limit_order_object* _order = nullptr;
bool should_match_orders = false;
};

class limit_order_cancel_evaluator : public evaluator<limit_order_cancel_evaluator>
Expand Down
26 changes: 19 additions & 7 deletions libraries/chain/market_evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,21 @@ void_result limit_order_update_evaluator::do_evaluate(const limit_order_update_o
// Check this is my order
FC_ASSERT(o.seller == _order->seller, "Cannot update someone else's order");

// Check new price is compatible
if (o.new_price)
FC_ASSERT(o.new_price->base.asset_id == _order->sell_price.base.asset_id &&
o.new_price->quote.asset_id == _order->sell_price.quote.asset_id,
// Check new price is compatible, and determine whether it becomes the best offer on the market
if (o.new_price) {
auto base_id = o.new_price->base.asset_id;
auto quote_id = o.new_price->quote.asset_id;
FC_ASSERT(base_id == _order->sell_price.base.asset_id && quote_id == _order->sell_price.quote.asset_id,
"Cannot update limit order with incompatible price");
const auto& order_index = d.get_index_type<limit_order_index>().indices().get<by_price>();
auto top_of_book = order_index.upper_bound(boost::make_tuple(price::max(base_id, quote_id)));
FC_ASSERT(top_of_book->sell_price.base.asset_id == base_id && top_of_book->sell_price.quote.asset_id == quote_id,
"Paradox: attempting to update an order in a market that has no orders? There's a logic error somewhere.");

// If the new price of our order is greater than the price of the order at the top of the book, we should match orders at the end.
// Otherwise, we can skip matching because there's no way this change could trigger orders to fill.
should_match_orders = (*o.new_price > top_of_book->sell_price);
}

// Check delta asset is compatible
if (o.delta_amount_to_sell) {
Expand All @@ -158,7 +168,7 @@ void_result limit_order_update_evaluator::do_evaluate(const limit_order_update_o
FC_ASSERT(*o.new_expiration >= d.head_block_time(),
"Cannot update limit order with past expiration");

return void_result();
return {};
} FC_CAPTURE_AND_RETHROW((o)) }

void_result limit_order_update_evaluator::do_apply(const limit_order_update_operation& o)
Expand All @@ -184,9 +194,11 @@ void_result limit_order_update_evaluator::do_apply(const limit_order_update_oper
loo.expiration = *o.new_expiration;
});

// TODO: check if order is at front of book and price moved in favor of buyer; if so, trigger matching
// Perform order matching if necessary
if (should_match_orders)
d.apply_order(*_order);

return void_result();
return {};
} FC_CAPTURE_AND_RETHROW((o)) }

void_result limit_order_cancel_evaluator::do_evaluate(const limit_order_cancel_operation& o)
Expand Down
4 changes: 1 addition & 3 deletions libraries/chain/protocol/market.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,4 @@ void bid_collateral_operation::validate()const
FC_ASSERT( debt_covered.amount == 0 || (debt_covered.amount > 0 && additional_collateral.amount > 0) );
} FC_CAPTURE_AND_RETHROW((*this)) }

}

} // graphene::chain
} } // graphene::chain
44 changes: 44 additions & 0 deletions tests/tests/operation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,50 @@ BOOST_AUTO_TEST_CASE(limit_order_update_test)
}
}

BOOST_AUTO_TEST_CASE(limit_order_update_match_test)
{
try {
ACTORS((nathan));
const auto& munee = create_user_issued_asset("MUNEE");

transfer(committee_account, nathan_id, asset(10000));
issue_uia(nathan, munee.amount(1000));

auto expiration = db.head_block_time() + 1000;
limit_order_id_type order_id_1 = create_sell_order(nathan, asset(999), munee.amount(100), expiration)->id;
limit_order_id_type order_id_2 = create_sell_order(nathan, munee.amount(100), asset(1001), expiration)->id;

update_limit_order(order_id_1, price(asset(1001), munee.amount(100)), asset(1));
BOOST_REQUIRE_EQUAL(db.find(order_id_1), nullptr);
BOOST_REQUIRE_EQUAL(db.find(order_id_2)->amount_for_sale().amount.value, 1);
} catch (fc::exception& e) {
edump((e.to_detail_string()));
throw;
}
}

BOOST_AUTO_TEST_CASE(limit_order_update_match_test_2)
{
try {
ACTORS((nathan));
const auto& munee = create_user_issued_asset("MUNEE");

transfer(committee_account, nathan_id, asset(10000));
issue_uia(nathan, munee.amount(1000));

auto expiration = db.head_block_time() + 1000;
limit_order_id_type order_id_1 = create_sell_order(nathan, asset(999), munee.amount(100), expiration)->id;
limit_order_id_type order_id_2 = create_sell_order(nathan, munee.amount(100), asset(1001), expiration)->id;

update_limit_order(order_id_2, price(munee.amount(100), asset(999)));
BOOST_REQUIRE_EQUAL(db.find(order_id_1), nullptr);
BOOST_REQUIRE_EQUAL(db.find(order_id_2), nullptr);
} catch (fc::exception& e) {
edump((e.to_detail_string()));
throw;
}
}

BOOST_AUTO_TEST_CASE( call_order_update_test )
{
try {
Expand Down

0 comments on commit 8da1f72

Please sign in to comment.