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]
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, )
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 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' )
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
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
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
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', )
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, )
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')
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, )
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, )
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, )
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, )
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
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, )
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', )
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, )
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 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, ''
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]