diff --git a/tests/backtest/test_backtest_profit_calculation.py b/tests/backtest/test_backtest_profit_calculation.py index 8fcb6c9c6..71b9755ef 100644 --- a/tests/backtest/test_backtest_profit_calculation.py +++ b/tests/backtest/test_backtest_profit_calculation.py @@ -297,11 +297,22 @@ def test_daily_returns(backtest_result_hourly: State): """ cum_profit = calculate_cumulative_daily_returns(backtest_result_hourly) assert isinstance(cum_profit, pd.Series) + + # remove last entry, since it was added to fill the gap + cum_profit = cum_profit[:-1] non_cum_profit = calculate_non_cumulative_daily_returns(backtest_result_hourly) assert isinstance(non_cum_profit, pd.Series) - non_cum_profit.add(1).cumprod().sub(1).iloc[-1] == pytest.approx(cum_profit.iloc[-1], abs=1e-10) + cum_profit_2 = non_cum_profit.add(1).cumprod().sub(1) + + assert cum_profit.index.equals(cum_profit_2.index) + + assert all(cum_profit - cum_profit_2 < 1e-10) + + assert cum_profit_2.iloc[-3] == pytest.approx(cum_profit.iloc[-3], abs=1e-10) + assert cum_profit_2.iloc[-2] == pytest.approx(cum_profit.iloc[-2], abs=1e-10) + assert cum_profit_2.iloc[-1] == pytest.approx(cum_profit.iloc[-1], abs=1e-10) def test_profitabilities_are_same(backtest_result_hourly: State): diff --git a/tests/test_state.py b/tests/test_state.py index 18a2a7d68..c6f380ac4 100644 --- a/tests/test_state.py +++ b/tests/test_state.py @@ -503,6 +503,7 @@ def test_statistics(usdc, weth_usdc, aave_usdc, start_ts): assert stats.long_short_metrics_latest["live_stats"].rows['won_positions'].value['Long'] == '1' assert stats.long_short_metrics_latest["live_stats"].rows['won_positions'].value['Short'] == '0' assert stats.long_short_metrics_latest["live_stats"].rows['average_position'].value['Long'] == '25.00%' + assert stats.long_short_metrics_latest["live_stats"].rows['return_percent'].value['All'] == '4.91%' assert stats.long_short_metrics_latest["backtested_stats"].rows == {} assert len(stats.positions) == 2 diff --git a/tradeexecutor/statistics/statistics_table.py b/tradeexecutor/statistics/statistics_table.py index 38a4a199a..5816bf763 100644 --- a/tradeexecutor/statistics/statistics_table.py +++ b/tradeexecutor/statistics/statistics_table.py @@ -141,7 +141,7 @@ def _serialise_long_short_stats_as_json_table( if compounding_returns is not None and len(compounding_returns) > 0: daily_returns = calculate_non_cumulative_daily_returns(source_state) portfolio_return = compounding_returns.iloc[-1] - annualised_return_percent = portfolio_return * 365 * 24 * 60 * 60 / (calculation_window_end_at - calculation_window_start_at).seconds + annualised_return_percent = portfolio_return * 365 * 24 * 60 * 60 / (calculation_window_end_at - calculation_window_start_at).total_seconds() summary.loc['Return %']['All'] = format_value(as_percent(portfolio_return)) summary.loc['Annualised return %']['All'] = format_value(as_percent(annualised_return_percent)) diff --git a/tradeexecutor/visual/equity_curve.py b/tradeexecutor/visual/equity_curve.py index 4667e38c0..544a0f5a8 100644 --- a/tradeexecutor/visual/equity_curve.py +++ b/tradeexecutor/visual/equity_curve.py @@ -561,5 +561,5 @@ def calculate_cumulative_daily_returns(state: State, freq_base: pd.offsets.DateO """ returns = calculate_compounding_realised_trading_profitability(state) _returns = returns.copy() - cumulative_daily_returns = _returns.add(1).resample(freq_base).prod(min_count=1).sub(1).ffill() + cumulative_daily_returns = _returns.resample(freq_base).last().ffill() return cumulative_daily_returns \ No newline at end of file