asset database::match( const call_order_object& call, const force_settlement_object& settle, const price& match_price, asset max_settlement ) { try { FC_ASSERT(call.get_debt().asset_id == settle.balance.asset_id ); FC_ASSERT(call.debt > 0 && call.collateral > 0 && settle.balance.amount > 0); auto settle_for_sale = std::min(settle.balance, max_settlement); auto call_debt = call.get_debt(); asset call_receives = std::min(settle_for_sale, call_debt); asset call_pays = call_receives * match_price; asset settle_pays = call_receives; asset settle_receives = call_pays; /** * If the least collateralized call position lacks sufficient * collateral to cover at the match price then this indicates a black * swan event according to the price feed, but only the market * can trigger a black swan. So now we must cancel the forced settlement * object. */ GRAPHENE_ASSERT( call_pays < call.get_collateral(), black_swan_exception, "" ); assert( settle_pays == settle_for_sale || call_receives == call.get_debt() ); fill_order(call, call_pays, call_receives); fill_order(settle, settle_pays, settle_receives); return call_receives; } FC_CAPTURE_AND_RETHROW( (call)(settle)(match_price)(max_settlement) ) }
OP_ERR fill_buy_order(uint32_t acct_id, orderbook_order_t *matched_order, option_order_t *order){ if(matched_order == NULL){ return NO_MATCH; } return fill_order(acct_id, order, matched_order); }
asset database::match( const call_order_object& call, const force_settlement_object& settle, const price& match_price, asset max_settlement ) { assert(call.get_debt().asset_id == settle.balance.asset_id ); assert(call.debt > 0 && call.collateral > 0 && settle.balance.amount > 0); auto settle_for_sale = std::min(settle.balance, max_settlement); auto call_debt = call.get_debt(); asset call_receives = std::min(settle_for_sale, call_debt), call_pays = call_receives * match_price, settle_pays = call_receives, settle_receives = call_pays; assert( settle_pays == settle_for_sale || call_receives == call.get_debt() ); fill_order(call, call_pays, call_receives); fill_order(settle, settle_pays, settle_receives); return call_receives; }
int database::match( const limit_order_object& usd, const OrderType& core, const price& match_price ) { assert( usd.sell_price.quote.asset_id == core.sell_price.base.asset_id ); assert( usd.sell_price.base.asset_id == core.sell_price.quote.asset_id ); assert( usd.for_sale > 0 && core.for_sale > 0 ); auto usd_for_sale = usd.amount_for_sale(); auto core_for_sale = core.amount_for_sale(); asset usd_pays, usd_receives, core_pays, core_receives; if( usd_for_sale <= core_for_sale * match_price ) { core_receives = usd_for_sale; usd_receives = usd_for_sale * match_price; } else { //This line once read: assert( core_for_sale < usd_for_sale * match_price ); //This assert is not always true -- see trade_amount_equals_zero in operation_tests.cpp //Although usd_for_sale is greater than core_for_sale * match_price, core_for_sale == usd_for_sale * match_price //Removing the assert seems to be safe -- apparently no asset is created or destroyed. usd_receives = core_for_sale; core_receives = core_for_sale * match_price; } core_pays = usd_receives; usd_pays = core_receives; assert( usd_pays == usd.amount_for_sale() || core_pays == core.amount_for_sale() ); int result = 0; result |= fill_order( usd, usd_pays, usd_receives, false ); result |= fill_order( core, core_pays, core_receives, true ) << 1; assert( result != 0 ); return result; }
void paintshop_staff(void *unusedpointer, unsigned long staff) { void *o; int i; (void)unusedpointer; /* avoid compiler warning */ i = 0; /* count orders filled for stats */ while (1) { #ifdef PRINT_ON kprintf("S %ld taking order\n", staff); #endif o = take_order(); if (o != NULL) { #ifdef PRINT_ON kprintf("S %ld filling\n", staff); #endif i++; fill_order(o); #ifdef PRINT_ON kprintf("S %ld serving\n", staff); #endif serve_order(o); } else { break; } }; kprintf("S %ld going home after mixing %d orders\n", staff, i); V(alldone); }
void solve_case(void) { int order[MAX_N]; int fixed, t; int len = 0; for (fixed = 1; fixed <= n; fixed++) { if (fill_order(fixed, order) != n) { /* cannot get all n people, not solvable */ fprintf(out, "Not solvable.\n"); return; } if ((t = inc_seq(order+1, n-1)) > len) { len = t; } if ((t = dec_seq(order+1, n-1)) > len) { len = t; } } fprintf(out, "Knot solvable.\n%d\n", n-1-len); }
/** * Starting with the least collateralized orders, fill them if their * call price is above the max(lowest bid,call_limit). * * This method will return true if it filled a short or limit * * @param mia - the market issued asset that should be called. * @param enable_black_swan - when adjusting collateral, triggering a black swan is invalid and will throw * if enable_black_swan is not set to true. * * @return true if a margin call was executed. */ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan) { try { if( !mia.is_market_issued() ) return false; if( check_for_blackswan( mia, enable_black_swan ) ) return false; const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this); if( bitasset.is_prediction_market ) return false; if( bitasset.current_feed.settlement_price.is_null() ) return false; const call_order_index& call_index = get_index_type<call_order_index>(); const auto& call_price_index = call_index.indices().get<by_price>(); 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 ); // stop when limit orders are selling too little USD for too much CORE auto min_price = bitasset.current_feed.max_short_squeeze_price(); assert( max_price.base.asset_id == min_price.base.asset_id ); // 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_end ) return false; auto call_min = price::min( bitasset.options.short_backing_asset, mia.id ); auto call_max = price::max( bitasset.options.short_backing_asset, mia.id ); auto call_itr = call_price_index.lower_bound( call_min ); auto call_end = call_price_index.upper_bound( call_max ); bool filled_limit = false; bool margin_called = false; while( !check_for_blackswan( mia, enable_black_swan ) && call_itr != call_end ) { bool filled_call = false; price match_price; asset usd_for_sale; if( limit_itr != limit_end ) { assert( limit_itr != limit_price_index.end() ); match_price = limit_itr->sell_price; usd_for_sale = limit_itr->amount_for_sale(); } else return margin_called; match_price.validate(); // would be margin called, but there is no matching order #436 bool feed_protected = ( bitasset.current_feed.settlement_price > ~call_itr->call_price ); if( feed_protected && (head_block_time() > HARDFORK_436_TIME) ) return margin_called; // would be margin called, but there is no matching order if( match_price > ~call_itr->call_price ) return margin_called; if( feed_protected ) { ilog( "Feed protected margin call executing (HARDFORK_436_TIME not here yet)" ); idump( (*call_itr) ); idump( (*limit_itr) ); } // idump((*call_itr)); // idump((*limit_itr)); // ilog( "match_price <= ~call_itr->call_price performing a margin call" ); margin_called = true; auto usd_to_buy = call_itr->get_debt(); if( usd_to_buy * match_price > call_itr->get_collateral() ) { elog( "black swan detected" ); edump((enable_black_swan)); FC_ASSERT( enable_black_swan ); globally_settle_asset(mia, bitasset.current_feed.settlement_price ); return true; } asset call_pays, call_receives, order_pays, order_receives; if( usd_to_buy >= usd_for_sale ) { // fill order call_receives = usd_for_sale; order_receives = usd_for_sale * match_price; call_pays = order_receives; order_pays = usd_for_sale; filled_limit = true; filled_call = (usd_to_buy == usd_for_sale); } else { // fill call call_receives = usd_to_buy; order_receives = usd_to_buy * match_price; call_pays = order_receives; order_pays = usd_to_buy; filled_call = true; } FC_ASSERT( filled_call || filled_limit ); auto old_call_itr = call_itr; if( filled_call ) ++call_itr; fill_order(*old_call_itr, call_pays, call_receives); auto old_limit_itr = filled_limit ? limit_itr++ : limit_itr; fill_order(*old_limit_itr, order_pays, order_receives, true); } // whlie call_itr != call_end return margin_called; } FC_CAPTURE_AND_RETHROW() }
/** * Starting with the least collateralized orders, fill them if their * call price is above the max(lowest bid,call_limit). * * This method will return true if it filled a short or limit * * @param mia - the market issued asset that should be called. * @param enable_black_swan - when adjusting collateral, triggering a black swan is invalid and will throw * if enable_black_swan is not set to true. * * @return true if a margin call was executed. */ bool database::check_call_orders(const asset_object& mia, bool enable_black_swan) { try { if( !mia.is_market_issued() ) return false; const asset_bitasset_data_object& bitasset = mia.bitasset_data(*this); if( bitasset.is_prediction_market ) return false; if( bitasset.current_feed.settlement_price.is_null() ) return false; const call_order_index& call_index = get_index_type<call_order_index>(); const auto& call_price_index = call_index.indices().get<by_price>(); 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 ); // stop when limit orders are selling too little USD for too much CORE auto min_price = bitasset.current_feed.max_short_squeeze_price(); assert( max_price.base.asset_id == min_price.base.asset_id ); // 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_end ) { return false; } auto call_itr = call_price_index.lower_bound( price::min( bitasset.options.short_backing_asset, mia.id ) ); auto call_end = call_price_index.upper_bound( price::max( bitasset.options.short_backing_asset, mia.id ) ); bool filled_limit = false; while( call_itr != call_end ) { bool filled_call = false; price match_price; asset usd_for_sale; if( limit_itr != limit_end ) { assert( limit_itr != limit_price_index.end() ); match_price = limit_itr->sell_price; usd_for_sale = limit_itr->amount_for_sale(); } else return filled_limit; match_price.validate(); if( match_price > ~call_itr->call_price ) { return filled_limit; } auto usd_to_buy = call_itr->get_debt(); if( usd_to_buy * match_price > call_itr->get_collateral() ) { FC_ASSERT( enable_black_swan ); //globally_settle_asset(mia, call_itr->get_debt() / call_itr->get_collateral()); globally_settle_asset(mia, bitasset.current_feed.settlement_price );// call_itr->get_debt() / call_itr->get_collateral()); return true; } asset call_pays, call_receives, order_pays, order_receives; if( usd_to_buy >= usd_for_sale ) { // fill order call_receives = usd_for_sale; order_receives = usd_for_sale * match_price; call_pays = order_receives; order_pays = usd_for_sale; filled_limit = true; filled_call = (usd_to_buy == usd_for_sale); } else { // fill call call_receives = usd_to_buy; order_receives = usd_to_buy * match_price; call_pays = order_receives; order_pays = usd_to_buy; filled_call = true; } auto old_call_itr = call_itr; if( filled_call ) ++call_itr; fill_order(*old_call_itr, call_pays, call_receives); auto old_limit_itr = filled_limit ? limit_itr++ : limit_itr; fill_order(*old_limit_itr, order_pays, order_receives); } // whlie call_itr != call_end return filled_limit; } FC_CAPTURE_AND_RETHROW() }