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' )
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 = 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)
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
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}'
def choose_pair(self): choices = set(KRAKEN_PAIRS) found = False while len(choices) != 0: pair = random.choice(tuple(choices)) choices.remove(pair) base, quote = pair_get_assets(pair) if base in self.funds or quote in self.funds: found = True break if not found: raise ValueError( 'Could not find a pair to trade with the current funds') return pair
def world_to_kraken_pair(tradeable_pairs: List[str], pair: str) -> str: base_currency, quote_currency = pair_get_assets(pair) if base_currency not in KRAKEN_TO_WORLD: base_currency = WORLD_TO_KRAKEN[base_currency] if quote_currency not in KRAKEN_TO_WORLD: quote_currency = WORLD_TO_KRAKEN[quote_currency] if base_currency + quote_currency in tradeable_pairs: new_pair = base_currency + quote_currency elif quote_currency + base_currency in tradeable_pairs: new_pair = quote_currency + base_currency else: raise ValueError( f'Unknown pair "{pair}" provided. Couldnt find {base_currency + quote_currency}' f' or {quote_currency + base_currency} in tradeable pairs', ) return new_pair
def world_to_kraken_pair(tradeable_pairs: List[str], pair: TradePair) -> str: base_asset, quote_asset = pair_get_assets(pair) if base_asset not in KRAKEN_TO_WORLD: base_asset = WORLD_TO_KRAKEN[base_asset] if quote_asset not in KRAKEN_TO_WORLD: quote_asset = WORLD_TO_KRAKEN[quote_asset] pair1 = base_asset + quote_asset pair2 = quote_asset + base_asset # 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 + quote_asset}' f' or {quote_asset + base_asset} in tradeable pairs', ) return new_pair
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
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(ValueError): pair_get_assets('_') with pytest.raises(ValueError): pair_get_assets('ETH_') with pytest.raises(ValueError): pair_get_assets('_BTC') with pytest.raises(ValueError): 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
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)
def create_action(self): """Create a random trade action""" ts = self.get_next_ts() # choose a random pair pair = self.choose_pair() # depending on our funds decide on what to do. Buy/sell base, quote = pair_get_assets(pair) if base not in self.funds: action_type = 'buy' elif quote not in self.funds: action_type = 'sell' else: # TODO: trade the one we have most of action_type = random.choice(('buy', 'sell')) # if we are buying we are going to spend from the quote asset if action_type == '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 * self.funds[ 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 of asset we bought if action_type == '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(base, quote, ts) fee_in_quote_currency = FVal(random.uniform( 0, MAX_FEE_USD_VALUE)) / quote_asset_usd_rate # create the trade trade = Trade( time=ts, location='kraken', 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}') if action_type == 'buy': # we buy so we increase our base asset by amount self.increase_asset(base, amount) # and decrease quote by amount * rate self.decrease_asset(quote, amount * rate) else: # we sell so we increase our quote asset self.increase_asset(quote, amount * rate) # and decrease our base asset self.decrease_asset(base, amount) # normally here you would input it into the appropriate fake exchange # but since we only got kraken faker now ... self.fake_kraken.append_trade(trade)