import json import os import random from logging import Logger, WARNING from time import sleep import pandas as pd from catalyst.assets._assets import TradingPair from logbook import TestHandler from catalyst.exchange.exchange_errors import ExchangeRequestError from catalyst.exchange.exchange_execution import ExchangeLimitOrder from catalyst.exchange.utils.exchange_utils import get_exchange_folder from catalyst.exchange.utils.test_utils import select_random_exchanges, \ handle_exchange_error, select_random_assets from catalyst.testing import ZiplineTestCase from catalyst.testing.fixtures import WithLogger from catalyst.exchange.utils.factory import get_exchanges, get_exchange log = Logger('TestSuiteExchange') class TestSuiteExchange(WithLogger, ZiplineTestCase): def _test_markets_exchange(self, exchange, attempts=0): assets = None try: exchange.init() # Verify that the assets and markets are populated if not exchange.markets: raise ValueError( 'no markets found' ) if not exchange.assets: raise ValueError( 'no assets derived from markets' ) assets = exchange.assets except ExchangeRequestError as e: sleep(5) if attempts > 5: handle_exchange_error(exchange, e) else: print( 're-trying an exchange request {} {}'.format( exchange.name, attempts ) ) self._test_markets_exchange(exchange, attempts + 1) except Exception as e: handle_exchange_error(exchange, e) return assets def test_markets(self): population = 3 results = dict() exchanges = select_random_exchanges(population) # Type: list[Exchange] for exchange in exchanges: assets = self._test_markets_exchange(exchange) if assets is not None: results[exchange.name] = len(assets) folder = get_exchange_folder(exchange.name) filename = os.path.join(folder, 'whitelist.json') symbols = [asset.symbol for asset in assets] with open(filename, 'wt') as handle: json.dump(symbols, handle, indent=4) series = pd.Series(results) print('the tested markets\n{}'.format(series)) if population is not None: assert (len(results) == population) pass def test_tickers(self): exchange_population = 3 asset_population = 15 # exchanges = select_random_exchanges( # exchange_population, # features=['fetchTickers'], # ) # Type: list[Exchange] exchanges = list(get_exchanges(['binance']).values()) for exchange in exchanges: exchange.init() if exchange.assets and len(exchange.assets) >= asset_population: assets = select_random_assets( exchange.assets, asset_population ) tickers = exchange.tickers(assets) assert len(tickers) == asset_population else: print( 'skipping exchange without assets {}'.format(exchange.name) ) exchange_population -= 1 pass def test_candles(self): exchange_population = 3 asset_population = 3 # exchanges = select_random_exchanges( # population=exchange_population, # features=['fetchOHLCV'], # ) # Type: list[Exchange] exchanges = list(get_exchanges(['binance']).values()) for exchange in exchanges: exchange.init() if exchange.assets and len(exchange.assets) >= asset_population: frequencies = exchange.get_candle_frequencies() freq = random.sample(frequencies, 1)[0] bar_count = random.randint(1, 10) end_dt = pd.Timestamp.utcnow().floor('1T') dt_range = pd.date_range( end=end_dt, periods=bar_count, freq=freq ) assets = select_random_assets( exchange.assets, asset_population ) candles = exchange.get_candles( freq=freq, assets=assets, bar_count=bar_count, start_dt=dt_range[0], ) assert len(candles) == asset_population else: print( 'skipping exchange without assets {}'.format(exchange.name) ) exchange_population -= 1 pass def test_orders(self): population = 3 quote_currency = 'eth' order_amount = 0.1 # exchanges = select_random_exchanges( # population=population, # features=['fetchOrder'], # is_authenticated=True, # base_currency=quote_currency, # ) # Type: list[Exchange] exchanges = [ get_exchange( 'binance', base_currency=quote_currency, must_authenticate=True, ) ] log_catcher = TestHandler() with log_catcher: for exchange in exchanges: exchange.init() assets = exchange.get_assets(quote_currency=quote_currency) asset = select_random_assets(assets, 1)[0] self.assertIsInstance(asset, TradingPair) tickers = exchange.tickers([asset]) price = tickers[asset]['last_price'] amount = order_amount / price limit_price = price * 0.8 style = ExchangeLimitOrder(limit_price=limit_price) order = exchange.order( asset=asset, amount=amount, style=style, ) sleep(1) open_order = exchange.get_order(order.id, asset) self.assertEqual(0, open_order.status) exchange.cancel_order(open_order, asset) sleep(1) canceled_order = exchange.get_order(open_order.id, asset) warnings = [record for record in log_catcher.records if record.level == WARNING] self.assertEqual(0, len(warnings)) self.assertEqual(2, canceled_order.status) print( 'tested {exchange} / {symbol}, order: {order}'.format( exchange=exchange.name, symbol=asset.symbol, order=order.id, ) ) pass