예제 #1
0
파일: bittrex.py 프로젝트: zalam003/rotki
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

    As we saw in https://github.com/rotki/rotki/issues/1281 it's quite possible
    that some keys don't exist in a trade. The required fields are here:
    https://bittrex.github.io/api/v3#definition-Order

    Throws:
        - UnknownAsset/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['fillQuantity'])
    timestamp = deserialize_timestamp_from_date(
        date=bittrex_trade['closedAt'],  # we only check closed orders
        formatstr='iso8601',
        location='bittrex',
    )
    if 'limit' in bittrex_trade:
        rate = deserialize_price(bittrex_trade['limit'])
    else:
        rate = Price(
            FVal(bittrex_trade['proceeds']) /
            FVal(bittrex_trade['fillQuantity']))
    order_type = deserialize_trade_type(bittrex_trade['direction'])
    fee = deserialize_fee(bittrex_trade['commission'])
    pair = bittrex_pair_to_world(bittrex_trade['marketSymbol'])
    quote_currency = get_pair_position_asset(pair, 'second')

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

    return Trade(
        timestamp=timestamp,
        location=Location.BITTREX,
        pair=pair,
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=quote_currency,
        link=str(bittrex_trade['id']),
    )
예제 #2
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,
    )
예제 #3
0
파일: bittrex.py 프로젝트: yairash/rotki
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:
        - UnknownAsset/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 = AssetAmount(
        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=Location.BITTREX,
        pair=pair,
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=quote_currency,
        link=str(bittrex_trade['OrderUuid']),
    )
예제 #4
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'])

    # pylint does not seem to see that Price is essentially FVal
    if not cost.is_close(amount * rate):  # pylint: disable=no-member
        log.warning(
            f'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,
    )

    # Kraken trades can have the same ordertxid and postxid for different trades ..
    # Also note postxid is optional and can be missing
    # The only thing that could differentiate them is timestamps in the milliseconds range
    # For example here are parts of two different kraken_trade:
    # {'ordertxid': 'AM4ZOZ-GLEMD-ZICOGR', 'postxid': 'AKH2SE-M7IF5-CFI7AT',
    # 'pair': 'XXBTZEUR', 'time': FVal(1561161486.2955)
    # {'ordertxid': 'AM4ZOZ-GLEMD-ZICOGR', 'postxid': 'AKH2SE-M7IF5-CFI7AT',
    # 'pair': 'XXBTZEUR', 'time': FVal(1561161486.3005)
    #
    # In order to counter this for the unique exchange trade link we are going
    # to use a concatenation of the above
    exchange_uuid = (
        str(kraken_trade['ordertxid']) +
        str(kraken_trade.get('postxid', '')) +  # postxid is optional
        str(kraken_trade['time']))

    return Trade(
        timestamp=timestamp,
        location=Location.KRAKEN,
        pair=currency_pair,
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=quote_currency,
        link=exchange_uuid,
    )
예제 #5
0
def test_get_pair_position_asset():
    asset = get_pair_position_asset('ETH_BTC', 'first')
    assert isinstance(asset, Asset)
    assert asset == A_ETH
    asset = get_pair_position_asset('ETH_BTC', 'second')
    assert isinstance(asset, Asset)
    assert asset == A_BTC

    with pytest.raises(AssertionError):
        get_pair_position_asset('ETH_BTC', 'third')
    with pytest.raises(AssertionError):
        get_pair_position_asset('ETH_BTC', 'sdsadsad')

    with pytest.raises(UnprocessableTradePair):
        get_pair_position_asset('_', 'first')
    with pytest.raises(UnprocessableTradePair):
        get_pair_position_asset('ETH_', 'first')
    with pytest.raises(UnprocessableTradePair):
        get_pair_position_asset('_BTC', 'second')
    with pytest.raises(UnprocessableTradePair):
        get_pair_position_asset('ETH_BTC_USD', 'first')

    with pytest.raises(UnknownAsset):
        get_pair_position_asset('ETH_FDFSFDSFDSF', 'second')
    with pytest.raises(UnknownAsset):
        get_pair_position_asset('FDFSFDSFDSF_BTC', 'first')

    assert get_pair_position_asset('ETH_RDN', 'first') == A_ETH
    assert get_pair_position_asset('ETH_RDN', 'second') == A_RDN
예제 #6
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'
    # Not catching DeserializationError here since we have asserts for the data
    # being strings right above

    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=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, ''