Пример #1
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(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 = base.to_kraken()
            kquote = quote.to_kraken()
            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 trade_pair_from_assets(base, quote)
Пример #2
0
    def trade_to_binance(self, trade: Trade) -> Dict[str, Any]:
        """Turns our trade into a binance trade"""
        base, quote = pair_get_assets(trade.pair)
        bbase = base.to_binance()
        bquote = quote.to_binance()
        binance_symbol = bbase + bquote
        # Binance trades have timestamps with 3 extra zeros at the end
        timestamp = trade.timestamp * 1000
        msg = 'The given trade symbol is not a valid binance pair'
        assert binance_symbol in self._symbols_to_pair, msg

        trade_data = {
            'symbol': binance_symbol,
            'id': 1,
            'orderId': 1,
            'price': str(trade.rate),
            'qty': str(trade.amount),
            'commission': str(trade.fee),
            'commissionAsset': str(trade.fee_currency.to_binance()),
            'time': timestamp,
            'isBuyer': trade.trade_type == TradeType.BUY,
            'isMaker': True,
            'isBestMatch': True,
        }
        return trade_data
Пример #3
0
def world_pair_to_bittrex(pair: TradePair) -> str:
    """Turns a rotkehlchen pair to a bittrex pair"""
    base_asset, quote_asset = pair_get_assets(pair)

    base_asset_str = base_asset.to_bittrex()
    quote_asset_str = quote_asset.to_bittrex()

    # In bittrex the pairs are inverted and use '-'
    return f'{quote_asset_str}-{base_asset_str}'
Пример #4
0
def world_to_kraken_pair(tradeable_pairs: List[str], pair: TradePair) -> str:
    base_asset, quote_asset = pair_get_assets(pair)

    base_asset_str = base_asset.to_kraken()
    quote_asset_str = quote_asset.to_kraken()

    pair1 = base_asset_str + quote_asset_str
    pair2 = quote_asset_str + base_asset_str

    # In some pairs, XXBT is XBT and ZEUR is EUR ...
    pair3 = None
    if 'XXBT' in pair1:
        pair3 = pair1.replace('XXBT', 'XBT')
    pair4 = None
    if 'XXBT' in pair2:
        pair4 = pair2.replace('XXBT', 'XBT')
    if 'ZEUR' in pair1:
        pair3 = pair1.replace('ZEUR', 'EUR')
    pair4 = None
    if 'ZEUR' in pair2:
        pair4 = pair2.replace('ZEUR', 'EUR')

    if pair1 in tradeable_pairs:
        new_pair = pair1
    elif pair2 in tradeable_pairs:
        new_pair = pair2
    elif pair3 in tradeable_pairs:
        new_pair = pair3
    elif pair4 in tradeable_pairs:
        new_pair = pair4
    else:
        raise ValueError(
            f'Unknown pair "{pair}" provided. Couldnt find {base_asset_str + quote_asset_str}'
            f' or {quote_asset_str + base_asset_str} in tradeable pairs',
        )

    return new_pair
Пример #5
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, A_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, A_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=deserialize_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)
Пример #6
0
def test_pair_get_assets():
    a1, a2 = pair_get_assets('ETH_BTC')
    assert isinstance(a1, Asset)
    assert a1 == A_ETH
    assert isinstance(a2, Asset)
    assert a2 == A_BTC

    with pytest.raises(UnprocessableTradePair):
        pair_get_assets('_')
    with pytest.raises(UnprocessableTradePair):
        pair_get_assets('ETH_')
    with pytest.raises(UnprocessableTradePair):
        pair_get_assets('_BTC')
    with pytest.raises(UnprocessableTradePair):
        pair_get_assets('ETH_BTC_USD')

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

    a1, a2 = pair_get_assets('ETH_RDN')
    assert isinstance(a1, Asset)
    assert a1 == A_ETH
    assert isinstance(a2, Asset)
    assert a2 == A_RDN
Пример #7
0
def trade_get_assets(trade: Union[Trade, AMMTrade]) -> Tuple[Asset, Asset]:
    if isinstance(trade, Trade):
        return pair_get_assets(trade.pair)

    # else should only be AMMTrade
    return trade.base_asset, trade.quote_asset  # type: ignore
Пример #8
0
def invert_pair(pair: TradePair) -> TradePair:
    left, right = pair_get_assets(pair)
    return trade_pair_from_assets(right, left)
Пример #9
0
 def quote_asset(self) -> Asset:
     _, quote = pair_get_assets(self.pair)
     return quote
Пример #10
0
 def base_asset(self) -> Asset:
     base, _ = pair_get_assets(self.pair)
     return base
Пример #11
0
            # amount_key = 'size' if case == KucoinCase.TRADES else 'amount'
            # amount = deserialize_asset_amount(raw_result['size'])
            fee = deserialize_fee(raw_result['fee'])
            trade_pair_symbol = raw_result['symbol']
            trade_pair = deserialize_trade_pair(trade_pair_symbol)
            if case == KucoinCase.TRADES:
                fee_currency_symbol = raw_result['feeCurrency']
                fee_currency = asset_from_kucoin(fee_currency_symbol)
                amount = deserialize_asset_amount(raw_result['size'])
                rate = deserialize_price(raw_result['price'])
                # new trades have the timestamp in ms
                timestamp = Timestamp(int(timestamp / 1000))
                trade_id = raw_result['tradeId']
            else:  # old v1 trades
                amount = deserialize_asset_amount(raw_result['amount'])
                base_asset, quote_asset = pair_get_assets(trade_pair)
                fee_currency = quote_asset if trade_type == TradeType.SELL else base_asset
                rate = deserialize_price(raw_result['dealPrice'])
                trade_id = raw_result['id']

        except KeyError as e:
            raise DeserializationError(f'Missing key: {str(e)}.') from e

        trade = Trade(
            timestamp=timestamp,
            location=Location.KUCOIN,
            pair=trade_pair,
            trade_type=trade_type,
            amount=amount,
            rate=rate,
            fee=fee,
Пример #12
0
def trade_get_assets(trade: Union[Trade, AMMTrade]) -> Tuple[Asset, Asset]:
    if isinstance(trade, Trade):
        return pair_get_assets(trade.pair)
    else:  # Should only be AMMTrade
        # can also be unknown ethereum token
        return trade.base_asset, trade.quote_asset  # type: ignore
Пример #13
0
def trade_get_assets(trade: Trade) -> Tuple[Asset, Asset]:
    return pair_get_assets(trade.pair)
Пример #14
0
    def query_online_trade_history(
        self,
        start_ts: Timestamp,
        end_ts: Timestamp,
    ) -> List[Trade]:
        """Queries coinbase pro for trades"""
        log.debug('Query coinbasepro trade history',
                  start_ts=start_ts,
                  end_ts=end_ts)

        trades = []
        raw_trades = []
        for batch in self._paginated_query(
                endpoint='orders',
                query_options={'status': 'done'},
        ):
            raw_trades.extend(batch)

        for entry in raw_trades:
            timestamp = coinbasepro_deserialize_timestamp(entry, 'created_at')
            if timestamp < start_ts or timestamp > end_ts:
                continue

            try:
                pair = coinbasepro_to_worldpair(entry['product_id'])
                # Fee currency seems to always be quote asset
                # https://github.com/ccxt/ccxt/blob/ddf3a15cbff01541f0b37c35891aa143bb7f9d7b/python/ccxt/coinbasepro.py#L724  # noqa: E501
                _, quote_asset = pair_get_assets(pair)
                trades.append(
                    Trade(
                        timestamp=timestamp,
                        location=Location.COINBASEPRO,
                        pair=coinbasepro_to_worldpair(entry['product_id']),
                        trade_type=deserialize_trade_type(entry['side']),
                        amount=deserialize_asset_amount(entry['size']),
                        rate=deserialize_price(entry['price']),
                        fee=deserialize_fee(entry['fill_fees']),
                        fee_currency=quote_asset,
                        link=entry['id'],
                        notes='',
                    ))
            except UnprocessableTradePair as e:
                self.msg_aggregator.add_warning(
                    f'Found unprocessable Coinbasepro pair {e.pair}. Ignoring the trade.',
                )
                continue
            except UnknownAsset as e:
                self.msg_aggregator.add_warning(
                    f'Found unknown Coinbasepro asset {e.asset_name}. '
                    f'Ignoring the trade.', )
                continue
            except (DeserializationError, KeyError) as e:
                msg = str(e)
                if isinstance(e, KeyError):
                    msg = f'Missing key entry for {msg}.'
                self.msg_aggregator.add_error(
                    'Failed to deserialize a coinbasepro trade. '
                    'Check logs for details. Ignoring it.', )
                log.error(
                    'Error processing a coinbasepro trade.',
                    raw_trade=entry,
                    error=msg,
                )
                continue

        return trades