Merge commit 'ee3f81fa31e39a8ae4ebcfe5b3d78f2dbc103e1b' into betting

This commit is contained in:
Eric Frias 2017-06-20 17:44:12 -04:00
commit 50fef80189
4 changed files with 285 additions and 128 deletions

View file

@ -31,6 +31,8 @@
#include <fc/crypto/hex.hpp> #include <fc/crypto/hex.hpp>
#include <boost/range/iterator_range.hpp> #include <boost/range/iterator_range.hpp>
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <cctype> #include <cctype>
@ -1090,56 +1092,37 @@ market_ticker database_api_impl::get_ticker( const string& base, const string& q
try { try {
if( base_id > quote_id ) std::swap(base_id, quote_id); if( base_id > quote_id ) std::swap(base_id, quote_id);
const auto& bidx = _db.get_index_type<bucket_index>(); uint32_t day = 86400;
const auto& by_key_idx = bidx.indices().get<by_key>();
uint32_t bucket_size = 86400;
auto now = fc::time_point_sec( fc::time_point::now() ); auto now = fc::time_point_sec( fc::time_point::now() );
auto itr = by_key_idx.lower_bound( bucket_key( base_id, quote_id, bucket_size,
now - bucket_size ) );
auto orders = get_order_book( base, quote, 1 ); auto orders = get_order_book( base, quote, 1 );
auto trades = get_trade_history( base, quote, now, fc::time_point_sec( now.sec_since_epoch() - day ), 100 );
if( itr != by_key_idx.end() && itr->key.base == base_id && itr->key.quote == quote_id && itr->key.seconds == bucket_size ) result.latest = trades[0].price;
for ( market_trade t: trades )
{ {
auto trades = get_trade_history( base, quote, now, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 ); result.base_volume += t.value;
result.quote_volume += t.amount;
}
if (assets[0]->id == base_id) while (trades.size() == 100)
{ {
result.latest = trades[0].price; trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - day ), 100 );
result.percent_change = ( result.latest / ( price_to_real( itr->open_quote, assets[1]->precision ) / price_to_real( itr->open_base, assets[0]->precision ) ) - 1 ) * 100;
//result.lowest_ask = price_to_real( itr->low_quote, assets[1]->precision ) / price_to_real( itr->low_base, assets[0]->precision );
//result.highest_bid = price_to_real( itr->high_quote, assets[1]->precision ) / price_to_real( itr->high_base, assets[0]->precision );
result.lowest_ask = orders.asks[0].first;
result.highest_bid = orders.bids[0].first;
}
else
{
result.latest = trades[0].price;
result.percent_change = ( result.latest / ( price_to_real( itr->open_base, assets[1]->precision ) / price_to_real( itr->open_quote, assets[0]->precision ) ) - 1) * 100;
//result.lowest_ask = price_to_real( itr->low_base, assets[1]->precision ) / price_to_real( itr->low_quote, assets[0]->precision );
//result.highest_bid = price_to_real( itr->high_base, assets[1]->precision ) / price_to_real( itr->high_quote, assets[0]->precision );
result.lowest_ask = orders.bids[0].first;
result.highest_bid = orders.asks[0].first;
}
for ( market_trade t: trades ) for ( market_trade t: trades )
{ {
result.base_volume += t.amount; result.base_volume += t.value;
result.quote_volume += t.value; result.quote_volume += t.amount;
} }
}
while (trades.size() == 100) trades = get_trade_history( base, quote, trades.back().date, fc::time_point_sec(), 1 );
{ result.percent_change = trades.size() > 0 ? ( ( result.latest / trades.back().price ) - 1 ) * 100 : 0;
for ( market_trade t: trades )
{
result.base_volume += t.amount;
result.quote_volume += t.value;
}
trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 );
}
//if (assets[0]->id == base_id)
{
result.lowest_ask = orders.asks[0].price;
result.highest_bid = orders.bids[0].price;
} }
return result; return result;
@ -1176,19 +1159,19 @@ market_volume database_api_impl::get_24_volume( const string& base, const string
for ( market_trade t: trades ) for ( market_trade t: trades )
{ {
result.base_volume += t.amount; result.base_volume += t.value;
result.quote_volume += t.value; result.quote_volume += t.amount;
} }
while (trades.size() == 100) while (trades.size() == 100)
{ {
trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 );
for ( market_trade t: trades ) for ( market_trade t: trades )
{ {
result.base_volume += t.amount; result.base_volume += t.value;
result.quote_volume += t.value; result.quote_volume += t.amount;
} }
trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 );
} }
return result; return result;
@ -1202,6 +1185,7 @@ order_book database_api::get_order_book( const string& base, const string& quote
order_book database_api_impl::get_order_book( const string& base, const string& quote, unsigned limit )const order_book database_api_impl::get_order_book( const string& base, const string& quote, unsigned limit )const
{ {
using boost::multiprecision::uint128_t;
FC_ASSERT( limit <= 50 ); FC_ASSERT( limit <= 50 );
order_book result; order_book result;
@ -1221,21 +1205,28 @@ order_book database_api_impl::get_order_book( const string& base, const string&
auto price_to_real = [&]( const price& p ) auto price_to_real = [&]( const price& p )
{ {
if( p.base.asset_id == base_id ) if( p.base.asset_id == base_id )
return asset_to_real( p.quote, assets[1]->precision ) / asset_to_real( p.base, assets[0]->precision ); return asset_to_real( p.base, assets[0]->precision ) / asset_to_real( p.quote, assets[1]->precision );
else else
return asset_to_real( p.base, assets[1]->precision ) / asset_to_real( p.quote, assets[0]->precision ); return asset_to_real( p.quote, assets[0]->precision ) / asset_to_real( p.base, assets[1]->precision );
}; };
for( const auto& o : orders ) { for( const auto& o : orders )
{
if( o.sell_price.base.asset_id == base_id ) if( o.sell_price.base.asset_id == base_id )
{ {
result.asks.push_back( std::make_pair( price_to_real(o.sell_price), order ord;
asset_to_real(o.sell_price.base, assets[0]->precision)) ); ord.price = price_to_real( o.sell_price );
ord.quote = asset_to_real( share_type( ( uint128_t( o.for_sale.value ) * o.sell_price.quote.amount.value ) / o.sell_price.base.amount.value ), assets[1]->precision );
ord.base = asset_to_real( o.for_sale, assets[0]->precision );
result.bids.push_back( ord );
} }
else else
{ {
result.bids.push_back( std::make_pair( price_to_real(o.sell_price), order ord;
asset_to_real(o.sell_price.quote, assets[0]->precision ) ) ); ord.price = price_to_real( o.sell_price );
ord.quote = asset_to_real( o.for_sale, assets[1]->precision );
ord.base = asset_to_real( share_type( ( uint64_t( o.for_sale.value ) * o.sell_price.quote.amount.value ) / o.sell_price.base.amount.value ), assets[0]->precision );
result.asks.push_back( ord );
} }
} }
@ -1290,13 +1281,13 @@ vector<market_trade> database_api_impl::get_trade_history( const string& base,
if( assets[0]->id == itr->op.receives.asset_id ) if( assets[0]->id == itr->op.receives.asset_id )
{ {
trade.amount = price_to_real( itr->op.receives.amount, assets[0]->precision ); trade.amount = price_to_real( itr->op.pays.amount, assets[1]->precision );
trade.value = price_to_real( itr->op.pays.amount, assets[1]->precision ); trade.value = price_to_real( itr->op.receives.amount, assets[0]->precision );
} }
else else
{ {
trade.amount = price_to_real( itr->op.pays.amount, assets[0]->precision ); trade.amount = price_to_real( itr->op.receives.amount, assets[1]->precision );
trade.value = price_to_real( itr->op.receives.amount, assets[1]->precision ); trade.value = price_to_real( itr->op.pays.amount, assets[0]->precision );
} }
trade.date = itr->time; trade.date = itr->time;

View file

@ -69,40 +69,47 @@ using namespace std;
class database_api_impl; class database_api_impl;
struct order
{
double price;
double quote;
double base;
};
struct order_book struct order_book
{ {
string base; string base;
string quote; string quote;
vector< pair<double,double> > bids; vector< order > bids;
vector< pair<double,double> > asks; vector< order > asks;
}; };
struct market_ticker struct market_ticker
{ {
string base; string base;
string quote; string quote;
double latest; double latest;
double lowest_ask; double lowest_ask;
double highest_bid; double highest_bid;
double percent_change; double percent_change;
double base_volume; double base_volume;
double quote_volume; double quote_volume;
}; };
struct market_volume struct market_volume
{ {
string base; string base;
string quote; string quote;
double base_volume; double base_volume;
double quote_volume; double quote_volume;
}; };
struct market_trade struct market_trade
{ {
fc::time_point_sec date; fc::time_point_sec date;
double price; double price;
double amount; double amount;
double value; double value;
}; };
/** /**
@ -587,6 +594,8 @@ class database_api
}; };
} } } }
FC_REFLECT( graphene::app::order, (price)(quote)(base) );
FC_REFLECT( graphene::app::order_book, (base)(quote)(bids)(asks) ); FC_REFLECT( graphene::app::order_book, (base)(quote)(bids)(asks) );
FC_REFLECT( graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume) ); FC_REFLECT( graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume) );
FC_REFLECT( graphene::app::market_volume, (base)(quote)(base_volume)(quote_volume) ); FC_REFLECT( graphene::app::market_volume, (base)(quote)(base_volume)(quote_volume) );

View file

@ -852,6 +852,51 @@ class wallet_api
bool fill_or_kill = false, bool fill_or_kill = false,
bool broadcast = false); bool broadcast = false);
/** Place a limit order attempting to sell one asset for another.
*
* This API call abstracts away some of the details of the sell_asset call to be more
* user friendly. All orders placed with sell never timeout and will not be killed if they
* cannot be filled immediately. If you wish for one of these parameters to be different,
* then sell_asset should be used instead.
*
* @param seller_account the account providing the asset being sold, and which will
* receive the processed of the sale.
* @param base The name or id of the asset to sell.
* @param quote The name or id of the asset to recieve.
* @param rate The rate in base:quote at which you want to sell.
* @param amount The amount of base you want to sell.
* @param broadcast true to broadcast the transaction on the network.
* @returns The signed transaction selling the funds.
*/
signed_transaction sell( string seller_account,
string base,
string quote,
double rate,
double amount,
bool broadcast );
/** Place a limit order attempting to buy one asset with another.
*
* This API call abstracts away some of the details of the sell_asset call to be more
* user friendly. All orders placed with buy never timeout and will not be killed if they
* cannot be filled immediately. If you wish for one of these parameters to be different,
* then sell_asset should be used instead.
*
* @param buyer_account The account buying the asset for another asset.
* @param base The name or id of the asset to buy.
* @param quote The name or id of the assest being offered as payment.
* @param rate The rate in base:quote at which you want to buy.
* @param amount the amount of base you want to buy.
* @param broadcast true to broadcast the transaction on the network.
* @param The signed transaction selling the funds.
*/
signed_transaction buy( string buyer_account,
string base,
string quote,
double rate,
double amount,
bool broadcast );
/** Borrow an asset or update the debt/collateral ratio for the loan. /** Borrow an asset or update the debt/collateral ratio for the loan.
* *
* This is the first step in shorting an asset. Call \c sell_asset() to complete the short. * This is the first step in shorting an asset. Call \c sell_asset() to complete the short.
@ -1404,6 +1449,8 @@ class wallet_api
bool broadcast /* = false */ bool broadcast /* = false */
); );
order_book get_order_book( const string& base, const string& quote, unsigned limit = 50);
vector<sport_object> list_sports() const; vector<sport_object> list_sports() const;
vector<event_group_object> list_event_groups(sport_id_type sport_id) const; vector<event_group_object> list_event_groups(sport_id_type sport_id) const;
vector<betting_market_group_object> list_betting_market_groups(event_id_type event_id) const; vector<betting_market_group_object> list_betting_market_groups(event_id_type event_id) const;
@ -1584,6 +1631,8 @@ FC_API( graphene::wallet::wallet_api,
(upgrade_account) (upgrade_account)
(create_account_with_brain_key) (create_account_with_brain_key)
(sell_asset) (sell_asset)
(sell)
(buy)
(borrow_asset) (borrow_asset)
(cancel_order) (cancel_order)
(transfer) (transfer)
@ -1669,4 +1718,5 @@ FC_API( graphene::wallet::wallet_api,
(propose_create_betting_market) (propose_create_betting_market)
(place_bet) (place_bet)
(propose_resolve_betting_market) (propose_resolve_betting_market)
(get_order_book)
) )

View file

@ -2166,6 +2166,90 @@ public:
} }
return ss.str(); return ss.str();
}; };
m["get_order_book"] = [this](variant result, const fc::variants& a)
{
auto orders = result.as<order_book>();
auto bids = orders.bids;
auto asks = orders.asks;
std::stringstream ss;
std::stringstream sum_stream;
sum_stream << "Sum(" << orders.base << ')';
double bid_sum = 0;
double ask_sum = 0;
const int spacing = 20;
auto prettify_num = [&]( double n )
{
//ss << n;
if (abs( round( n ) - n ) < 0.00000000001 )
{
//ss << setiosflags( !ios::fixed ) << (int) n; // doesn't compile on Linux with gcc
ss << (int) n;
}
else if (n - floor(n) < 0.000001)
{
ss << setiosflags( ios::fixed ) << setprecision(10) << n;
}
else
{
ss << setiosflags( ios::fixed ) << setprecision(6) << n;
}
};
ss << setprecision( 8 ) << setiosflags( ios::fixed ) << setiosflags( ios::left );
ss << ' ' << setw( (spacing * 4) + 6 ) << "BUY ORDERS" << "SELL ORDERS\n"
<< ' ' << setw( spacing + 1 ) << "Price" << setw( spacing ) << orders.quote << ' ' << setw( spacing )
<< orders.base << ' ' << setw( spacing ) << sum_stream.str()
<< " " << setw( spacing + 1 ) << "Price" << setw( spacing ) << orders.quote << ' ' << setw( spacing )
<< orders.base << ' ' << setw( spacing ) << sum_stream.str()
<< "\n====================================================================================="
<< "|=====================================================================================\n";
for (int i = 0; i < bids.size() || i < asks.size() ; i++)
{
if ( i < bids.size() )
{
bid_sum += bids[i].base;
ss << ' ' << setw( spacing );
prettify_num( bids[i].price );
ss << ' ' << setw( spacing );
prettify_num( bids[i].quote );
ss << ' ' << setw( spacing );
prettify_num( bids[i].base );
ss << ' ' << setw( spacing );
prettify_num( bid_sum );
ss << ' ';
}
else
{
ss << setw( (spacing * 4) + 5 ) << ' ';
}
ss << '|';
if ( i < asks.size() )
{
ask_sum += asks[i].base;
ss << ' ' << setw( spacing );
prettify_num( asks[i].price );
ss << ' ' << setw( spacing );
prettify_num( asks[i].quote );
ss << ' ' << setw( spacing );
prettify_num( asks[i].base );
ss << ' ' << setw( spacing );
prettify_num( ask_sum );
}
ss << '\n';
}
ss << endl
<< "Buy Total: " << bid_sum << ' ' << orders.base << endl
<< "Sell Total: " << ask_sum << ' ' << orders.base << endl;
return ss.str();
};
return m; return m;
} }
@ -3552,6 +3636,28 @@ signed_transaction wallet_api::sell_asset(string seller_account,
symbol_to_receive, expiration, fill_or_kill, broadcast); symbol_to_receive, expiration, fill_or_kill, broadcast);
} }
signed_transaction wallet_api::sell( string seller_account,
string base,
string quote,
double rate,
double amount,
bool broadcast )
{
return my->sell_asset( seller_account, std::to_string( amount ), base,
std::to_string( rate * amount ), quote, 0, false, broadcast );
}
signed_transaction wallet_api::buy( string buyer_account,
string base,
string quote,
double rate,
double amount,
bool broadcast )
{
return my->sell_asset( buyer_account, std::to_string( rate * amount ), quote,
std::to_string( amount ), base, 0, false, broadcast );
}
signed_transaction wallet_api::borrow_asset(string seller_name, string amount_to_sell, signed_transaction wallet_api::borrow_asset(string seller_name, string amount_to_sell,
string asset_symbol, string amount_of_collateral, bool broadcast) string asset_symbol, string amount_of_collateral, bool broadcast)
{ {
@ -4355,11 +4461,12 @@ signed_transaction wallet_api::propose_resolve_betting_market(
return my->sign_transaction(tx, broadcast); return my->sign_transaction(tx, broadcast);
} }
// default ctor necessary for FC_REFLECT order_book wallet_api::get_order_book( const string& base, const string& quote, unsigned limit )
signed_block_with_info::signed_block_with_info()
{ {
return( my->_remote_db->get_order_book( base, quote, limit ) );
} }
// default ctor necessary for FC_REFLECT
signed_block_with_info::signed_block_with_info( const signed_block& block ) signed_block_with_info::signed_block_with_info( const signed_block& block )
: signed_block( block ) : signed_block( block )
{ {