Beispiel #1
0
def test_deserialize_trade():
    trade1 = deserialize_trade(raw_trade1)
    assert isinstance(trade1, Trade)
    assert trade1.timestamp == Timestamp(1516985746)
    assert trade1.location == Location.EXTERNAL
    assert trade1.pair == TradePair('ETH_EUR')
    assert trade1.trade_type == TradeType.BUY
    assert trade1.amount == FVal('20.51')
    assert trade1.rate == FVal('134.1')
    assert trade1.fee == FVal('0.01')
    assert trade1.fee_currency == A_ETH
    assert isinstance(trade1.fee_currency, Asset)
    assert trade1.link == ''
    assert trade1.notes == ''

    trade2 = deserialize_trade(raw_trade2)
    assert isinstance(trade2, Trade)
    assert trade2.timestamp == Timestamp(1537985746)
    assert trade2.location == Location.KRAKEN
    assert trade2.pair == TradePair('ETH_BTC')
    assert trade2.trade_type == TradeType.SELL
    assert trade2.amount == FVal('2.80')
    assert trade2.rate == FVal('0.1234')
    assert trade2.fee == FVal('0.01')
    assert trade2.fee_currency == A_ETH
    assert isinstance(trade2.fee_currency, Asset)
    assert trade2.link == 'a link can be here'
    assert trade2.notes == 'notes can be here'

    another_raw_trade = raw_trade2.copy()
    another_raw_trade['fee_currency'] = 'UNKNOWN'
    with pytest.raises(UnknownAsset):
        deserialize_trade(another_raw_trade)
Beispiel #2
0
def assert_cointracking_import_results(rotki: Rotkehlchen):
    """A utility function to help assert on correctness of importing data from cointracking.info"""
    trades = rotki.data.db.get_trades()
    asset_movements = rotki.data.db.get_asset_movements()
    warnings = rotki.msg_aggregator.consume_warnings()
    errors = rotki.msg_aggregator.consume_warnings()
    assert len(errors) == 0
    assert len(warnings) == 3

    expected_trades = [
        Trade(
            timestamp=Timestamp(1566687660),
            location=Location.COINBASE,
            pair=TradePair('ETH_EUR'),
            trade_type=TradeType.BUY,
            amount=AssetAmount(FVal('0.05772716')),
            rate=Price(FVal('190.3783245183029963712055123')),
            fee=Fee(ZERO),
            fee_currency=A_ETH,
            link='',
            notes='',
        ),
        Trade(
            timestamp=Timestamp(1567418400),
            location=Location.EXTERNAL,
            pair=TradePair('BTC_USD'),
            trade_type=TradeType.BUY,
            amount=AssetAmount(FVal('0.00100000')),
            rate=Price(ZERO),
            fee=Fee(ZERO),
            fee_currency=A_BTC,
            link='',
            notes='Just a small gift from someone',
        )
    ]
    assert expected_trades == trades

    expected_movements = [
        AssetMovement(
            location=Location.POLONIEX,
            category=AssetMovementCategory.DEPOSIT,
            timestamp=Timestamp(1565848620),
            asset=A_XMR,
            amount=AssetAmount(FVal('5')),
            fee_asset=A_XMR,
            fee=Fee(ZERO),
            link='',
        ),
        AssetMovement(
            location=Location.COINBASE,
            category=AssetMovementCategory.WITHDRAWAL,
            timestamp=Timestamp(1566726120),
            asset=A_ETH,
            amount=AssetAmount(FVal('0.05770427')),
            fee_asset=A_ETH,
            fee=Fee(ZERO),
            link='',
        )
    ]
    assert expected_movements == asset_movements
Beispiel #3
0
def test_deserialize_trade():
    trade1 = deserialize_trade(raw_trade1)
    assert isinstance(trade1, Trade)
    assert trade1.timestamp == Timestamp(1516985746)
    assert trade1.location == 'external'
    assert trade1.pair == TradePair('ETH_EUR')
    assert trade1.trade_type == TradeType.BUY
    assert trade1.amount == FVal('20.51')
    assert trade1.rate == FVal('134.1')
    assert trade1.fee == FVal('0.01')
    assert trade1.fee_currency == A_ETH
    assert trade1.link == ''
    assert trade1.notes == ''

    trade2 = deserialize_trade(raw_trade2)
    assert isinstance(trade2, Trade)
    assert trade2.timestamp == Timestamp(1537985746)
    assert trade2.location == 'kraken'
    assert trade2.pair == TradePair('ETH_BTC')
    assert trade2.trade_type == TradeType.SELL
    assert trade2.amount == FVal('2.80')
    assert trade2.rate == FVal('0.1234')
    assert trade2.fee == FVal('0.01')
    assert trade2.fee_currency == A_ETH
    assert trade2.link == 'a link can be here'
    assert trade2.notes == 'notes can be here'
Beispiel #4
0
def test_query_online_trade_history(mock_bitstamp, start_ts, since_id):
    """Test `since_id` value will change depending on `start_ts` value.
    Also tests `db_trades` are sorted by `link` (as int) in ascending mode.
    """
    trades = [
        Trade(
            timestamp=1606995000,
            location=Location.BITSTAMP,
            pair=TradePair('EUR_USD'),
            trade_type=TradeType.SELL,
            amount=FVal("1.22000000"),
            rate=FVal("0.81967213"),
            fee=FVal("0.00610000"),
            fee_currency=Asset('EUR'),
            link='5',
            notes='',
        ),
        Trade(
            timestamp=1606901400,
            location=Location.BITSTAMP,
            pair=TradePair('BTC_USD'),
            trade_type=TradeType.BUY,
            amount=FVal("0.50000000"),
            rate=FVal("0.00005000"),
            fee=FVal("20.00000000"),
            fee_currency=Asset('USD'),
            link='2',
            notes='',
        ),
    ]
    database = MagicMock()
    database.get_trades.return_value = trades

    expected_call = call(
        start_ts=start_ts,
        end_ts=2,
        options={
            'since_id': since_id,
            'limit': 1000,
            'sort': 'asc',
            'offset': 0,
        },
        case='trades',
    )
    with patch.object(mock_bitstamp,
                      'db',
                      new_callable=MagicMock(return_value=database)):
        with patch.object(mock_bitstamp,
                          '_api_query_paginated') as mock_api_query_paginated:
            mock_bitstamp.query_online_trade_history(
                start_ts=Timestamp(start_ts),
                end_ts=Timestamp(2),
            )
            assert mock_api_query_paginated.call_args == expected_call
Beispiel #5
0
def deserialize_trade_pair(pair: str) -> TradePair:
    """Takes a trade pair string, makes sure it's valid, wraps it in proper type and returns it"""
    try:
        pair_get_assets(TradePair(pair))
    except UnprocessableTradePair as e:
        raise DeserializationError(str(e))
    except UnknownAsset as e:
        raise DeserializationError(
            f'Unknown asset {e.asset_name} found while processing trade pair',
        )

    return TradePair(pair)
Beispiel #6
0
def test_deserialize_trade_sell(mock_bitstamp):
    raw_trade = {
        'id': 5,
        'type': 2,
        'datetime': '2020-12-03 11:30:00',
        'eur': '-1.00000000',
        'usd': '1.22000000',
        'eur_usd': '0.81967213',
        'fee': '0.00610000',
        'order_id': 3,
    }
    expected_trade = Trade(
        timestamp=1606995000,
        location=Location.BITSTAMP,
        pair=TradePair('EUR_USD'),
        trade_type=TradeType.SELL,
        amount=FVal('1'),
        rate=FVal('0.81967213'),
        fee=FVal('0.00610000'),
        fee_currency=Asset('USD'),
        link='5',
        notes='',
    )
    trade = mock_bitstamp._deserialize_trade(raw_trade)
    assert trade == expected_trade

    raw_trade = {
        'id': 10,
        'type': 2,
        'datetime': '2019-06-25 21:41:08.802256',
        'btc': '-1.81213214',
        'usd': '0',
        'btc_eur': '10119.82',
        'eur': '18338.45',
        'fee': '40.35000',
        'order_id': 3,
    }
    expected_trade = Trade(
        timestamp=1561498868,
        location=Location.BITSTAMP,
        pair=TradePair('BTC_EUR'),
        trade_type=TradeType.SELL,
        amount=FVal('1.81213214'),
        rate=FVal('10119.82'),
        fee=FVal('40.35'),
        fee_currency=Asset('EUR'),
        link='10',
        notes='',
    )
    trade = mock_bitstamp._deserialize_trade(raw_trade)
    assert trade == expected_trade
Beispiel #7
0
def get_pair_position(pair: TradePair, position: str) -> Asset:
    assert position == 'first' or position == 'second'
    currencies = pair.split('_')
    if len(currencies) != 2:
        raise ValueError("Could not split {} pair".format(pair))
    currency = currencies[0] if position == 'first' else currencies[1]
    return cast(Asset, currency)
Beispiel #8
0
    def choose_pair(
            self,
            timestamp: Timestamp,
            price_query: Callable[[Asset, Asset, Timestamp], FVal],
    ) -> TradePair:
        """Choose a random pair to trade from the available pairs at the selected timestamp"""
        choices = set(list(self.asset_pairs['result'].keys()))
        found = False
        while len(choices) != 0:
            pair = random.choice(tuple(choices))
            choices.remove(pair)
            pair = kraken_to_world_pair(pair)
            base, quote = pair_get_assets(pair)
            kbase = WORLD_TO_KRAKEN[base]
            kquote = WORLD_TO_KRAKEN[quote]
            if kbase in self.balances_dict or kquote in self.balances_dict:
                # Before choosing make sure that at the selected timestamp both of
                # the pair assets exist (had a price)
                if not assets_exist_at_time(base, quote, timestamp, price_query):
                    continue
                found = True
                break

        if not found:
            raise ValueError('Could not find a pair to trade with the current funds')
        return TradePair(f'{base}_{quote}')
Beispiel #9
0
def test_deserialize_trade_sell(mock_bitfinex):
    mock_bitfinex.currency_map = {'UST': 'USDt'}
    mock_bitfinex.pair_bfx_symbols_map = {'ETHUST': ('ETH', 'UST')}
    raw_result = [
        399251013,
        'tETHUST',
        1573485493000,
        33963608932,
        -0.26334268,
        187.37,
        'LIMIT',
        None,
        -1,
        -0.09868591,
        'USD',
    ]
    expected_trade = Trade(
        timestamp=Timestamp(1573485493),
        location=Location.BITFINEX,
        pair=TradePair('ETH_USDT'),
        trade_type=TradeType.SELL,
        amount=AssetAmount(FVal('0.26334268')),
        rate=Price(FVal('187.37')),
        fee=Fee(FVal('0.09868591')),
        fee_currency=Asset('USD'),
        link='399251013',
        notes='',
    )
    trade = mock_bitfinex._deserialize_trade(raw_result=raw_result)
    assert trade == expected_trade
Beispiel #10
0
    def choose_pair(
        self,
        timestamp: Timestamp,
        price_query: Callable[[Asset, Asset, Timestamp], FVal],
    ) -> TradePair:
        """Choose a random pair to trade from the available pairs at the selected timestamp"""
        choices = set(list(self._symbols_to_pair.keys()))
        found = False
        while len(choices) != 0:
            pair = random.choice(tuple(choices))
            choices.remove(pair)
            binance_pair = self._symbols_to_pair[pair]
            bbase = binance_pair.base_asset
            bquote = binance_pair.quote_asset
            base = binance_to_world(bbase)
            quote = binance_to_world(bquote)
            if bbase in self.balances_dict or bquote in self.balances_dict:
                if bbase in DISALLOWED_ASSETS or bquote in DISALLOWED_ASSETS:
                    continue

                # Before choosing make sure that at the selected timestamp both of
                # the pair assets exist (had a price)
                if not assets_exist_at_time(base, quote, timestamp,
                                            price_query):
                    continue

                found = True
                break

        if not found:
            raise ValueError(
                'Could not find a pair to trade with the current funds')
        return TradePair(f'{base}_{quote}')
def pair_get_assets(pair: TradePair) -> Tuple[Asset, Asset]:
    """Returns a tuple with the (base, quote) assets"""
    assets = pair.split('_')
    if len(assets) != 2:
        raise ValueError(f'Could not split {pair} pair')

    return cast(Asset, assets[0]), cast(Asset, assets[1])
Beispiel #12
0
def test_deserialize_trade_buy(mock_bitstamp):
    raw_trade = {
        'id': 2,
        'type': 2,
        'datetime': '2020-12-02 09:30:00',
        'btc': '0.50000000',
        'usd': '-10000.00000000',
        'btc_usd': '0.00005000',
        'fee': '20.00000000',
        'order_id': 2,
    }
    expected_trade = Trade(
        timestamp=1606901400,
        location=Location.BITSTAMP,
        pair=TradePair('BTC_USD'),
        trade_type=TradeType.BUY,
        amount=FVal("0.50000000"),
        rate=FVal("0.00005000"),
        fee=FVal("20.00000000"),
        fee_currency=Asset('USD'),
        link='2',
        notes='',
    )
    trade = mock_bitstamp._deserialize_trade(raw_trade)
    assert trade == expected_trade
Beispiel #13
0
def mock_exchange_data_in_db(exchanges, rotki) -> None:
    db = rotki.data.db
    for exchange_name in exchanges:
        db.add_trades([
            Trade(
                timestamp=Timestamp(1),
                location=deserialize_location(exchange_name),
                pair=TradePair('BTC_ETH'),
                trade_type=TradeType.BUY,
                amount=AssetAmount(FVal(1)),
                rate=Price(FVal(1)),
                fee=Fee(FVal('0.1')),
                fee_currency=A_ETH,
                link='foo',
                notes='boo',
            )
        ])
        db.update_used_query_range(name=f'{exchange_name}_trades',
                                   start_ts=0,
                                   end_ts=9999)
        db.update_used_query_range(name=f'{exchange_name}_margins',
                                   start_ts=0,
                                   end_ts=9999)
        db.update_used_query_range(name=f'{exchange_name}_asset_movements',
                                   start_ts=0,
                                   end_ts=9999)  # noqa: E501
Beispiel #14
0
def gemini_symbol_to_pair(symbol: str) -> TradePair:
    """Turns a gemini symbol product into our trade pair format

    - Can raise UnprocessableTradePair if symbol is in unexpected format
    - Case raise UnknownAsset if any of the pair assets are not known to Rotki
    """
    if len(symbol) == 6:
        base_asset = Asset(symbol[:3].upper())
        quote_asset = Asset(symbol[3:].upper())
    elif len(symbol) == 7:
        try:
            base_asset = Asset(symbol[:4].upper())
            quote_asset = Asset(symbol[4:].upper())
        except UnknownAsset:
            base_asset = Asset(symbol[:3].upper())
            quote_asset = Asset(symbol[3:].upper())
    elif len(symbol) == 8:
        if 'storj' in symbol:
            base_asset = Asset(symbol[:5].upper())
            quote_asset = Asset(symbol[5:].upper())
        else:
            base_asset = Asset(symbol[:4].upper())
            quote_asset = Asset(symbol[4:].upper())
    else:
        raise UnprocessableTradePair(symbol)

    return TradePair(f'{base_asset.identifier}_{quote_asset.identifier}')
Beispiel #15
0
    def query_online_trade_history(
        self,
        start_ts: Timestamp,
        end_ts: Timestamp,
    ) -> List[Trade]:
        raw_data = self.return_trade_history(
            currency_pair='all',
            start=start_ts,
            end=end_ts,
        )

        results_length = 0
        for _, v in raw_data.items():
            results_length += len(v)

        log.debug('Poloniex trade history query', results_num=results_length)

        if results_length >= 10000:
            raise ValueError(
                'Poloniex api has a 10k limit to trade history. Have not implemented'
                ' a solution for more than 10k trades at the moment', )

        our_trades = []
        for pair, trades in raw_data.items():
            for trade in trades:
                category = trade.get('category', None)
                try:
                    if category == 'exchange' or category == 'settlement':
                        our_trades.append(
                            trade_from_poloniex(trade, TradePair(pair)))
                    elif category == 'marginTrade':
                        # We don't take poloniex margin trades into account at the moment
                        continue
                    else:
                        self.msg_aggregator.add_error(
                            f'Error deserializing a poloniex trade. Unknown trade '
                            f'category {category} found.', )
                        continue
                except UnsupportedAsset as e:
                    self.msg_aggregator.add_warning(
                        f'Found poloniex trade with unsupported asset'
                        f' {e.asset_name}. Ignoring it.', )
                    continue
                except UnknownAsset as e:
                    self.msg_aggregator.add_warning(
                        f'Found poloniex trade with unknown asset'
                        f' {e.asset_name}. Ignoring it.', )
                    continue
                except (UnprocessableTradePair, DeserializationError) as e:
                    self.msg_aggregator.add_error(
                        'Error deserializing a poloniex trade. Check the logs '
                        'and open a bug report.', )
                    log.error(
                        'Error deserializing poloniex trade',
                        trade=trade,
                        error=str(e),
                    )
                    continue

        return our_trades
Beispiel #16
0
def test_deserialize_v1_trade(mock_kucoin):
    raw_result = {
        'id': 'xxxx',
        'symbol': 'NANO-ETH',
        'dealPrice': '0.015743',
        'dealValue': '0.00003441',
        'amount': '0.002186',
        'fee': '0.00000003',
        'side': 'sell',
        'createdAt': 1520471876,
    }
    expected_trade = Trade(
        timestamp=Timestamp(1520471876),
        location=Location.KUCOIN,
        pair=TradePair('NANO_ETH'),
        trade_type=TradeType.SELL,
        amount=AssetAmount(FVal('0.002186')),
        rate=Price(FVal('0.015743')),
        fee=Fee(FVal('0.00000003')),
        fee_currency=Asset('ETH'),
        link='xxxx',
        notes='',
    )
    trade = mock_kucoin._deserialize_trade(
        raw_result=raw_result,
        case=KucoinCase.OLD_TRADES,
    )
    assert trade == expected_trade
Beispiel #17
0
def test_deserialize_trade_sell(mock_bitstamp):
    raw_trade = {
        'id': 5,
        'type': 2,
        'datetime': '2020-12-03 11:30:00',
        'eur': '-1.00000000',
        'usd': '1.22000000',
        'eur_usd': '0.81967213',
        'fee': '0.00610000',
        'order_id': 3,
    }
    expected_trade = Trade(
        timestamp=1606995000,
        location=Location.BITSTAMP,
        pair=TradePair('EUR_USD'),
        trade_type=TradeType.SELL,
        amount=FVal("1.22000000"),
        rate=FVal("0.81967213"),
        fee=FVal("0.00610000"),
        fee_currency=Asset('EUR'),
        link='5',
        notes='',
    )
    trade = mock_bitstamp._deserialize_trade(raw_trade)
    assert trade == expected_trade
Beispiel #18
0
    def _deserialize_trade(self, raw_result: List[Any]) -> Trade:
        """Process a trade result from Bitfinex and deserialize it.

        The base and quote assets are instantiated using the `fee_currency_symbol`
        (from raw_result[10]) over the pair (from raw_result[1]).

        Known pairs format: 'tETHUST', 'tETH:UST'.

        Can raise DeserializationError.

        Schema reference in:
        https://docs.bitfinex.com/reference#rest-auth-trades
        """
        amount = deserialize_asset_amount(raw_result[4])
        trade_type = TradeType.BUY if amount >= ZERO else TradeType.SELL
        bfx_pair = self._process_bfx_pair(raw_result[1])
        if bfx_pair not in self.pair_bfx_symbols_map:
            raise DeserializationError(
                f'Could not deserialize bitfinex trade pair {raw_result[1]}. '
                f'Raw trade: {raw_result}', )

        bfx_base_asset_symbol, bfx_quote_asset_symbol = self.pair_bfx_symbols_map[
            bfx_pair]
        try:
            base_asset = asset_from_bitfinex(
                bitfinex_name=bfx_base_asset_symbol,
                currency_map=self.currency_map,
            )
            quote_asset = asset_from_bitfinex(
                bitfinex_name=bfx_quote_asset_symbol,
                currency_map=self.currency_map,
            )
            fee_asset = asset_from_bitfinex(
                bitfinex_name=raw_result[10],
                currency_map=self.currency_map,
            )
        except (UnknownAsset, UnsupportedAsset) as e:
            asset_tag = 'Unknown' if isinstance(
                e, UnknownAsset) else 'Unsupported'
            raise DeserializationError(
                f'{asset_tag} {e.asset_name} found while processing trade pair due to: {str(e)}',
            ) from e

        trade = Trade(
            timestamp=Timestamp(int(raw_result[2] / 1000)),
            location=Location.BITFINEX,
            pair=TradePair(
                f'{base_asset.identifier}_{quote_asset.identifier}'),
            trade_type=trade_type,
            amount=AssetAmount(abs(amount)),
            rate=deserialize_price(raw_result[5]),
            fee=Fee(abs(deserialize_fee(raw_result[9]))),
            fee_currency=fee_asset,
            link=str(raw_result[0]),
            notes='',
        )
        return trade
Beispiel #19
0
    def query_online_trade_history(
        self,
        start_ts: Timestamp,
        end_ts: Timestamp,
    ) -> List[Trade]:
        raw_data = self.return_trade_history(
            start=start_ts,
            end=end_ts,
        )

        results_length = 0
        for _, v in raw_data.items():
            results_length += len(v)

        log.debug('Poloniex trade history query', results_num=results_length)
        our_trades = []
        for pair, trades in raw_data.items():
            for trade in trades:
                category = trade.get('category', None)
                try:
                    if category in ('exchange', 'settlement'):
                        timestamp = deserialize_timestamp_from_poloniex_date(
                            trade['date'])
                        if timestamp < start_ts or timestamp > end_ts:
                            continue
                        our_trades.append(
                            trade_from_poloniex(trade, TradePair(pair)))
                    elif category == 'marginTrade':
                        # We don't take poloniex margin trades into account at the moment
                        continue
                    else:
                        self.msg_aggregator.add_error(
                            f'Error deserializing a poloniex trade. Unknown trade '
                            f'category {category} found.', )
                        continue
                except UnsupportedAsset as e:
                    self.msg_aggregator.add_warning(
                        f'Found poloniex trade with unsupported asset'
                        f' {e.asset_name}. Ignoring it.', )
                    continue
                except UnknownAsset as e:
                    self.msg_aggregator.add_warning(
                        f'Found poloniex trade with unknown asset'
                        f' {e.asset_name}. Ignoring it.', )
                    continue
                except (UnprocessableTradePair, DeserializationError) as e:
                    self.msg_aggregator.add_error(
                        'Error deserializing a poloniex trade. Check the logs '
                        'and open a bug report.', )
                    log.error(
                        'Error deserializing poloniex trade',
                        trade=trade,
                        error=str(e),
                    )
                    continue

        return our_trades
Beispiel #20
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'])
    binance_pair = binance_symbols_to_pair[binance_trade['symbol']]
    timestamp = binance_trade['time']

    base_asset = binance_to_world(binance_pair.base_asset)
    quote_asset = binance_to_world(binance_pair.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 = 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=TradePair(f'{base_asset}_{quote_asset}'),
        trade_type=order_type,
        amount=amount,
        rate=rate,
        fee=fee,
        fee_currency=fee_currency,
    )
Beispiel #21
0
def test_invert_pair():
    pair = invert_pair('ETH_BTC')
    assert pair == TradePair('BTC_ETH')

    with pytest.raises(ValueError):
        invert_pair('_')
    with pytest.raises(ValueError):
        invert_pair('ETH_')
    with pytest.raises(ValueError):
        invert_pair('_BTC')
    with pytest.raises(ValueError):
        invert_pair('ETH_BTC_USD')

    with pytest.raises(UnknownAsset):
        invert_pair('ETH_FDFSFDSFDSF')
    with pytest.raises(UnknownAsset):
        invert_pair('FDFSFDSFDSF_BTC')

    pair = invert_pair('ETH_RDN')
    assert pair == TradePair('RDN_ETH')
Beispiel #22
0
def _split_pair(pair: TradePair) -> Tuple[str, str]:
    assets = pair.split('_')
    if len(assets) != 2:
        # Could not split the pair
        raise UnprocessableTradePair(pair)

    if len(assets[0]) == 0 or len(assets[1]) == 0:
        # no base or no quote asset
        raise UnprocessableTradePair(pair)

    return assets[0], assets[1]
Beispiel #23
0
def _split_pair(pair: TradePair) -> Tuple[str, str]:
    assets = pair.split('_')
    if len(assets) != 2:
        raise ValueError(f'Could not split {pair} pair')

    if len(assets[0]) == 0:
        raise ValueError(f'Splitting {pair} yielded no base asset')

    if len(assets[1]) == 0:
        raise ValueError(f'Splitting {pair} yielded no quote asset')

    return assets[0], assets[1]
Beispiel #24
0
def coinbasepro_to_worldpair(product: str) -> TradePair:
    """Turns a coinbasepro product into our trade pair format

    - Can raise UnprocessableTradePair if product is in unexpected format
    - Case raise UnknownAsset if any of the pair assets are not known to Rotki
    """
    parts = product.split('-')
    if len(parts) != 2:
        raise UnprocessableTradePair(product)

    base_asset = Asset(parts[0])
    quote_asset = Asset(parts[1])

    return TradePair(f'{base_asset.identifier}_{quote_asset.identifier}')
Beispiel #25
0
def trade_from_coinbase(raw_trade: Dict[str, Any]) -> Optional[Trade]:
    """Turns a coinbase transaction into a rotkehlchen Trade.

    https://developers.coinbase.com/api/v2?python#buys
    If the coinbase transaction is not a trade related transaction returns None

    Throws:
        - UnknownAsset due to Asset instantiation
        - DeserializationError due to unexpected format of dict entries
        - KeyError due to dict entires missing an expected entry
    """

    if raw_trade['status'] != 'completed':
        # We only want to deal with completed trades
        return None

    if raw_trade['instant']:
        raw_time = raw_trade['created_at']
    else:
        raw_time = raw_trade['payout_at']
    timestamp = deserialize_timestamp_from_date(raw_time, 'iso8601',
                                                'coinbase')
    trade_type = deserialize_trade_type(raw_trade['resource'])
    tx_amount = deserialize_asset_amount(raw_trade['amount']['amount'])
    tx_asset = asset_from_coinbase(raw_trade['amount']['currency'],
                                   time=timestamp)
    native_amount = deserialize_asset_amount(raw_trade['subtotal']['amount'])
    native_asset = asset_from_coinbase(raw_trade['subtotal']['currency'],
                                       time=timestamp)
    # in coinbase you are buying/selling tx_asset for native_asset
    pair = TradePair(f'{tx_asset.identifier}_{native_asset.identifier}')
    amount = tx_amount
    # The rate is how much you get/give in quotecurrency if you buy/sell 1 unit of base currency
    rate = Price(native_amount / tx_amount)
    fee_amount = deserialize_fee(raw_trade['fee']['amount'])
    fee_asset = asset_from_coinbase(raw_trade['fee']['currency'],
                                    time=timestamp)

    return Trade(
        timestamp=timestamp,
        location=Location.COINBASE,
        pair=pair,
        trade_type=trade_type,
        amount=amount,
        rate=rate,
        fee=fee_amount,
        fee_currency=fee_asset,
        link=str(raw_trade['id']),
    )
Beispiel #26
0
def deserialize_trade_pair(trade_pair_symbol: str) -> TradePair:
    """May raise:
    - UnprocessableTradePair
    - UnknownAsset
    - UnsupportedAsset
    """
    try:
        base_asset_symbol, quote_asset_symbol = trade_pair_symbol.split('-')
    except ValueError as e:
        raise UnprocessableTradePair(trade_pair_symbol) from e

    base_asset = asset_from_kucoin(base_asset_symbol)
    quote_asset = asset_from_kucoin(quote_asset_symbol)

    return TradePair(f'{base_asset.identifier}_{quote_asset.identifier}')
Beispiel #27
0
def bittrex_pair_to_world(given_pair: str) -> Tuple[Asset, Asset]:
    """
    Turns a pair written in bittrex to way to rotki base/quote asset

    Throws:
        - UnsupportedAsset due to asset_from_bittrex()
        - UnprocessableTradePair if the pair can't be split into its parts
    """
    if not isinstance(given_pair, str):
        raise DeserializationError(
            f'Could not deserialize bittrex trade pair. Expected a string '
            f'but found {type(given_pair)}', )
    pair = TradePair(given_pair.replace('-', '_'))
    base_asset = asset_from_bittrex(get_pair_position_str(pair, 'first'))
    quote_asset = asset_from_bittrex(get_pair_position_str(pair, 'second'))
    return base_asset, quote_asset
Beispiel #28
0
def bittrex_pair_to_world(given_pair: str) -> TradePair:
    """
    Turns a pair written in the bittrex way to Rotkehlchen way

    Throws:
        - UnsupportedAsset due to asset_from_bittrex()
    """
    pair = TradePair(given_pair.replace('-', '_'))
    base_currency = asset_from_bittrex(get_pair_position_str(pair, 'first'))
    quote_currency = asset_from_bittrex(get_pair_position_str(pair, 'second'))

    # 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 = trade_pair_from_assets(quote_currency, base_currency)
    return pair
Beispiel #29
0
def test_serialize_deserialize_trade():
    trade = Trade(
        timestamp=Timestamp(1537985746),
        location=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
Beispiel #30
0
def bittrex_pair_to_world(given_pair: str) -> TradePair:
    """
    Turns a pair written in the bittrex way to Rotkehlchen way

    Throws:
        - UnsupportedAsset due to asset_from_bittrex()
        - UnprocessableTradePair if the pair can't be split into its parts
    """
    if not isinstance(given_pair, str):
        raise DeserializationError(
            f'Could not deserialize bittrex trade pair. Expected a string '
            f'but found {type(given_pair)}', )
    pair = TradePair(given_pair.replace('-', '_'))
    # Check that there is no unsupported asset in the trade
    _ = asset_from_bittrex(get_pair_position_str(pair, 'first'))
    _ = asset_from_bittrex(get_pair_position_str(pair, 'second'))
    return pair