def test_app_currency(): from jesse.routes import router from jesse.enums import exchanges, timeframes router.initiate([{ 'exchange': exchanges.BITFINEX, 'symbol': 'ETH-USD', 'timeframe': timeframes.HOUR_3, 'strategy': 'Test19' }]) assert jh.app_currency() == 'USD'
def run(debug_mode, user_config: dict, routes: List[Dict[str, str]], extra_routes: List[Dict[str, str]], start_date: str, finish_date: str, optimal_total: int, csv: bool, json: bool) -> None: from jesse.config import config, set_config config['app']['trading_mode'] = 'optimize' # debug flag config['app']['debug_mode'] = debug_mode cpu_cores = int(user_config['cpu_cores']) # inject config set_config(user_config) # set routes router.initiate(routes, extra_routes) store.app.set_session_id() register_custom_exception_handler() # clear the screen if not jh.should_execute_silently(): click.clear() # validate routes validate_routes(router) print('loading candles...') # load historical candles and divide them into training # and testing periods (15% for test, 85% for training) training_candles, testing_candles = _get_training_and_testing_candles( start_date, finish_date) # clear the screen click.clear() optimizer = Optimizer(training_candles, testing_candles, optimal_total, cpu_cores, csv, json, start_date, finish_date) # start the process optimizer.run()
def set_up_with_fee(is_futures_trading=False): reset_config() config['env']['exchanges'][exchanges.SANDBOX]['fee'] = 0.002 config['env']['exchanges'][exchanges.SANDBOX]['assets'] = [ { 'asset': 'USDT', 'balance': 1000 }, { 'asset': 'BTC', 'balance': 0 }, ] if is_futures_trading: # used only in futures trading config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'futures' else: config['env']['exchanges'][exchanges.SANDBOX]['type'] = 'spot' config['env']['exchanges'][ exchanges.SANDBOX]['settlement_currency'] = 'USDT' config['app']['trading_mode'] = 'backtest' config['app']['considering_exchanges'] = ['Sandbox'] router.initiate([{ 'exchange': exchanges.SANDBOX, 'symbol': 'BTC-USDT', 'timeframe': '5m', 'strategy': 'Test19' }], []) global position global exchange global broker position = selectors.get_position(exchanges.SANDBOX, 'BTC-USDT') position.current_price = 50 exchange = selectors.get_exchange(exchanges.SANDBOX) broker = Broker(position, exchanges.SANDBOX, 'BTC-USDT', timeframes.MINUTE_5)
def run( debug_mode, user_config: dict, routes: List[Dict[str, str]], extra_routes: List[Dict[str, str]], start_date: str, finish_date: str, candles: dict = None, chart: bool = False, tradingview: bool = False, full_reports: bool = False, csv: bool = False, json: bool = False ) -> None: if not jh.is_unit_testing(): # at every second, we check to see if it's time to execute stuff status_checker = Timeloop() @status_checker.job(interval=timedelta(seconds=1)) def handle_time(): if process_status() != 'started': raise exceptions.Termination status_checker.start() from jesse.config import config, set_config config['app']['trading_mode'] = 'backtest' # debug flag config['app']['debug_mode'] = debug_mode # inject config if not jh.is_unit_testing(): set_config(user_config) # set routes router.initiate(routes, extra_routes) store.app.set_session_id() register_custom_exception_handler() # clear the screen if not jh.should_execute_silently(): click.clear() # validate routes validate_routes(router) # initiate candle store store.candles.init_storage(5000) # load historical candles if candles is None: candles = load_candles(start_date, finish_date) click.clear() if not jh.should_execute_silently(): sync_publish('general_info', { 'session_id': jh.get_session_id(), 'debug_mode': str(config['app']['debug_mode']), }) # candles info key = f"{config['app']['considering_candles'][0][0]}-{config['app']['considering_candles'][0][1]}" sync_publish('candles_info', stats.candles_info(candles[key]['candles'])) # routes info sync_publish('routes_info', stats.routes(router.routes)) # run backtest simulation simulator(candles, run_silently=jh.should_execute_silently()) # hyperparameters (if any) if not jh.should_execute_silently(): sync_publish('hyperparameters', stats.hyperparameters(router.routes)) if not jh.should_execute_silently(): if store.completed_trades.count > 0: sync_publish('metrics', report.portfolio_metrics()) routes_count = len(router.routes) more = f"-and-{routes_count - 1}-more" if routes_count > 1 else "" study_name = f"{router.routes[0].strategy_name}-{router.routes[0].exchange}-{router.routes[0].symbol}-{router.routes[0].timeframe}{more}-{start_date}-{finish_date}" store_logs(study_name, json, tradingview, csv) if chart: charts.portfolio_vs_asset_returns(study_name) sync_publish('equity_curve', charts.equity_curve()) # QuantStats' report if full_reports: price_data = [] # load close candles for Buy and hold and calculate pct_change for index, c in enumerate(config['app']['considering_candles']): exchange, symbol = c[0], c[1] if exchange in config['app']['trading_exchanges'] and symbol in config['app']['trading_symbols']: # fetch from database candles_tuple = Candle.select( Candle.timestamp, Candle.close ).where( Candle.timestamp.between(jh.date_to_timestamp(start_date), jh.date_to_timestamp(finish_date) - 60000), Candle.exchange == exchange, Candle.symbol == symbol ).order_by(Candle.timestamp.asc()).tuples() candles = np.array(candles_tuple) timestamps = candles[:, 0] price_data.append(candles[:, 1]) price_data = np.transpose(price_data) price_df = pd.DataFrame(price_data, index=pd.to_datetime(timestamps, unit="ms"), dtype=float).resample( 'D').mean() price_pct_change = price_df.pct_change(1).fillna(0) bh_daily_returns_all_routes = price_pct_change.mean(1) quantstats.quantstats_tearsheet(bh_daily_returns_all_routes, study_name) else: sync_publish('equity_curve', None) sync_publish('metrics', None) # close database connection from jesse.services.db import database database.close_connection()
def _isolated_backtest(config: dict, routes: List[Dict[str, str]], extra_routes: List[Dict[str, str]], candles: dict, run_silently: bool = True, hyperparameters: dict = None) -> dict: from jesse.services.validators import validate_routes from jesse.modes.backtest_mode import simulator from jesse.config import config as jesse_config, reset_config from jesse.routes import router from jesse.store import store from jesse.config import set_config from jesse.services import metrics from jesse.services import required_candles import jesse.helpers as jh jesse_config['app']['trading_mode'] = 'backtest' # inject (formatted) configuration values set_config(_format_config(config)) # set routes router.initiate(routes, extra_routes) # register_custom_exception_handler() validate_routes(router) # TODO: further validate routes and allow only one exchange # TODO: validate the name of the exchange in the config and the route? or maybe to make sure it's a supported exchange # initiate candle store store.candles.init_storage(5000) # divide candles into warm_up_candles and trading_candles and then inject warm_up_candles max_timeframe = jh.max_timeframe( jesse_config['app']['considering_timeframes']) warm_up_num = config['warm_up_candles'] * jh.timeframe_to_one_minutes( max_timeframe) trading_candles = candles if warm_up_num != 0: for c in jesse_config['app']['considering_candles']: key = jh.key(c[0], c[1]) # update trading_candles trading_candles[key]['candles'] = candles[key]['candles'][ warm_up_num:] # inject warm-up candles required_candles.inject_required_candles_to_store( candles[key]['candles'][:warm_up_num], c[0], c[1]) # run backtest simulation simulator(trading_candles, run_silently, hyperparameters) result = { 'metrics': { 'total': 0, 'win_rate': 0, 'net_profit_percentage': 0 }, 'charts': None, 'logs': None, } if store.completed_trades.count > 0: # add metrics result['metrics'] = metrics.trades(store.completed_trades.trades, store.app.daily_balance) # add charts result['charts'] = charts.portfolio_vs_asset_returns() # add logs result['logs'] = store.logs.info # reset store and config so rerunning would be flawlessly possible reset_config() store.reset() return result