Add cash-deploy backtest that buys drawdowns from a cash reserve - #2
Merged
Conversation
Add a tactical cash-deployment strategy: hold a cash reserve at the fed funds rate, deploy it into stocks in tranches as the S&P draws down from its all-time high, and drip it back toward the target reserve at new highs. Includes named deploy rules (Käyttäjän sääntö, Kasvuoptimi, Riskioptimi, Suositus), a dedicated stateful engine, a Streamlit page, and comparison baselines (100% stocks, static split) via the existing simulator. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new “tactical cash-deployment” backtest path to the Portfolio Research Lab: maintaining a cash reserve that deploys into equities in tranches on drawdowns from ATH, then refills back toward a target reserve at new highs, with UI + shared data-loading support and expanded tests.
Changes:
- Introduces a stateful cash-deploy simulation engine (
run_cash_deploy) plus result object and event log. - Adds new Pydantic models for deploy rules/config and ships four named preset rules.
- Adds a Sharpe ratio metric (including vs-cash usage), a shared
load_stocks_cashloader, a new Streamlit “Cash Deploy” page, and comprehensive tests.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_models.py | Adds validation coverage for DeployRule, CashDeployConfig, and preset rules. |
| tests/test_metrics.py | Adds unit tests for the new Sharpe ratio metric. |
| tests/test_data.py | Adds tests for the shared load_stocks_cash loader behavior and validation. |
| tests/test_cash_deploy.py | Adds end-to-end tests for deploy/refill mechanics and event schema. |
| tests/conftest.py | Adds a reusable hand-checkable stocks+cash fixture for cash-deploy tests. |
| src/portfolio_research_lab/models.py | Adds DeployRule, CashDeployConfig, and preset deploy rules. |
| src/portfolio_research_lab/metrics.py | Adds sharpe_ratio metric used by the new UI. |
| src/portfolio_research_lab/data.py | Adds load_stocks_cash to centralize construction of the stocks+cash price frame. |
| src/portfolio_research_lab/cash_deploy.py | New path-dependent cash-deployment engine with deploy/refill event logging. |
| app/pages/1_Cash_Deploy.py | New Streamlit multipage UI for the cash-deploy strategy + baselines and event log. |
| app/Home.py | Refactors existing stocks+cash loading to reuse data.load_stocks_cash. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+69
to
+79
| if len(returns) < 2: | ||
| return 0.0 | ||
| if isinstance(risk_free, pd.Series): | ||
| rf: pd.Series | float = risk_free.reindex(returns.index).fillna(0.0) | ||
| else: | ||
| rf = risk_free | ||
| excess = returns - rf | ||
| vol = annualized_volatility(excess, periods_per_year) | ||
| if vol == 0.0: | ||
| return 0.0 | ||
| return float(excess.mean() * periods_per_year / vol) |
Rename the four preset deploy rules from Finnish to English: User rule, Growth optimum, Risk optimum, Recommended. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
cash reserve (money-market at the fed funds rate), deploy it into stocks in
tranches as the S&P 500 draws down from its all-time high, then drip it back
toward the target reserve at new highs. The question it answers: does buying
drawdowns from a reserve beat a plain static stock/cash split?
Kasvuoptimi, Riskioptimi, Suositus — plus a custom-rule builder.
cash_deploy.py) with a tranche base lockedper drawdown episode; the existing fixed-weight
run_simulationis reused forthe 100% stocks and static split comparison baselines.
vs. cash), equity curve, stock/cash composition chart, drawdown, and a
deploy/refill event log. The stocks+cash loader is shared into
data.load_stocks_cashsoHome.pyand the new page use one implementation.which understates equity returns and mildly favours cash — surfaced as a
caveat on the page.
How to test
Verified on real data (1954–2026): the reserve deploys progressively through the
2008 and 2020 drawdowns and refills on recovery; cash stays ≥ 0 and equity > 0
across all 18,127 days. 89 tests pass; lint + typecheck green.
Security review
No security-impacting changes.