From 3ab801ae7bddc5be778bb95150586c4d86a4b57a Mon Sep 17 00:00:00 2001 From: Eric Frias Date: Tue, 29 May 2018 11:36:10 -0400 Subject: [PATCH] Restore the original bet matching for back taker bets --- libraries/chain/db_bet.cpp | 61 ++++++++++++++++++++++----------- tests/betting/betting_tests.cpp | 41 ++++++++++++++-------- 2 files changed, 67 insertions(+), 35 deletions(-) diff --git a/libraries/chain/db_bet.cpp b/libraries/chain/db_bet.cpp index 9cf7eeb7..e0bd5a2f 100644 --- a/libraries/chain/db_bet.cpp +++ b/libraries/chain/db_bet.cpp @@ -398,6 +398,7 @@ bool bet_was_matched(database& db, const bet_object& bet, */ int match_bet(database& db, const bet_object& taker_bet, const bet_object& maker_bet ) { + //fc_idump(fc::logger::get("betting"), (taker_bet)(maker_bet)); assert(taker_bet.amount_to_bet.asset_id == maker_bet.amount_to_bet.asset_id); assert(taker_bet.amount_to_bet.amount > 0 && maker_bet.amount_to_bet.amount > 0); assert(taker_bet.back_or_lay == bet_type::back ? taker_bet.backer_multiplier <= maker_bet.backer_multiplier : @@ -427,16 +428,16 @@ int match_bet(database& db, const bet_object& taker_bet, const bet_object& maker // now figure out how much of the maker bet we'll consume. We don't yet know whether the maker or taker // will be the limiting factor. share_type maximum_factor_taker_is_willing_to_pay = taker_bet.amount_to_bet.amount / taker_odds_ratio; - share_type maximum_factor_taker_is_willing_to_receive = taker_bet.get_exact_matching_amount() / maker_odds_ratio; - share_type maximum_taker_factor; - bool taker_was_limited_by_matching_amount = maximum_factor_taker_is_willing_to_receive < maximum_factor_taker_is_willing_to_pay; - if (taker_was_limited_by_matching_amount) - maximum_taker_factor = maximum_factor_taker_is_willing_to_receive; - else - maximum_taker_factor = maximum_factor_taker_is_willing_to_pay; - - fc_idump(fc::logger::get("betting"), (maximum_factor_taker_is_willing_to_pay)(maximum_factor_taker_is_willing_to_receive)(maximum_taker_factor)); + share_type maximum_taker_factor = maximum_factor_taker_is_willing_to_pay; + if (taker_bet.back_or_lay == bet_type::lay) { + share_type maximum_factor_taker_is_willing_to_receive = taker_bet.get_exact_matching_amount() / maker_odds_ratio; + //fc_idump(fc::logger::get("betting"), (maximum_factor_taker_is_willing_to_pay)); + bool taker_was_limited_by_matching_amount = maximum_factor_taker_is_willing_to_receive < maximum_factor_taker_is_willing_to_pay; + if (taker_was_limited_by_matching_amount) + maximum_taker_factor = maximum_factor_taker_is_willing_to_receive; + } + //fc_idump(fc::logger::get("betting"), (maximum_factor_taker_is_willing_to_pay)(maximum_taker_factor)); share_type maximum_maker_factor = maker_bet.amount_to_bet.amount / maker_odds_ratio; share_type maximum_factor = std::min(maximum_taker_factor, maximum_maker_factor); @@ -480,15 +481,35 @@ int match_bet(database& db, const bet_object& taker_bet, const bet_object& maker std::tie(takers_odds_back_odds_ratio, takers_odds_lay_odds_ratio) = taker_bet.get_ratio(); const share_type& takers_odds_taker_odds_ratio = taker_bet.back_or_lay == bet_type::back ? takers_odds_back_odds_ratio : takers_odds_lay_odds_ratio; const share_type& takers_odds_maker_odds_ratio = taker_bet.back_or_lay == bet_type::back ? takers_odds_lay_odds_ratio : takers_odds_back_odds_ratio; + share_type taker_refund_amount; - share_type unrounded_taker_remaining_amount_to_match = taker_bet.get_exact_matching_amount() - maker_amount_to_match; - // because we matched at the maker's odds and not the taker's odds, the remaining amount to match - // may not be an even multiple of the taker's odds; round it down. - share_type taker_remaining_factor = unrounded_taker_remaining_amount_to_match / takers_odds_maker_odds_ratio; - share_type taker_remaining_maker_amount_to_match = taker_remaining_factor * takers_odds_maker_odds_ratio; - share_type taker_remaining_bet_amount = taker_remaining_factor * takers_odds_taker_odds_ratio; + if (taker_bet.back_or_lay == bet_type::back) + { + // because we matched at the maker's odds and not the taker's odds, the remaining amount to match + // may not be an even multiple of the taker's odds; round it down. + share_type taker_remaining_factor = (taker_bet.amount_to_bet.amount - taker_amount_to_match) / takers_odds_taker_odds_ratio; + share_type taker_remaining_bet_amount = taker_remaining_factor * takers_odds_taker_odds_ratio; + taker_refund_amount = taker_bet.amount_to_bet.amount - taker_amount_to_match - taker_remaining_bet_amount; + //idump((taker_remaining_factor)(taker_remaining_bet_amount)(taker_refund_amount)); + } + else + { + // the taker bet is a lay bet. because we matched at the maker's odds and not the taker's odds, + // there are two things we need to take into account. First, we may have achieved more of a position + // than we expected had we matched at our taker odds. If so, we can refund the unused stake. + // Second, the remaining amount to match may not be an even multiple of the taker's odds; round it down. + share_type unrounded_taker_remaining_amount_to_match = taker_bet.get_exact_matching_amount() - maker_amount_to_match; + //idump((unrounded_taker_remaining_amount_to_match)); - share_type taker_refund_amount = taker_bet.amount_to_bet.amount - taker_amount_to_match - taker_remaining_bet_amount; + // because we matched at the maker's odds and not the taker's odds, the remaining amount to match + // may not be an even multiple of the taker's odds; round it down. + share_type taker_remaining_factor = unrounded_taker_remaining_amount_to_match / takers_odds_maker_odds_ratio; + share_type taker_remaining_maker_amount_to_match = taker_remaining_factor * takers_odds_maker_odds_ratio; + share_type taker_remaining_bet_amount = taker_remaining_factor * takers_odds_taker_odds_ratio; + + taker_refund_amount = taker_bet.amount_to_bet.amount - taker_amount_to_match - taker_remaining_bet_amount; + //idump((taker_remaining_factor)(taker_remaining_maker_amount_to_match)(taker_remaining_bet_amount)(taker_refund_amount)); + } if (taker_refund_amount > share_type()) { @@ -496,10 +517,10 @@ int match_bet(database& db, const bet_object& taker_bet, const bet_object& maker taker_bet_object.amount_to_bet.amount -= taker_refund_amount; }); fc_dlog(fc::logger::get("betting"), "Refunding ${taker_refund_amount} to taker because we matched at the maker's odds of " - "${maker_odds} instead of the taker's odds ${taker_odds}", - ("taker_refund_amount", taker_refund_amount) - ("maker_odds", maker_bet.backer_multiplier) - ("taker_odds", taker_bet.backer_multiplier)); + "${maker_odds} instead of the taker's odds ${taker_odds}", + ("taker_refund_amount", taker_refund_amount) + ("maker_odds", maker_bet.backer_multiplier) + ("taker_odds", taker_bet.backer_multiplier)); fc_ddump(fc::logger::get("betting"), (taker_bet)); db.adjust_balance(taker_bet.bettor_id, asset(taker_refund_amount, taker_bet.amount_to_bet.asset_id)); diff --git a/tests/betting/betting_tests.cpp b/tests/betting/betting_tests.cpp index 4b587977..60c3804f 100644 --- a/tests/betting/betting_tests.cpp +++ b/tests/betting/betting_tests.cpp @@ -508,32 +508,40 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts) // lay 46 at 1.94 odds (50:47) -- this is too small to be placed on the books and there's // nothing for it to match, so it should be canceled + BOOST_TEST_MESSAGE("lay 46 at 1.94 odds (50:47) -- this is too small to be placed on the books and there's nothing for it to match, so it should be canceled"); place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(46, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); + BOOST_TEST_MESSAGE("alice's balance should be " << alice_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); - +ilog("message"); // lay 47 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here + BOOST_TEST_MESSAGE("alice lays 470 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here"); place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(47, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 47; + BOOST_TEST_MESSAGE("alice's balance should be " << alice_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // lay 100 at 1.91 odds (100:91) -- this is an inexact match, we should get refunded 9 and leave a bet for 91 on the books place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(100, asset_id_type()), 191 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 91; + BOOST_TEST_MESSAGE("alice's balance should be " << alice_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); transfer(account_id_type(), bob_id, asset(10000000)); share_type bob_expected_balance = 10000000; + BOOST_TEST_MESSAGE("bob's balance should be " << bob_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); // now have bob match it with a back of 300 at 1.5 // This should: - // match the full 47 @ 1.94 with 50, and be refunded 44 (leaving 206 left in the bet) - // match the full 91 @ 1.91 with 100, and be refunded 82 (leaving 24 in the bet) - // bob's balance goes down by 300 - 44 - 82 = 124 - // leaves a back bet of 24 @ 1.5 on the books + // match the full 47 @ 1.94 with 50 + // match the full 91 @ 1.91 with 100 + // bob's balance goes down by 300 (150 is matched, 150 is still on the books) + // leaves a back bet of 150 @ 1.5 on the books + BOOST_TEST_MESSAGE("now have bob match it with a back of 300 at 1.5"); place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(300, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); - bob_expected_balance -= 300 - 44 - 82; + bob_expected_balance -= 300; + BOOST_TEST_MESSAGE("bob's balance should be " << bob_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); } FC_LOG_AND_RETHROW() @@ -552,8 +560,10 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts2) BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); // lay 470 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here + BOOST_TEST_MESSAGE("alice lays 470 at 1.94 odds (50:47) -- this is an exact amount, nothing surprising should happen here"); place_bet(alice_id, capitals_win_market.id, bet_type::lay, asset(470, asset_id_type()), 194 * GRAPHENE_BETTING_ODDS_PRECISION / 100); alice_expected_balance -= 470; + BOOST_TEST_MESSAGE("alice's balance should be " << alice_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(alice_id, asset_id_type()), alice_expected_balance.value); transfer(account_id_type(), bob_id, asset(10000000)); @@ -562,13 +572,14 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts2) // now have bob match it with a back of 900 at 1.5 // This should: - // match 423 out of the 470 @ 1.94 with 450, and be refunded 396 (leaving 54 left in the bet) - // this is as close as bob can get without getting of a position than he planned, so the remainder - // of bob's bet is canceled (refunding the remaining 54) - // bob's balance goes down by the 450 he paid matching the bet. - // alice's bet remains on the books as a lay of 47 @ 1.94 + // match all 500 of bob's bet, and leave 400 @ 1.5 on the books + // bob's balance goes down by the 900 he paid (500 matched, 400 unmatched) + // alice's bet is completely removed from the books. + BOOST_TEST_MESSAGE("now have bob match it with a back of 900 at 1.5"); place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(900, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); - bob_expected_balance -= 900 - 396 - 54; + bob_expected_balance -= 900; + + BOOST_TEST_MESSAGE("bob's balance should be " << bob_expected_balance.value); BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); } FC_LOG_AND_RETHROW() @@ -597,11 +608,11 @@ BOOST_AUTO_TEST_CASE(match_using_takers_expected_amounts3) // now have bob match it with a back of 1000 at 1.5 // This should: - // match all of the 470 @ 1.94 with 500, and be refunded 440 (leaving 60 left in the bet) - // bob's balance goes down by the 500 he paid matching the bet and the 60 that is left. + // match all of the 470 @ 1.94 with 500, and leave 500 left on the books + // bob's balance goes down by the 1000 he paid, 500 matching, 500 unmatching // alice's bet is removed from the books place_bet(bob_id, capitals_win_market.id, bet_type::back, asset(1000, asset_id_type()), 15 * GRAPHENE_BETTING_ODDS_PRECISION / 10); - bob_expected_balance -= 1000 - 440; + bob_expected_balance -= 1000; BOOST_REQUIRE_EQUAL(get_balance(bob_id, asset_id_type()), bob_expected_balance.value); } FC_LOG_AND_RETHROW()