Example #1
0
def test_limit_trade_list_to_period():
    trade1 = Trade(
        timestamp=1459427707,
        location='kraken',
        pair='ETH_BTC',
        trade_type=TradeType.BUY,
        amount=FVal(1),
        rate=FVal(1),
        fee=FVal('0.1'),
        fee_currency=A_ETH,
    )
    trade2 = Trade(
        timestamp=1469427707,
        location='poloniex',
        pair='ETH_BTC',
        trade_type=TradeType.BUY,
        amount=FVal(1),
        rate=FVal(1),
        fee=FVal('0.1'),
        fee_currency=A_ETH,
    )
    trade3 = Trade(
        timestamp=1479427707,
        location='poloniex',
        pair='ETH_BTC',
        trade_type=TradeType.BUY,
        amount=FVal(1),
        rate=FVal(1),
        fee=FVal('0.1'),
        fee_currency=A_ETH,
    )

    full_list = [trade1, trade2, trade3]
    assert limit_trade_list_to_period(full_list, 1459427706,
                                      1479427708) == full_list
    assert limit_trade_list_to_period(full_list, 1459427707,
                                      1479427708) == full_list
    assert limit_trade_list_to_period(full_list, 1459427707,
                                      1479427707) == full_list

    expected = [trade2, trade3]
    assert limit_trade_list_to_period(full_list, 1459427708,
                                      1479427707) == expected
    expected = [trade2]
    assert limit_trade_list_to_period(full_list, 1459427708,
                                      1479427706) == expected
    assert limit_trade_list_to_period(full_list, 0, 10) == []
    assert limit_trade_list_to_period(full_list, 1479427708, 1479427719) == []
    assert limit_trade_list_to_period([trade1], 1459427707,
                                      1459427707) == [trade1]
    assert limit_trade_list_to_period([trade2], 1469427707,
                                      1469427707) == [trade2]
    assert limit_trade_list_to_period([trade3], 1479427707,
                                      1479427707) == [trade3]
    assert limit_trade_list_to_period(full_list, 1459427707,
                                      1459427707) == [trade1]
    assert limit_trade_list_to_period(full_list, 1469427707,
                                      1469427707) == [trade2]
    assert limit_trade_list_to_period(full_list, 1479427707,
                                      1479427707) == [trade3]
Example #2
0
def trade_from_poloniex(poloniex_trade: Dict[str, Any], pair: TradePair) -> Trade:
    """Turn a poloniex trade returned from poloniex trade history to our common trade
    history format

    Throws:
        - UnsupportedAsset due to asset_from_poloniex()
    """

    trade_type = trade_type_from_string(poloniex_trade['type'])
    amount = FVal(poloniex_trade['amount'])
    rate = FVal(poloniex_trade['rate'])
    perc_fee = FVal(poloniex_trade['fee'])
    base_currency = asset_from_poloniex(get_pair_position_str(pair, 'first'))
    quote_currency = asset_from_poloniex(get_pair_position_str(pair, 'second'))
    timestamp = createTimeStamp(poloniex_trade['date'], formatstr="%Y-%m-%d %H:%M:%S")
    cost = rate * amount
    if trade_type == TradeType.BUY:
        fee = amount * perc_fee
        fee_currency = quote_currency
    elif trade_type == TradeType.SELL:
        fee = cost * perc_fee
        fee_currency = base_currency
    else:
        raise ValueError('Got unexpected trade type "{}" for poloniex trade'.format(trade_type))

    if poloniex_trade['category'] == 'settlement':
        if trade_type == TradeType.BUY:
            trade_type = TradeType.SETTLEMENT_BUY
        else:
            trade_type = TradeType.SETTLEMENT_SELL

    log.debug(
        'Processing poloniex Trade',
        sensitive_log=True,
        timestamp=timestamp,
        order_type=trade_type,
        pair=pair,
        base_currency=base_currency,
        quote_currency=quote_currency,
        amount=amount,
        fee=fee,
        rate=rate,
    )

    # Use the converted assets in our pair
    pair = trade_pair_from_assets(base_currency, quote_currency)
    # Since in Poloniex the base currency is the cost currency, iow in poloniex
    # for BTC_ETH we buy ETH with BTC and sell ETH for BTC, we need to turn it
    # into the Rotkehlchen way which is following the base/quote approach.
    pair = invert_pair(pair)
    return Trade(
        timestamp=timestamp,
        location='poloniex',
        pair=pair,
        trade_type=trade_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=fee_currency,
    )
Example #3
0
def trade_from_binance(binance_trade: Dict) -> Trade:
    """Turn a binance trade returned from trade history to our common trade
    history format"""
    amount = FVal(binance_trade['qty'])
    rate = FVal(binance_trade['price'])
    pair = binance_pair_to_world(binance_trade['symbol'])

    base_asset, quote_asset = pair_get_assets(pair)

    if binance_trade['isBuyer']:
        order_type = 'buy'
        # e.g. in RDNETH we buy RDN by paying ETH
        cost_currency = quote_asset
    else:
        order_type = 'sell'
        # e.g. in RDNETH we sell RDN to obtain ETH
        cost_currency = base_asset

    fee_currency = binance_trade['commissionAsset']
    fee = FVal(binance_trade['commission'])
    cost = rate * amount

    return Trade(
        timestamp=binance_trade['time'],
        pair=pair,
        type=order_type,
        rate=rate,
        cost=cost,
        cost_currency=cost_currency,
        fee=fee,
        fee_currency=fee_currency,
        amount=amount,
        location='binance'
    )
Example #4
0
def trade_from_bittrex(bittrex_trade: Dict) -> Trade:
    """Turn a bittrex trade returned from bittrex trade history to our common trade
    history format"""
    amount = FVal(bittrex_trade['Quantity']) - FVal(bittrex_trade['QuantityRemaining'])
    rate = FVal(bittrex_trade['PricePerUnit'])
    order_type = bittrex_trade['OrderType']
    bittrex_price = FVal(bittrex_trade['Price'])
    bittrex_commission = FVal(bittrex_trade['Commission'])
    pair = bittrex_pair_to_world(bittrex_trade['Exchange'])
    base_currency = get_pair_position(pair, 'first')
    if order_type == 'LIMIT_BUY':
        order_type = 'buy'
        cost = bittrex_price + bittrex_commission
        fee = bittrex_commission
    elif order_type == 'LIMIT_SEL':
        order_type = 'sell'
        cost = bittrex_price - bittrex_commission
        fee = bittrex_commission
    else:
        raise ValueError('Got unexpected order type "{}" for bittrex trade'.format(order_type))

    return Trade(
        timestamp=bittrex_trade['TimeStamp'],
        pair=pair,
        type=order_type,
        rate=rate,
        cost=cost,
        cost_currency=base_currency,
        fee=fee,
        fee_currency=base_currency,
        amount=amount,
        location='bittrex'
    )
Example #5
0
def test_bittrex_query_trade_history(bittrex):
    """Test that turning a bittrex trade to our format works"""
    # turn caching off
    bittrex.cache_ttl_secs = 0

    def mock_order_history(url):  # pylint: disable=unused-argument
        response = MockResponse(200, BITTREX_ORDER_HISTORY_RESPONSE)
        return response

    with patch.object(bittrex.session, 'get', side_effect=mock_order_history):
        trades = bittrex.query_trade_history(0, 1564301134, 1564301134)

    expected_trade = Trade(
        timestamp=1392249600,
        location='bittrex',
        pair='LTC_BTC',
        trade_type=TradeType.BUY,
        amount=FVal('667.03644955'),
        rate=FVal('0.0000295'),
        fee=FVal('0.00004921'),
        fee_currency=A_BTC,
    )

    assert len(trades) == 1
    assert trades[0] == expected_trade
Example #6
0
def test_binance_query_trade_history(function_scope_binance):
    """Test that turning a binance trade as returned by the server to our format works"""
    binance = function_scope_binance
    binance.cache_ttl_secs = 0

    def mock_my_trades(url):  # pylint: disable=unused-argument
        if 'symbol=BNBBTC' in url:
            text = BINANCE_MYTRADES_RESPONSE
        else:
            text = '[]'

        return MockResponse(200, text)

    with patch.object(binance.session, 'get', side_effect=mock_my_trades):
        trades = binance.query_trade_history(0, 1564301134, 1564301134)

    expected_trade = Trade(
        timestamp=1499865549,
        location='binance',
        pair='BNB_BTC',
        trade_type=TradeType.BUY,
        amount=FVal('12'),
        rate=FVal('4.00000100'),
        fee=FVal('10.10000000'),
        fee_currency=A_BNB,
    )

    assert len(trades) == 1
    assert trades[0] == expected_trade
Example #7
0
def test_serialize_deserialize_trade():
    trade = Trade(
        timestamp=Timestamp(1537985746),
        location='kraken',
        pair=TradePair('ETH_BTC'),
        trade_type=TradeType.SELL,
        amount=FVal('2.80'),
        rate=FVal('0.1234'),
        fee=FVal('0.01'),
        fee_currency=A_ETH,
        link='a link can be here',
        notes='notes can be here',
    )
    serialized_trade = rlk_jsondumps(trade._asdict())
    assert serialized_trade == rlk_jsondumps(raw_trade2)
    deserialized_trade = deserialize_trade(raw_trade2)
    assert deserialized_trade == trade
Example #8
0
def trade_from_binance(
    binance_trade: Dict,
    binance_symbols_to_pair: Dict[str, BinancePair],
) -> Trade:
    """Turn a binance trade returned from trade history to our common trade
    history format

    From the official binance api docs (01/09/18):
    https://github.com/binance-exchange/binance-official-api-docs/blob/62ff32d27bb32d9cc74d63d547c286bb3c9707ef/rest-api.md#terminology

    base asset refers to the asset that is the quantity of a symbol.
    quote asset refers to the asset that is the price of a symbol.
    """
    amount = FVal(binance_trade['qty'])
    rate = FVal(binance_trade['price'])
    pair = binance_symbols_to_pair[binance_trade['symbol']]
    timestamp = binance_trade['time']

    base_asset = pair.base_asset
    quote_asset = pair.quote_asset

    if binance_trade['isBuyer']:
        order_type = 'buy'
        # e.g. in RDNETH we buy RDN by paying ETH
    else:
        order_type = 'sell'

    cost_currency = quote_asset
    fee_currency = binance_trade['commissionAsset']
    fee = FVal(binance_trade['commission'])
    cost = rate * amount

    log.debug(
        'Processing binance Trade',
        sensitive_log=True,
        amount=amount,
        rate=rate,
        timestamp=timestamp,
        pair=binance_trade['symbol'],
        base_asset=base_asset,
        quote=quote_asset,
        order_type=order_type,
        commision_asset=binance_trade['commissionAsset'],
        fee=fee,
    )

    return Trade(
        timestamp=timestamp,
        pair=base_asset + '_' + quote_asset,
        type=order_type,
        rate=rate,
        cost=cost,
        cost_currency=cost_currency,
        fee=fee,
        fee_currency=fee_currency,
        amount=amount,
        location='binance',
    )
Example #9
0
def trade_from_binance(
    binance_trade: Dict,
    binance_symbols_to_pair: Dict[str, BinancePair],
) -> Trade:
    """Turn a binance trade returned from trade history to our common trade
    history format

    From the official binance api docs (01/09/18):
    https://github.com/binance-exchange/binance-official-api-docs/blob/62ff32d27bb32d9cc74d63d547c286bb3c9707ef/rest-api.md#terminology

    base asset refers to the asset that is the quantity of a symbol.
    quote asset refers to the asset that is the price of a symbol.

    Can throw UnsupportedAsset due to asset_from_binance
    """
    amount = FVal(binance_trade['qty'])
    rate = FVal(binance_trade['price'])
    binance_pair = binance_symbols_to_pair[binance_trade['symbol']]
    timestamp = binance_trade['time']

    base_asset = asset_from_binance(binance_pair.binance_base_asset)
    quote_asset = asset_from_binance(binance_pair.binance_quote_asset)

    if binance_trade['isBuyer']:
        order_type = TradeType.BUY
        # e.g. in RDNETH we buy RDN by paying ETH
    else:
        order_type = TradeType.SELL

    fee_currency = asset_from_binance(binance_trade['commissionAsset'])
    fee = FVal(binance_trade['commission'])

    log.debug(
        'Processing binance Trade',
        sensitive_log=True,
        amount=amount,
        rate=rate,
        timestamp=timestamp,
        pair=binance_trade['symbol'],
        base_asset=base_asset,
        quote=quote_asset,
        order_type=order_type,
        commision_asset=binance_trade['commissionAsset'],
        fee=fee,
    )

    return Trade(
        timestamp=timestamp,
        location='binance',
        pair=trade_pair_from_assets(base_asset, quote_asset),
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=fee_currency,
    )
Example #10
0
def trade_from_poloniex(poloniex_trade, pair):
    """Turn a poloniex trade returned from poloniex trade history to our common trade
    history format"""

    trade_type = poloniex_trade['type']
    amount = FVal(poloniex_trade['amount'])
    rate = FVal(poloniex_trade['rate'])
    perc_fee = FVal(poloniex_trade['fee'])
    base_currency = get_pair_position(pair, 'first')
    quote_currency = get_pair_position(pair, 'second')
    timestamp = createTimeStamp(poloniex_trade['date'],
                                formatstr="%Y-%m-%d %H:%M:%S"),
    if trade_type == 'buy':
        cost = rate * amount
        cost_currency = base_currency
        fee = amount * perc_fee
        fee_currency = quote_currency
    elif trade_type == 'sell':
        cost = amount * rate
        cost_currency = base_currency
        fee = cost * perc_fee
        fee_currency = base_currency
    else:
        raise ValueError(
            'Got unexpected trade type "{}" for poloniex trade'.format(
                trade_type))

    if poloniex_trade['category'] == 'settlement':
        trade_type = "settlement_%s" % trade_type

    log.debug(
        'Processing poloniex Trade',
        sensitive_log=True,
        timestamp=timestamp,
        order_type=trade_type,
        pair=pair,
        base_currency=base_currency,
        quote_currency=quote_currency,
        amount=amount,
        cost=cost,
        fee=fee,
        rate=rate,
    )

    return Trade(timestamp=timestamp,
                 pair=pair,
                 type=trade_type,
                 rate=rate,
                 cost=cost,
                 cost_currency=cost_currency,
                 fee=fee,
                 fee_currency=fee_currency,
                 amount=amount,
                 location='poloniex')
Example #11
0
def trade_from_kraken(kraken_trade: Dict[str, Any]) -> Trade:
    """Turn a kraken trade returned from kraken trade history to our common trade
    history format

    - Can raise UnknownAsset due to kraken_to_world_pair
    - Can raise UnprocessableTradePair due to kraken_to_world_pair
    - Can raise DeserializationError due to dict entries not being as expected
    - Can raise KeyError due to dict entries missing an expected entry
    """
    currency_pair = kraken_to_world_pair(kraken_trade['pair'])
    quote_currency = get_pair_position_asset(currency_pair, 'second')

    timestamp = deserialize_timestamp_from_kraken(kraken_trade['time'])
    amount = deserialize_asset_amount(kraken_trade['vol'])
    cost = deserialize_price(kraken_trade['cost'])
    fee = deserialize_fee(kraken_trade['fee'])
    order_type = deserialize_trade_type(kraken_trade['type'])
    rate = deserialize_price(kraken_trade['price'])

    if cost != amount * rate:
        log.warning(
            'cost ({cost}) != amount ({amount}) * rate ({rate}) for kraken trade'
        )

    log.debug(
        'Processing kraken Trade',
        sensitive_log=True,
        timestamp=timestamp,
        order_type=order_type,
        kraken_pair=kraken_trade['pair'],
        pair=currency_pair,
        quote_currency=quote_currency,
        amount=amount,
        cost=cost,
        fee=fee,
        rate=rate,
    )

    return Trade(
        timestamp=timestamp,
        location='kraken',
        pair=currency_pair,
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=quote_currency,
    )
Example #12
0
def trade_from_bittrex(bittrex_trade: Dict[str, Any]) -> Trade:
    """Turn a bittrex trade returned from bittrex trade history to our common trade
    history format

    Throws:
        - UnsupportedAsset due to bittrex_pair_to_world()
"""
    amount = FVal(bittrex_trade['Quantity']) - FVal(
        bittrex_trade['QuantityRemaining'])
    rate = FVal(bittrex_trade['PricePerUnit'])
    order_type = bittrex_trade['OrderType']
    bittrex_price = FVal(bittrex_trade['Price'])
    bittrex_commission = FVal(bittrex_trade['Commission'])
    pair = bittrex_pair_to_world(bittrex_trade['Exchange'])
    quote_currency = get_pair_position_asset(pair, 'second')
    fee = bittrex_commission
    if order_type == 'LIMIT_BUY':
        order_type = TradeType.BUY
    elif order_type == 'LIMIT_SELL':
        order_type = TradeType.SELL
    else:
        raise ValueError(
            'Got unexpected order type "{}" for bittrex trade'.format(
                order_type))

    log.debug(
        'Processing bittrex Trade',
        sensitive_log=True,
        amount=amount,
        rate=rate,
        order_type=order_type,
        price=bittrex_price,
        fee=bittrex_commission,
        bittrex_pair=bittrex_trade['Exchange'],
        pair=pair,
    )

    return Trade(
        timestamp=bittrex_trade['TimeStamp'],
        location='bittrex',
        pair=pair,
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=quote_currency,
    )
Example #13
0
def trade_from_kraken(kraken_trade: Dict[str, Any]) -> Trade:
    """Turn a kraken trade returned from kraken trade history to our common trade
    history format

    - Can raise UnknownAsset due to kraken_to_world_pair
    - Can raise UnprocessableTradePair due to kraken_to_world_pair
    """
    currency_pair = kraken_to_world_pair(kraken_trade['pair'])
    quote_currency = get_pair_position_asset(currency_pair, 'second')
    # Kraken timestamps have floating point
    timestamp = Timestamp(
        convert_to_int(kraken_trade['time'], accept_only_exact=False))
    amount = FVal(kraken_trade['vol'])
    cost = FVal(kraken_trade['cost'])
    fee = FVal(kraken_trade['fee'])
    order_type = trade_type_from_string(kraken_trade['type'])
    rate = FVal(kraken_trade['price'])

    if cost != amount * rate:
        log.warning(
            'cost ({cost}) != amount ({amount}) * rate ({rate}) for kraken trade'
        )

    log.debug(
        'Processing kraken Trade',
        sensitive_log=True,
        timestamp=timestamp,
        order_type=order_type,
        kraken_pair=kraken_trade['pair'],
        pair=currency_pair,
        quote_currency=quote_currency,
        amount=amount,
        cost=cost,
        fee=fee,
        rate=rate,
    )

    return Trade(
        timestamp=timestamp,
        location='kraken',
        pair=currency_pair,
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=quote_currency,
    )
Example #14
0
def trade_from_bittrex(bittrex_trade: Dict[str, Any]) -> Trade:
    """Turn a bittrex trade returned from bittrex trade history to our common trade
    history format"""
    amount = FVal(bittrex_trade['Quantity']) - FVal(bittrex_trade['QuantityRemaining'])
    rate = FVal(bittrex_trade['PricePerUnit'])
    order_type = bittrex_trade['OrderType']
    bittrex_price = FVal(bittrex_trade['Price'])
    bittrex_commission = FVal(bittrex_trade['Commission'])
    pair = bittrex_pair_to_world(bittrex_trade['Exchange'])
    base_currency = get_pair_position(pair, 'first')
    fee = bittrex_commission
    if order_type == 'LIMIT_BUY':
        order_type = TradeType.BUY
    elif order_type == 'LIMIT_SEL':
        order_type = TradeType.SELL
    else:
        raise ValueError('Got unexpected order type "{}" for bittrex trade'.format(order_type))

    log.debug(
        'Processing bittrex Trade',
        sensitive_log=True,
        amount=amount,
        rate=rate,
        order_type=order_type,
        price=bittrex_price,
        fee=bittrex_commission,
        bittrex_pair=bittrex_trade['Exchange'],
        pair=pair,
    )

    # Since in Bittrex the base currency is the cost currency, iow in Bittrex
    # for BTC_ETH we buy ETH with BTC and sell ETH for BTC, we need to turn it
    # into the Rotkehlchen way which is following the base/quote approach.
    pair = invert_pair(pair)

    return Trade(
        timestamp=bittrex_trade['TimeStamp'],
        location='bittrex',
        pair=pair,
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=base_currency,
    )
Example #15
0
def test_trade_get_assets():
    trade = Trade(
        timestamp=1546985746,
        location='bittrex',
        pair=TradePair('BTC_ETH'),
        trade_type=TradeType.BUY,
        amount=FVal(10),
        rate=FVal(0.05),
        fee=FVal(0.001),
        fee_currency=A_ETH,
        link='',
        notes='',
    )
    a1, a2 = trade_get_assets(trade)
    assert isinstance(a1, Asset)
    assert a1 == A_BTC
    assert isinstance(a2, Asset)
    assert a2 == A_ETH
Example #16
0
def trade_from_kraken(kraken_trade):
    """Turn a kraken trade returned from kraken trade history to our common trade
    history format"""
    currency_pair = kraken_to_world_pair(kraken_trade['pair'])
    quote_currency = get_pair_position(currency_pair, 'second')
    return Trade(
        # Kraken timestamps have floating point ...
        timestamp=convert_to_int(kraken_trade['time'], accept_only_exact=False),
        pair=currency_pair,
        type=kraken_trade['type'],
        rate=FVal(kraken_trade['price']),
        cost=FVal(kraken_trade['cost']),
        cost_currency=quote_currency,
        fee=FVal(kraken_trade['fee']),
        fee_currency=quote_currency,
        amount=FVal(kraken_trade['vol']),
        location='kraken'
    )
def trade_from_bittrex(bittrex_trade: Dict[str, Any]) -> Trade:
    """Turn a bittrex trade returned from bittrex trade history to our common trade
    history format

    Throws:
        - UnsupportedAsset due to bittrex_pair_to_world()
        - DeserializationError due to unexpected format of dict entries
        - KeyError due to dict entries missing an expected entry
    """
    amount = (
        deserialize_asset_amount(bittrex_trade['Quantity']) -
        deserialize_asset_amount(bittrex_trade['QuantityRemaining'])
    )
    timestamp = deserialize_timestamp_from_bittrex_date(bittrex_trade['TimeStamp'])
    rate = deserialize_price(bittrex_trade['PricePerUnit'])
    order_type = deserialize_trade_type(bittrex_trade['OrderType'])
    bittrex_price = deserialize_price(bittrex_trade['Price'])
    fee = deserialize_fee(bittrex_trade['Commission'])
    pair = bittrex_pair_to_world(bittrex_trade['Exchange'])
    quote_currency = get_pair_position_asset(pair, 'second')

    log.debug(
        'Processing bittrex Trade',
        sensitive_log=True,
        amount=amount,
        rate=rate,
        order_type=order_type,
        price=bittrex_price,
        fee=fee,
        bittrex_pair=bittrex_trade['Exchange'],
        pair=pair,
    )

    return Trade(
        timestamp=timestamp,
        location='bittrex',
        pair=pair,
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=quote_currency,
    )
Example #18
0
def trade_from_kraken(kraken_trade):
    """Turn a kraken trade returned from kraken trade history to our common trade
    history format"""
    currency_pair = kraken_to_world_pair(kraken_trade['pair'])
    quote_currency = get_pair_position(currency_pair, 'second')
    # Kraken timestamps have floating point
    timestamp = convert_to_int(kraken_trade['time'], accept_only_exact=False)
    amount = FVal(kraken_trade['vol'])
    cost = FVal(kraken_trade['cost'])
    fee = FVal(kraken_trade['fee'])
    order_type = kraken_trade['type']
    rate = FVal(kraken_trade['price'])

    log.debug(
        'Processing kraken Trade',
        sensitive_log=True,
        timestamp=timestamp,
        order_type=order_type,
        kraken_pair=kraken_trade['pair'],
        pair=currency_pair,
        quote_currency=quote_currency,
        amount=amount,
        cost=cost,
        fee=fee,
        rate=rate,
    )

    return Trade(
        timestamp=timestamp,
        pair=currency_pair,
        type=order_type,
        rate=rate,
        cost=cost,
        cost_currency=quote_currency,
        fee=fee,
        fee_currency=quote_currency,
        amount=amount,
        location='kraken',
    )
Example #19
0
def trade_from_binance(
    binance_trade: Dict,
    binance_symbols_to_pair: Dict[str, BinancePair],
) -> Trade:
    """Turn a binance trade returned from trade history to our common trade
    history format

    From the official binance api docs (01/09/18):
    https://github.com/binance-exchange/binance-official-api-docs/blob/62ff32d27bb32d9cc74d63d547c286bb3c9707ef/rest-api.md#terminology

    base asset refers to the asset that is the quantity of a symbol.
    quote asset refers to the asset that is the price of a symbol.

    Throws:
        - UnsupportedAsset due to asset_from_binance
        - DeserializationError due to unexpected format of dict entries
        - KeyError due to dict entries missing an expected entry
    """
    amount = deserialize_asset_amount(binance_trade['qty'])
    rate = deserialize_price(binance_trade['price'])
    if binance_trade['symbol'] not in binance_symbols_to_pair:
        raise DeserializationError(
            f'Error reading a binance trade. Could not find '
            f'{binance_trade["symbol"]} in binance_symbols_to_pair', )

    binance_pair = binance_symbols_to_pair[binance_trade['symbol']]
    timestamp = deserialize_timestamp_from_binance(binance_trade['time'])

    base_asset = asset_from_binance(binance_pair.binance_base_asset)
    quote_asset = asset_from_binance(binance_pair.binance_quote_asset)

    if binance_trade['isBuyer']:
        order_type = TradeType.BUY
        # e.g. in RDNETH we buy RDN by paying ETH
    else:
        order_type = TradeType.SELL

    fee_currency = asset_from_binance(binance_trade['commissionAsset'])
    fee = deserialize_fee(binance_trade['commission'])

    log.debug(
        'Processing binance Trade',
        sensitive_log=True,
        amount=amount,
        rate=rate,
        timestamp=timestamp,
        pair=binance_trade['symbol'],
        base_asset=base_asset,
        quote=quote_asset,
        order_type=order_type,
        commision_asset=binance_trade['commissionAsset'],
        fee=fee,
    )

    return Trade(
        timestamp=timestamp,
        location='binance',
        pair=trade_pair_from_assets(base_asset, quote_asset),
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=fee_currency,
    )
Example #20
0
    def create_action(self, index: int, ts: Timestamp):
        """Create a random trade action on a random exchange depending
        on the funds that are available in that exchange"""
        # choose an exchange at random
        exchange_name = random.choice(ALLOWED_EXCHANGES)
        exchange = getattr(self, exchange_name)
        # choose a random pair at that exchange
        pair = exchange.choose_pair(
            timestamp=ts,
            price_query=self.query_historical_price,
        )
        print(
            f'Creating trade {index + 1} / {self.trades_number} in {exchange_name}'
            f' for the pair: {pair} at timestamp {ts}', )
        # depending on our funds decide on what to do. Buy/sell
        base, quote = pair_get_assets(pair)
        if exchange.get_balance(base) is None:
            action_type = TradeType.BUY
        elif exchange.get_balance(quote) is None:
            action_type = TradeType.SELL
        else:
            # TODO: trade the one we have most of
            action_type = random.choice(list(TradeType))

        # if we are buying we are going to spend from the quote asset
        if action_type == TradeType.BUY:
            spending_asset = quote
        else:  # selling spends from the base asset
            spending_asset = base
        # get a spending asset amount within our per-trade equivalent range and
        # our available funds
        spending_usd_rate = self.query_historical_price(
            spending_asset, 'USD', ts)
        max_usd_in_spending_asset = spending_usd_rate * exchange.get_balance(
            spending_asset)
        max_usd_equivalent_to_spend = min(max_usd_in_spending_asset,
                                          MAX_TRADE_USD_VALUE)
        rate = self.query_historical_price(base, quote, ts)
        usd_to_spend = FVal(
            random.uniform(0.01, float(max_usd_equivalent_to_spend)))
        amount_in_spending_asset = usd_to_spend / spending_usd_rate
        # if we are buying then the amount is the amount of asset we bought
        if action_type == TradeType.BUY:
            amount = amount_in_spending_asset / rate
        # if we are selling the amount is the spending asset amount
        else:
            amount = amount_in_spending_asset

        quote_asset_usd_rate = self.query_historical_price(quote, 'USD', ts)
        fee_in_quote_currency = FVal(random.uniform(
            0, MAX_FEE_USD_VALUE)) / quote_asset_usd_rate

        # create the trade
        trade = Trade(
            timestamp=ts,
            location=exchange_name,
            pair=pair,
            trade_type=action_type,
            amount=amount,
            rate=rate,
            fee=fee_in_quote_currency,
            fee_currency=quote,
            link='',
            notes='',
        )
        logger.info(f'Created trade: {trade}')

        # Adjust our global and per exchange accounting
        if action_type == TradeType.BUY:
            # we buy so we increase our base asset by amount
            self.increase_asset(base, amount, exchange_name)
            # and decrease quote by amount * rate
            self.decrease_asset(quote, amount * rate, exchange_name)
        else:
            # we sell so we increase our quote asset
            self.increase_asset(quote, amount * rate, exchange_name)
            # and decrease our base asset
            self.decrease_asset(base, amount, exchange_name)

        # finally add it to the exchange
        exchange.append_trade(trade)
Example #21
0
def verify_otctrade_data(
        data: ExternalTrade,
) -> Tuple[Optional[Trade], str]:
    """
    Takes in the trade data dictionary, validates it and returns a trade instance

    If there is an error it returns an error message in the second part of the tuple
    """
    for field in otc_fields:
        if field not in data:
            return None, f'{field} was not provided'

        if data[field] in ('', None) and field not in otc_optional_fields:
            return None, f'{field} was empty'

        if field in otc_numerical_fields and not is_number(data[field]):
            return None, f'{field} should be a number'

    # Satisfy mypy typing
    assert isinstance(data['otc_pair'], str)
    assert isinstance(data['otc_fee_currency'], str)
    assert isinstance(data['otc_fee'], str)

    pair = TradePair(data['otc_pair'])
    try:
        first = get_pair_position_asset(pair, 'first')
        second = get_pair_position_asset(pair, 'second')
        fee_currency = Asset(data['otc_fee_currency'])
    except UnknownAsset as e:
        return None, f'Provided asset {e.asset_name} is not known to Rotkehlchen'

    try:
        trade_type = deserialize_trade_type(str(data['otc_type']))
        amount = deserialize_asset_amount(data['otc_amount'])
        rate = deserialize_price(data['otc_rate'])
        fee = deserialize_fee(data['otc_fee'])
    except DeserializationError as e:
        return None, f'Deserialization Error: {str(e)}'
    try:
        assert isinstance(data['otc_timestamp'], str)
        timestamp = create_timestamp(data['otc_timestamp'], formatstr='%d/%m/%Y %H:%M')
    except ValueError as e:
        return None, f'Could not process the given datetime: {e}'

    log.debug(
        'Creating OTC trade data',
        sensitive_log=True,
        pair=pair,
        trade_type=trade_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=fee_currency,
    )

    if data['otc_fee_currency'] not in (first, second):
        return None, 'Trade fee currency should be one of the two in the currency pair'

    if data['otc_type'] not in ('buy', 'sell'):
        return None, 'Trade type can only be buy or sell'

    trade = Trade(
        timestamp=timestamp,
        location='external',
        pair=pair,
        trade_type=trade_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=fee_currency,
        link=str(data['otc_link']),
        notes=str(data['otc_notes']),
    )

    return trade, ''
Example #22
0
def test_trade_from_binance(mock_binance):
    binance_trades_list = [
        {
            'symbol': 'RDNETH',
            'id': 1,
            'orderId': 1,
            'price': FVal(0.0063213),
            'qty': FVal(5.0),
            'commission': FVal(0.005),
            'commissionAsset': 'RDN',
            'time': 1512561941,
            'isBuyer': True,
            'isMaker': False,
            'isBestMatch': True,
        }, {
            'symbol': 'ETHUSDT',
            'id': 1,
            'orderId': 1,
            'price': FVal(481.0),
            'qty': FVal(0.505),
            'commission': FVal(0.242905),
            'commissionAsset': 'USDT',
            'time': 1531117990,
            'isBuyer': False,
            'isMaker': True,
            'isBestMatch': True,
        }, {
            'symbol': 'BTCUSDT',
            'id': 1,
            'orderId': 1,
            'price': FVal(6376.39),
            'qty': FVal(0.051942),
            'commission': FVal(0.00005194),
            'commissionAsset': 'BTC',
            'time': 1531728338,
            'isBuyer': True,
            'isMaker': False,
            'isBestMatch': True,
        }, {
            'symbol': 'ADAUSDT',
            'id': 1,
            'orderId': 1,
            'price': FVal(0.17442),
            'qty': FVal(285.2),
            'commission': FVal(0.00180015),
            'commissionAsset': 'BNB',
            'time': 1531871806,
            'isBuyer': False,
            'isMaker': True,
            'isBestMatch': True,
        },
    ]
    our_expected_list = [
        Trade(
            timestamp=1512561941,
            location='binance',
            pair='RDN_ETH',
            trade_type=TradeType.BUY,
            amount=FVal(5.0),
            rate=FVal(0.0063213),
            fee=FVal(0.005),
            fee_currency='RDN',
        ),
        Trade(
            timestamp=1531117990,
            location='binance',
            pair='ETH_USDT',
            trade_type=TradeType.SELL,
            amount=FVal(0.505),
            rate=FVal(481.0),
            fee=FVal(0.242905),
            fee_currency='USDT',
        ),
        Trade(
            timestamp=1531728338,
            location='binance',
            pair='BTC_USDT',
            trade_type=TradeType.BUY,
            amount=FVal(0.051942),
            rate=FVal(6376.39),
            fee=FVal(0.00005194),
            fee_currency='BTC',
        ),
        Trade(
            timestamp=1531871806,
            location='binance',
            pair='ADA_USDT',
            trade_type=TradeType.SELL,
            amount=FVal(285.2),
            rate=FVal(0.17442),
            fee=FVal(0.00180015),
            fee_currency='BNB',
        ),
    ]

    for idx, binance_trade in enumerate(binance_trades_list):
        our_trade = trade_from_binance(binance_trade, mock_binance.symbols_to_pair)
        assert our_trade == our_expected_list[idx]