コード例 #1
0
def _get_order_book(base_asset,
                    quote_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):
    """Gets the current order book for a specified asset pair

    @param: normalized_fee_required: Only specify if buying BTC. If specified, the order book will be pruned down to only
     show orders at and above this fee_required
    @param: normalized_fee_provided: Only specify if selling BTC. If specified, the order book will be pruned down to only
     show orders at and above this fee_provided
    """
    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 base_asset_info or not quote_asset_info:
        raise Exception("Invalid asset(s)")

    # TODO: limit # results to 8 or so for each book (we have to sort as well to limit)
    base_bid_filters = [
        {
            "field": "get_asset",
            "op": "==",
            "value": base_asset
        },
        {
            "field": "give_asset",
            "op": "==",
            "value": quote_asset
        },
    ]
    base_ask_filters = [
        {
            "field": "get_asset",
            "op": "==",
            "value": quote_asset
        },
        {
            "field": "give_asset",
            "op": "==",
            "value": base_asset
        },
    ]
    if base_asset == config.BTC or quote_asset == config.BTC:
        extra_filters = [
            {
                'field': 'give_remaining',
                'op': '>',
                'value': 0
            },  # don't show empty BTC orders
            {
                'field': 'get_remaining',
                'op': '>',
                'value': 0
            },  # don't show empty BTC orders
            {
                'field': 'fee_required_remaining',
                'op': '>=',
                'value': 0
            },
            {
                'field': 'fee_provided_remaining',
                'op': '>=',
                'value': 0
            },
        ]
        base_bid_filters += extra_filters
        base_ask_filters += extra_filters

    base_bid_orders = util.call_jsonrpc_api("get_orders", {
        'filters': base_bid_filters,
        'show_expired': False,
        'status': 'open',
        'order_by': 'block_index',
        'order_dir': 'asc',
    },
                                            abort_on_error=True)['result']

    base_ask_orders = util.call_jsonrpc_api("get_orders", {
        'filters': base_ask_filters,
        'show_expired': False,
        'status': 'open',
        'order_by': 'block_index',
        'order_dir': 'asc',
    },
                                            abort_on_error=True)['result']

    def get_o_pct(o):
        if o['give_asset'] == config.BTC:  # NB: fee_provided could be zero here
            pct_fee_provided = float(
                (D(o['fee_provided_remaining']) / D(o['give_quantity'])))
        else:
            pct_fee_provided = None
        if o['get_asset'] == config.BTC:  # NB: fee_required could be zero here
            pct_fee_required = float(
                (D(o['fee_required_remaining']) / D(o['get_quantity'])))
        else:
            pct_fee_required = None
        return pct_fee_provided, pct_fee_required

    # filter results by pct_fee_provided and pct_fee_required for BTC pairs as appropriate
    filtered_base_bid_orders = []
    filtered_base_ask_orders = []
    if base_asset == config.BTC or quote_asset == config.BTC:
        for o in base_bid_orders:
            pct_fee_provided, pct_fee_required = get_o_pct(o)
            addToBook = True
            if bid_book_min_pct_fee_provided is not None and pct_fee_provided is not None and pct_fee_provided < bid_book_min_pct_fee_provided:
                addToBook = False
            if bid_book_min_pct_fee_required is not None and pct_fee_required is not None and pct_fee_required < bid_book_min_pct_fee_required:
                addToBook = False
            if bid_book_max_pct_fee_required is not None and pct_fee_required is not None and pct_fee_required > bid_book_max_pct_fee_required:
                addToBook = False
            if addToBook:
                filtered_base_bid_orders.append(o)
        for o in base_ask_orders:
            pct_fee_provided, pct_fee_required = get_o_pct(o)
            addToBook = True
            if ask_book_min_pct_fee_provided is not None and pct_fee_provided is not None and pct_fee_provided < ask_book_min_pct_fee_provided:
                addToBook = False
            if ask_book_min_pct_fee_required is not None and pct_fee_required is not None and pct_fee_required < ask_book_min_pct_fee_required:
                addToBook = False
            if ask_book_max_pct_fee_required is not None and pct_fee_required is not None and pct_fee_required > ask_book_max_pct_fee_required:
                addToBook = False
            if addToBook:
                filtered_base_ask_orders.append(o)
    else:
        filtered_base_bid_orders += base_bid_orders
        filtered_base_ask_orders += base_ask_orders

    def make_book(orders, isBidBook):
        book = {}
        for o in orders:
            if o['give_asset'] == base_asset:
                if base_asset == config.BTC and o[
                        'give_quantity'] <= config.ORDER_BTC_DUST_LIMIT_CUTOFF:
                    continue  # filter dust orders, if necessary

                give_quantity = blockchain.normalize_quantity(
                    o['give_quantity'], base_asset_info['divisible'])
                get_quantity = blockchain.normalize_quantity(
                    o['get_quantity'], quote_asset_info['divisible'])
                unit_price = float((D(get_quantity) / D(give_quantity)))
                remaining = blockchain.normalize_quantity(
                    o['give_remaining'], base_asset_info['divisible'])
            else:
                if quote_asset == config.BTC and o[
                        'give_quantity'] <= config.ORDER_BTC_DUST_LIMIT_CUTOFF:
                    continue  # filter dust orders, if necessary

                give_quantity = blockchain.normalize_quantity(
                    o['give_quantity'], quote_asset_info['divisible'])
                get_quantity = blockchain.normalize_quantity(
                    o['get_quantity'], base_asset_info['divisible'])
                unit_price = float((D(give_quantity) / D(get_quantity)))
                remaining = blockchain.normalize_quantity(
                    o['get_remaining'], base_asset_info['divisible'])
            id = "%s_%s_%s" % (base_asset, quote_asset, unit_price)
            #^ key = {base}_{bid}_{unit_price}, values ref entries in book
            book.setdefault(id, {
                'unit_price': unit_price,
                'quantity': 0,
                'count': 0
            })
            book[id]['quantity'] += remaining  # base quantity outstanding
            book[id]['count'] += 1  # num orders at this price level
        book = sorted(iter(book.values()),
                      key=operator.itemgetter('unit_price'),
                      reverse=isBidBook)
        #^ convert to list and sort -- bid book = descending, ask book = ascending
        return book

    # compile into a single book, at volume tiers
    base_bid_book = make_book(filtered_base_bid_orders, True)
    base_ask_book = make_book(filtered_base_ask_orders, False)

    # get stats like the spread and median
    if base_bid_book and base_ask_book:
        # don't do abs(), as this is "the amount by which the ask price exceeds the bid", so I guess it could be negative
        # if there is overlap in the book (right?)
        bid_ask_spread = float((D(base_ask_book[0]['unit_price']) -
                                D(base_bid_book[0]['unit_price'])))
        bid_ask_median = float((D(
            max(base_ask_book[0]['unit_price'],
                base_bid_book[0]['unit_price'])) -
                                (D(abs(bid_ask_spread)) / 2)))
    else:
        bid_ask_spread = 0
        bid_ask_median = 0

    # compose depth and round out quantities
    bid_depth = D(0)
    for o in base_bid_book:
        o['quantity'] = float(D(o['quantity']))
        bid_depth += D(o['quantity'])
        o['depth'] = float(D(bid_depth))
    bid_depth = float(D(bid_depth))
    ask_depth = D(0)
    for o in base_ask_book:
        o['quantity'] = float(D(o['quantity']))
        ask_depth += D(o['quantity'])
        o['depth'] = float(D(ask_depth))
    ask_depth = float(D(ask_depth))

    # compose raw orders
    orders = filtered_base_bid_orders + filtered_base_ask_orders
    for o in orders:
        # add in the blocktime to help makes interfaces more user-friendly (i.e. avoid displaying block
        # indexes and display datetimes instead)
        o['block_time'] = calendar.timegm(
            util.get_block_time(o['block_index']).timetuple()) * 1000

    result = {
        'base_bid_book': base_bid_book,
        'base_ask_book': base_ask_book,
        'bid_depth': bid_depth,
        'ask_depth': ask_depth,
        'bid_ask_spread': bid_ask_spread,
        'bid_ask_median': bid_ask_median,
        'raw_orders': orders,
        'base_asset': base_asset,
        'quote_asset': quote_asset
    }
    return result
コード例 #2
0
def _get_order_book(base_asset, quote_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):
    """Gets the current order book for a specified asset pair
    
    @param: normalized_fee_required: Only specify if buying BTC. If specified, the order book will be pruned down to only
     show orders at and above this fee_required
    @param: normalized_fee_provided: Only specify if selling BTC. If specified, the order book will be pruned down to only
     show orders at and above this fee_provided
    """
    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 base_asset_info or not quote_asset_info:
        raise Exception("Invalid asset(s)")
    
    #TODO: limit # results to 8 or so for each book (we have to sort as well to limit)
    base_bid_filters = [
        {"field": "get_asset", "op": "==", "value": base_asset},
        {"field": "give_asset", "op": "==", "value": quote_asset},
    ]
    base_ask_filters = [
        {"field": "get_asset", "op": "==", "value": quote_asset},
        {"field": "give_asset", "op": "==", "value": base_asset},
    ]
    if base_asset == config.BTC or quote_asset == config.BTC:
        extra_filters = [
            {'field': 'give_remaining', 'op': '>', 'value': 0}, #don't show empty BTC orders
            {'field': 'get_remaining', 'op': '>', 'value': 0}, #don't show empty BTC orders
            {'field': 'fee_required_remaining', 'op': '>=', 'value': 0},
            {'field': 'fee_provided_remaining', 'op': '>=', 'value': 0},
        ]
        base_bid_filters += extra_filters
        base_ask_filters += extra_filters
    
    base_bid_orders = util.call_jsonrpc_api("get_orders", {
         'filters': base_bid_filters,
         'show_expired': False,
         'status': 'open',
         'order_by': 'block_index',
         'order_dir': 'asc',
        }, abort_on_error=True)['result']

    base_ask_orders = util.call_jsonrpc_api("get_orders", {
         'filters': base_ask_filters,
         'show_expired': False,
         'status': 'open',
         'order_by': 'block_index',
         'order_dir': 'asc',
        }, abort_on_error=True)['result']
    
    def get_o_pct(o):
        if o['give_asset'] == config.BTC: #NB: fee_provided could be zero here
            pct_fee_provided = float(( D(o['fee_provided_remaining']) / D(o['give_quantity']) ))
        else: pct_fee_provided = None
        if o['get_asset'] == config.BTC: #NB: fee_required could be zero here
            pct_fee_required = float(( D(o['fee_required_remaining']) / D(o['get_quantity']) ))
        else: pct_fee_required = None
        return pct_fee_provided, pct_fee_required

    #filter results by pct_fee_provided and pct_fee_required for BTC pairs as appropriate
    filtered_base_bid_orders = []
    filtered_base_ask_orders = []
    if base_asset == config.BTC or quote_asset == config.BTC:      
        for o in base_bid_orders:
            pct_fee_provided, pct_fee_required = get_o_pct(o)
            addToBook = True
            if bid_book_min_pct_fee_provided is not None and pct_fee_provided is not None and pct_fee_provided < bid_book_min_pct_fee_provided:
                addToBook = False
            if bid_book_min_pct_fee_required is not None and pct_fee_required is not None and pct_fee_required < bid_book_min_pct_fee_required:
                addToBook = False
            if bid_book_max_pct_fee_required is not None and pct_fee_required is not None and pct_fee_required > bid_book_max_pct_fee_required:
                addToBook = False
            if addToBook: filtered_base_bid_orders.append(o)
        for o in base_ask_orders:
            pct_fee_provided, pct_fee_required = get_o_pct(o)
            addToBook = True
            if ask_book_min_pct_fee_provided is not None and pct_fee_provided is not None and pct_fee_provided < ask_book_min_pct_fee_provided:
                addToBook = False
            if ask_book_min_pct_fee_required is not None and pct_fee_required is not None and pct_fee_required < ask_book_min_pct_fee_required:
                addToBook = False
            if ask_book_max_pct_fee_required is not None and pct_fee_required is not None and pct_fee_required > ask_book_max_pct_fee_required:
                addToBook = False
            if addToBook: filtered_base_ask_orders.append(o)
    else:
        filtered_base_bid_orders += base_bid_orders
        filtered_base_ask_orders += base_ask_orders


    def make_book(orders, isBidBook):
        book = {}
        for o in orders:
            if o['give_asset'] == base_asset:
                if base_asset == config.BTC and o['give_quantity'] <= config.ORDER_BTC_DUST_LIMIT_CUTOFF:
                    continue #filter dust orders, if necessary
                
                give_quantity = blockchain.normalize_quantity(o['give_quantity'], base_asset_info['divisible'])
                get_quantity = blockchain.normalize_quantity(o['get_quantity'], quote_asset_info['divisible'])
                unit_price = float(( D(get_quantity) / D(give_quantity) ))
                remaining = blockchain.normalize_quantity(o['give_remaining'], base_asset_info['divisible'])
            else:
                if quote_asset == config.BTC and o['give_quantity'] <= config.ORDER_BTC_DUST_LIMIT_CUTOFF:
                    continue #filter dust orders, if necessary

                give_quantity = blockchain.normalize_quantity(o['give_quantity'], quote_asset_info['divisible'])
                get_quantity = blockchain.normalize_quantity(o['get_quantity'], base_asset_info['divisible'])
                unit_price = float(( D(give_quantity) / D(get_quantity) ))
                remaining = blockchain.normalize_quantity(o['get_remaining'], base_asset_info['divisible'])
            id = "%s_%s_%s" % (base_asset, quote_asset, unit_price)
            #^ key = {base}_{bid}_{unit_price}, values ref entries in book
            book.setdefault(id, {'unit_price': unit_price, 'quantity': 0, 'count': 0})
            book[id]['quantity'] += remaining #base quantity outstanding
            book[id]['count'] += 1 #num orders at this price level
        book = sorted(book.itervalues(), key=operator.itemgetter('unit_price'), reverse=isBidBook)
        #^ convert to list and sort -- bid book = descending, ask book = ascending
        return book
    
    #compile into a single book, at volume tiers
    base_bid_book = make_book(filtered_base_bid_orders, True)
    base_ask_book = make_book(filtered_base_ask_orders, False)

    #get stats like the spread and median
    if base_bid_book and base_ask_book:
        #don't do abs(), as this is "the amount by which the ask price exceeds the bid", so I guess it could be negative
        # if there is overlap in the book (right?)
        bid_ask_spread = float(( D(base_ask_book[0]['unit_price']) - D(base_bid_book[0]['unit_price']) ))
        bid_ask_median = float(( D( max(base_ask_book[0]['unit_price'], base_bid_book[0]['unit_price']) ) - (D(abs(bid_ask_spread)) / 2) ))
    else:
        bid_ask_spread = 0
        bid_ask_median = 0
    
    #compose depth and round out quantities
    bid_depth = D(0)
    for o in base_bid_book:
        o['quantity'] = float(D(o['quantity']))
        bid_depth += D(o['quantity'])
        o['depth'] = float(D(bid_depth))
    bid_depth = float(D(bid_depth))
    ask_depth = D(0)
    for o in base_ask_book:
        o['quantity'] = float(D(o['quantity']))
        ask_depth += D(o['quantity'])
        o['depth'] = float(D(ask_depth))
    ask_depth = float(D(ask_depth))
    
    #compose raw orders
    orders = filtered_base_bid_orders + filtered_base_ask_orders
    for o in orders:
        #add in the blocktime to help makes interfaces more user-friendly (i.e. avoid displaying block
        # indexes and display datetimes instead)
        o['block_time'] = time.mktime(util.get_block_time(o['block_index']).timetuple()) * 1000
        
    result = {
        'base_bid_book': base_bid_book,
        'base_ask_book': base_ask_book,
        'bid_depth': bid_depth,
        'ask_depth': ask_depth,
        'bid_ask_spread': bid_ask_spread,
        'bid_ask_median': bid_ask_median,
        'raw_orders': orders,
        'base_asset': base_asset,
        'quote_asset': quote_asset
    }
    return result