Progress on margin call tests
This commit is contained in:
parent
66ab805458
commit
db43f41de8
6 changed files with 384 additions and 264 deletions
|
|
@ -126,4 +126,26 @@ namespace graphene { namespace chain {
|
|||
FC_ASSERT( maintenance_collateral_ratio >= maximum_short_squeeze_ratio );
|
||||
} FC_CAPTURE_AND_RETHROW( (*this) ) }
|
||||
|
||||
price price_feed::max_short_squeeze_price()const
|
||||
{
|
||||
asset collateral = settlement_price.quote;
|
||||
fc::uint128 tmp( collateral.amount.value );
|
||||
tmp *= maximum_short_squeeze_ratio - 1000;
|
||||
tmp /= 1000;
|
||||
FC_ASSERT( tmp <= GRAPHENE_MAX_SHARE_SUPPLY );
|
||||
collateral.amount = tmp.to_uint64();
|
||||
return settlement_price.base / collateral;
|
||||
}
|
||||
price price_feed::maintenance_price()const
|
||||
{
|
||||
asset collateral = settlement_price.quote;
|
||||
fc::uint128 tmp( collateral.amount.value );
|
||||
tmp *= maintenance_collateral_ratio - 1000;
|
||||
tmp /= 1000;
|
||||
FC_ASSERT( tmp <= GRAPHENE_MAX_SHARE_SUPPLY );
|
||||
collateral.amount = tmp.to_uint64();
|
||||
return settlement_price.base / collateral;
|
||||
}
|
||||
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
|
|||
|
|
@ -308,6 +308,7 @@ void_result asset_update_feed_producers_evaluator::do_apply(const asset_update_f
|
|||
a.update_median_feeds(db().head_block_time());
|
||||
});
|
||||
|
||||
|
||||
return void_result();
|
||||
}
|
||||
|
||||
|
|
@ -396,6 +397,9 @@ void_result asset_publish_feeds_evaluator::do_apply(const asset_publish_feed_ope
|
|||
a.update_median_feeds(d.head_block_time());
|
||||
});
|
||||
|
||||
/// TODO: only do this if the median feed actually changed, otherwise there is no point
|
||||
db().check_call_orders( base );
|
||||
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW((o)) }
|
||||
|
||||
|
|
|
|||
|
|
@ -388,10 +388,12 @@ bool database::check_call_orders( const asset_object& mia, bool enable_black_swa
|
|||
const limit_order_index& limit_index = get_index_type<limit_order_index>();
|
||||
const auto& limit_price_index = limit_index.indices().get<by_price>();
|
||||
|
||||
// looking for limit orders selling the most USD for the least CORE
|
||||
auto max_price = price::max( mia.id, bitasset.options.short_backing_asset );
|
||||
auto min_price = bitasset.current_feed.max_short_squeeze_price();
|
||||
/*
|
||||
if( require_orders )
|
||||
// stop when limit orders are selling too little USD for too much CORE
|
||||
//auto min_price = bitasset.current_feed.max_short_squeeze_price();
|
||||
auto min_price = price::min( mia.id, bitasset.options.short_backing_asset );
|
||||
idump((bitasset.current_feed.settlement_price)(bitasset.current_feed.settlement_price.to_real()));
|
||||
{
|
||||
for( const auto& order : limit_price_index )
|
||||
wdump((order)(order.sell_price.to_real()));
|
||||
|
|
@ -404,24 +406,21 @@ bool database::check_call_orders( const asset_object& mia, bool enable_black_swa
|
|||
wdump((max_price)(max_price.to_real()));
|
||||
wdump((min_price)(min_price.to_real()));
|
||||
}
|
||||
*/
|
||||
|
||||
FC_ASSERT( max_price.base.asset_id == min_price.base.asset_id );
|
||||
assert( max_price.base.asset_id == min_price.base.asset_id );
|
||||
// wlog( "from ${a} Debt/Col to ${b} Debt/Col ", ("a", max_price.to_real())("b",min_price.to_real()) );
|
||||
// NOTE limit_price_index is sorted from greatest to least
|
||||
auto limit_itr = limit_price_index.lower_bound( max_price );
|
||||
auto limit_end = limit_price_index.upper_bound( min_price );
|
||||
|
||||
/*
|
||||
if( limit_itr != limit_price_index.end() )
|
||||
wdump((*limit_itr)(limit_itr->sell_price.to_real()));
|
||||
if( limit_end != limit_price_index.end() )
|
||||
wdump((*limit_end)(limit_end->sell_price.to_real()));
|
||||
*/
|
||||
|
||||
if( limit_itr == limit_end )
|
||||
{
|
||||
//wlog( "no orders available to fill margin calls" );
|
||||
wlog( "no orders available to fill margin calls" );
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -158,10 +158,7 @@ namespace graphene { namespace chain {
|
|||
* debt * settlement_price < debt * maintenance
|
||||
* debt * maintenance_price() < debt * max_short_squeeze_price()
|
||||
*/
|
||||
price maintenance_price()const
|
||||
{
|
||||
return ~price::call_price( settlement_price.base, settlement_price.quote, maintenance_collateral_ratio );
|
||||
}
|
||||
price maintenance_price()const;
|
||||
|
||||
/** When selling collateral to pay off debt, the least amount of debt to receive should be
|
||||
* min_usd = max_short_squeeze_price() * collateral
|
||||
|
|
@ -169,10 +166,7 @@ namespace graphene { namespace chain {
|
|||
* This is provided to ensure that a black swan cannot be trigged due to poor liquidity alone, it
|
||||
* must be confirmed by having the max_short_squeeze_price() move below the black swan price.
|
||||
*/
|
||||
price max_short_squeeze_price()const
|
||||
{
|
||||
return ~price::call_price( settlement_price.base, settlement_price.quote, maximum_short_squeeze_ratio );
|
||||
}
|
||||
price max_short_squeeze_price()const;
|
||||
///@}
|
||||
|
||||
friend bool operator == ( const price_feed& a, const price_feed& b )
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
namespace graphene { namespace chain {
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
|
||||
database_fixture::database_fixture()
|
||||
: app(), db( *app.chain_database() )
|
||||
|
|
@ -745,25 +746,25 @@ void database_fixture::print_market( const string& syma, const string& symb )con
|
|||
const auto& limit_idx = db.get_index_type<limit_order_index>();
|
||||
const auto& price_idx = limit_idx.indices().get<by_price>();
|
||||
|
||||
cout << std::fixed;
|
||||
cout.precision(5);
|
||||
cout << std::setw(10) << std::left << "NAME" << " ";
|
||||
cout << std::setw(16) << std::right << "FOR SALE" << " ";
|
||||
cout << std::setw(16) << std::right << "FOR WHAT" << " ";
|
||||
cout << std::setw(10) << std::right << "PRICE" << " ";
|
||||
cout << std::setw(10) << std::right << "1/PRICE" << "\n";
|
||||
cout << string(70, '=') << std::endl;
|
||||
cerr << std::fixed;
|
||||
cerr.precision(5);
|
||||
cerr << std::setw(10) << std::left << "NAME" << " ";
|
||||
cerr << std::setw(16) << std::right << "FOR SALE" << " ";
|
||||
cerr << std::setw(16) << std::right << "FOR WHAT" << " ";
|
||||
cerr << std::setw(10) << std::right << "PRICE (S/W)" << " ";
|
||||
cerr << std::setw(10) << std::right << "1/PRICE (W/S)" << "\n";
|
||||
cerr << string(70, '=') << std::endl;
|
||||
auto cur = price_idx.begin();
|
||||
while( cur != price_idx.end() )
|
||||
{
|
||||
cout << std::setw( 10 ) << std::left << cur->seller(db).name << " ";
|
||||
cout << std::setw( 10 ) << std::right << cur->for_sale.value << " ";
|
||||
cout << std::setw( 5 ) << std::left << cur->amount_for_sale().asset_id(db).symbol << " ";
|
||||
cout << std::setw( 10 ) << std::right << cur->amount_to_receive().amount.value << " ";
|
||||
cout << std::setw( 5 ) << std::left << cur->amount_to_receive().asset_id(db).symbol << " ";
|
||||
cout << std::setw( 10 ) << std::right << cur->sell_price.to_real() << " ";
|
||||
cout << std::setw( 10 ) << std::right << (~cur->sell_price).to_real() << " ";
|
||||
cout << "\n";
|
||||
cerr << std::setw( 10 ) << std::left << cur->seller(db).name << " ";
|
||||
cerr << std::setw( 10 ) << std::right << cur->for_sale.value << " ";
|
||||
cerr << std::setw( 5 ) << std::left << cur->amount_for_sale().asset_id(db).symbol << " ";
|
||||
cerr << std::setw( 10 ) << std::right << cur->amount_to_receive().amount.value << " ";
|
||||
cerr << std::setw( 5 ) << std::left << cur->amount_to_receive().asset_id(db).symbol << " ";
|
||||
cerr << std::setw( 10 ) << std::right << cur->sell_price.to_real() << " ";
|
||||
cerr << std::setw( 10 ) << std::right << (~cur->sell_price).to_real() << " ";
|
||||
cerr << "\n";
|
||||
++cur;
|
||||
}
|
||||
}
|
||||
|
|
@ -793,8 +794,10 @@ void database_fixture::print_call_orders()const
|
|||
cout << std::setw(10) << std::right << "TYPE" << " ";
|
||||
cout << std::setw(16) << std::right << "DEBT" << " ";
|
||||
cout << std::setw(16) << std::right << "COLLAT" << " ";
|
||||
cout << std::setw(16) << std::right << "CALL PRICE" << " ";
|
||||
cout << std::setw(16) << std::right << "~CALL PRICE" << "\n";
|
||||
cout << std::setw(16) << std::right << "CALL PRICE(D/C)" << " ";
|
||||
cout << std::setw(16) << std::right << "~CALL PRICE(C/D)" << " ";
|
||||
cout << std::setw(16) << std::right << "SWAN(D/C)" << " ";
|
||||
cout << std::setw(16) << std::right << "SWAN(C/D)" << "\n";
|
||||
cout << string(70, '=');
|
||||
|
||||
for( const call_order_object& o : db.get_index_type<call_order_index>().indices() )
|
||||
|
|
@ -805,6 +808,8 @@ void database_fixture::print_call_orders()const
|
|||
cout << std::setw( 16 ) << std::right << pretty( o.get_collateral() ) << " ";
|
||||
cout << std::setw( 16 ) << std::right << o.call_price.to_real() << " ";
|
||||
cout << std::setw( 16 ) << std::right << (~o.call_price).to_real() << " ";
|
||||
cout << std::setw( 16 ) << std::right << (o.get_debt()/o.get_collateral()).to_real() << " ";
|
||||
cout << std::setw( 16 ) << std::right << (~(o.get_debt()/o.get_collateral())).to_real() << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
|
@ -818,7 +823,7 @@ void database_fixture::print_joint_market( const string& syma, const string& sym
|
|||
cout << std::setw(10) << std::right << "TYPE" << " ";
|
||||
cout << std::setw(16) << std::right << "FOR SALE" << " ";
|
||||
cout << std::setw(16) << std::right << "FOR WHAT" << " ";
|
||||
cout << std::setw(16) << std::right << "PRICE" << "\n";
|
||||
cout << std::setw(16) << std::right << "PRICE (S/W)" << "\n";
|
||||
cout << string(70, '=');
|
||||
|
||||
const auto& limit_idx = db.get_index_type<limit_order_index>();
|
||||
|
|
|
|||
|
|
@ -39,10 +39,25 @@ using namespace graphene::chain;
|
|||
|
||||
BOOST_FIXTURE_TEST_SUITE( operation_tests, database_fixture )
|
||||
|
||||
BOOST_AUTO_TEST_CASE( feed_limit_logic_test )
|
||||
{
|
||||
try {
|
||||
asset usd(100,1);
|
||||
asset core(200,1);
|
||||
price_feed feed;
|
||||
feed.settlement_price = usd / core;
|
||||
|
||||
FC_ASSERT( usd * feed.settlement_price < usd * feed.maintenance_price() );
|
||||
FC_ASSERT( usd * feed.maintenance_price() < usd * feed.max_short_squeeze_price() );
|
||||
|
||||
} catch (fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
BOOST_AUTO_TEST_CASE( call_order_update_test )
|
||||
{
|
||||
try {
|
||||
BOOST_TEST_MESSAGE("creating actors dan and sam" );
|
||||
ACTORS((dan)(sam));
|
||||
const auto& bitusd = create_bitasset("BITUSD");
|
||||
const auto& core = asset_id_type()(db);
|
||||
|
|
@ -121,6 +136,315 @@ BOOST_AUTO_TEST_CASE( call_order_update_test )
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This test sets up a situation where a margin call will be executed and ensures that
|
||||
* it is properly filled.
|
||||
*
|
||||
* A margin call can happen in the following situation:
|
||||
* 0. there exists a bid above the mas short squeeze price
|
||||
* 1. highest bid is lower than the call price of an order
|
||||
* 2. the asset is not a prediction market
|
||||
* 3. there is a valid price feed
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE( margin_call_limit_test )
|
||||
{ try {
|
||||
ACTORS((buyer)(seller)(borrower)(borrower2)(feedproducer));
|
||||
|
||||
const auto& bitusd = create_bitasset("BITUSD");
|
||||
const auto& core = asset_id_type()(db);
|
||||
|
||||
int64_t init_balance(1000000);
|
||||
|
||||
transfer(genesis_account, buyer_id, asset(init_balance));
|
||||
transfer(genesis_account, borrower_id, asset(init_balance));
|
||||
transfer(genesis_account, borrower2_id, asset(init_balance));
|
||||
update_feed_producers( bitusd, {feedproducer.id} );
|
||||
|
||||
price_feed current_feed;
|
||||
current_feed.settlement_price = bitusd.amount( 100 ) / core.amount(100);
|
||||
auto default_call_price = ~price::call_price( bitusd.amount(100), asset(100), 1750);
|
||||
|
||||
// starting out with price 1:1
|
||||
publish_feed( bitusd, feedproducer, current_feed );
|
||||
|
||||
// start out with 2:1 collateral
|
||||
borrow( borrower, bitusd.amount(5000), asset(10000), default_call_price );
|
||||
borrow( borrower2, bitusd.amount(5000), asset(30000), default_call_price );
|
||||
elog( "selling USD at 1:1, should be ok because we have 2:1 collateral" );
|
||||
create_sell_order( borrower, bitusd.amount(5000), core.amount(5000) );
|
||||
elog( "buying USD at 1:1" );
|
||||
create_sell_order( buyer, core.amount(5000), bitusd.amount(5000) );
|
||||
|
||||
BOOST_REQUIRE_EQUAL( get_balance( borrower, bitusd ), 0 );
|
||||
BOOST_REQUIRE_EQUAL( get_balance( buyer, bitusd ), 4950 ); // 1% market fee
|
||||
BOOST_REQUIRE_EQUAL( get_balance( borrower, core ), init_balance - 10000 + 5000 );
|
||||
BOOST_REQUIRE_EQUAL( get_balance( buyer, core ), init_balance - 5000 );
|
||||
|
||||
ilog( "print call orders..." );
|
||||
print_call_orders();
|
||||
ilog( "print market..." );
|
||||
print_market( "", "" );
|
||||
|
||||
// sell the BitUSD for 50% more which represents a 33% fall in the value of the collateral
|
||||
const auto order = create_sell_order( borrower2, bitusd.amount(1000), core.amount(1400) );
|
||||
const auto order2 = create_sell_order( borrower2, bitusd.amount(1000), core.amount(1600) );
|
||||
const auto order3 = create_sell_order( borrower2, bitusd.amount(1000), core.amount(1700) );
|
||||
const auto order4 = create_sell_order( borrower2, bitusd.amount(1000), core.amount(1800) );
|
||||
const auto order5 = create_sell_order( borrower2, bitusd.amount(950), core.amount(1850) );
|
||||
|
||||
ilog( "print call orders..." );
|
||||
print_call_orders();
|
||||
ilog( "print market..." );
|
||||
print_market( "", "" );
|
||||
|
||||
FC_ASSERT( order, "order should not match because sell price is below short squeeze protection" );
|
||||
wdump((bitusd.bitasset_data(db).current_feed.max_short_squeeze_price().to_real()));
|
||||
wdump((bitusd.bitasset_data(db).current_feed.maintenance_price().to_real()));
|
||||
wdump(((order->sell_price).to_real()));
|
||||
|
||||
// update the feed to indicate a 33% drop in value
|
||||
BOOST_TEST_MESSAGE( "Update feed to indicate CORE fell in value by 33%" );
|
||||
current_feed.settlement_price = bitusd.amount( 100 ) / core.amount(200);
|
||||
publish_feed( bitusd, feedproducer, current_feed );
|
||||
|
||||
|
||||
/*
|
||||
const asset_object& bitusd = create_bitasset( "BITUSD" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
|
||||
db.modify( bitusd.bitasset_data(db), [&]( asset_bitasset_data_object& usd ){
|
||||
usd.current_feed.call_limit = core.amount(3) / bitusd.amount(1);
|
||||
});
|
||||
|
||||
const account_object& shorter1 = create_account( "shorter1" );
|
||||
const account_object& shorter2 = create_account( "shorter2" );
|
||||
const account_object& buyer1 = create_account( "buyer1" );
|
||||
const account_object& buyer2 = create_account( "buyer2" );
|
||||
|
||||
transfer( genesis_account(db), shorter1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), shorter2, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer2, asset( 10000 ) );
|
||||
|
||||
BOOST_REQUIRE( create_sell_order( buyer1, asset(1000), bitusd.amount(1000) ) );
|
||||
BOOST_REQUIRE( !create_short( shorter1, bitusd.amount(1000), asset(1000) ) );
|
||||
BOOST_REQUIRE_EQUAL( get_balance(buyer1, bitusd), 990 ); // 1000 - 1% fee
|
||||
|
||||
const auto& call_index = db.get_index_type<call_order_index>().indices().get<by_account>();
|
||||
const auto call_itr = call_index.find(boost::make_tuple(shorter1.id, bitusd.id));
|
||||
BOOST_REQUIRE( call_itr != call_index.end() );
|
||||
const call_order_object& call = *call_itr;
|
||||
BOOST_CHECK(call.get_collateral() == core.amount(2000));
|
||||
BOOST_CHECK(call.get_debt() == bitusd.amount(1000));
|
||||
BOOST_CHECK(call.call_price == price(core.amount(1500), bitusd.amount(1000)));
|
||||
BOOST_CHECK_EQUAL(get_balance(shorter1, core), 9000);
|
||||
|
||||
ilog( "=================================== START===================================\n\n");
|
||||
// this should cause the highest bid to below the margin call threshold
|
||||
// which means it should be filled by the cover
|
||||
auto unmatched = create_sell_order( buyer1, bitusd.amount(495), core.amount(750) );
|
||||
if( unmatched ) edump((*unmatched));
|
||||
BOOST_CHECK( !unmatched );
|
||||
BOOST_CHECK(call.get_debt() == bitusd.amount(505));
|
||||
BOOST_CHECK(call.get_collateral() == core.amount(1250));
|
||||
|
||||
auto below_call_price = create_sell_order(buyer1, bitusd.amount(200), core.amount(1));
|
||||
BOOST_REQUIRE(below_call_price);
|
||||
auto above_call_price = create_sell_order(buyer1, bitusd.amount(200), core.amount(303));
|
||||
BOOST_REQUIRE(above_call_price);
|
||||
auto above_id = above_call_price->id;
|
||||
|
||||
cancel_limit_order(*below_call_price);
|
||||
BOOST_CHECK_THROW(db.get_object(above_id), fc::exception);
|
||||
BOOST_CHECK(call.get_debt() == bitusd.amount(305));
|
||||
BOOST_CHECK(call.get_collateral() == core.amount(947));
|
||||
|
||||
below_call_price = create_sell_order(buyer1, bitusd.amount(200), core.amount(1));
|
||||
BOOST_REQUIRE(below_call_price);
|
||||
auto below_id = below_call_price->id;
|
||||
above_call_price = create_sell_order(buyer1, bitusd.amount(95), core.amount(144));
|
||||
BOOST_REQUIRE(above_call_price);
|
||||
above_id = above_call_price->id;
|
||||
auto match_below_call = create_sell_order(buyer2, core.amount(1), bitusd.amount(200));
|
||||
BOOST_CHECK(!match_below_call);
|
||||
|
||||
BOOST_CHECK_THROW(db.get_object(above_id), fc::exception);
|
||||
BOOST_CHECK_THROW(db.get_object(below_id), fc::exception);
|
||||
BOOST_CHECK(call.get_debt() == bitusd.amount(210));
|
||||
BOOST_CHECK(call.get_collateral() == core.amount(803));
|
||||
*/
|
||||
} catch( const fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( margin_call_limit_test_protected )
|
||||
{ try {
|
||||
FC_ASSERT( !"TODO - Reimplement with new short semantics" );
|
||||
/*
|
||||
const asset_object& bitusd = create_bitasset( "BITUSD" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
|
||||
db.modify( bitusd.bitasset_data(db), [&]( asset_bitasset_data_object& usd ){
|
||||
usd.current_feed.call_limit = core.amount(1) / bitusd.amount(1);
|
||||
});
|
||||
|
||||
const account_object& shorter1 = create_account( "shorter1" );
|
||||
const account_object& shorter2 = create_account( "shorter2" );
|
||||
const account_object& buyer1 = create_account( "buyer1" );
|
||||
const account_object& buyer2 = create_account( "buyer2" );
|
||||
|
||||
transfer( genesis_account(db), shorter1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), shorter2, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer2, asset( 10000 ) );
|
||||
|
||||
BOOST_REQUIRE( create_sell_order( buyer1, asset(1000), bitusd.amount(1000) ) );
|
||||
BOOST_REQUIRE( !create_short( shorter1, bitusd.amount(1000), asset(1000) ) );
|
||||
BOOST_REQUIRE_EQUAL( get_balance(buyer1, bitusd), 990 ); // 1000 - 1% fee
|
||||
|
||||
ilog( "=================================== START===================================\n\n");
|
||||
// this should cause the highest bid to below the margin call threshold
|
||||
// which means it should be filled by the cover
|
||||
auto unmatched = create_sell_order( buyer1, bitusd.amount(990), core.amount(1500) );
|
||||
if( unmatched ) edump((*unmatched));
|
||||
BOOST_REQUIRE( unmatched );
|
||||
*/
|
||||
|
||||
} catch( const fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( dont_margin_call_limit_test )
|
||||
{ try {
|
||||
FC_ASSERT( !"TODO - Reimplement with new short semantics" );
|
||||
/*
|
||||
const asset_object& bitusd = create_bitasset( "BITUSD" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
|
||||
db.modify( bitusd.bitasset_data(db), [&]( asset_bitasset_data_object& usd ){
|
||||
usd.current_feed.call_limit = core.amount(3) / bitusd.amount(1);
|
||||
});
|
||||
|
||||
const account_object& shorter1 = create_account( "shorter1" );
|
||||
const account_object& shorter2 = create_account( "shorter2" );
|
||||
const account_object& buyer1 = create_account( "buyer1" );
|
||||
const account_object& buyer2 = create_account( "buyer2" );
|
||||
|
||||
transfer( genesis_account(db), shorter1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), shorter2, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer2, asset( 10000 ) );
|
||||
|
||||
BOOST_REQUIRE( create_sell_order( buyer1, asset(1000), bitusd.amount(1000) ) );
|
||||
BOOST_REQUIRE( !create_short( shorter1, bitusd.amount(1000), asset(1000) ) );
|
||||
BOOST_REQUIRE_EQUAL( get_balance(buyer1, bitusd), 990 ); // 1000 - 1% fee
|
||||
|
||||
// this should cause the highest bid to below the margin call threshold
|
||||
// which means it should be filled by the cover
|
||||
auto unmatched = create_sell_order( buyer1, bitusd.amount(990), core.amount(1100) );
|
||||
if( unmatched ) edump((*unmatched));
|
||||
BOOST_REQUIRE( unmatched );
|
||||
*/
|
||||
|
||||
} catch( const fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( margin_call_short_test )
|
||||
{ try {
|
||||
FC_ASSERT( !"TODO - Reimplement with new short semantics" );
|
||||
/*
|
||||
const asset_object& bitusd = create_bitasset( "BITUSD" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
|
||||
db.modify( bitusd.bitasset_data(db), [&]( asset_bitasset_data_object& usd ){
|
||||
usd.current_feed.call_limit = core.amount(3) / bitusd.amount(1);
|
||||
});
|
||||
|
||||
const account_object& shorter1 = create_account( "shorter1" );
|
||||
const account_object& shorter2 = create_account( "shorter2" );
|
||||
const account_object& buyer1 = create_account( "buyer1" );
|
||||
const account_object& buyer2 = create_account( "buyer2" );
|
||||
|
||||
transfer( genesis_account(db), shorter1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), shorter2, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer2, asset( 10000 ) );
|
||||
|
||||
BOOST_REQUIRE( create_sell_order( buyer1, asset(1000), bitusd.amount(1000) ) );
|
||||
BOOST_REQUIRE( !create_short( shorter1, bitusd.amount(1000), asset(1000) ) );
|
||||
BOOST_REQUIRE_EQUAL( get_balance(buyer1, bitusd), 990 ); // 1000 - 1% fee
|
||||
ilog( "=================================== START===================================\n\n");
|
||||
|
||||
// this should cause the highest bid to below the margin call threshold
|
||||
// which means it should be filled by the cover
|
||||
auto unmatched = create_short( buyer1, bitusd.amount(990), core.amount(1500) );
|
||||
if( unmatched ) edump((*unmatched));
|
||||
BOOST_REQUIRE( !unmatched );
|
||||
*/
|
||||
|
||||
} catch( const fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( margin_call_short_test_limit_protected )
|
||||
{ try {
|
||||
FC_ASSERT( !"TODO - Reimplement with new short semantics" );
|
||||
/*
|
||||
const asset_object& bitusd = create_bitasset( "BITUSD" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
|
||||
db.modify( bitusd.bitasset_data(db), [&]( asset_bitasset_data_object& usd ){
|
||||
usd.current_feed.call_limit = core.amount(3) / bitusd.amount(4);
|
||||
});
|
||||
|
||||
const account_object& shorter1 = create_account( "shorter1" );
|
||||
const account_object& shorter2 = create_account( "shorter2" );
|
||||
const account_object& buyer1 = create_account( "buyer1" );
|
||||
const account_object& buyer2 = create_account( "buyer2" );
|
||||
|
||||
transfer( genesis_account(db), shorter1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), shorter2, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer2, asset( 10000 ) );
|
||||
|
||||
BOOST_REQUIRE( create_sell_order( buyer1, asset(1000), bitusd.amount(1000) ) );
|
||||
BOOST_REQUIRE( !create_short( shorter1, bitusd.amount(1000), asset(1000) ) );
|
||||
BOOST_REQUIRE_EQUAL( get_balance(buyer1, bitusd), 990 ); // 1000 - 1% fee
|
||||
ilog( "=================================== START===================================\n\n");
|
||||
|
||||
// this should cause the highest bid to below the margin call threshold
|
||||
// which means it should be filled by the cover
|
||||
auto unmatched = create_short( buyer1, bitusd.amount(990), core.amount(1500) );
|
||||
if( unmatched ) edump((*unmatched));
|
||||
BOOST_REQUIRE( unmatched );
|
||||
*/
|
||||
|
||||
} catch( const fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( create_account_test )
|
||||
{
|
||||
try {
|
||||
|
|
@ -947,234 +1271,6 @@ BOOST_AUTO_TEST_CASE( trade_amount_equals_zero )
|
|||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( margin_call_limit_test )
|
||||
{ try {
|
||||
FC_ASSERT( !"TODO - Reimplement with new short semantics" );
|
||||
/*
|
||||
const asset_object& bitusd = create_bitasset( "BITUSD" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
|
||||
db.modify( bitusd.bitasset_data(db), [&]( asset_bitasset_data_object& usd ){
|
||||
usd.current_feed.call_limit = core.amount(3) / bitusd.amount(1);
|
||||
});
|
||||
|
||||
const account_object& shorter1 = create_account( "shorter1" );
|
||||
const account_object& shorter2 = create_account( "shorter2" );
|
||||
const account_object& buyer1 = create_account( "buyer1" );
|
||||
const account_object& buyer2 = create_account( "buyer2" );
|
||||
|
||||
transfer( genesis_account(db), shorter1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), shorter2, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer2, asset( 10000 ) );
|
||||
|
||||
BOOST_REQUIRE( create_sell_order( buyer1, asset(1000), bitusd.amount(1000) ) );
|
||||
BOOST_REQUIRE( !create_short( shorter1, bitusd.amount(1000), asset(1000) ) );
|
||||
BOOST_REQUIRE_EQUAL( get_balance(buyer1, bitusd), 990 ); // 1000 - 1% fee
|
||||
|
||||
const auto& call_index = db.get_index_type<call_order_index>().indices().get<by_account>();
|
||||
const auto call_itr = call_index.find(boost::make_tuple(shorter1.id, bitusd.id));
|
||||
BOOST_REQUIRE( call_itr != call_index.end() );
|
||||
const call_order_object& call = *call_itr;
|
||||
BOOST_CHECK(call.get_collateral() == core.amount(2000));
|
||||
BOOST_CHECK(call.get_debt() == bitusd.amount(1000));
|
||||
BOOST_CHECK(call.call_price == price(core.amount(1500), bitusd.amount(1000)));
|
||||
BOOST_CHECK_EQUAL(get_balance(shorter1, core), 9000);
|
||||
|
||||
ilog( "=================================== START===================================\n\n");
|
||||
// this should cause the highest bid to below the margin call threshold
|
||||
// which means it should be filled by the cover
|
||||
auto unmatched = create_sell_order( buyer1, bitusd.amount(495), core.amount(750) );
|
||||
if( unmatched ) edump((*unmatched));
|
||||
BOOST_CHECK( !unmatched );
|
||||
BOOST_CHECK(call.get_debt() == bitusd.amount(505));
|
||||
BOOST_CHECK(call.get_collateral() == core.amount(1250));
|
||||
|
||||
auto below_call_price = create_sell_order(buyer1, bitusd.amount(200), core.amount(1));
|
||||
BOOST_REQUIRE(below_call_price);
|
||||
auto above_call_price = create_sell_order(buyer1, bitusd.amount(200), core.amount(303));
|
||||
BOOST_REQUIRE(above_call_price);
|
||||
auto above_id = above_call_price->id;
|
||||
|
||||
cancel_limit_order(*below_call_price);
|
||||
BOOST_CHECK_THROW(db.get_object(above_id), fc::exception);
|
||||
BOOST_CHECK(call.get_debt() == bitusd.amount(305));
|
||||
BOOST_CHECK(call.get_collateral() == core.amount(947));
|
||||
|
||||
below_call_price = create_sell_order(buyer1, bitusd.amount(200), core.amount(1));
|
||||
BOOST_REQUIRE(below_call_price);
|
||||
auto below_id = below_call_price->id;
|
||||
above_call_price = create_sell_order(buyer1, bitusd.amount(95), core.amount(144));
|
||||
BOOST_REQUIRE(above_call_price);
|
||||
above_id = above_call_price->id;
|
||||
auto match_below_call = create_sell_order(buyer2, core.amount(1), bitusd.amount(200));
|
||||
BOOST_CHECK(!match_below_call);
|
||||
|
||||
BOOST_CHECK_THROW(db.get_object(above_id), fc::exception);
|
||||
BOOST_CHECK_THROW(db.get_object(below_id), fc::exception);
|
||||
BOOST_CHECK(call.get_debt() == bitusd.amount(210));
|
||||
BOOST_CHECK(call.get_collateral() == core.amount(803));
|
||||
*/
|
||||
} catch( const fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( margin_call_limit_test_protected )
|
||||
{ try {
|
||||
FC_ASSERT( !"TODO - Reimplement with new short semantics" );
|
||||
/*
|
||||
const asset_object& bitusd = create_bitasset( "BITUSD" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
|
||||
db.modify( bitusd.bitasset_data(db), [&]( asset_bitasset_data_object& usd ){
|
||||
usd.current_feed.call_limit = core.amount(1) / bitusd.amount(1);
|
||||
});
|
||||
|
||||
const account_object& shorter1 = create_account( "shorter1" );
|
||||
const account_object& shorter2 = create_account( "shorter2" );
|
||||
const account_object& buyer1 = create_account( "buyer1" );
|
||||
const account_object& buyer2 = create_account( "buyer2" );
|
||||
|
||||
transfer( genesis_account(db), shorter1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), shorter2, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer2, asset( 10000 ) );
|
||||
|
||||
BOOST_REQUIRE( create_sell_order( buyer1, asset(1000), bitusd.amount(1000) ) );
|
||||
BOOST_REQUIRE( !create_short( shorter1, bitusd.amount(1000), asset(1000) ) );
|
||||
BOOST_REQUIRE_EQUAL( get_balance(buyer1, bitusd), 990 ); // 1000 - 1% fee
|
||||
|
||||
ilog( "=================================== START===================================\n\n");
|
||||
// this should cause the highest bid to below the margin call threshold
|
||||
// which means it should be filled by the cover
|
||||
auto unmatched = create_sell_order( buyer1, bitusd.amount(990), core.amount(1500) );
|
||||
if( unmatched ) edump((*unmatched));
|
||||
BOOST_REQUIRE( unmatched );
|
||||
*/
|
||||
|
||||
} catch( const fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( dont_margin_call_limit_test )
|
||||
{ try {
|
||||
FC_ASSERT( !"TODO - Reimplement with new short semantics" );
|
||||
/*
|
||||
const asset_object& bitusd = create_bitasset( "BITUSD" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
|
||||
db.modify( bitusd.bitasset_data(db), [&]( asset_bitasset_data_object& usd ){
|
||||
usd.current_feed.call_limit = core.amount(3) / bitusd.amount(1);
|
||||
});
|
||||
|
||||
const account_object& shorter1 = create_account( "shorter1" );
|
||||
const account_object& shorter2 = create_account( "shorter2" );
|
||||
const account_object& buyer1 = create_account( "buyer1" );
|
||||
const account_object& buyer2 = create_account( "buyer2" );
|
||||
|
||||
transfer( genesis_account(db), shorter1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), shorter2, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer2, asset( 10000 ) );
|
||||
|
||||
BOOST_REQUIRE( create_sell_order( buyer1, asset(1000), bitusd.amount(1000) ) );
|
||||
BOOST_REQUIRE( !create_short( shorter1, bitusd.amount(1000), asset(1000) ) );
|
||||
BOOST_REQUIRE_EQUAL( get_balance(buyer1, bitusd), 990 ); // 1000 - 1% fee
|
||||
|
||||
// this should cause the highest bid to below the margin call threshold
|
||||
// which means it should be filled by the cover
|
||||
auto unmatched = create_sell_order( buyer1, bitusd.amount(990), core.amount(1100) );
|
||||
if( unmatched ) edump((*unmatched));
|
||||
BOOST_REQUIRE( unmatched );
|
||||
*/
|
||||
|
||||
} catch( const fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( margin_call_short_test )
|
||||
{ try {
|
||||
FC_ASSERT( !"TODO - Reimplement with new short semantics" );
|
||||
/*
|
||||
const asset_object& bitusd = create_bitasset( "BITUSD" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
|
||||
db.modify( bitusd.bitasset_data(db), [&]( asset_bitasset_data_object& usd ){
|
||||
usd.current_feed.call_limit = core.amount(3) / bitusd.amount(1);
|
||||
});
|
||||
|
||||
const account_object& shorter1 = create_account( "shorter1" );
|
||||
const account_object& shorter2 = create_account( "shorter2" );
|
||||
const account_object& buyer1 = create_account( "buyer1" );
|
||||
const account_object& buyer2 = create_account( "buyer2" );
|
||||
|
||||
transfer( genesis_account(db), shorter1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), shorter2, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer2, asset( 10000 ) );
|
||||
|
||||
BOOST_REQUIRE( create_sell_order( buyer1, asset(1000), bitusd.amount(1000) ) );
|
||||
BOOST_REQUIRE( !create_short( shorter1, bitusd.amount(1000), asset(1000) ) );
|
||||
BOOST_REQUIRE_EQUAL( get_balance(buyer1, bitusd), 990 ); // 1000 - 1% fee
|
||||
ilog( "=================================== START===================================\n\n");
|
||||
|
||||
// this should cause the highest bid to below the margin call threshold
|
||||
// which means it should be filled by the cover
|
||||
auto unmatched = create_short( buyer1, bitusd.amount(990), core.amount(1500) );
|
||||
if( unmatched ) edump((*unmatched));
|
||||
BOOST_REQUIRE( !unmatched );
|
||||
*/
|
||||
|
||||
} catch( const fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( margin_call_short_test_limit_protected )
|
||||
{ try {
|
||||
FC_ASSERT( !"TODO - Reimplement with new short semantics" );
|
||||
/*
|
||||
const asset_object& bitusd = create_bitasset( "BITUSD" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
|
||||
db.modify( bitusd.bitasset_data(db), [&]( asset_bitasset_data_object& usd ){
|
||||
usd.current_feed.call_limit = core.amount(3) / bitusd.amount(4);
|
||||
});
|
||||
|
||||
const account_object& shorter1 = create_account( "shorter1" );
|
||||
const account_object& shorter2 = create_account( "shorter2" );
|
||||
const account_object& buyer1 = create_account( "buyer1" );
|
||||
const account_object& buyer2 = create_account( "buyer2" );
|
||||
|
||||
transfer( genesis_account(db), shorter1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), shorter2, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer1, asset( 10000 ) );
|
||||
transfer( genesis_account(db), buyer2, asset( 10000 ) );
|
||||
|
||||
BOOST_REQUIRE( create_sell_order( buyer1, asset(1000), bitusd.amount(1000) ) );
|
||||
BOOST_REQUIRE( !create_short( shorter1, bitusd.amount(1000), asset(1000) ) );
|
||||
BOOST_REQUIRE_EQUAL( get_balance(buyer1, bitusd), 990 ); // 1000 - 1% fee
|
||||
ilog( "=================================== START===================================\n\n");
|
||||
|
||||
// this should cause the highest bid to below the margin call threshold
|
||||
// which means it should be filled by the cover
|
||||
auto unmatched = create_short( buyer1, bitusd.amount(990), core.amount(1500) );
|
||||
if( unmatched ) edump((*unmatched));
|
||||
BOOST_REQUIRE( unmatched );
|
||||
*/
|
||||
|
||||
} catch( const fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an order that cannot be filled immediately and have the
|
||||
|
|
|
|||
Loading…
Reference in a new issue