Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend get_top_markets API #1911

Draft
wants to merge 3 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions libraries/app/api_objects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ market_ticker::market_ticker(const market_ticker_object& mto,
const fc::time_point_sec& now,
const asset_object& asset_base,
const asset_object& asset_quote,
const order_book& orders)
const optional<order_book>& orders)
{
time = now;
base = asset_base.symbol;
Expand Down Expand Up @@ -67,10 +67,13 @@ market_ticker::market_ticker(const market_ticker_object& mto,
base_volume = uint128_amount_to_string( bv, asset_base.precision );
quote_volume = uint128_amount_to_string( qv, asset_quote.precision );

if(!orders.asks.empty())
lowest_ask = orders.asks[0].price;
if(!orders.bids.empty())
highest_bid = orders.bids[0].price;
if( orders.valid() )
{
if( !orders->asks.empty() )
lowest_ask = orders->asks[0].price;
if( !orders->bids.empty() )
highest_bid = orders->bids[0].price;
}
}

market_ticker::market_ticker(const fc::time_point_sec& now,
Expand Down
229 changes: 144 additions & 85 deletions libraries/app/database_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,9 @@ vector<optional<extended_asset_object>> database_api_impl::lookup_asset_symbols(
result.reserve(symbols_or_ids.size());
std::transform(symbols_or_ids.begin(), symbols_or_ids.end(), std::back_inserter(result),
[this, &assets_by_symbol](const string& symbol_or_id) -> optional<extended_asset_object> {
if( !symbol_or_id.empty() && std::isdigit(symbol_or_id[0]) )
if( symbol_or_id.empty() )
return optional<extended_asset_object>();
if( std::isdigit(symbol_or_id[0]) )
{
auto ptr = _db.find(variant(symbol_or_id, 1).as<asset_id_type>(1));
return ptr == nullptr? optional<extended_asset_object>() : extend_asset( *ptr );
Expand Down Expand Up @@ -991,12 +993,14 @@ vector<limit_order_object> database_api_impl::get_account_limit_orders(
if (account == nullptr)
return results;

auto assets = lookup_asset_symbols( {base, quote} );
FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
const asset_object* base_ptr = get_asset_from_string( base, false );
FC_ASSERT( base_ptr, "Invalid base asset: ${s}", ("s",base) );

auto base_id = assets[0]->id;
auto quote_id = assets[1]->id;
const asset_object* quote_ptr = get_asset_from_string( quote, false );
FC_ASSERT( quote_ptr, "Invalid quote asset: ${s}", ("s",quote) );

asset_id_type base_id = base_ptr->id;
asset_id_type quote_id = quote_ptr->id;

if (ostart_price.valid()) {
FC_ASSERT(ostart_price->base.asset_id == base_id, "Base asset inconsistent with start price");
Expand Down Expand Up @@ -1262,28 +1266,29 @@ market_ticker database_api_impl::get_ticker( const string& base, const string& q
{
FC_ASSERT( _app_options && _app_options->has_market_history_plugin, "Market history plugin is not enabled." );

const auto assets = lookup_asset_symbols( {base, quote} );
const asset_object* base_ptr = get_asset_from_string( base, false );
FC_ASSERT( base_ptr, "Invalid base asset: ${s}", ("s",base) );

FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
const asset_object* quote_ptr = get_asset_from_string( quote, false );
FC_ASSERT( quote_ptr, "Invalid quote asset: ${s}", ("s",quote) );

auto base_id = assets[0]->id;
auto quote_id = assets[1]->id;
asset_id_type base_id = base_ptr->id;
asset_id_type quote_id = quote_ptr->id;
if( base_id > quote_id ) std::swap( base_id, quote_id );
const auto& ticker_idx = _db.get_index_type<market_ticker_index>().indices().get<by_market>();
auto itr = ticker_idx.find( std::make_tuple( base_id, quote_id ) );
const fc::time_point_sec now = _db.head_block_time();
if( itr != ticker_idx.end() )
{
order_book orders;
optional<order_book> orders;
if (!skip_order_book)
{
orders = get_order_book(assets[0]->symbol, assets[1]->symbol, 1);
orders = get_order_book( *base_ptr, *quote_ptr, 1 );
}
return market_ticker(*itr, now, *assets[0], *assets[1], orders);
return market_ticker(*itr, now, *base_ptr, *quote_ptr, orders);
}
// if no ticker is found for this market we return an empty ticker
market_ticker empty_result(now, *assets[0], *assets[1]);
market_ticker empty_result(now, *base_ptr, *quote_ptr);
return empty_result;
}

Expand Down Expand Up @@ -1316,72 +1321,73 @@ order_book database_api_impl::get_order_book( const string& base, const string&
uint64_t api_limit_get_order_book=_app_options->api_limit_get_order_book;
FC_ASSERT( limit <= api_limit_get_order_book );

order_book result;
result.base = base;
result.quote = quote;
const asset_object* base_ptr = get_asset_from_string( base, false );
FC_ASSERT( base_ptr, "Invalid base asset: ${s}", ("s",base) );

auto assets = lookup_asset_symbols( {base, quote} );
FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
const asset_object* quote_ptr = get_asset_from_string( quote, false );
FC_ASSERT( quote_ptr, "Invalid quote asset: ${s}", ("s",quote) );

auto base_id = assets[0]->id;
auto quote_id = assets[1]->id;
auto orders = get_limit_orders( base_id, quote_id, limit );

for( const auto& o : orders )
{
if( o.sell_price.base.asset_id == base_id )
{
order ord;
ord.price = price_to_string( o.sell_price, *assets[0], *assets[1] );
ord.quote = assets[1]->amount_to_string( share_type( fc::uint128_t( o.for_sale.value )
* o.sell_price.quote.amount.value
/ o.sell_price.base.amount.value ) );
ord.base = assets[0]->amount_to_string( o.for_sale );
result.bids.push_back( ord );
}
else
{
order ord;
ord.price = price_to_string( o.sell_price, *assets[0], *assets[1] );
ord.quote = assets[1]->amount_to_string( o.for_sale );
ord.base = assets[0]->amount_to_string( share_type( fc::uint128_t( o.for_sale.value )
* o.sell_price.quote.amount.value
/ o.sell_price.base.amount.value ) );
result.asks.push_back( ord );
}
}
order_book result = get_order_book( *base_ptr, *quote_ptr, limit );
result.base = base;
result.quote = quote;

return result;
}

vector<market_ticker> database_api::get_top_markets(uint32_t limit)const
vector<market_ticker> database_api::get_top_markets( uint32_t limit, const optional<string>& base )const
{
return my->get_top_markets(limit);
return my->get_top_markets( limit, base );
}

vector<market_ticker> database_api_impl::get_top_markets(uint32_t limit)const
vector<market_ticker> database_api_impl::get_top_markets( uint32_t limit, const optional<string>& base )const
{
FC_ASSERT( _app_options && _app_options->has_market_history_plugin, "Market history plugin is not enabled." );

FC_ASSERT( limit <= 100 );

const auto& volume_idx = _db.get_index_type<market_ticker_index>().indices().get<by_volume>();
auto itr = volume_idx.rbegin();
vector<market_ticker> result;

if( limit == 0 ) // shortcut to save a DB query
return result;

result.reserve(limit);
const fc::time_point_sec now = _db.head_block_time();

while( itr != volume_idx.rend() && result.size() < limit)
if( !base.valid() || *base == "" )
{
std::set<std::pair<asset_id_type, asset_id_type>> inserted;
const auto& volume_idx = _db.get_index_type<market_ticker_index>().indices().get<by_volume>();
for( auto itr = volume_idx.begin(); limit > 0 && itr != volume_idx.end(); ++itr )
{
const auto& tick = *itr;
// skip if the flipped market is already in the result
if( inserted.find( std::make_pair( tick.quote, tick.base ) ) != inserted.end() )
continue;
inserted.insert( std::make_pair( tick.base, tick.quote ) );

const asset_object& base_obj = tick.base(_db);
const asset_object& quote_obj = tick.quote(_db);
order_book orders = get_order_book( base_obj, quote_obj, 1 );
result.emplace_back( tick, now, base_obj, quote_obj, orders );
--limit;
}
}
else // specified base asset
{
const asset_object base = itr->base(_db);
const asset_object quote = itr->quote(_db);
order_book orders;
orders = get_order_book(base.symbol, quote.symbol, 1);
const asset_object& base_obj = *get_asset_from_string( *base );

result.emplace_back(market_ticker(*itr, now, base, quote, orders));
++itr;
const auto& asset_volume_idx = _db.get_index_type<market_ticker_index>().indices().get<by_asset_volume>();
auto range = asset_volume_idx.equal_range( base_obj.id );

for( auto itr = range.first; limit > 0 && itr != range.second; ++itr, --limit )
{
const auto& tick = *itr;
const asset_object& quote_obj = tick.quote(_db);
order_book orders = get_order_book( base_obj, quote_obj, 1 );
result.emplace_back( tick, now, base_obj, quote_obj, orders );
}
}

return result;
}

Expand All @@ -1404,12 +1410,14 @@ vector<market_trade> database_api_impl::get_trade_history( const string& base,

FC_ASSERT( limit <= 100 );

auto assets = lookup_asset_symbols( {base, quote} );
FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
const asset_object* base_ptr = get_asset_from_string( base, false );
FC_ASSERT( base_ptr, "Invalid base asset: ${s}", ("s",base) );

const asset_object* quote_ptr = get_asset_from_string( quote, false );
FC_ASSERT( quote_ptr, "Invalid quote asset: ${s}", ("s",quote) );

auto base_id = assets[0]->id;
auto quote_id = assets[1]->id;
asset_id_type base_id = base_ptr->id;
asset_id_type quote_id = quote_ptr->id;

if( base_id > quote_id ) std::swap( base_id, quote_id );

Expand All @@ -1427,19 +1435,19 @@ vector<market_trade> database_api_impl::get_trade_history( const string& base,
{
market_trade trade;

if( assets[0]->id == itr->op.receives.asset_id )
if( base_id == itr->op.receives.asset_id )
{
trade.amount = assets[1]->amount_to_string( itr->op.pays );
trade.value = assets[0]->amount_to_string( itr->op.receives );
trade.amount = quote_ptr->amount_to_string( itr->op.pays );
trade.value = base_ptr->amount_to_string( itr->op.receives );
}
else
{
trade.amount = assets[1]->amount_to_string( itr->op.receives );
trade.value = assets[0]->amount_to_string( itr->op.pays );
trade.amount = quote_ptr->amount_to_string( itr->op.receives );
trade.value = base_ptr->amount_to_string( itr->op.pays );
}

trade.date = itr->time;
trade.price = price_to_string( itr->op.fill_price, *assets[0], *assets[1] );
trade.price = price_to_string( itr->op.fill_price, *base_ptr, *quote_ptr );

if( itr->op.is_maker )
{
Expand Down Expand Up @@ -1498,12 +1506,14 @@ vector<market_trade> database_api_impl::get_trade_history_by_sequence(
FC_ASSERT( start >= 0 );
int64_t start_seq = -start;

auto assets = lookup_asset_symbols( {base, quote} );
FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) );
FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) );
const asset_object* base_ptr = get_asset_from_string( base, false );
FC_ASSERT( base_ptr, "Invalid base asset: ${s}", ("s",base) );

const asset_object* quote_ptr = get_asset_from_string( quote, false );
FC_ASSERT( quote_ptr, "Invalid quote asset: ${s}", ("s",quote) );

auto base_id = assets[0]->id;
auto quote_id = assets[1]->id;
asset_id_type base_id = base_ptr->id;
asset_id_type quote_id = quote_ptr->id;

if( base_id > quote_id ) std::swap( base_id, quote_id );
const auto& history_idx = _db.get_index_type<graphene::market_history::history_index>().indices().get<by_key>();
Expand Down Expand Up @@ -1533,19 +1543,19 @@ vector<market_trade> database_api_impl::get_trade_history_by_sequence(
{
market_trade trade;

if( assets[0]->id == itr->op.receives.asset_id )
if( base_id == itr->op.receives.asset_id )
{
trade.amount = assets[1]->amount_to_string( itr->op.pays );
trade.value = assets[0]->amount_to_string( itr->op.receives );
trade.amount = quote_ptr->amount_to_string( itr->op.pays );
trade.value = base_ptr->amount_to_string( itr->op.receives );
}
else
{
trade.amount = assets[1]->amount_to_string( itr->op.receives );
trade.value = assets[0]->amount_to_string( itr->op.pays );
trade.amount = quote_ptr->amount_to_string( itr->op.receives );
trade.value = base_ptr->amount_to_string( itr->op.pays );
}

trade.date = itr->time;
trade.price = price_to_string( itr->op.fill_price, *assets[0], *assets[1] );
trade.price = price_to_string( itr->op.fill_price, *base_ptr, *quote_ptr );

if( itr->op.is_maker )
{
Expand Down Expand Up @@ -2409,9 +2419,6 @@ vector<optional<extended_asset_object>> database_api_impl::get_assets( const vec
vector<limit_order_object> database_api_impl::get_limit_orders( const asset_id_type a, const asset_id_type b,
const uint32_t limit )const
{
uint64_t api_limit_get_limit_orders=_app_options->api_limit_get_limit_orders;
FC_ASSERT( limit <= api_limit_get_limit_orders );

const auto& limit_order_idx = _db.get_index_type<limit_order_index>();
const auto& limit_price_idx = limit_order_idx.indices().get<by_price>();

Expand Down Expand Up @@ -2440,6 +2447,58 @@ vector<limit_order_object> database_api_impl::get_limit_orders( const asset_id_t
return result;
}

// helper function for fewer DB queries
order_book database_api_impl::get_order_book( const asset_object& base, const asset_object& quote,
unsigned limit )const
{
order_book result;

asset_id_type base_id = base.id;
asset_id_type quote_id = quote.id;

const auto& limit_price_idx = _db.get_index_type<limit_order_index>().indices().get<by_price>();

uint32_t count = 0;
auto limit_itr = limit_price_idx.lower_bound( price::max( base_id, quote_id ) );
auto limit_end = limit_price_idx.upper_bound( price::min( base_id, quote_id ) );
while( limit_itr != limit_end && count < limit )
{
const auto& o = *limit_itr;

order ord;
ord.price = price_to_string( o.sell_price, base, quote );
ord.quote = quote.amount_to_string( share_type( fc::uint128_t( o.for_sale.value )
* o.sell_price.quote.amount.value
/ o.sell_price.base.amount.value ) );
ord.base = base.amount_to_string( o.for_sale );
result.bids.push_back( std::move(ord) );

++limit_itr;
++count;
}

count = 0;
limit_itr = limit_price_idx.lower_bound( price::max( quote_id, base_id ) );
limit_end = limit_price_idx.upper_bound( price::min( quote_id, base_id ) );
while( limit_itr != limit_end && count < limit )
{
const auto& o = *limit_itr;

order ord;
ord.price = price_to_string( o.sell_price, base, quote );
ord.quote = quote.amount_to_string( o.for_sale );
ord.base = base.amount_to_string( share_type( fc::uint128_t( o.for_sale.value )
* o.sell_price.quote.amount.value
/ o.sell_price.base.amount.value ) );
result.asks.push_back( std::move(ord) );

++limit_itr;
++count;
}

return result;
}

bool database_api_impl::is_impacted_account( const flat_set<account_id_type>& accounts)
{
if( !_subscribed_accounts.size() || !accounts.size() )
Expand Down
6 changes: 5 additions & 1 deletion libraries/app/database_api_impl.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
market_volume get_24_volume( const string& base, const string& quote )const;
order_book get_order_book( const string& base, const string& quote,
unsigned limit = 50 )const;
vector<market_ticker> get_top_markets( uint32_t limit )const;
vector<market_ticker> get_top_markets( uint32_t limit, const optional<string>& base )const;
vector<market_trade> get_trade_history( const string& base, const string& quote,
fc::time_point_sec start, fc::time_point_sec stop,
unsigned limit = 100 )const;
Expand Down Expand Up @@ -235,6 +235,10 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
vector<limit_order_object> get_limit_orders( const asset_id_type a, const asset_id_type b,
const uint32_t limit )const;

// helper function for fewer DB queries
order_book get_order_book( const asset_object& base, const asset_object& quote,
unsigned limit = 50 )const;

////////////////////////////////////////////////
// Subscription
////////////////////////////////////////////////
Expand Down
Loading