示例#1
0
def get_trade_history(asset1=None, asset2=None, start_ts=None, end_ts=None, limit=50):
    """
    Gets last N of trades within a specific date range (normally, for a specified asset pair, but this can
    be left blank to get any/all trades).
    """
    assert (asset1 and asset2) or (not asset1 and not asset2) #cannot have one asset, but not the other

    if limit > 500:
        raise Exception("Requesting history of too many trades")

    now_ts = time.mktime(datetime.datetime.utcnow().timetuple())
    if not end_ts: #default to current datetime
        end_ts = now_ts
    if not start_ts: #default to 30 days before the end date
        start_ts = end_ts - (30 * 24 * 60 * 60) 

    filters = {
        "block_time": {
            "$gte": datetime.datetime.utcfromtimestamp(start_ts)
        } if end_ts == now_ts else {
            "$gte": datetime.datetime.utcfromtimestamp(start_ts),
            "$lte": datetime.datetime.utcfromtimestamp(end_ts)                    
        }
    }
    if asset1 and asset2:
        base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
        filters["base_asset"] = base_asset
        filters["quote_asset"] = quote_asset

    last_trades = config.mongo_db.trades.find(filters, {'_id': 0}).sort("block_time", pymongo.DESCENDING).limit(limit)
    if not last_trades.count():
        return False #no suitable trade data to form a market price
    last_trades = list(last_trades)
    return last_trades 
示例#2
0
def parse_trade_book(msg, msg_data):
    #book trades
    if (msg['category'] == 'order_matches'
        and ((msg['command'] == 'update' and msg_data['status'] == 'completed') #for a trade with BTC involved, but that is settled (completed)
             or ('forward_asset' in msg_data and msg_data['forward_asset'] != config.BTC and msg_data['backward_asset'] != config.BTC))): #or for a trade without BTC on either end

        if msg['command'] == 'update' and msg_data['status'] == 'completed':
            #an order is being updated to a completed status (i.e. a BTCpay has completed)
            tx0_hash, tx1_hash = msg_data['order_match_id'][:64], msg_data['order_match_id'][65:]
            #get the order_match this btcpay settles
            order_match = util.jsonrpc_api("get_order_matches",
                {'filters': [
                 {'field': 'tx0_hash', 'op': '==', 'value': tx0_hash},
                 {'field': 'tx1_hash', 'op': '==', 'value': tx1_hash}]
                }, abort_on_error=False)['result'][0]
        else:
            assert msg_data['status'] == 'completed' #should not enter a pending state for non BTC matches
            order_match = msg_data

        forward_asset_info = config.mongo_db.tracked_assets.find_one({'asset': order_match['forward_asset']})
        backward_asset_info = config.mongo_db.tracked_assets.find_one({'asset': order_match['backward_asset']})
        assert forward_asset_info and backward_asset_info
        base_asset, quote_asset = util.assets_to_asset_pair(order_match['forward_asset'], order_match['backward_asset'])
        
        #don't create trade records from order matches with BTC that are under the dust limit
        if    (order_match['forward_asset'] == config.BTC and order_match['forward_quantity'] <= config.ORDER_BTC_DUST_LIMIT_CUTOFF) \
           or (order_match['backward_asset'] == config.BTC and order_match['backward_quantity'] <= config.ORDER_BTC_DUST_LIMIT_CUTOFF):
            logger.debug("Order match %s ignored due to %s under dust limit." % (order_match['tx0_hash'] + order_match['tx1_hash'], config.BTC))
            return 'ABORT_THIS_MESSAGE_PROCESSING'

        #take divisible trade quantities to floating point
        forward_quantity = blockchain.normalize_quantity(order_match['forward_quantity'], forward_asset_info['divisible'])
        backward_quantity = blockchain.normalize_quantity(order_match['backward_quantity'], backward_asset_info['divisible'])
        
        #compose trade
        trade = {
            'block_index': config.state['cur_block']['block_index'],
            'block_time': config.state['cur_block']['block_time_obj'],
            'message_index': msg['message_index'], #secondary temporaral ordering off of when
            'order_match_id': order_match['tx0_hash'] + '_' + order_match['tx1_hash'],
            'order_match_tx0_index': order_match['tx0_index'],
            'order_match_tx1_index': order_match['tx1_index'],
            'order_match_tx0_address': order_match['tx0_address'],
            'order_match_tx1_address': order_match['tx1_address'],
            'base_asset': base_asset,
            'quote_asset': quote_asset,
            'base_quantity': order_match['forward_quantity'] if order_match['forward_asset'] == base_asset else order_match['backward_quantity'],
            'quote_quantity': order_match['backward_quantity'] if order_match['forward_asset'] == base_asset else order_match['forward_quantity'],
            'base_quantity_normalized': forward_quantity if order_match['forward_asset'] == base_asset else backward_quantity,
            'quote_quantity_normalized': backward_quantity if order_match['forward_asset'] == base_asset else forward_quantity,
        }
        trade['unit_price'] = float(
            ( D(trade['quote_quantity_normalized']) / D(trade['base_quantity_normalized']) ).quantize(
                D('.00000000'), rounding=decimal.ROUND_HALF_EVEN))
        trade['unit_price_inverse'] = float(
            ( D(trade['base_quantity_normalized']) / D(trade['quote_quantity_normalized']) ).quantize(
                D('.00000000'), rounding=decimal.ROUND_HALF_EVEN))

        config.mongo_db.trades.insert(trade)
        logger.info("Procesed Trade from tx %s :: %s" % (msg['message_index'], trade))
示例#3
0
def get_pairs_with_orders(addresses=[], max_pairs=12):

    pairs_with_orders = []

    sources = '''AND source IN ({})'''.format(','.join(['?' for e in range(0, len(addresses))]))

    sql = '''SELECT (MIN(give_asset, get_asset) || '/' || MAX(give_asset, get_asset)) AS pair,
                    COUNT(*) AS order_count
             FROM orders
             WHERE give_asset != get_asset AND status = ? {} 
             GROUP BY pair 
             ORDER BY order_count DESC
             LIMIT ?'''.format(sources)

    bindings = ['open'] + addresses + [max_pairs]

    my_pairs = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result']

    for my_pair in my_pairs:
        base_asset, quote_asset = util.assets_to_asset_pair(*tuple(my_pair['pair'].split("/")))
        top_pair = {
            'base_asset': base_asset,
            'quote_asset': quote_asset,
            'my_order_count': my_pair['order_count']
        }
        if my_pair['pair'] == 'BTC/XCP':  # XCP/BTC always in first
            pairs_with_orders.insert(0, top_pair)
        else:
            pairs_with_orders.append(top_pair)

    return pairs_with_orders
示例#4
0
def get_order_book_simple(asset1, asset2, min_pct_fee_provided=None, max_pct_fee_required=None):
    #DEPRECATED 1.5
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    result = _get_order_book(base_asset, quote_asset,
        bid_book_min_pct_fee_provided=min_pct_fee_provided,
        bid_book_max_pct_fee_required=max_pct_fee_required,
        ask_book_min_pct_fee_provided=min_pct_fee_provided,
        ask_book_max_pct_fee_required=max_pct_fee_required)
    return result
示例#5
0
文件: dex.py 项目: loon3/counterblock
def get_market_details(asset1,
                       asset2,
                       min_fee_provided=0.95,
                       max_fee_required=0.95):

    yesterday = int(time.time() - (24 * 60 * 60))
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)

    supplies = get_assets_supply([base_asset, quote_asset])

    price, trend, price24h, progression = get_price_movement(base_asset,
                                                             quote_asset,
                                                             supplies=supplies)

    buy_orders = []
    sell_orders = []
    market_orders = get_market_orders(base_asset,
                                      quote_asset,
                                      supplies=supplies,
                                      min_fee_provided=min_fee_provided,
                                      max_fee_required=max_fee_required)
    for order in market_orders:
        if order['type'] == 'SELL':
            sell_orders.append(order)
        elif order['type'] == 'BUY':
            buy_orders.append(order)

    last_trades = get_market_trades(base_asset, quote_asset, supplies=supplies)

    ext_info = False
    if config.mongo_db:
        ext_info = config.mongo_db.asset_extended_info.find_one(
            {'asset': base_asset}, {'_id': 0})
        if ext_info and 'info_data' in ext_info:
            ext_info = ext_info['info_data']
        else:
            ext_info = False

    return {
        'base_asset': base_asset,
        'quote_asset': quote_asset,
        'price': format(price, ".8f"),
        'trend': trend,
        'progression': format(progression, ".2f"),
        'price_24h': format(price24h, ".8f"),
        'supply': supplies[base_asset][0],
        'base_asset_divisible': supplies[base_asset][1],
        'quote_asset_divisible': supplies[quote_asset][1],
        'buy_orders': sorted(buy_orders,
                             key=lambda x: D(x['price']),
                             reverse=True),
        'sell_orders': sorted(sell_orders, key=lambda x: D(x['price'])),
        'last_trades': last_trades,
        'base_asset_infos': ext_info
    }
示例#6
0
def get_asset_pair_market_info(asset1=None, asset2=None, limit=50):
    """Given two arbitrary assets, returns the base asset and the quote asset.
    """
    #DEPRECATED 1.5
    assert (asset1 and asset2) or (asset1 is None and asset2 is None)
    if asset1 and asset2:
        base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
        pair_info = config.mongo_db.asset_pair_market_info.find({'base_asset': base_asset, 'quote_asset': quote_asset}, {'_id': 0})
    else:
        pair_info = config.mongo_db.asset_pair_market_info.find({}, {'_id': 0}).sort('completed_trades_count', pymongo.DESCENDING).limit(limit)
        #^ sort by this for now, may want to sort by a market_cap value in the future
    return list(pair_info) or []
示例#7
0
def get_asset_pair_market_info(asset1=None, asset2=None, limit=50):
    """Given two arbitrary assets, returns the base asset and the quote asset.
    """
    # DEPRECATED 1.5
    assert (asset1 and asset2) or (asset1 is None and asset2 is None)
    if asset1 and asset2:
        base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
        pair_info = config.mongo_db.asset_pair_market_info.find({'base_asset': base_asset, 'quote_asset': quote_asset}, {'_id': 0})
    else:
        pair_info = config.mongo_db.asset_pair_market_info.find({}, {'_id': 0}).sort('completed_trades_count', pymongo.DESCENDING).limit(limit)
        #^ sort by this for now, may want to sort by a market_cap value in the future
    return list(pair_info) or []
示例#8
0
def get_order_book_buysell(buy_asset, sell_asset, pct_fee_provided=None, pct_fee_required=None):
    # DEPRECATED 1.5
    base_asset, quote_asset = util.assets_to_asset_pair(buy_asset, sell_asset)
    bid_book_min_pct_fee_provided = None
    bid_book_min_pct_fee_required = None
    bid_book_max_pct_fee_required = None
    ask_book_min_pct_fee_provided = None
    ask_book_min_pct_fee_required = None
    ask_book_max_pct_fee_required = None
    if base_asset == config.BTC:
        if buy_asset == config.BTC:
            # if BTC is base asset and we're buying it, we're buying the BASE. we require a BTC fee (we're on the bid (bottom) book and we want a lower price)
            # - show BASE buyers (bid book) that require a BTC fee >= what we require (our side of the book)
            # - show BASE sellers (ask book) that provide a BTC fee >= what we require
            bid_book_min_pct_fee_required = pct_fee_required  # my competition at the given fee required
            ask_book_min_pct_fee_provided = pct_fee_required
        elif sell_asset == config.BTC:
            # if BTC is base asset and we're selling it, we're selling the BASE. we provide a BTC fee (we're on the ask (top) book and we want a higher price)
            # - show BASE buyers (bid book) that provide a BTC fee >= what we provide
            # - show BASE sellers (ask book) that require a BTC fee <= what we provide (our side of the book)
            bid_book_max_pct_fee_required = pct_fee_provided
            ask_book_min_pct_fee_provided = pct_fee_provided  # my competition at the given fee provided
    elif quote_asset == config.BTC:
        assert base_asset == config.XCP  # only time when this is the case
        if buy_asset == config.BTC:
            # if BTC is quote asset and we're buying it, we're selling the BASE. we require a BTC fee (we're on the ask (top) book and we want a higher price)
            # - show BASE buyers (bid book) that provide a BTC fee >= what we require
            # - show BASE sellers (ask book) that require a BTC fee >= what we require (our side of the book)
            bid_book_min_pct_fee_provided = pct_fee_required
            ask_book_min_pct_fee_required = pct_fee_required  # my competition at the given fee required
        elif sell_asset == config.BTC:
            # if BTC is quote asset and we're selling it, we're buying the BASE. we provide a BTC fee (we're on the bid (bottom) book and we want a lower price)
            # - show BASE buyers (bid book) that provide a BTC fee >= what we provide (our side of the book)
            # - show BASE sellers (ask book) that require a BTC fee <= what we provide
            bid_book_min_pct_fee_provided = pct_fee_provided  # my compeitition at the given fee provided
            ask_book_max_pct_fee_required = pct_fee_provided

    result = _get_order_book(
        base_asset, quote_asset,
        bid_book_min_pct_fee_provided=bid_book_min_pct_fee_provided,
        bid_book_min_pct_fee_required=bid_book_min_pct_fee_required,
        bid_book_max_pct_fee_required=bid_book_max_pct_fee_required,
        ask_book_min_pct_fee_provided=ask_book_min_pct_fee_provided,
        ask_book_min_pct_fee_required=ask_book_min_pct_fee_required,
        ask_book_max_pct_fee_required=ask_book_max_pct_fee_required)

    # filter down raw_orders to be only open sell orders for what the caller is buying
    open_sell_orders = []
    for o in result['raw_orders']:
        if o['give_asset'] == buy_asset:
            open_sell_orders.append(o)
    result['raw_orders'] = open_sell_orders
    return result
示例#9
0
def get_order_book_buysell(buy_asset, sell_asset, pct_fee_provided=None, pct_fee_required=None):
    #DEPRECATED 1.5
    base_asset, quote_asset = util.assets_to_asset_pair(buy_asset, sell_asset)
    bid_book_min_pct_fee_provided = None
    bid_book_min_pct_fee_required = None
    bid_book_max_pct_fee_required = None
    ask_book_min_pct_fee_provided = None
    ask_book_min_pct_fee_required = None
    ask_book_max_pct_fee_required = None
    if base_asset == config.BTC:
        if buy_asset == config.BTC:
            #if BTC is base asset and we're buying it, we're buying the BASE. we require a BTC fee (we're on the bid (bottom) book and we want a lower price)
            # - show BASE buyers (bid book) that require a BTC fee >= what we require (our side of the book)
            # - show BASE sellers (ask book) that provide a BTC fee >= what we require
            bid_book_min_pct_fee_required = pct_fee_required #my competition at the given fee required
            ask_book_min_pct_fee_provided = pct_fee_required
        elif sell_asset == config.BTC:
            #if BTC is base asset and we're selling it, we're selling the BASE. we provide a BTC fee (we're on the ask (top) book and we want a higher price)
            # - show BASE buyers (bid book) that provide a BTC fee >= what we provide 
            # - show BASE sellers (ask book) that require a BTC fee <= what we provide (our side of the book)
            bid_book_max_pct_fee_required = pct_fee_provided
            ask_book_min_pct_fee_provided = pct_fee_provided #my competition at the given fee provided
    elif quote_asset == config.BTC:
        assert base_asset == config.XCP #only time when this is the case
        if buy_asset == config.BTC:
            #if BTC is quote asset and we're buying it, we're selling the BASE. we require a BTC fee (we're on the ask (top) book and we want a higher price)
            # - show BASE buyers (bid book) that provide a BTC fee >= what we require 
            # - show BASE sellers (ask book) that require a BTC fee >= what we require (our side of the book)
            bid_book_min_pct_fee_provided = pct_fee_required
            ask_book_min_pct_fee_required = pct_fee_required #my competition at the given fee required
        elif sell_asset == config.BTC:
            #if BTC is quote asset and we're selling it, we're buying the BASE. we provide a BTC fee (we're on the bid (bottom) book and we want a lower price)
            # - show BASE buyers (bid book) that provide a BTC fee >= what we provide (our side of the book)
            # - show BASE sellers (ask book) that require a BTC fee <= what we provide 
            bid_book_min_pct_fee_provided = pct_fee_provided #my compeitition at the given fee provided
            ask_book_max_pct_fee_required = pct_fee_provided

    result = _get_order_book(base_asset, quote_asset,
        bid_book_min_pct_fee_provided=bid_book_min_pct_fee_provided,
        bid_book_min_pct_fee_required=bid_book_min_pct_fee_required,
        bid_book_max_pct_fee_required=bid_book_max_pct_fee_required,
        ask_book_min_pct_fee_provided=ask_book_min_pct_fee_provided,
        ask_book_min_pct_fee_required=ask_book_min_pct_fee_required,
        ask_book_max_pct_fee_required=ask_book_max_pct_fee_required)
    
    #filter down raw_orders to be only open sell orders for what the caller is buying
    open_sell_orders = []
    for o in result['raw_orders']:
        if o['give_asset'] == buy_asset:
            open_sell_orders.append(o)
    result['raw_orders'] = open_sell_orders
    return result
示例#10
0
def get_market_price_summary(asset1, asset2, with_last_trades=0, start_dt=None, end_dt=None):
    """Gets a synthesized trading "market price" for a specified asset pair (if available), as well as additional info.
    If no price is available, False is returned.
    """
    if not end_dt:
        end_dt = datetime.datetime.utcnow()
    if not start_dt:
        start_dt = end_dt - datetime.timedelta(days=10) #default to 10 days in the past
    
    #look for the last max 6 trades within the past 10 day window
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    base_asset_info = config.mongo_db.tracked_assets.find_one({'asset': base_asset})
    quote_asset_info = config.mongo_db.tracked_assets.find_one({'asset': quote_asset})
    
    if not isinstance(with_last_trades, int) or with_last_trades < 0 or with_last_trades > 30:
        raise Exception("Invalid with_last_trades")
    
    if not base_asset_info or not quote_asset_info:
        raise Exception("Invalid asset(s)")
    
    last_trades = config.mongo_db.trades.find({
            "base_asset": base_asset,
            "quote_asset": quote_asset,
            'block_time': { "$gte": start_dt, "$lte": end_dt }
        },
        {'_id': 0, 'block_index': 1, 'block_time': 1, 'unit_price': 1, 'base_quantity_normalized': 1, 'quote_quantity_normalized': 1}
    ).sort("block_time", pymongo.DESCENDING).limit(max(config.MARKET_PRICE_DERIVE_NUM_POINTS, with_last_trades))
    if not last_trades.count():
        return None #no suitable trade data to form a market price (return None, NOT False here)
    last_trades = list(last_trades)
    last_trades.reverse() #from newest to oldest
    
    market_price = get_market_price(
        [last_trades[i]['unit_price'] for i in xrange(min(len(last_trades), config.MARKET_PRICE_DERIVE_NUM_POINTS))],
        [(last_trades[i]['base_quantity_normalized'] + last_trades[i]['quote_quantity_normalized']) for i in xrange(min(len(last_trades), config.MARKET_PRICE_DERIVE_NUM_POINTS))])
    result = {
        'market_price': float(D(market_price)),
        'base_asset': base_asset,
        'quote_asset': quote_asset,
    }
    if with_last_trades:
        #[0]=block_time, [1]=unit_price, [2]=base_quantity_normalized, [3]=quote_quantity_normalized, [4]=block_index
        result['last_trades'] = [[
            t['block_time'],
            t['unit_price'],
            t['base_quantity_normalized'],
            t['quote_quantity_normalized'],
            t['block_index']
        ] for t in last_trades]
    else:
        result['last_trades'] = []
    return result
示例#11
0
def get_order_book_simple(asset1,
                          asset2,
                          min_pct_fee_provided=None,
                          max_pct_fee_required=None):
    # DEPRECATED 1.5
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    result = _get_order_book(
        base_asset,
        quote_asset,
        bid_book_min_pct_fee_provided=min_pct_fee_provided,
        bid_book_max_pct_fee_required=max_pct_fee_required,
        ask_book_min_pct_fee_provided=min_pct_fee_provided,
        ask_book_max_pct_fee_required=max_pct_fee_required)
    return result
示例#12
0
def get_market_orders(asset1, asset2, addresses=[], supplies=None, min_fee_provided=0.95, max_fee_required=0.95):

    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    if not supplies:
        supplies = get_assets_supply([asset1, asset2])

    market_orders = []
    buy_orders = []
    sell_orders = []

    sql = '''SELECT orders.*, blocks.block_time FROM orders INNER JOIN blocks ON orders.block_index=blocks.block_index 
             WHERE  status = ? '''
    bindings = ['open']

    if len(addresses) > 0:
        sql += '''AND source IN ({}) '''.format(','.join(['?' for e in range(0,len(addresses))]))
        bindings += addresses

    sql += '''AND give_remaining > 0 
              AND give_asset IN (?, ?) 
              AND get_asset IN (?, ?) 
              ORDER BY tx_index DESC'''

    bindings +=  [asset1, asset2, asset1, asset2]

    orders = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result']

    for order in orders:
        market_order = {}

        exclude = False
        if order['give_asset'] == 'BTC':
            try:
                fee_provided = order['fee_provided'] / (order['give_quantity'] / 100)
                market_order['fee_provided'] = format(D(order['fee_provided']) / (D(order['give_quantity']) / D(100)), '.2f') 
            except Exception, e:
                fee_provided = min_fee_provided - 1 # exclude
            
            exclude = fee_provided < min_fee_provided

        elif order['get_asset'] == 'BTC':
            try:
                fee_required = order['fee_required'] / (order['get_quantity'] / 100)
                market_order['fee_required'] = format(D(order['fee_required']) / (D(order['get_quantity']) / D(100)), '.2f')
            except Exception, e:
                fee_required = max_fee_required + 1 # exclude    
示例#13
0
def get_base_quote_asset(asset1, asset2):
    """Given two arbitrary assets, returns the base asset and the quote asset.
    """
    #DEPRECATED 1.5
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    base_asset_info = config.mongo_db.tracked_assets.find_one({'asset': base_asset})
    quote_asset_info = config.mongo_db.tracked_assets.find_one({'asset': quote_asset})
    pair_name = "%s/%s" % (base_asset, quote_asset)

    if not base_asset_info or not quote_asset_info:
        raise Exception("Invalid asset(s)")

    return {
        'base_asset': base_asset,
        'quote_asset': quote_asset,
        'pair_name': pair_name
    }
示例#14
0
def get_base_quote_asset(asset1, asset2):
    """Given two arbitrary assets, returns the base asset and the quote asset.
    """
    # DEPRECATED 1.5
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    base_asset_info = config.mongo_db.tracked_assets.find_one({'asset': base_asset})
    quote_asset_info = config.mongo_db.tracked_assets.find_one({'asset': quote_asset})
    pair_name = "%s/%s" % (base_asset, quote_asset)

    if not base_asset_info or not quote_asset_info:
        raise Exception("Invalid asset(s)")

    return {
        'base_asset': base_asset,
        'quote_asset': quote_asset,
        'pair_name': pair_name
    }
示例#15
0
def get_market_details(asset1, asset2, min_fee_provided=0.95, max_fee_required=0.95):

    yesterday = int(time.time() - (24 * 60 * 60))
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)

    supplies = get_assets_supply([base_asset, quote_asset])

    price, trend, price24h, progression = get_price_movement(base_asset, quote_asset, supplies=supplies)

    buy_orders = []
    sell_orders = []
    market_orders = get_market_orders(base_asset, quote_asset, supplies=supplies, min_fee_provided=min_fee_provided, max_fee_required=max_fee_required)
    for order in market_orders:
        if order['type'] == 'SELL':
            sell_orders.append(order)
        elif order['type'] == 'BUY':
            buy_orders.append(order)

    last_trades = get_market_trades(base_asset, quote_asset, supplies=supplies)

    ext_info = False
    if config.mongo_db:
        ext_info = config.mongo_db.asset_extended_info.find_one({'asset': base_asset}, {'_id': 0})
        if ext_info and 'info_data' in ext_info:
            ext_info = ext_info['info_data']
        else:
            ext_info = False

    return {
        'base_asset': base_asset,
        'quote_asset': quote_asset,
        'price': format(price, ".8f"),
        'trend': trend,
        'progression': format(progression, ".2f"),
        'price_24h': format(price24h, ".8f"),
        'supply': supplies[base_asset][0],
        'base_asset_divisible': supplies[base_asset][1],
        'quote_asset_divisible': supplies[quote_asset][1],
        'buy_orders': sorted(buy_orders, key=lambda x: D(x['price']), reverse=True),
        'sell_orders': sorted(sell_orders, key=lambda x: D(x['price'])),
        'last_trades': last_trades,
        'base_asset_infos': ext_info
    }
示例#16
0
def get_trade_history(asset1=None,
                      asset2=None,
                      start_ts=None,
                      end_ts=None,
                      limit=50):
    """
    Gets last N of trades within a specific date range (normally, for a specified asset pair, but this can
    be left blank to get any/all trades).
    """
    assert (asset1 and asset2) or (
        not asset1 and not asset2)  # cannot have one asset, but not the other

    if limit > 500:
        raise Exception("Requesting history of too many trades")

    now_ts = calendar.timegm(time.gmtime())
    if not end_ts:  # default to current datetime
        end_ts = now_ts
    if not start_ts:  # default to 30 days before the end date
        start_ts = end_ts - (30 * 24 * 60 * 60)

    filters = {
        "block_time": {
            "$gte": datetime.datetime.utcfromtimestamp(start_ts)
        } if end_ts == now_ts else {
            "$gte": datetime.datetime.utcfromtimestamp(start_ts),
            "$lte": datetime.datetime.utcfromtimestamp(end_ts)
        }
    }
    if asset1 and asset2:
        base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
        filters["base_asset"] = base_asset
        filters["quote_asset"] = quote_asset

    last_trades = config.mongo_db.trades.find(filters, {
        '_id': 0
    }).sort("block_time", pymongo.DESCENDING).limit(limit)
    if not last_trades.count():
        return False  # no suitable trade data to form a market price
    last_trades = list(last_trades)
    return last_trades
示例#17
0
def get_pairs_with_orders(addresses=[], max_pairs=12):

    pairs_with_orders = []

    sources = '''AND source IN ({})'''.format(','.join(
        ['?' for e in range(0, len(addresses))]))

    sql = '''SELECT (MIN(give_asset, get_asset) || '/' || MAX(give_asset, get_asset)) AS pair,
                    COUNT(*) AS order_count
             FROM orders
             WHERE give_asset != get_asset AND status = ? {} 
             GROUP BY pair 
             ORDER BY order_count DESC
             LIMIT ?'''.format(sources)

    bindings = ['open'] + addresses + [max_pairs]

    my_pairs = util.call_jsonrpc_api('sql', {
        'query': sql,
        'bindings': bindings
    })['result']

    for my_pair in my_pairs:
        base_asset, quote_asset = util.assets_to_asset_pair(
            *tuple(my_pair['pair'].split("/")))
        top_pair = {
            'base_asset': base_asset,
            'quote_asset': quote_asset,
            'my_order_count': my_pair['order_count']
        }
        if my_pair['pair'] == config.BTC_TO_XCP:  # XCP/BTC always in first
            pairs_with_orders.insert(0, top_pair)
        else:
            pairs_with_orders.append(top_pair)

    return pairs_with_orders
def compile_asset_pair_market_info():
    """Compiles the pair-level statistics that show on the View Prices page of counterwallet, for instance"""
    #loop through all open orders, and compile a listing of pairs, with a count of open orders for each pair
    mongo_db = config.mongo_db
    end_dt = datetime.datetime.utcnow()
    start_dt = end_dt - datetime.timedelta(days=1)
    start_block_index, end_block_index = database.get_block_indexes_for_dates(
        start_dt=start_dt, end_dt=end_dt)
    open_orders = util.call_jsonrpc_api("get_orders", {
        'filters': [
            {
                'field': 'give_remaining',
                'op': '>',
                'value': 0
            },
            {
                'field': 'get_remaining',
                'op': '>',
                'value': 0
            },
            {
                'field': 'fee_required_remaining',
                'op': '>=',
                'value': 0
            },
            {
                'field': 'fee_provided_remaining',
                'op': '>=',
                'value': 0
            },
        ],
        'status':
        'open',
        'show_expired':
        False,
    },
                                        abort_on_error=True)['result']
    pair_data = {}
    asset_info = {}

    def get_price(base_quantity_normalized, quote_quantity_normalized):
        return float(D(quote_quantity_normalized / base_quantity_normalized))

    #COMPOSE order depth, lowest ask, and highest bid column data
    for o in open_orders:
        (base_asset,
         quote_asset) = util.assets_to_asset_pair(o['give_asset'],
                                                  o['get_asset'])
        pair = '%s/%s' % (base_asset, quote_asset)
        base_asset_info = asset_info.get(
            base_asset, mongo_db.tracked_assets.find_one({'asset':
                                                          base_asset}))
        if base_asset not in asset_info:
            asset_info[base_asset] = base_asset_info
        quote_asset_info = asset_info.get(
            quote_asset,
            mongo_db.tracked_assets.find_one({'asset': quote_asset}))
        if quote_asset not in asset_info:
            asset_info[quote_asset] = quote_asset_info

        pair_data.setdefault(
            pair, {
                'open_orders_count': 0,
                'lowest_ask': None,
                'highest_bid': None,
                'completed_trades_count': 0,
                'vol_base': 0,
                'vol_quote': 0
            })
        #^ highest ask = open order selling base, highest bid = open order buying base
        #^ we also initialize completed_trades_count, vol_base, vol_quote because every pair inited here may
        # not have cooresponding data out of the trades_data_by_pair aggregation below
        pair_data[pair]['open_orders_count'] += 1
        base_quantity_normalized = blockchain.normalize_quantity(
            o['give_quantity'] if base_asset == o['give_asset'] else
            o['get_quantity'], base_asset_info['divisible'])
        quote_quantity_normalized = blockchain.normalize_quantity(
            o['give_quantity'] if quote_asset == o['give_asset'] else
            o['get_quantity'], quote_asset_info['divisible'])
        order_price = get_price(base_quantity_normalized,
                                quote_quantity_normalized)
        if base_asset == o['give_asset']:  #selling base
            if pair_data[pair]['lowest_ask'] is None or order_price < pair_data[
                    pair]['lowest_ask']:
                pair_data[pair]['lowest_ask'] = order_price
        elif base_asset == o['get_asset']:  #buying base
            if pair_data[pair][
                    'highest_bid'] is None or order_price > pair_data[pair][
                        'highest_bid']:
                pair_data[pair]['highest_bid'] = order_price

    #COMPOSE volume data (in XCP and BTC), and % change data
    #loop through all trade volume over the past 24h, and match that to the open orders
    trades_data_by_pair = mongo_db.trades.aggregate([
        {
            "$match": {
                "block_time": {
                    "$gte": start_dt,
                    "$lte": end_dt
                }
            }
        },
        {
            "$project": {
                "base_asset": 1,
                "quote_asset": 1,
                "base_quantity_normalized": 1,  #to derive base volume
                "quote_quantity_normalized": 1  #to derive quote volume
            }
        },
        {
            "$group": {
                "_id": {
                    "base_asset": "$base_asset",
                    "quote_asset": "$quote_asset"
                },
                "vol_base": {
                    "$sum": "$base_quantity_normalized"
                },
                "vol_quote": {
                    "$sum": "$quote_quantity_normalized"
                },
                "count": {
                    "$sum": 1
                },
            }
        }
    ])
    trades_data_by_pair = [] if not trades_data_by_pair[
        'ok'] else trades_data_by_pair['result']
    for e in trades_data_by_pair:
        pair = '%s/%s' % (e['_id']['base_asset'], e['_id']['quote_asset'])
        pair_data.setdefault(pair, {
            'open_orders_count': 0,
            'lowest_ask': None,
            'highest_bid': None
        })
        #^ initialize an empty pair in the event there are no open orders for that pair, but there ARE completed trades for it
        pair_data[pair]['completed_trades_count'] = e['count']
        pair_data[pair]['vol_base'] = e['vol_base']
        pair_data[pair]['vol_quote'] = e['vol_quote']

    #compose price data, relative to BTC and XCP
    mps_xcp_btc, xcp_btc_price, btc_xcp_price = get_price_primatives()
    for pair, e in pair_data.iteritems():
        base_asset, quote_asset = pair.split('/')
        _24h_vol_in_btc = None
        _24h_vol_in_xcp = None
        #derive asset price data, expressed in BTC and XCP, for the given volumes
        if base_asset == config.XCP:
            _24h_vol_in_xcp = e['vol_base']
            _24h_vol_in_btc = blockchain.round_out(
                e['vol_base'] * xcp_btc_price) if xcp_btc_price else 0
        elif base_asset == config.BTC:
            _24h_vol_in_xcp = blockchain.round_out(
                e['vol_base'] * btc_xcp_price) if btc_xcp_price else 0
            _24h_vol_in_btc = e['vol_base']
        else:  #base is not XCP or BTC
            price_summary_in_xcp, price_summary_in_btc, price_in_xcp, price_in_btc, aggregated_price_in_xcp, aggregated_price_in_btc = \
                get_xcp_btc_price_info(base_asset, mps_xcp_btc, xcp_btc_price, btc_xcp_price, with_last_trades=0, start_dt=start_dt, end_dt=end_dt)
            if price_in_xcp:
                _24h_vol_in_xcp = blockchain.round_out(e['vol_base'] *
                                                       price_in_xcp)
            if price_in_btc:
                _24h_vol_in_btc = blockchain.round_out(e['vol_base'] *
                                                       price_in_btc)

            if _24h_vol_in_xcp is None or _24h_vol_in_btc is None:
                #the base asset didn't have price data against BTC or XCP, or both...try against the quote asset instead
                price_summary_in_xcp, price_summary_in_btc, price_in_xcp, price_in_btc, aggregated_price_in_xcp, aggregated_price_in_btc = \
                    get_xcp_btc_price_info(quote_asset, mps_xcp_btc, xcp_btc_price, btc_xcp_price, with_last_trades=0, start_dt=start_dt, end_dt=end_dt)
                if _24h_vol_in_xcp is None and price_in_xcp:
                    _24h_vol_in_xcp = blockchain.round_out(e['vol_quote'] *
                                                           price_in_xcp)
                if _24h_vol_in_btc is None and price_in_btc:
                    _24h_vol_in_btc = blockchain.round_out(e['vol_quote'] *
                                                           price_in_btc)
            pair_data[pair]['24h_vol_in_{}'.format(
                config.XCP.lower())] = _24h_vol_in_xcp  #might still be None
            pair_data[pair]['24h_vol_in_{}'.format(
                config.BTC.lower())] = _24h_vol_in_btc  #might still be None

        #get % change stats -- start by getting the first trade directly before the 24h period starts
        prev_trade = mongo_db.trades.find({
            "base_asset": base_asset,
            "quote_asset": quote_asset,
            "block_time": {
                '$lt': start_dt
            }
        }).sort('block_time', pymongo.DESCENDING).limit(1)
        latest_trade = mongo_db.trades.find({
            "base_asset": base_asset,
            "quote_asset": quote_asset
        }).sort('block_time', pymongo.DESCENDING).limit(1)
        if not prev_trade.count():  #no previous trade before this 24hr period
            pair_data[pair]['24h_pct_change'] = None
        else:
            prev_trade = prev_trade[0]
            latest_trade = latest_trade[0]
            prev_trade_price = get_price(
                prev_trade['base_quantity_normalized'],
                prev_trade['quote_quantity_normalized'])
            latest_trade_price = get_price(
                latest_trade['base_quantity_normalized'],
                latest_trade['quote_quantity_normalized'])
            pair_data[pair]['24h_pct_change'] = (
                (latest_trade_price - prev_trade_price) /
                prev_trade_price) * 100
        pair_data[pair]['last_updated'] = end_dt
        #print "PRODUCED", pair, pair_data[pair]
        mongo_db.asset_pair_market_info.update(
            {
                'base_asset': base_asset,
                'quote_asset': quote_asset
            }, {"$set": pair_data[pair]},
            upsert=True)

    #remove any old pairs that were not just updated
    mongo_db.asset_pair_market_info.remove({'last_updated': {'$lt': end_dt}})
    logger.info("Recomposed 24h trade statistics for %i asset pairs: %s" %
                (len(pair_data), ', '.join(pair_data.keys())))
示例#19
0
def compile_asset_pair_market_info():
    """Compiles the pair-level statistics that show on the View Prices page of counterwallet, for instance"""
    #loop through all open orders, and compile a listing of pairs, with a count of open orders for each pair
    end_dt = datetime.datetime.utcnow()
    start_dt = end_dt - datetime.timedelta(days=1)
    start_block_index, end_block_index = database.get_block_indexes_for_dates(start_dt=start_dt, end_dt=end_dt)
    open_orders = util.call_jsonrpc_api("get_orders",
        { 'filters': [
            {'field': 'give_remaining', 'op': '>', 'value': 0},
            {'field': 'get_remaining', 'op': '>', 'value': 0},
            {'field': 'fee_required_remaining', 'op': '>=', 'value': 0},
            {'field': 'fee_provided_remaining', 'op': '>=', 'value': 0},
          ],
          'status': 'open',
          'show_expired': False,
        }, abort_on_error=True)['result']
    pair_data = {}
    asset_info = {}
    
    def get_price(base_quantity_normalized, quote_quantity_normalized):
        return float(D(quote_quantity_normalized / base_quantity_normalized ))
    
    #COMPOSE order depth, lowest ask, and highest bid column data
    for o in open_orders:
        (base_asset, quote_asset) = util.assets_to_asset_pair(o['give_asset'], o['get_asset'])
        pair = '%s/%s' % (base_asset, quote_asset)
        base_asset_info = asset_info.get(base_asset, config.mongo_db.tracked_assets.find_one({ 'asset': base_asset }))
        if base_asset not in asset_info: asset_info[base_asset] = base_asset_info
        quote_asset_info = asset_info.get(quote_asset, config.mongo_db.tracked_assets.find_one({ 'asset': quote_asset }))
        if quote_asset not in asset_info: asset_info[quote_asset] = quote_asset_info
        
        pair_data.setdefault(pair, {'open_orders_count': 0, 'lowest_ask': None, 'highest_bid': None,
            'completed_trades_count': 0, 'vol_base': 0, 'vol_quote': 0})
        #^ highest ask = open order selling base, highest bid = open order buying base
        #^ we also initialize completed_trades_count, vol_base, vol_quote because every pair inited here may
        # not have cooresponding data out of the trades_data_by_pair aggregation below
        pair_data[pair]['open_orders_count'] += 1
        base_quantity_normalized = blockchain.normalize_quantity(o['give_quantity'] if base_asset == o['give_asset'] else o['get_quantity'], base_asset_info['divisible'])
        quote_quantity_normalized = blockchain.normalize_quantity(o['give_quantity'] if quote_asset == o['give_asset'] else o['get_quantity'], quote_asset_info['divisible'])
        order_price = get_price(base_quantity_normalized, quote_quantity_normalized)
        if base_asset == o['give_asset']: #selling base
            if pair_data[pair]['lowest_ask'] is None or order_price < pair_data[pair]['lowest_ask']: 
                pair_data[pair]['lowest_ask'] = order_price
        elif base_asset == o['get_asset']: #buying base
            if pair_data[pair]['highest_bid'] is None or order_price > pair_data[pair]['highest_bid']:
                pair_data[pair]['highest_bid'] = order_price
    
    #COMPOSE volume data (in XCP and BTC), and % change data
    #loop through all trade volume over the past 24h, and match that to the open orders
    trades_data_by_pair = config.mongo_db.trades.aggregate([
        {"$match": {
            "block_time": {"$gte": start_dt, "$lte": end_dt } }
        },
        {"$project": {
            "base_asset": 1,
            "quote_asset": 1,
            "base_quantity_normalized": 1, #to derive base volume
            "quote_quantity_normalized": 1 #to derive quote volume
        }},
        {"$group": {
            "_id":   {"base_asset": "$base_asset", "quote_asset": "$quote_asset"},
            "vol_base":   {"$sum": "$base_quantity_normalized"},
            "vol_quote":   {"$sum": "$quote_quantity_normalized"},
            "count": {"$sum": 1},
        }}
    ])
    for e in trades_data_by_pair:
        pair = '%s/%s' % (e['_id']['base_asset'], e['_id']['quote_asset'])
        pair_data.setdefault(pair, {'open_orders_count': 0, 'lowest_ask': None, 'highest_bid': None})
        #^ initialize an empty pair in the event there are no open orders for that pair, but there ARE completed trades for it
        pair_data[pair]['completed_trades_count'] = e['count']
        pair_data[pair]['vol_base'] = e['vol_base'] 
        pair_data[pair]['vol_quote'] = e['vol_quote'] 
    
    #compose price data, relative to BTC and XCP
    mps_xcp_btc, xcp_btc_price, btc_xcp_price = get_price_primatives()
    for pair, e in pair_data.iteritems():
        base_asset, quote_asset = pair.split('/')
        _24h_vol_in_btc = None
        _24h_vol_in_xcp = None
        #derive asset price data, expressed in BTC and XCP, for the given volumes
        if base_asset == config.XCP:
            _24h_vol_in_xcp = e['vol_base']
            _24h_vol_in_btc = blockchain.round_out(e['vol_base'] * xcp_btc_price) if xcp_btc_price else 0
        elif base_asset == config.BTC:
            _24h_vol_in_xcp = blockchain.round_out(e['vol_base'] * btc_xcp_price) if btc_xcp_price else 0
            _24h_vol_in_btc = e['vol_base']
        else: #base is not XCP or BTC
            price_summary_in_xcp, price_summary_in_btc, price_in_xcp, price_in_btc, aggregated_price_in_xcp, aggregated_price_in_btc = \
                get_xcp_btc_price_info(base_asset, mps_xcp_btc, xcp_btc_price, btc_xcp_price, with_last_trades=0, start_dt=start_dt, end_dt=end_dt)
            if price_in_xcp:
                _24h_vol_in_xcp = blockchain.round_out(e['vol_base'] * price_in_xcp)
            if price_in_btc:
                _24h_vol_in_btc = blockchain.round_out(e['vol_base'] * price_in_btc)
            
            if _24h_vol_in_xcp is None or _24h_vol_in_btc is None:
                #the base asset didn't have price data against BTC or XCP, or both...try against the quote asset instead
                price_summary_in_xcp, price_summary_in_btc, price_in_xcp, price_in_btc, aggregated_price_in_xcp, aggregated_price_in_btc = \
                    get_xcp_btc_price_info(quote_asset, mps_xcp_btc, xcp_btc_price, btc_xcp_price, with_last_trades=0, start_dt=start_dt, end_dt=end_dt)
                if _24h_vol_in_xcp is None and price_in_xcp:
                    _24h_vol_in_xcp = blockchain.round_out(e['vol_quote'] * price_in_xcp)
                if _24h_vol_in_btc is None and price_in_btc:
                    _24h_vol_in_btc = blockchain.round_out(e['vol_quote'] * price_in_btc)
            pair_data[pair]['24h_vol_in_{}'.format(config.XCP.lower())] = _24h_vol_in_xcp #might still be None
            pair_data[pair]['24h_vol_in_{}'.format(config.BTC.lower())] = _24h_vol_in_btc #might still be None
        
        #get % change stats -- start by getting the first trade directly before the 24h period starts
        prev_trade = config.mongo_db.trades.find({
            "base_asset": base_asset,
            "quote_asset": quote_asset,
            "block_time": {'$lt': start_dt}}).sort('block_time', pymongo.DESCENDING).limit(1)
        latest_trade = config.mongo_db.trades.find({
            "base_asset": base_asset,
            "quote_asset": quote_asset}).sort('block_time', pymongo.DESCENDING).limit(1)
        if not prev_trade.count(): #no previous trade before this 24hr period
            pair_data[pair]['24h_pct_change'] = None
        else:
            prev_trade = prev_trade[0]
            latest_trade = latest_trade[0]
            prev_trade_price = get_price(prev_trade['base_quantity_normalized'], prev_trade['quote_quantity_normalized'])
            latest_trade_price = get_price(latest_trade['base_quantity_normalized'], latest_trade['quote_quantity_normalized'])
            pair_data[pair]['24h_pct_change'] = ((latest_trade_price - prev_trade_price) / prev_trade_price) * 100
        pair_data[pair]['last_updated'] = end_dt
        #print "PRODUCED", pair, pair_data[pair] 
        config.mongo_db.asset_pair_market_info.update( {'base_asset': base_asset, 'quote_asset': quote_asset}, {"$set": pair_data[pair]}, upsert=True)
        
    #remove any old pairs that were not just updated
    config.mongo_db.asset_pair_market_info.remove({'last_updated': {'$lt': end_dt}})
    logger.info("Recomposed 24h trade statistics for %i asset pairs: %s" % (len(pair_data), ', '.join(pair_data.keys())))
示例#20
0
def get_market_trades(asset1, asset2, addresses=[], limit=50, supplies=None):
    limit = min(limit, 100)
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    if not supplies:
        supplies = get_assets_supply([asset1, asset2])
    market_trades = []

    sources = ''
    bindings = ['expired']
    if len(addresses) > 0:
        placeholder = ','.join(['?' for e in range(0, len(addresses))])
        sources = '''AND (tx0_address IN ({}) OR tx1_address IN ({}))'''.format(placeholder, placeholder)
        bindings += addresses + addresses

    sql = '''SELECT order_matches.*, blocks.block_time FROM order_matches INNER JOIN blocks ON order_matches.block_index=blocks.block_index
             WHERE status != ? {}
                AND forward_asset IN (?, ?) 
                AND backward_asset IN (?, ?) 
             ORDER BY block_index DESC
             LIMIT ?'''.format(sources)

    bindings += [asset1, asset2, asset1, asset2, limit]

    order_matches = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result']

    for order_match in order_matches:

        if order_match['tx0_address'] in addresses:
            trade = {}
            trade['match_id'] = order_match['id']
            trade['source'] = order_match['tx0_address']
            trade['countersource'] = order_match['tx1_address']
            trade['block_index'] = order_match['block_index']
            trade['block_time'] = order_match['block_time']
            trade['status'] = order_match['status']
            if order_match['forward_asset'] == base_asset:
                trade['type'] = 'SELL'
                trade['price'] = calculate_price(order_match['forward_quantity'], order_match['backward_quantity'], supplies[order_match['forward_asset']][1], supplies[order_match['backward_asset']][1], 'SELL')
                trade['amount'] = order_match['forward_quantity']
                trade['total'] = order_match['backward_quantity']
            else:
                trade['type'] = 'BUY'
                trade['price'] = calculate_price(order_match['backward_quantity'], order_match['forward_quantity'], supplies[order_match['backward_asset']][1], supplies[order_match['forward_asset']][1], 'BUY')
                trade['amount'] = order_match['backward_quantity']
                trade['total'] = order_match['forward_quantity']
            market_trades.append(trade)

        if len(addresses) == 0 or order_match['tx1_address'] in addresses:
            trade = {}
            trade['match_id'] = order_match['id']
            trade['source'] = order_match['tx1_address']
            trade['countersource'] = order_match['tx0_address']
            trade['block_index'] = order_match['block_index']
            trade['block_time'] = order_match['block_time']
            trade['status'] = order_match['status']
            if order_match['backward_asset'] == base_asset:
                trade['type'] = 'SELL'
                trade['price'] = calculate_price(order_match['backward_quantity'], order_match['forward_quantity'], supplies[order_match['backward_asset']][1], supplies[order_match['forward_asset']][1], 'SELL')
                trade['amount'] = order_match['backward_quantity']
                trade['total'] = order_match['forward_quantity']
            else:
                trade['type'] = 'BUY'
                trade['price'] = calculate_price(order_match['forward_quantity'], order_match['backward_quantity'], supplies[order_match['forward_asset']][1], supplies[order_match['backward_asset']][1], 'BUY')
                trade['amount'] = order_match['forward_quantity']
                trade['total'] = order_match['backward_quantity']
            market_trades.append(trade)

    return market_trades
示例#21
0
def get_market_orders(asset1, asset2, addresses=[], supplies=None, min_fee_provided=0.95, max_fee_required=0.95):

    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    if not supplies:
        supplies = get_assets_supply([asset1, asset2])

    market_orders = []
    buy_orders = []
    sell_orders = []

    sql = '''SELECT orders.*, blocks.block_time FROM orders INNER JOIN blocks ON orders.block_index=blocks.block_index 
             WHERE  status = ? '''
    bindings = ['open']

    if len(addresses) > 0:
        sql += '''AND source IN ({}) '''.format(','.join(['?' for e in range(0, len(addresses))]))
        bindings += addresses

    sql += '''AND give_remaining > 0 
              AND give_asset IN (?, ?) 
              AND get_asset IN (?, ?) 
              ORDER BY tx_index DESC'''

    bindings += [asset1, asset2, asset1, asset2]

    orders = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result']

    for order in orders:
        market_order = {}

        exclude = False
        if order['give_asset'] == 'BTC':
            try:
                fee_provided = order['fee_provided'] / (order['give_quantity'] / 100)
                market_order['fee_provided'] = format(D(order['fee_provided']) / (D(order['give_quantity']) / D(100)), '.2f')
            except Exception as e:
                fee_provided = min_fee_provided - 1  # exclude

            exclude = fee_provided < min_fee_provided

        elif order['get_asset'] == 'BTC':
            try:
                fee_required = order['fee_required'] / (order['get_quantity'] / 100)
                market_order['fee_required'] = format(D(order['fee_required']) / (D(order['get_quantity']) / D(100)), '.2f')
            except Exception as e:
                fee_required = max_fee_required + 1  # exclude

            exclude = fee_required > max_fee_required

        if not exclude:
            if order['give_asset'] == base_asset:
                try:
                    price = calculate_price(order['give_quantity'], order['get_quantity'], supplies[order['give_asset']][1], supplies[order['get_asset']][1], 'SELL')
                except:
                    continue
                market_order['type'] = 'SELL'
                market_order['amount'] = order['give_remaining']
                market_order['total'] = D(order['give_remaining']) * D(price)
                if not supplies[order['give_asset']][1] and supplies[order['get_asset']][1]:
                    market_order['total'] = int(market_order['total'] * config.UNIT)
                elif supplies[order['give_asset']][1] and not supplies[order['get_asset']][1]:
                    market_order['total'] = int(market_order['total'] / config.UNIT)
                else:
                    market_order['total'] = int(market_order['total'])
            else:
                try:
                    price = calculate_price(order['get_quantity'], order['give_quantity'], supplies[order['get_asset']][1], supplies[order['give_asset']][1], 'BUY')
                except:
                    continue
                market_order['type'] = 'BUY'
                market_order['total'] = order['give_remaining']
                market_order['amount'] = D(order['give_remaining']) / D(price)
                if supplies[order['give_asset']][1] and not supplies[order['get_asset']][1]:
                    market_order['amount'] = int(market_order['amount'] / config.UNIT)
                elif not supplies[order['give_asset']][1] and supplies[order['get_asset']][1]:
                    market_order['amount'] = int(market_order['amount'] * config.UNIT)
                else:
                    market_order['amount'] = int(market_order['amount'])

            market_order['price'] = price

            if len(addresses) > 0:
                completed = format(((D(order['give_quantity']) - D(order['give_remaining'])) / D(order['give_quantity'])) * D(100), '.2f')
                market_order['completion'] = "{}%".format(completed)
                market_order['tx_index'] = order['tx_index']
                market_order['tx_hash'] = order['tx_hash']
                market_order['source'] = order['source']
                market_order['block_index'] = order['block_index']
                market_order['block_time'] = order['block_time']
                market_orders.append(market_order)
            else:
                if market_order['type'] == 'SELL':
                    sell_orders.append(market_order)
                else:
                    buy_orders.append(market_order)

    if len(addresses) == 0:
        market_orders = merge_same_price_orders(sell_orders) + merge_same_price_orders(buy_orders)

    return market_orders
示例#22
0
def get_market_trades(asset1, asset2, addresses=[], limit=50, supplies=None):
    limit = min(limit, 100)
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    if not supplies:
        supplies = get_assets_supply([asset1, asset2])
    market_trades = []

    sources = ''
    bindings = ['expired']
    if len(addresses) > 0:
        placeholder = ','.join(['?' for e in range(0,len(addresses))])
        sources = '''AND (tx0_address IN ({}) OR tx1_address IN ({}))'''.format(placeholder, placeholder)
        bindings += addresses + addresses

    sql = '''SELECT order_matches.*, blocks.block_time FROM order_matches INNER JOIN blocks ON order_matches.block_index=blocks.block_index
             WHERE status != ? {}
                AND forward_asset IN (?, ?) 
                AND backward_asset IN (?, ?) 
             ORDER BY block_index DESC
             LIMIT ?'''.format(sources)

    bindings +=  [asset1, asset2, asset1, asset2, limit]

    order_matches = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result']

    for order_match in order_matches:

        if order_match['tx0_address'] in addresses:
            trade = {}
            trade['match_id'] = order_match['id']
            trade['source'] = order_match['tx0_address']
            trade['countersource'] = order_match['tx1_address']
            trade['block_index'] = order_match['block_index']
            trade['block_time'] = order_match['block_time']
            trade['status'] = order_match['status']
            if order_match['forward_asset'] == base_asset:
                trade['type'] = 'SELL'
                trade['price'] = calculate_price(order_match['forward_quantity'], order_match['backward_quantity'], supplies[order_match['forward_asset']][1], supplies[order_match['backward_asset']][1], 'SELL')
                trade['amount'] = order_match['forward_quantity']
                trade['total'] = order_match['backward_quantity']
            else:
                trade['type'] = 'BUY'
                trade['price'] = calculate_price(order_match['backward_quantity'], order_match['forward_quantity'], supplies[order_match['backward_asset']][1], supplies[order_match['forward_asset']][1], 'BUY')
                trade['amount'] = order_match['backward_quantity']
                trade['total'] = order_match['forward_quantity']
            market_trades.append(trade)

        if len(addresses)==0 or order_match['tx1_address'] in addresses:
            trade = {}
            trade['match_id'] = order_match['id']
            trade['source'] = order_match['tx1_address']
            trade['countersource'] = order_match['tx0_address']
            trade['block_index'] = order_match['block_index']
            trade['block_time'] = order_match['block_time']
            trade['status'] = order_match['status']
            if order_match['backward_asset'] == base_asset:
                trade['type'] = 'SELL'
                trade['price'] = calculate_price(order_match['backward_quantity'], order_match['forward_quantity'], supplies[order_match['backward_asset']][1], supplies[order_match['forward_asset']][1], 'SELL')
                trade['amount'] = order_match['backward_quantity']
                trade['total'] = order_match['forward_quantity']
            else:
                trade['type'] = 'BUY'
                trade['price'] = calculate_price(order_match['forward_quantity'], order_match['backward_quantity'], supplies[order_match['forward_asset']][1], supplies[order_match['backward_asset']][1], 'BUY')
                trade['amount'] = order_match['forward_quantity']
                trade['total'] = order_match['backward_quantity']
            market_trades.append(trade)

    return market_trades
示例#23
0
def get_market_price_history(asset1, asset2, start_ts=None, end_ts=None, as_dict=False):
    """Return block-by-block aggregated market history data for the specified asset pair, within the specified date range.
    @returns List of lists (or list of dicts, if as_dict is specified).
        * If as_dict is False, each embedded list has 8 elements [block time (epoch in MS), open, high, low, close, volume, # trades in block, block index]
        * If as_dict is True, each dict in the list has the keys: block_time (epoch in MS), block_index, open, high, low, close, vol, count
        
    Aggregate on an an hourly basis 
    """
    now_ts = time.mktime(datetime.datetime.utcnow().timetuple())
    if not end_ts: #default to current datetime
        end_ts = now_ts
    if not start_ts: #default to 180 days before the end date
        start_ts = end_ts - (180 * 24 * 60 * 60) 
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    
    #get ticks -- open, high, low, close, volume
    result = config.mongo_db.trades.aggregate([
        {"$match": {
            "base_asset": base_asset,
            "quote_asset": quote_asset,
            "block_time": {
                "$gte": datetime.datetime.utcfromtimestamp(start_ts)
            } if end_ts == now_ts else {
                "$gte": datetime.datetime.utcfromtimestamp(start_ts),
                "$lte": datetime.datetime.utcfromtimestamp(end_ts)                    
            }                
        }},
        {"$project": {
            "year":  {"$year": "$block_time"},
            "month": {"$month": "$block_time"},
            "day":   {"$dayOfMonth": "$block_time"},
            "hour":  {"$hour": "$block_time"},
            "block_index": 1,
            "unit_price": 1,
            "base_quantity_normalized": 1 #to derive volume
        }},
        {"$group": {
            "_id":   {"year": "$year", "month": "$month", "day": "$day", "hour": "$hour"},
            "open":  {"$first": "$unit_price"},
            "high":  {"$max": "$unit_price"},
            "low":   {"$min": "$unit_price"},
            "close": {"$last": "$unit_price"},
            "vol":   {"$sum": "$base_quantity_normalized"},
            "count": {"$sum": 1},
        }},
        {"$sort": SON([("_id.year", pymongo.ASCENDING), ("_id.month", pymongo.ASCENDING), ("_id.day", pymongo.ASCENDING), ("_id.hour", pymongo.ASCENDING)])},
    ])
    result = list(result)
    if not len(result):
        return False
    
    midline = [((r['high'] + r['low']) / 2.0) for r in result]
    if as_dict:
        for i in xrange(len(result)):
            result[i]['interval_time'] = int(time.mktime(datetime.datetime(
                result[i]['_id']['year'], result[i]['_id']['month'], result[i]['_id']['day'], result[i]['_id']['hour']).timetuple()) * 1000)
            result[i]['midline'] = midline[i]
            del result[i]['_id']
        return result
    else:
        list_result = []
        for i in xrange(len(result)):
            list_result.append([
                int(time.mktime(datetime.datetime(
                    result[i]['_id']['year'], result[i]['_id']['month'], result[i]['_id']['day'], result[i]['_id']['hour']).timetuple()) * 1000),
                result[i]['open'], result[i]['high'], result[i]['low'], result[i]['close'], result[i]['vol'],
                result[i]['count'], midline[i]
            ])
        return list_result
示例#24
0
def get_market_orders(asset1, asset2, addresses=[], supplies=None, min_fee_provided=0.95, max_fee_required=0.95):

    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)
    if not supplies:
        supplies = get_assets_supply([asset1, asset2])

    market_orders = []
    buy_orders = []
    sell_orders = []

    sql = '''SELECT orders.*, blocks.block_time FROM orders INNER JOIN blocks ON orders.block_index=blocks.block_index
             WHERE  status = ? '''
    bindings = ['open']

    if len(addresses) > 0:
        sql += '''AND source IN ({}) '''.format(','.join(['?' for e in range(0, len(addresses))]))
        bindings += addresses

    sql += '''AND give_remaining > 0
              AND give_asset IN (?, ?)
              AND get_asset IN (?, ?)
              ORDER BY tx_index DESC'''

    bindings += [asset1, asset2, asset1, asset2]

    orders = util.call_jsonrpc_api('sql', {'query': sql, 'bindings': bindings})['result']

    for order in orders:
        market_order = {}

        exclude = False
        if order['give_asset'] == config.BTC:
            try:
                fee_provided = order['fee_provided'] / (order['give_quantity'] / 100)
                market_order['fee_provided'] = format(D(order['fee_provided']) / (D(order['give_quantity']) / D(100)), '.2f')
            except Exception as e:
                fee_provided = min_fee_provided - 1  # exclude

            exclude = fee_provided < min_fee_provided

        elif order['get_asset'] == config.BTC:
            try:
                fee_required = order['fee_required'] / (order['get_quantity'] / 100)
                market_order['fee_required'] = format(D(order['fee_required']) / (D(order['get_quantity']) / D(100)), '.2f')
            except Exception as e:
                fee_required = max_fee_required + 1  # exclude

            exclude = fee_required > max_fee_required

        if not exclude:
            if order['give_asset'] == base_asset:
                try:
                    price = calculate_price(order['give_quantity'], order['get_quantity'], supplies[order['give_asset']][1], supplies[order['get_asset']][1], 'SELL')
                except:
                    continue
                market_order['type'] = 'SELL'
                market_order['amount'] = order['give_remaining']
                market_order['total'] = D(order['give_remaining']) * D(price)
                if not supplies[order['give_asset']][1] and supplies[order['get_asset']][1]:
                    market_order['total'] = int(market_order['total'] * config.UNIT)
                elif supplies[order['give_asset']][1] and not supplies[order['get_asset']][1]:
                    market_order['total'] = int(market_order['total'] / config.UNIT)
                else:
                    market_order['total'] = int(market_order['total'])
            else:
                try:
                    price = calculate_price(order['get_quantity'], order['give_quantity'], supplies[order['get_asset']][1], supplies[order['give_asset']][1], 'BUY')
                except:
                    continue
                market_order['type'] = 'BUY'
                market_order['total'] = order['give_remaining']
                market_order['amount'] = D(order['give_remaining']) / D(price)
                if supplies[order['give_asset']][1] and not supplies[order['get_asset']][1]:
                    market_order['amount'] = int(market_order['amount'] / config.UNIT)
                elif not supplies[order['give_asset']][1] and supplies[order['get_asset']][1]:
                    market_order['amount'] = int(market_order['amount'] * config.UNIT)
                else:
                    market_order['amount'] = int(market_order['amount'])

            market_order['price'] = price

            if len(addresses) > 0:
                completed = format(((D(order['give_quantity']) - D(order['give_remaining'])) / D(order['give_quantity'])) * D(100), '.2f')
                market_order['completion'] = "{}%".format(completed)
                market_order['tx_index'] = order['tx_index']
                market_order['tx_hash'] = order['tx_hash']
                market_order['source'] = order['source']
                market_order['block_index'] = order['block_index']
                market_order['block_time'] = order['block_time']
                market_orders.append(market_order)
            else:
                if market_order['type'] == 'SELL':
                    sell_orders.append(market_order)
                else:
                    buy_orders.append(market_order)

    if len(addresses) == 0:
        market_orders = merge_same_price_orders(sell_orders) + merge_same_price_orders(buy_orders)

    return market_orders
示例#25
0
def parse_trade_book(msg, msg_data):
    # book trades
    if (msg['category'] == 'order_matches' and
        ((msg['command'] == 'update' and msg_data['status'] == 'completed')
         or  # for a trade with BTC involved, but that is settled (completed)
         ('forward_asset' in msg_data
          and msg_data['forward_asset'] != config.BTC
          and msg_data['backward_asset'] != config.BTC))
        ):  # or for a trade without BTC on either end

        if msg['command'] == 'update' and msg_data['status'] == 'completed':
            # an order is being updated to a completed status (i.e. a BTCpay has completed)
            tx0_hash, tx1_hash = msg_data['order_match_id'][:64], msg_data[
                'order_match_id'][65:]
            # get the order_match this btcpay settles
            order_match = util.jsonrpc_api("get_order_matches", {
                'filters': [{
                    'field': 'tx0_hash',
                    'op': '==',
                    'value': tx0_hash
                }, {
                    'field': 'tx1_hash',
                    'op': '==',
                    'value': tx1_hash
                }]
            },
                                           abort_on_error=False)['result'][0]
        else:
            assert msg_data[
                'status'] == 'completed'  # should not enter a pending state for non BTC matches
            order_match = msg_data

        forward_asset_info = config.mongo_db.tracked_assets.find_one(
            {'asset': order_match['forward_asset']})
        backward_asset_info = config.mongo_db.tracked_assets.find_one(
            {'asset': order_match['backward_asset']})
        assert forward_asset_info and backward_asset_info
        base_asset, quote_asset = util.assets_to_asset_pair(
            order_match['forward_asset'], order_match['backward_asset'])

        # don't create trade records from order matches with BTC that are under the dust limit
        if ((order_match['forward_asset'] == config.BTC
             and order_match['forward_quantity'] <=
             config.ORDER_BTC_DUST_LIMIT_CUTOFF)
                or (order_match['backward_asset'] == config.BTC
                    and order_match['backward_quantity'] <=
                    config.ORDER_BTC_DUST_LIMIT_CUTOFF)):
            logger.debug("Order match %s ignored due to %s under dust limit." %
                         (order_match['tx0_hash'] + order_match['tx1_hash'],
                          config.BTC))
            return 'ABORT_THIS_MESSAGE_PROCESSING'

        # take divisible trade quantities to floating point
        forward_quantity = blockchain.normalize_quantity(
            order_match['forward_quantity'], forward_asset_info['divisible'])
        backward_quantity = blockchain.normalize_quantity(
            order_match['backward_quantity'], backward_asset_info['divisible'])

        # compose trade
        trade = {
            'block_index':
            config.state['cur_block']['block_index'],
            'block_time':
            config.state['cur_block']['block_time_obj'],
            'message_index':
            msg['message_index'],  # secondary temporaral ordering off of when
            'order_match_id':
            order_match['tx0_hash'] + '_' + order_match['tx1_hash'],
            'order_match_tx0_index':
            order_match['tx0_index'],
            'order_match_tx1_index':
            order_match['tx1_index'],
            'order_match_tx0_address':
            order_match['tx0_address'],
            'order_match_tx1_address':
            order_match['tx1_address'],
            'base_asset':
            base_asset,
            'quote_asset':
            quote_asset,
            'base_quantity':
            order_match['forward_quantity'] if order_match['forward_asset']
            == base_asset else order_match['backward_quantity'],
            'quote_quantity':
            order_match['backward_quantity'] if order_match['forward_asset']
            == base_asset else order_match['forward_quantity'],
            'base_quantity_normalized':
            forward_quantity if order_match['forward_asset'] == base_asset else
            backward_quantity,
            'quote_quantity_normalized':
            backward_quantity if order_match['forward_asset'] == base_asset
            else forward_quantity,
        }
        d = D(trade['quote_quantity_normalized']) / D(
            trade['base_quantity_normalized'])
        d = d.quantize(EIGHT_PLACES,
                       rounding=decimal.ROUND_HALF_EVEN,
                       context=decimal.Context(prec=30))
        trade['unit_price'] = float(d)

        d = D(trade['base_quantity_normalized']) / D(
            trade['quote_quantity_normalized'])
        d = d.quantize(EIGHT_PLACES,
                       rounding=decimal.ROUND_HALF_EVEN,
                       context=decimal.Context(prec=30))
        trade['unit_price_inverse'] = float(d)

        config.mongo_db.trades.insert(trade)
        logger.info("Procesed Trade from tx %s :: %s" %
                    (msg['message_index'], trade))
示例#26
0
def get_market_price_history(asset1,
                             asset2,
                             start_ts=None,
                             end_ts=None,
                             as_dict=False):
    """Return block-by-block aggregated market history data for the specified asset pair, within the specified date range.
    @returns List of lists (or list of dicts, if as_dict is specified).
        * If as_dict is False, each embedded list has 8 elements [block time (epoch in MS), open, high, low, close, volume, # trades in block, block index]
        * If as_dict is True, each dict in the list has the keys: block_time (epoch in MS), block_index, open, high, low, close, vol, count

    Aggregate on an an hourly basis 
    """
    now_ts = calendar.timegm(time.gmtime())
    if not end_ts:  # default to current datetime
        end_ts = now_ts
    if not start_ts:  # default to 180 days before the end date
        start_ts = end_ts - (180 * 24 * 60 * 60)
    base_asset, quote_asset = util.assets_to_asset_pair(asset1, asset2)

    # get ticks -- open, high, low, close, volume
    result = config.mongo_db.trades.aggregate([
        {
            "$match": {
                "base_asset": base_asset,
                "quote_asset": quote_asset,
                "block_time": {
                    "$gte": datetime.datetime.utcfromtimestamp(start_ts)
                } if end_ts == now_ts else {
                    "$gte": datetime.datetime.utcfromtimestamp(start_ts),
                    "$lte": datetime.datetime.utcfromtimestamp(end_ts)
                }
            }
        },
        {
            "$project": {
                "year": {
                    "$year": "$block_time"
                },
                "month": {
                    "$month": "$block_time"
                },
                "day": {
                    "$dayOfMonth": "$block_time"
                },
                "hour": {
                    "$hour": "$block_time"
                },
                "block_index": 1,
                "unit_price": 1,
                "base_quantity_normalized": 1  # to derive volume
            }
        },
        {
            "$group": {
                "_id": {
                    "year": "$year",
                    "month": "$month",
                    "day": "$day",
                    "hour": "$hour"
                },
                "open": {
                    "$first": "$unit_price"
                },
                "high": {
                    "$max": "$unit_price"
                },
                "low": {
                    "$min": "$unit_price"
                },
                "close": {
                    "$last": "$unit_price"
                },
                "vol": {
                    "$sum": "$base_quantity_normalized"
                },
                "count": {
                    "$sum": 1
                },
            }
        },
        {
            "$sort":
            SON([("_id.year", pymongo.ASCENDING),
                 ("_id.month", pymongo.ASCENDING),
                 ("_id.day", pymongo.ASCENDING),
                 ("_id.hour", pymongo.ASCENDING)])
        },
    ])
    result = list(result)
    if not len(result):
        return False

    midline = [((r['high'] + r['low']) / 2.0) for r in result]
    if as_dict:
        for i in range(len(result)):
            result[i]['interval_time'] = int(
                calendar.timegm(
                    datetime.datetime(
                        result[i]['_id']['year'], result[i]['_id']['month'],
                        result[i]['_id']['day'],
                        result[i]['_id']['hour']).timetuple()) * 1000)
            result[i]['midline'] = midline[i]
            del result[i]['_id']
        return result
    else:
        list_result = []
        for i in range(len(result)):
            list_result.append([
                int(
                    calendar.timegm(
                        datetime.datetime(
                            result[i]['_id']['year'],
                            result[i]['_id']['month'], result[i]['_id']['day'],
                            result[i]['_id']['hour']).timetuple()) * 1000),
                result[i]['open'], result[i]['high'], result[i]['low'],
                result[i]['close'], result[i]['vol'], result[i]['count'],
                midline[i]
            ])
        return list_result