def livetrade(): # TODO: for now, we assume that we trade on one exchange only. Later, we need to support for more than one exchange at a time # sum up balance of all trading exchanges starting_balance = 0 current_balance = 0 for e in store.exchanges.storage: starting_balance += store.exchanges.storage[e].starting_assets[ jh.app_currency()] current_balance += store.exchanges.storage[e].assets[jh.app_currency()] starting_balance = round(starting_balance, 2) current_balance = round(current_balance, 2) # short trades summary if len(store.completed_trades.trades): df = pd.DataFrame.from_records( [t.to_dict() for t in store.completed_trades.trades]) total = len(df) winning_trades = len(df.loc[df['PNL'] > 0]) losing_trades = len(df.loc[df['PNL'] < 0]) pnl = round(df['PNL'].sum(), 2) pnl_perc = round((pnl / starting_balance) * 100, 2) else: pnl, pnl_perc, total, winning_trades, losing_trades = 0, 0, 0, 0, 0 routes = [{ 'exchange': r.exchange, 'symbol': r.symbol, 'timeframe': r.timeframe, 'strategy': r.strategy_name } for r in router.routes] return { 'session_id': store.app.session_id, 'started_at': str(store.app.starting_time), 'current_time': str(jh.now_to_timestamp()), 'started_balance': str(starting_balance), 'current_balance': str(current_balance), 'debug_mode': str(config['app']['debug_mode']), 'paper_mode': str(jh.is_paper_trading()), 'count_error_logs': str(len(store.logs.errors)), 'count_info_logs': str(len(store.logs.info)), 'count_active_orders': str(store.orders.count_all_active_orders()), 'open_positions': str(store.positions.count_open_positions()), 'pnl': str(pnl), 'pnl_perc': str(pnl_perc), 'count_trades': str(total), 'count_winning_trades': str(winning_trades), 'count_losing_trades': str(losing_trades), 'routes': routes }
def test_app_currency(): from jesse.routes import router from jesse.enums import exchanges, timeframes router.set_routes([ (exchanges.BITFINEX, 'ETH-USD', timeframes.HOUR_3, 'Test19'), ]) assert jh.app_currency() == 'USD'
def save_daily_portfolio_balance() -> None: balances = [] # add exchange balances for key, e in store.exchanges.storage.items(): balances.append(e.assets[jh.app_currency()]) # store daily_balance of assets into database if jh.is_livetrading(): for asset_key, asset_value in e.assets.items(): store_daily_balance_into_db({ 'id': jh.generate_unique_id(), 'timestamp': jh.now(), 'identifier': jh.get_config('env.identifier', 'main'), 'exchange': e.name, 'asset': asset_key, 'balance': asset_value, }) # add open position values for key, pos in store.positions.storage.items(): if pos.is_open: balances.append(pos.pnl) total = sum(balances) store.app.daily_balance.append(total) logger.info('Saved daily portfolio balance: {}'.format(round(total, 2)))
def tradingview_logs(study_name: str) -> None: starting_balance = 0 for e in store.exchanges.storage: starting_balance += store.exchanges.storage[e].starting_assets[ jh.app_currency()] tv_text = f'//@version=4\nstrategy("{study_name}", overlay=true, initial_capital={starting_balance}, commission_type=strategy.commission.percent, commission_value=0.2)\n' for i, t in enumerate(store.completed_trades.trades[::-1][:]): tv_text += '\n' for j, o in enumerate(t.orders): when = f"time_close == {int(o.executed_at)}" if int(o.executed_at) % (jh.timeframe_to_one_minutes(t.timeframe) * 60_000) != 0: when = f"time_close >= {int(o.executed_at)} and time_close - {int(o.executed_at) + jh.timeframe_to_one_minutes(t.timeframe) * 60_000} < {jh.timeframe_to_one_minutes(t.timeframe) * 60_000}" if j == len(t.orders) - 1: tv_text += f'strategy.close("{i}", when = {when})\n' else: tv_text += f'strategy.order("{i}", {1 if t.type == "long" else 0}, {abs(o.qty)}, {o.price}, when = {when})\n' path = f'storage/trading-view-pine-editor/{study_name}.txt' os.makedirs('./storage/trading-view-pine-editor', exist_ok=True) with open(path, 'w+') as outfile: outfile.write(tv_text) print(f'\nPine-editor output saved at: \n{path}')
def save_daily_portfolio_balance() -> None: balances = [] # add exchange balances for key, e in store.exchanges.storage.items(): balances.append(e.assets[jh.app_currency()]) # # store daily_balance of assets into database # if jh.is_livetrading(): # for asset_key, asset_value in e.assets.items(): # store_daily_balance_into_db({ # 'id': jh.generate_unique_id(), # 'timestamp': jh.now(), # 'identifier': jh.get_config('env.identifier', 'main'), # 'exchange': e.name, # 'asset': asset_key, # 'balance': asset_value, # }) # add open position values for key, pos in store.positions.storage.items(): if pos.is_open: balances.append(pos.pnl) total = sum(balances) store.app.daily_balance.append(total) # TEMP: disable storing in database for now if not jh.is_livetrading(): logger.info(f'Saved daily portfolio balance: {round(total, 2)}')
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 save_daily_portfolio_balance(): balances = [] # add exchange balances for key, e in store.exchanges.storage.items(): balances.append(e.assets[helpers.app_currency()]) # add open position values for key, pos in store.positions.storage.items(): if pos.is_open: balances.append(pos.pnl) total = sum(balances) store.app.daily_balance.append(total) logger.info('Saved daily portfolio balance: {}'.format(round(total, 2)))
def positions() -> list: arr = [] for r in router.routes: if r.strategy is None: continue p: Position = r.strategy.position arr.append({ 'currency': jh.app_currency(), 'type': p.type, 'strategy_name': p.strategy.name, 'symbol': p.symbol, 'leverage': p.leverage, 'opened_at': p.opened_at, 'qty': p.qty, 'value': round(p.value, 2), 'entry': p.entry_price, 'current_price': p.current_price, 'liq_price': p.liquidation_price, 'pnl': p.pnl, 'pnl_perc': p.pnl_percentage }) return arr
def livetrade() -> List[Union[List[Union[str, Any]], List[str], List[Union[ str, int]], List[Union[str, Dict[str, Union[str, int]], Dict[ str, str], Dict[str, bool], Dict[str, Union[Dict[str, Union[ int, str, List[Dict[str, Union[str, int]]]]], Dict[str, Union[ float, str, int, List[Dict[str, Union[str, int]]]]]]], Dict[ str, int]]]]]: # sum up balance of all trading exchanges starting_balance = 0 current_balance = 0 for e in store.exchanges.storage: starting_balance += store.exchanges.storage[e].starting_assets[ jh.app_currency()] current_balance += store.exchanges.storage[e].assets[jh.app_currency()] starting_balance = round(starting_balance, 2) current_balance = round(current_balance, 2) arr = [[ 'started at', jh.timestamp_to_arrow(store.app.starting_time).humanize() ], ['current time', jh.timestamp_to_time(jh.now_to_timestamp())[:19]], ['errors/info', f'{len(store.logs.errors)}/{len(store.logs.info)}'], ['active orders', store.orders.count_all_active_orders()], ['open positions', store.positions.count_open_positions()]] # TODO: for now, we assume that we trade on one exchange only. Later, we need to support for more than one exchange at a time first_exchange = selectors.get_exchange(router.routes[0].exchange) if first_exchange.type == 'futures': arr.append([ 'started/current balance', f'{starting_balance}/{current_balance}' ]) else: # loop all trading exchanges for exchange in selectors.get_all_exchanges(): # loop all assets for asset_name, asset_balance in exchange.assets.items(): if asset_name == jh.base_asset(router.routes[0].symbol): current_price = selectors.get_current_price( router.routes[0].exchange, router.routes[0].symbol) arr.append([ f'{asset_name}', f'{round(exchange.available_assets[asset_name], 5)}/{round(asset_balance, 5)} ({jh.format_currency(round(asset_balance * current_price, 2))} { jh.quote_asset(router.routes[0].symbol)})' ]) else: arr.append([ f'{asset_name}', f'{round(exchange.available_assets[asset_name], 5)}/{round(asset_balance, 5)}' ]) # short trades summary if len(store.completed_trades.trades): df = pd.DataFrame.from_records( [t.to_dict() for t in store.completed_trades.trades]) total = len(df) winning_trades = df.loc[df['PNL'] > 0] losing_trades = df.loc[df['PNL'] < 0] pnl = round(df['PNL'].sum(), 2) pnl_percentage = round((pnl / starting_balance) * 100, 2) arr.append([ 'total/winning/losing trades', f'{total}/{len(winning_trades)}/{len(losing_trades)}' ]) arr.append(['PNL (%)', f'${pnl} ({pnl_percentage}%)']) if config['app']['debug_mode']: arr.append(['debug mode', config['app']['debug_mode']]) if config['app']['is_test_driving']: arr.append(['Test Drive', config['app']['is_test_driving']]) return arr
def trades(trades_list: list, daily_balance: list) -> dict: starting_balance = 0 current_balance = 0 for e in store.exchanges.storage: starting_balance += store.exchanges.storage[e].starting_assets[ jh.app_currency()] current_balance += store.exchanges.storage[e].assets[jh.app_currency()] if len(trades_list) == 0: return None df = pd.DataFrame.from_records([t.to_dict() for t in trades_list]) total_completed = len(df) winning_trades = df.loc[df['PNL'] > 0] total_winning_trades = len(winning_trades) losing_trades = df.loc[df['PNL'] < 0] total_losing_trades = len(losing_trades) arr = df['PNL'].to_numpy() pos = np.clip(arr, 0, 1).astype(bool).cumsum() neg = np.clip(arr, -1, 0).astype(bool).cumsum() current_streak = np.where( arr >= 0, pos - np.maximum.accumulate(np.where(arr <= 0, pos, 0)), -neg + np.maximum.accumulate(np.where(arr >= 0, neg, 0))) s_min = current_streak.min() losing_streak = 0 if s_min > 0 else abs(s_min) s_max = current_streak.max() winning_streak = 0 if s_max < 0 else s_max largest_losing_trade = df['PNL'].min() largest_winning_trade = df['PNL'].max() win_rate = len(winning_trades) / (len(losing_trades) + len(winning_trades)) max_R = df['R'].max() min_R = df['R'].min() mean_R = df['R'].mean() longs_count = len(df.loc[df['type'] == 'long']) shorts_count = len(df.loc[df['type'] == 'short']) longs_percentage = longs_count / (longs_count + shorts_count) * 100 short_percentage = 100 - longs_percentage fee = df['fee'].sum() net_profit = df['PNL'].sum() net_profit_percentage = (net_profit / starting_balance) * 100 average_win = winning_trades['PNL'].mean() average_loss = abs(losing_trades['PNL'].mean()) ratio_avg_win_loss = average_win / average_loss expectancy = (0 if np.isnan(average_win) else average_win) * win_rate - ( 0 if np.isnan(average_loss) else average_loss) * (1 - win_rate) expectancy = expectancy expectancy_percentage = (expectancy / starting_balance) * 100 expected_net_profit_every_100_trades = expectancy_percentage * 100 average_holding_period = df['holding_period'].mean() average_winning_holding_period = winning_trades['holding_period'].mean() average_losing_holding_period = losing_trades['holding_period'].mean() gross_profit = df.loc[df['PNL'] > 0]['PNL'].sum() gross_loss = df.loc[df['PNL'] < 0]['PNL'].sum() daily_returns = pd.Series(daily_balance).pct_change(1).values max_drawdown = crypto_empyrical.max_drawdown(daily_returns) * 100 annual_return = crypto_empyrical.annual_return(daily_returns) * 100 sharpe_ratio = crypto_empyrical.sharpe_ratio(daily_returns) calmar_ratio = crypto_empyrical.calmar_ratio(daily_returns) sortino_ratio = crypto_empyrical.sortino_ratio(daily_returns) omega_ratio = crypto_empyrical.omega_ratio(daily_returns) total_open_trades = store.app.total_open_trades open_pl = store.app.total_open_pl return { 'total': np.nan if np.isnan(total_completed) else total_completed, 'total_winning_trades': np.nan if np.isnan(total_winning_trades) else total_winning_trades, 'total_losing_trades': np.nan if np.isnan(total_losing_trades) else total_losing_trades, 'starting_balance': np.nan if np.isnan(starting_balance) else starting_balance, 'finishing_balance': np.nan if np.isnan(current_balance) else current_balance, 'win_rate': np.nan if np.isnan(win_rate) else win_rate, 'max_R': np.nan if np.isnan(max_R) else max_R, 'min_R': np.nan if np.isnan(min_R) else min_R, 'mean_R': np.nan if np.isnan(mean_R) else mean_R, 'ratio_avg_win_loss': np.nan if np.isnan(ratio_avg_win_loss) else ratio_avg_win_loss, 'longs_count': np.nan if np.isnan(longs_count) else longs_count, 'longs_percentage': np.nan if np.isnan(longs_percentage) else longs_percentage, 'short_percentage': np.nan if np.isnan(short_percentage) else short_percentage, 'shorts_count': np.nan if np.isnan(shorts_count) else shorts_count, 'fee': np.nan if np.isnan(fee) else fee, 'net_profit': np.nan if np.isnan(net_profit) else net_profit, 'net_profit_percentage': np.nan if np.isnan(net_profit_percentage) else net_profit_percentage, 'average_win': np.nan if np.isnan(average_win) else average_win, 'average_loss': np.nan if np.isnan(average_loss) else average_loss, 'expectancy': np.nan if np.isnan(expectancy) else expectancy, 'expectancy_percentage': np.nan if np.isnan(expectancy_percentage) else expectancy_percentage, 'expected_net_profit_every_100_trades': np.nan if np.isnan(expected_net_profit_every_100_trades) else expected_net_profit_every_100_trades, 'average_holding_period': average_holding_period, 'average_winning_holding_period': average_winning_holding_period, 'average_losing_holding_period': average_losing_holding_period, 'gross_profit': gross_profit, 'gross_loss': gross_loss, 'max_drawdown': max_drawdown, 'annual_return': annual_return, 'sharpe_ratio': sharpe_ratio, 'calmar_ratio': calmar_ratio, 'sortino_ratio': sortino_ratio, 'omega_ratio': omega_ratio, 'total_open_trades': total_open_trades, 'open_pl': open_pl, 'winning_streak': winning_streak, 'losing_streak': losing_streak, 'largest_losing_trade': largest_losing_trade, 'largest_winning_trade': largest_winning_trade, 'current_streak': current_streak[-1], }
def trades(trades_list: list, daily_balance: list): starting_balance = 0 current_balance = 0 for e in store.exchanges.storage: starting_balance += store.exchanges.storage[e].starting_assets[ jh.app_currency()] current_balance += store.exchanges.storage[e].assets[jh.app_currency()] starting_balance = round(starting_balance, 2) current_balance = round(current_balance, 2) if len(trades_list) == 0: return None df = pd.DataFrame.from_records([t.to_dict() for t in trades_list]) total_completed = len(df) winning_trades = df.loc[df['PNL'] > 0] total_winning_trades = len(winning_trades) losing_trades = df.loc[df['PNL'] < 0] total_losing_trades = len(losing_trades) losing_i = df['PNL'] < 0 losing_streaks = losing_i.ne(losing_i.shift()).cumsum() losing_streak = losing_streaks[losing_i].value_counts().max() winning_i = df['PNL'] > 0 winning_streaks = winning_i.ne(winning_i.shift()).cumsum() winning_streak = winning_streaks[winning_i].value_counts().max() largest_losing_trade = round(df['PNL'].min(), 2) largest_winning_trade = round(df['PNL'].max(), 2) win_rate = len(winning_trades) / (len(losing_trades) + len(winning_trades)) max_R = round(df['R'].max(), 2) min_R = round(df['R'].min(), 2) mean_R = round(df['R'].mean(), 2) longs_count = len(df.loc[df['type'] == 'long']) shorts_count = len(df.loc[df['type'] == 'short']) longs_percentage = longs_count / (longs_count + shorts_count) * 100 short_percentage = 100 - longs_percentage fee = df['fee'].sum() net_profit = round(df['PNL'].sum(), 2) net_profit_percentage = round((net_profit / starting_balance) * 100, 2) average_win = round(winning_trades['PNL'].mean(), 2) average_loss = round(abs(losing_trades['PNL'].mean()), 2) ratio_avg_win_loss = average_win / average_loss expectancy = (0 if np.isnan(average_win) else average_win) * win_rate - ( 0 if np.isnan(average_loss) else average_loss) * (1 - win_rate) expectancy = round(expectancy, 2) expectancy_percentage = round((expectancy / starting_balance) * 100, 2) expected_net_profit_every_100_trades = round(expectancy_percentage * 100, 2) average_holding_period = df['holding_period'].mean() average_winning_holding_period = winning_trades['holding_period'].mean() average_losing_holding_period = losing_trades['holding_period'].mean() gross_profit = round(df.loc[df['PNL'] > 0]['PNL'].sum(), 2) gross_loss = round(df.loc[df['PNL'] < 0]['PNL'].sum(), 2) daily_returns = pd.Series(daily_balance).pct_change(1).values max_drawdown = round(crypto_empyrical.max_drawdown(daily_returns) * 100, 2) annual_return = round( crypto_empyrical.annual_return(daily_returns) * 100, 2) sharpe_ratio = round(crypto_empyrical.sharpe_ratio(daily_returns), 2) calmar_ratio = round(crypto_empyrical.calmar_ratio(daily_returns), 2) sortino_ratio = round(crypto_empyrical.sortino_ratio(daily_returns), 2) omega_ratio = round(crypto_empyrical.omega_ratio(daily_returns), 2) total_open_trades = store.app.total_open_trades open_pl = store.app.total_open_pl return { 'total': np.nan if np.isnan(total_completed) else total_completed, 'total_winning_trades': np.nan if np.isnan(total_winning_trades) else total_winning_trades, 'total_losing_trades': np.nan if np.isnan(total_losing_trades) else total_losing_trades, 'starting_balance': np.nan if np.isnan(starting_balance) else starting_balance, 'finishing_balance': np.nan if np.isnan(current_balance) else current_balance, 'win_rate': np.nan if np.isnan(win_rate) else win_rate, 'max_R': np.nan if np.isnan(max_R) else max_R, 'min_R': np.nan if np.isnan(min_R) else min_R, 'mean_R': np.nan if np.isnan(mean_R) else mean_R, 'ratio_avg_win_loss': np.nan if np.isnan(ratio_avg_win_loss) else ratio_avg_win_loss, 'longs_count': np.nan if np.isnan(longs_count) else longs_count, 'longs_percentage': np.nan if np.isnan(longs_percentage) else longs_percentage, 'short_percentage': np.nan if np.isnan(short_percentage) else short_percentage, 'shorts_count': np.nan if np.isnan(shorts_count) else shorts_count, 'fee': np.nan if np.isnan(fee) else fee, 'net_profit': np.nan if np.isnan(net_profit) else net_profit, 'net_profit_percentage': np.nan if np.isnan(net_profit_percentage) else net_profit_percentage, 'average_win': np.nan if np.isnan(average_win) else average_win, 'average_loss': np.nan if np.isnan(average_loss) else average_loss, 'expectancy': np.nan if np.isnan(expectancy) else expectancy, 'expectancy_percentage': np.nan if np.isnan(expectancy_percentage) else expectancy_percentage, 'expected_net_profit_every_100_trades': np.nan if np.isnan(expected_net_profit_every_100_trades) else expected_net_profit_every_100_trades, 'average_holding_period': average_holding_period, 'average_winning_holding_period': average_winning_holding_period, 'average_losing_holding_period': average_losing_holding_period, 'gross_profit': gross_profit, 'gross_loss': gross_loss, 'max_drawdown': max_drawdown, 'annual_return': annual_return, 'sharpe_ratio': sharpe_ratio, 'calmar_ratio': calmar_ratio, 'sortino_ratio': sortino_ratio, 'omega_ratio': omega_ratio, 'total_open_trades': total_open_trades, 'open_pl': open_pl, 'winning_streak': winning_streak, 'losing_streak': losing_streak, 'largest_losing_trade': largest_losing_trade, 'largest_winning_trade': largest_winning_trade, }
def trades(trades_list: List[CompletedTrade], daily_balance: list, final: bool = True) -> dict: starting_balance = 0 current_balance = 0 for e in store.exchanges.storage: starting_balance += store.exchanges.storage[e].starting_assets[ jh.app_currency()] current_balance += store.exchanges.storage[e].assets[jh.app_currency()] if not trades_list: return {'total': 0, 'win_rate': 0, 'net_profit_percentage': 0} df = pd.DataFrame.from_records([t.to_dict() for t in trades_list]) total_completed = len(df) winning_trades = df.loc[df['PNL'] > 0] total_winning_trades = len(winning_trades) losing_trades = df.loc[df['PNL'] < 0] total_losing_trades = len(losing_trades) arr = df['PNL'].to_numpy() pos = np.clip(arr, 0, 1).astype(bool).cumsum() neg = np.clip(arr, -1, 0).astype(bool).cumsum() current_streak = np.where( arr >= 0, pos - np.maximum.accumulate(np.where(arr <= 0, pos, 0)), -neg + np.maximum.accumulate(np.where(arr >= 0, neg, 0))) s_min = current_streak.min() losing_streak = 0 if s_min > 0 else abs(s_min) s_max = current_streak.max() winning_streak = max(s_max, 0) largest_losing_trade = 0 if total_losing_trades == 0 else losing_trades[ 'PNL'].min() largest_winning_trade = 0 if total_winning_trades == 0 else winning_trades[ 'PNL'].max() win_rate = len(winning_trades) / (len(losing_trades) + len(winning_trades)) longs_count = len(df.loc[df['type'] == 'long']) shorts_count = len(df.loc[df['type'] == 'short']) longs_percentage = longs_count / (longs_count + shorts_count) * 100 shorts_percentage = 100 - longs_percentage fee = df['fee'].sum() net_profit = df['PNL'].sum() net_profit_percentage = (net_profit / starting_balance) * 100 average_win = winning_trades['PNL'].mean() average_loss = abs(losing_trades['PNL'].mean()) ratio_avg_win_loss = average_win / average_loss expectancy = (0 if np.isnan(average_win) else average_win) * win_rate - ( 0 if np.isnan(average_loss) else average_loss) * (1 - win_rate) expectancy = expectancy expectancy_percentage = (expectancy / starting_balance) * 100 expected_net_profit_every_100_trades = expectancy_percentage * 100 average_holding_period = df['holding_period'].mean() average_winning_holding_period = winning_trades['holding_period'].mean() average_losing_holding_period = losing_trades['holding_period'].mean() gross_profit = winning_trades['PNL'].sum() gross_loss = losing_trades['PNL'].sum() start_date = datetime.fromtimestamp(store.app.starting_time / 1000) date_index = pd.date_range(start=start_date, periods=len(daily_balance)) daily_return = pd.DataFrame(daily_balance, index=date_index).pct_change(1) total_open_trades = store.app.total_open_trades open_pl = store.app.total_open_pl max_drawdown = np.nan annual_return = np.nan sharpe_ratio = np.nan calmar_ratio = np.nan sortino_ratio = np.nan omega_ratio = np.nan serenity_index = np.nan smart_sharpe = np.nan smart_sortino = np.nan if len(daily_return) > 2: max_drawdown = stats.max_drawdown(daily_return).values[0] * 100 annual_return = stats.cagr(daily_return).values[0] * 100 sharpe_ratio = stats.sharpe(daily_return, periods=365).values[0] calmar_ratio = stats.calmar(daily_return).values[0] sortino_ratio = stats.sortino(daily_return, periods=365).values[0] omega_ratio = stats.omega(daily_return, periods=365) serenity_index = stats.serenity_index(daily_return).values[0] # As those calculations are slow they are only done for the final report and not at self.metrics in the strategy. if final: smart_sharpe = stats.smart_sharpe(daily_return, periods=365).values[0] smart_sortino = stats.smart_sortino(daily_return, periods=365).values[0] return { 'total': np.nan if np.isnan(total_completed) else total_completed, 'total_winning_trades': np.nan if np.isnan(total_winning_trades) else total_winning_trades, 'total_losing_trades': np.nan if np.isnan(total_losing_trades) else total_losing_trades, 'starting_balance': np.nan if np.isnan(starting_balance) else starting_balance, 'finishing_balance': np.nan if np.isnan(current_balance) else current_balance, 'win_rate': np.nan if np.isnan(win_rate) else win_rate, 'ratio_avg_win_loss': np.nan if np.isnan(ratio_avg_win_loss) else ratio_avg_win_loss, 'longs_count': np.nan if np.isnan(longs_count) else longs_count, 'longs_percentage': np.nan if np.isnan(longs_percentage) else longs_percentage, 'shorts_percentage': np.nan if np.isnan(shorts_percentage) else shorts_percentage, 'shorts_count': np.nan if np.isnan(shorts_count) else shorts_count, 'fee': np.nan if np.isnan(fee) else fee, 'net_profit': np.nan if np.isnan(net_profit) else net_profit, 'net_profit_percentage': np.nan if np.isnan(net_profit_percentage) else net_profit_percentage, 'average_win': np.nan if np.isnan(average_win) else average_win, 'average_loss': np.nan if np.isnan(average_loss) else average_loss, 'expectancy': np.nan if np.isnan(expectancy) else expectancy, 'expectancy_percentage': np.nan if np.isnan(expectancy_percentage) else expectancy_percentage, 'expected_net_profit_every_100_trades': np.nan if np.isnan(expected_net_profit_every_100_trades) else expected_net_profit_every_100_trades, 'average_holding_period': average_holding_period, 'average_winning_holding_period': average_winning_holding_period, 'average_losing_holding_period': average_losing_holding_period, 'gross_profit': gross_profit, 'gross_loss': gross_loss, 'max_drawdown': np.nan if np.isnan(max_drawdown) else max_drawdown, 'annual_return': np.nan if np.isnan(annual_return) else annual_return, 'sharpe_ratio': np.nan if np.isnan(sharpe_ratio) else sharpe_ratio, 'calmar_ratio': np.nan if np.isnan(calmar_ratio) else calmar_ratio, 'sortino_ratio': np.nan if np.isnan(sortino_ratio) else sortino_ratio, 'omega_ratio': np.nan if np.isnan(omega_ratio) else omega_ratio, 'serenity_index': np.nan if np.isnan(serenity_index) else serenity_index, 'smart_sharpe': np.nan if np.isnan(smart_sharpe) else smart_sharpe, 'smart_sortino': np.nan if np.isnan(smart_sortino) else smart_sortino, 'total_open_trades': total_open_trades, 'open_pl': open_pl, 'winning_streak': winning_streak, 'losing_streak': losing_streak, 'largest_losing_trade': largest_losing_trade, 'largest_winning_trade': largest_winning_trade, 'current_streak': current_streak[-1], }