def portfolio_metrics(): data = stats.trades(store.completed_trades.trades, store.app.daily_balance) return [['Total Closed Trades', data['total']], [ 'Total Net Profit', '{} ({})'.format(round(data['net_profit'], 4), str(data['net_profit_percentage']) + '%') ], [ 'Starting => Finishing Balance', '{} => {}'.format(round(data['starting_balance'], 2), round(data['finishing_balance'], 2)) ], ['Total Open Trades', data['total_open_trades']], ['Open PL', round(data['open_pl'], 2)], ['Total Paid Fees', round(data['fee'], 2)], ['Max Drawdown', '{}%'.format(data['max_drawdown'])], ['Sharpe Ratio', data['sharpe_ratio']], ['Annual Return', '{}%'.format(data['annual_return'])], [ 'Expectancy', '{} ({})'.format( round(data['expectancy'], 2), str(round(data['expectancy_percentage'], 2)) + '%') ], [ 'Avg Win | Avg Loss', '{} | {}'.format(round(data['average_win'], 2), round(data['average_loss'], 2)) ], ['Ratio Avg Win / Avg Loss', round(data['ratio_avg_win_loss'], 2)], ['Percent Profitable', str(round(data['win_rate'] * 100)) + '%'], [ 'Longs | Shorts', '{}% | {}%'.format(round(data['longs_percentage']), round(data['short_percentage'])) ], [ 'Avg Holding Time', jh.readable_duration(data['average_holding_period'], 3) ], [ 'Winning Trades Avg Holding Time', np.nan if np.isnan(data['average_winning_holding_period']) else jh.readable_duration(data['average_winning_holding_period'], 3) ], [ 'Losing Trades Avg Holding Time', np.nan if np.isnan(data['average_losing_holding_period']) else jh.readable_duration(data['average_losing_holding_period'], 3) ]]
def portfolio_metrics(): data = stats.trades(store.completed_trades.trades, store.app.daily_balance) metrics = [ ['Total Closed Trades', data['total']], ['Total Net Profit', '{} ({})'.format(jh.format_currency(round(data['net_profit'], 4)), str(data['net_profit_percentage']) + '%')], ['Starting => Finishing Balance', '{} => {}'.format(jh.format_currency(round(data['starting_balance'], 2)), jh.format_currency(round(data['finishing_balance'], 2)))], ['Total Open Trades', data['total_open_trades']], ['Open PL', jh.format_currency(round(data['open_pl'], 2))], ['Total Paid Fees', jh.format_currency(round(data['fee'], 2))], ['Max Drawdown', '{}%'.format(data['max_drawdown'])], ['Annual Return', '{}%'.format(data['annual_return'])], ['Expectancy', '{} ({})'.format(jh.format_currency(round(data['expectancy'], 2)), str(round(data['expectancy_percentage'], 2)) + '%')], ['Avg Win | Avg Loss', '{} | {}'.format(jh.format_currency(round(data['average_win'], 2)), jh.format_currency(round(data['average_loss'], 2)))], ['Ratio Avg Win / Avg Loss', round(data['ratio_avg_win_loss'], 2)], ['Percent Profitable', str(round(data['win_rate'] * 100)) + '%'], ['Longs | Shorts', '{}% | {}%'.format(round(data['longs_percentage']), round(data['short_percentage']))], ['Avg Holding Time', jh.readable_duration(data['average_holding_period'], 3)], ['Winning Trades Avg Holding Time', np.nan if np.isnan(data['average_winning_holding_period']) else jh.readable_duration( data['average_winning_holding_period'], 3)], ['Losing Trades Avg Holding Time', np.nan if np.isnan(data['average_losing_holding_period']) else jh.readable_duration( data['average_losing_holding_period'], 3)] ] if jh.get_config('env.metrics.sharpe_ratio', True): metrics.append(['Sharpe Ratio', data['sharpe_ratio']]) if jh.get_config('env.metrics.calmar_ratio', False): metrics.append(['Calmar Ratio', data['calmar_ratio']]) if jh.get_config('env.metrics.sortino_ratio', False): metrics.append(['Sortino Ratio', data['sortino_ratio']]) if jh.get_config('env.metrics.omega_ratio', False): metrics.append(['Omega Ratio', data['omega_ratio']]) if jh.get_config('env.metrics.winning_streak', False): metrics.append(['Winning Streak', data['winning_streak']]) if jh.get_config('env.metrics.losing_streak', False): metrics.append(['Losing Streak', data['losing_streak']]) if jh.get_config('env.metrics.largest_winning_trade', False): metrics.append(['Largest Winning Trade', jh.format_currency(data['largest_winning_trade'])]) if jh.get_config('env.metrics.largest_losing_trade', False): metrics.append(['Largest Losing Trade', jh.format_currency(data['largest_losing_trade'])]) if jh.get_config('env.metrics.total_winning_trades', False): metrics.append(['Total Winning Trades', data['total_winning_trades']]) if jh.get_config('env.metrics.total_losing_trades', False): metrics.append(['Total Losing Trades', data['total_losing_trades']]) return metrics
def fitness(self, dna) -> tuple: hp = jh.dna_to_hp(self.strategy_hp, dna) # init candle store store.candles.init_storage(5000) # inject required TRAINING candles to the candle store for num, c in enumerate(config['app']['considering_candles']): required_candles.inject_required_candles_to_store( self.training_initial_candles[num], c[0], c[1]) # run backtest simulation simulator(self.training_candles, hp) log = '' # TODO: some of these have to be dynamic based on how many days it's trading for like for example "total" # I'm guessing we should accept "optimal" total from command line if store.completed_trades.count > 5: training_data = stats.trades(store.completed_trades.trades, store.app.daily_balance) total_effect_rate = log10(training_data['total']) / log10( self.optimal_total) if total_effect_rate > 1: total_effect_rate = 1 win_rate = training_data['win_rate'] ratio_config = jh.get_config('env.optimization.ratio', 'sharpe') if ratio_config == 'sharpe': ratio = training_data['sharpe_ratio'] elif ratio_config == 'calmar': ratio = training_data['calmar_ratio'] elif ratio_config == 'sortiono': ratio = training_data['sortino_ratio'] elif ratio_config == 'omega': ratio = training_data['omega_ratio'] else: raise ValueError( 'The entered ratio configuration `{}` for the optimization is unknown. Choose between sharpe, calmar, sortino and omega.' .format(ratio_config)) if ratio < 0: score = 0.0001 # reset store store.reset() return score, log ratio_normalized = jh.normalize(ratio, -.5, 4) # log for debugging/monitoring log = 'win-rate: {}%, total: {}, PNL: {}%'.format( int(win_rate * 100), training_data['total'], round(training_data['net_profit_percentage'], 2), ) score = total_effect_rate * ratio_normalized # perform backtest with testing data. this is using data # model hasn't trained for. if it works well, there is # high change it will do good with future data too. store.reset() store.candles.init_storage(5000) # inject required TESTING candles to the candle store for num, c in enumerate(config['app']['considering_candles']): required_candles.inject_required_candles_to_store( self.testing_initial_candles[num], c[0], c[1]) # run backtest simulation simulator(self.testing_candles, hp) testing_data = stats.trades(store.completed_trades.trades, store.app.daily_balance) # log for debugging/monitoring log += ' || ' if store.completed_trades.count > 0: log += 'win-rate: {}%, total: {}, PNL: {}%'.format( int(testing_data['win_rate'] * 100), testing_data['total'], round(testing_data['net_profit_percentage'], 2), ) if testing_data['net_profit_percentage'] > 0 and training_data[ 'net_profit_percentage'] > 0: log = jh.style(log, 'bold') else: log += 'win-rate: -, total: -, PNL%: -' else: score = 0.0001 # reset store store.reset() return score, log
def fitness(self, dna) -> tuple: hp = jh.dna_to_hp(self.strategy_hp, dna) # init candle store store.candles.init_storage(5000) # inject required TRAINING candles to the candle store required_candles.inject_required_candles_to_store( self.required_initial_training_candles, self.exchange, self.symbol) # run backtest simulation simulator(self.training_candles, hp) log = '' # TODO: some of these have to be dynamic based on how many days it's trading for like for example "total" # I'm guessing we should accept "optimal" total from command line if store.completed_trades.count > 5: training_data = stats.trades(store.completed_trades.trades) optimal_expected_total = 100 total = jh.normalize(training_data['total'], 0, 200) total_effect_rate = log10( training_data['total']) / log10(optimal_expected_total) win_rate = training_data['win_rate'] # log for debugging/monitoring log = 'win_rate:[{}-{}], total:[{}-{}], PNL%:[{}], TER:[{}]'.format( round(win_rate, 2), round(training_data['win_rate'], 2), round(total, 2), training_data['total'], round(training_data['pnl_percentage'], 2), round(total_effect_rate, 3)) # the fitness score score = win_rate * total_effect_rate # perform backtest with testing data. this is using data # model hasn't trained for. if it works well, there is # high change it will do good with future data too. store.reset() store.candles.init_storage(5000) # inject required TESTING candles to the candle store required_candles.inject_required_candles_to_store( self.required_initial_testing_candles, self.exchange, self.symbol) # run backtest simulation simulator(self.testing_candles, hp) testing_data = stats.trades(store.completed_trades.trades) # log for debugging/monitoring log += ' | ' log += 'win_rate:[{}], total:[{}], PNL%:[{}]'.format( round(testing_data['win_rate'], 2), testing_data['total'], round(testing_data['pnl_percentage'], 2), ) if testing_data['pnl_percentage'] > 0 and training_data[ 'pnl_percentage'] > 0: log = jh.style(log, 'bold') else: score = 0.0001 # reset store store.reset() return score, log