Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RuntimeWarning: Degrees of freedom <= 0 for slice #1251

Closed
Goon83 opened this issue Mar 19, 2025 · 3 comments · Fixed by #1253
Closed

RuntimeWarning: Degrees of freedom <= 0 for slice #1251

Goon83 opened this issue Mar 19, 2025 · 3 comments · Fixed by #1253
Labels
bug Something isn't working

Comments

@Goon83
Copy link

Goon83 commented Mar 19, 2025

Expected behavior

from multiprocessing import Process, freeze_support, set_start_method
from backtesting import Backtest, Strategy
from backtesting.lib import crossover
from backtesting.test import SMA, GOOG

class SmaCross(Strategy):
    ma1_period = 10  # Default values
    ma2_period = 20

    def init(self):
        price = self.data.Close
        self.ma1 = self.I(SMA, price, self.ma1_period)
        self.ma2 = self.I(SMA, price, self.ma2_period)

    def next(self):
        if crossover(self.ma1, self.ma2):
            self.buy()
        elif crossover(self.ma2, self.ma1):
            self.position.close()

if __name__ == "__main__":
    freeze_support()
    bt = Backtest(GOOG, SmaCross, cash=10000000000000)

    # Optimize `ma1_period` and `ma2_period` in the range [5, 50] with step of 5
    stats = bt.optimize(
        ma1_period=range(5, 50, 5),
        ma2_period=range(5, 50, 5),  # Ensure ma2_period range makes sense in the context
        maximize='Sharpe Ratio',  # Optimize for best Sharpe ratio
    )

    bt.plot()
    print(stats)

Error happens at _stats.py:161:

if (len(equity_log_returns) == 0):
        print(len(equity_log_returns), len(market_log_returns))
        print(np.any(np.isnan(equity_log_returns)), np.any(np.isnan(market_log_returns)))
        print(np.any(np.isinf(equity_log_returns)), np.any(np.isinf(market_log_returns)))
        cov_matrix = np.cov(equity_log_returns, market_log_returns)

Errors info

0 0
False False
False False
.venv/lib/python3.13/site-packages/numpy/lib/_function_base_impl.py:552: RuntimeWarning: Mean of empty slice.
  avg = a.mean(axis, **keepdims_kw)
.venv/lib/python3.13/site-packages/numpy/_core/_methods.py:137: RuntimeWarning: invalid value encountered in divide
  ret = um.true_divide(
.venv/lib/python3.13/site-packages/backtesting/_stats.py:161: RuntimeWarning: Degrees of freedom <= 0 for slice
  cov_matrix = np.cov(equity_log_returns, market_log_returns)
.venv/lib/python3.13/site-packages/numpy/lib/_function_base_impl.py:2894: RuntimeWarning: divide by zero encountered in divide
  c *= np.true_divide(1, fact)
.venv/lib/python3.13/site-packages/numpy/lib/_function_base_impl.py:2894: RuntimeWarning: invalid value encountered in multiply
  c *= np.true_divide(1, fact)

Code sample

Actual behavior

eroor

Additional info, steps to reproduce, full crash traceback, screenshots

No response

Software versions

  • Backtesting version: 0.?.?
  • bokeh.__version__:
  • OS:
@Goon83
Copy link
Author

Goon83 commented Mar 19, 2025

backtesting 0.6.3

@Goon83 Goon83 changed the title Short title loaded with keywords RuntimeWarning: Degrees of freedom <= 0 for slice Mar 19, 2025
@kernc
Copy link
Owner

kernc commented Mar 20, 2025

Seems to warn on line:

cov_matrix = np.cov(equity_log_returns, market_log_returns)

@jensnesten Since git blames you for that line, would you happen to know what the issue is and how to mitigate? 😅

@kernc kernc added the bug Something isn't working label Mar 20, 2025
@jensnesten
Copy link
Contributor

This happens because there are cases where we dont have enough data points to calculate covariance. We can fix the warning by setting proper checks before calculating:

if len(equity_log_returns) > 1 and len(market_log_returns) > 1:
        cov_matrix = np.cov(equity_log_returns, market_log_returns)
        beta = cov_matrix[0, 1] / cov_matrix[1, 1]
        s.loc['Alpha [%]'] = s.loc['Return [%]'] - risk_free_rate * 100 - beta * (s.loc['Buy & Hold Return [%]'] - risk_free_rate * 100)  # noqa: E501
        s.loc['Beta'] = beta
    else:
        s.loc['Alpha [%]'] = np.nan
        s.loc['Beta'] = np.nan

kernc pushed a commit that referenced this issue Mar 26, 2025
Fixes #1251: covariance calculation for insufficient data points
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants