Skip to content

Latest commit

 

History

29 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rolling Leverage Optimization Benchmarks

This project investigates a numerical optimization problem from the Leverage Optimization tool of my portfolio backtesting website doradoquant.com: given a historical price series, what constant daily leverage would have produced the highest compounded growth over each rolling window?

The goal is not to build another backtesting interface. It is to isolate and benchmark the mathematical component that repeatedly solves this problem so I can make an informed implementation choice for my web application. The rolling calculation may run thousands of related optimizations for one price series, so the choice of numerical method directly affects user-facing latency.

Why this project matters

This benchmark isolates the rolling-leverage optimization used by the Leverage Optimization tool on my portfolio backtesting website, doradoquant.com.

The calculation repeatedly solves closely related optimization problems across a price series. Since a single request may require thousands of rolling-window solves, numerical method selection can affect both runtime and user experience.

The notebook compares several methods under the same objective, data, leverage bounds, and stopping criteria. It measures elapsed time and internal computation counts, then varies the rolling period, tolerance, and leverage range to identify where each method performs best.

The results provide a practical basis for selecting the default optimizer in the website while retaining an alternative method for short-window workloads and robustness comparisons.

Optimization problem

For a constant leverage $L$ and daily returns $r_i$, the portfolio value after $n$ trading days is proportional to

$$ V_n(L) = \prod_{i=1}^{n}(1 + Lr_i). $$

Maximizing the logarithm is equivalent to maximizing the compounded value and is more convenient numerically:

$$ f(L) = \sum_{i=1}^{n}\log(1 + Lr_i). $$

The optimizers find the root of the first derivative,

$$ f'(L) = \sum_{i=1}^{n}\frac{r_i}{1 + Lr_i}, $$

within a configurable leverage interval. The valid domain must also satisfy

$$ 1 + Lr_i > 0 \quad \text{for every return } r_i, $$

so that no leveraged daily return produces a portfolio value at or below zero. Because the objective is concave over this domain, a valid derivative root is the maximum; if the root is outside the requested interval, the constrained solution is at a bound.

Algorithms compared

Each implementation follows the same RollingLeverageOptimizer interface and solves both the full price history and every complete rolling return window. The benchmark compares:

  1. Brent's method — a bracketed root-finding method applied directly to the derivative. It does not depend on an initial guess and provides a robust baseline.
  2. Newton-Raphson starting from 1 — uses the same fixed initial leverage for every window.
  3. Newton-Raphson starting from the overall optimum — uses the full-history solution as the initial guess for every rolling window.
  4. Newton-Raphson with a warm start — uses the previous rolling window's solution as the next initial guess, exploiting the overlap between adjacent windows.

The Newton implementations are safeguarded: they respect the valid leverage domain and fall back to Brent's method if a Newton step becomes invalid or fails to converge normally. This combines the speed of Newton iterations with a reliability mechanism for difficult windows.

Every run returns:

  • the full-history optimal leverage;
  • the time-indexed rolling optimal-leverage series;
  • the number of internal objective/derivative evaluations;
  • elapsed runtime.

Using both elapsed time and internal computation count helps distinguish machine-dependent timing noise from the amount of work performed by an algorithm.

Experiment design

The notebook downloads SPY's complete available adjusted closing-price history from Yahoo Finance. Adjusted prices account for splits and distributions, which makes the resulting returns more appropriate for a long-term compounding comparison.

The practical baseline is:

  • rolling period: 1,260 trading days (approximately five years);
  • derivative tolerance: $10^{-4}$;
  • leverage bounds: $[-5, 5]$.

The benchmark first compares all four methods under this shared configuration. It then varies one setting at a time while keeping the others at the baseline:

  • Rolling period: short tactical windows through windows approaching the size of the dataset;
  • Tolerance: from $10^{-1}$ through $10^{-7}$, compared with a $10^{-10}$ reference run;
  • Leverage range: symmetric half-widths from $0.5$ to $10$ around a center of zero.

The sensitivity analysis records total and per-solve runtime, total and average internal computations, the resulting leverage statistics, and the fraction of rolling solutions that reach a requested bound. Tolerance experiments also compare each optimizer with its own tighter reference solution, so numerical accuracy is evaluated independently of the optimizer choice.

Results

Baseline comparison

The optimizers produced matching rolling-leverage results, confirming that the methods were solving the same optimization problem.

Optimizer accuracy verification

Under the baseline configuration—1,260-day rolling period, $10^{-4}$ tolerance, and leverage bounds of $[-5, 5]$—warm-start Newton-Raphson was the fastest and required the fewest internal computations.

Optimizer Elapsed time (seconds) Internal computations
Newton-Raphson (warm start) 0.2586 17,156
Newton-Raphson (start = 1) 0.3002 22,063
Newton-Raphson (start = overall) 0.3011 21,446
Brent's method 0.3206 42,914

Rolling-period sensitivity

These figures show how total runtime and per-solve runtime change as the rolling period increases.

Rolling-period sensitivity: elapsed time

Rolling-period sensitivity: internal computations

The results show that Brent's method is competitive for short rolling periods, while warm-start Newton-Raphson becomes more efficient for longer windows.

Tolerance sensitivity

These figures show how runtime, internal computation count, and leverage accuracy change as the numerical tolerance becomes tighter.

Tolerance sensitivity: runtime and computations

Tolerance sensitivity: leverage error

Tighter tolerances generally increase computational cost. The comparison with a tighter reference solution helps evaluate the resulting leverage difference rather than treating the stopping tolerance as a direct accuracy guarantee.

Leverage-bound sensitivity

These figures show how the requested leverage range affects optimizer performance and how often rolling solutions reach a requested bound.

Leverage-bound sensitivity: runtime and computations

Leverage-bound sensitivity: bound hits

The warm-start method remained the strongest overall performer across the tested leverage ranges, while wider ranges made its performance advantage more apparent.

Overall conclusions

The experiments produced a clear, practical result: Newton-Raphson with a warm start is the strongest general-purpose method for this rolling problem.

  • Warm-start Newton-Raphson is the preferred default for longer windows. Adjacent rolling windows overlap heavily, so the previous solution is an effective initial estimate. This method generally delivered the lowest runtime and fewest internal computations once the rolling period moved past the shortest-window region. Its advantage was visible across the tested tolerances and leverage ranges, especially with looser tolerances and wider intervals.
  • Brent's method is valuable for short windows and as a robustness reference. It was faster for rolling periods below approximately 100 trading days and used fewer computations for the shortest windows, particularly below roughly 21 days. Its bracketing behavior makes it a useful independent comparison even though it is not the best default for the five-year rolling analysis.
  • Total workload and per-solve efficiency tell different stories. Short rolling periods create many more windows. As the period grows, the number of windows falls while the cost of each solve increases. A useful approximation is $W(p) \propto p(N-p)$, where $N$ is the number of returns and $p$ is the rolling period; this explains why total work can peak near half the dataset length even though the longest individual windows are the most expensive.
  • Tolerance should be chosen by leverage accuracy, not runtime alone. Looser tolerances can reduce work, but the acceptable value depends on how much leverage difference the application can tolerate. The reference comparisons make that tradeoff visible rather than treating the stopping tolerance as a direct guarantee of leverage accuracy.
  • Bounds are both a practical constraint and a numerical control. They represent the investable leverage range and can change the constrained solution when the unconstrained optimum lies outside the interval. Wider intervals also made the warm-start advantage more apparent in the benchmark.

For the portfolio tool, the resulting recommendation is to use warm-start Newton-Raphson with the $1{,}260$-day, $10^{-4}$, $[-5, 5]$ baseline as the default configuration, while keeping Brent's method available for short-window workloads and independent robustness checks.

Running the notebook

  1. Open the repository in VS Code.
  2. Create or select the repository's .venv Python interpreter for the notebook.
  3. Install the dependencies listed in requirements.txt.
  4. Open src/rolling-leverage-optimization-benchmarks.ipynb and run the cells from top to bottom.

The first data cell downloads adjusted SPY prices from Yahoo Finance and therefore requires internet access. The sensitivity experiments perform many optimizer runs and may take substantially longer than the introductory benchmark.

Repository structure

finmath/
  __init__.py       Public optimizer exports
  optimizers.py     Shared interface and numerical implementations
src/
  rolling-leverage-optimization-benchmarks.ipynb
                    Benchmark, plots, sensitivity analysis, and conclusions
requirements.txt    Python dependencies

Technologies

The implementation uses Python, NumPy, pandas, SciPy, Matplotlib, and yfinance. The notebook is designed to run interactively in Jupyter through VS Code, while the optimizer classes remain reusable as a small standalone Python package.

About

High-performance benchmarking of warm-started numerical solvers, closed-form approximations, and vectorized methods for rolling daily leverage optimization in quantitative portfolio management.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages