feat: add compounded flag to calmar() for non-compounded return streams#509
Open
wavebyrd wants to merge 385 commits intoranaroussi:mainfrom
Open
feat: add compounded flag to calmar() for non-compounded return streams#509wavebyrd wants to merge 385 commits intoranaroussi:mainfrom
wavebyrd wants to merge 385 commits intoranaroussi:mainfrom
Conversation
… pandas resample apply function
…mpound value is retured in pandas resampler apply function
Match dates logic on make_index function
Adjust parameter order, fixes ranaroussi#142
remove duplicate type check
fix an typo where a cumprod series, not a single compound value is returned in…
Signed-off-by: ran <ran@aroussi.com>
…ted, due to dataframes being unnecessarily updated
'Risk-Free Rate %'] = _pd.Series(s_rf)*100 so that it shows in the report as the right percentage (specifically in html report)
…ate-report temporary fix for: Rf rate when not 0 metrics are incorrectly calculated due to dataframe alteration
fixing saving HTML file
- Handle Series results from DataFrame.sum() operations - Use replace(0, NaN) for Series, scalar check for single values - Fixes ValueError when checking truth value of Series
Fixed ValueError 'truth value of Series is ambiguous' for: - sortino: Use replace(0, NaN) for Series downside - outlier_win_ratio: Handle Series positive_mean - outlier_loss_ratio: Handle Series negative_mean - risk_return_ratio: Handle Series std - ulcer_performance_index: Handle Series ulcer index - serenity_index: Handle Series std and denominator - gain_to_pain_ratio: Handle Series downside All functions now properly return Series for DataFrame inputs
Added comprehensive DataFrame input handling fixes to prevent ValueError
When using qs.reports.html with a benchmark, payoff_ratio receives a DataFrame containing both strategy and benchmark columns. This caused avg_loss to return a Series, leading to 'ValueError: truth value of Series is ambiguous' when checking if avg_loss_val == 0. Solution: Handle both Series and scalar cases properly using isinstance check and replace(0, NaN) for Series.
Added fix for issue ranaroussi#463 - payoff_ratio DataFrame handling
…ry_factor Issue ranaroussi#463 was not fully resolved in 0.0.73. Fixed: - kelly_criterion: Properly handle Series from DataFrame inputs (was using 'or' operator which fails on Series) - recovery_factor: Handle Series max_dd from DataFrame inputs Both functions now properly detect Series vs scalar and handle accordingly. Tested with qs.reports.metrics() using benchmark.
Complete resolution of issue ranaroussi#463 with kelly_criterion and recovery_factor fixes
- Updated make_index default rebalance from '1M' to '1ME' - Removed warning suppression in _compat.py - Ensures clean execution with pandas 2.2.0+ - Bumped version to 0.0.75
… comparisons Previously, benchmark yearly returns would change based on the strategy's trading calendar due to date alignment dropping returns on non-trading days. This fix preserves the original benchmark data before alignment and uses it for EOY calculations, ensuring benchmark returns remain constant regardless of which strategy they're compared against. Changes: - Store original benchmark data in HTML reports before alignment - Use original benchmark for EOY comparison calculations - Benchmark returns now consistent whether comparing PSEI vs PSEI or TEVA vs PSEI Fixes ranaroussi#457 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Previously, comparing data with different timezones (or timezone-aware vs timezone-naive) would cause "Cannot compare dtypes" errors. This fix: - Normalizes all data to UTC then removes timezone info for consistency - Handles timezone normalization in safe_resample, aggregate_returns, and compare - Ensures benchmark and strategy data can be compared regardless of original timezone - Prevents date misalignment issues like comparing 2024-01-10+0400 to 2024-01-10-0700 All timezone combinations now work correctly, enabling reliable cross-market analysis between US, European, and Asian markets. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Updated all pct_change() calls to explicitly use fill_method=None to prevent the deprecation warning: "The default fill_method='pad' in Series.pct_change is deprecated and will be removed in a future version." Changes: - utils.py: Fixed pct_change() in _prepare_returns, download_returns, and _prepare_benchmark - _plotting/wrappers.py: Fixed pct_change() in portfolio calculations - All instances now use fill_method=None with explicit fillna(0) where needed This ensures compatibility with pandas 2.x and future versions. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
The conditional_value_at_risk function now correctly handles DataFrame inputs by dropping NaN values after filtering returns below the VaR threshold. This prevents NaN values from skewing the mean calculation and ensures consistent CVaR results for both Series and DataFrame inputs. Additionally, new comprehensive tests were added to verify the fix and to cover related issues ranaroussi#467 and ranaroussi#468, ensuring the CVaR calculation and report generation work correctly without errors. Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
- Bumped version from 0.0.76 to 0.0.77 - Updated CHANGELOG.md to document fixes for issues ranaroussi#467 and ranaroussi#468 - Issue ranaroussi#467: CVaR calculation now works correctly with DataFrame inputs - Issue ranaroussi#468: Confirmed already resolved in previous versions 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
## Packaging & Dependencies - Migrated from setup.py to pyproject.toml - Python 3.10+ minimum (dropped 3.8, 3.9) - pandas 2.0+, numpy 1.24+, scipy 1.11+, seaborn 0.13+, matplotlib 3.7+ ## New Features - Monte Carlo simulation module (_montecarlo.py) - Confidence intervals for returns, Sharpe, drawdown, CAGR - Bootstrap resampling with configurable simulations - Path simulation and Monte Carlo plots - Parameters table in HTML reports (issue ranaroussi#472) - Average drawdown line in underwater plot (issue ranaroussi#489) - Chrome dark mode support (issue ranaroussi#492) ## Bug Fixes (15+ issues resolved) - ranaroussi#491: HTML report with benchmark Series - ranaroussi#486: reports.metrics vs reports.full inconsistency - ranaroussi#485: Benchmark Omega always same as strategy - ranaroussi#484: make_index incorrect calculation - ranaroussi#481: NaN in EOY Returns vs Benchmark - ranaroussi#480: Inconsistent metrics benchmark vs return-only - ranaroussi#479: EOY Returns vs Benchmark section issues - ranaroussi#475: Double "%" in HTML report - ranaroussi#477: Noisy variance warning messages - ranaroussi#467: CVaR calculation for DataFrame inputs - Fixed timezone normalization for cross-market comparisons - Fixed FutureWarning for deprecated pandas pct_change() - Fixed parameters kwarg not being used in html reports ## Code Quality - Added comprehensive type hints to 20+ stats.py functions - Uses Python 3.10+ union syntax (X | Y) - Added py.typed marker for PEP 561 - Simplified _compat.py and _numpy_compat.py (removed obsolete checks) - README converted from RST to Markdown 🤖 Generated with Claude Code Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ates feat: 2026 Modernization - Python 3.10+, Monte Carlo, Bug Fixes
- Added section explaining that metrics like win_rate, consecutive_wins, payoff_ratio, and profit_factor are period-based (not trade-based) - Updated Python version badge to 3.10+ - Updated requirements section to match pyproject.toml Addresses concerns raised in ranaroussi#493 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…etrics docs: clarify period-based vs trade-based metrics
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](actions/checkout@v4...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
These test files were created during development/debugging and should not be in the repository root. The proper tests are in tests/ directory. Removed: - test_comprehensive.py - test_fixes.py - test_issue_467.py - test_issue_468.py Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* chore: remove old test files from root directory These test files were created during development/debugging and should not be in the repository root. The proper tests are in tests/ directory. Removed: - test_comprehensive.py - test_fixes.py - test_issue_467.py - test_issue_468.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add developer instructions to PROJECT.md - Added project structure documentation - Added testing and code quality commands - Added common tasks (new metrics, deps, version bump) - Added gotchas section 🤖 Generated with Claude Code --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* chore: remove old test files from root directory These test files were created during development/debugging and should not be in the repository root. The proper tests are in tests/ directory. Removed: - test_comprehensive.py - test_fixes.py - test_issue_467.py - test_issue_468.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add developer instructions to PROJECT.md - Added project structure documentation - Added testing and code quality commands - Added common tasks (new metrics, deps, version bump) - Added gotchas section 🤖 Generated with Claude Code * docs: add DeepWiki badge to README 🤖 Generated with Claude Code --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…ussi#500) * chore: remove old test files from root directory These test files were created during development/debugging and should not be in the repository root. The proper tests are in tests/ directory. Removed: - test_comprehensive.py - test_fixes.py - test_issue_467.py - test_issue_468.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add developer instructions to PROJECT.md - Added project structure documentation - Added testing and code quality commands - Added common tasks (new metrics, deps, version bump) - Added gotchas section 🤖 Generated with Claude Code * docs: add DeepWiki badge to README 🤖 Generated with Claude Code * fix: resolve circular import error on import (ranaroussi#499) Defer stats import in utils.py to avoid circular dependency: - __init__.py imports stats, utils - stats.py imports utils - utils.py was importing stats at module level (circular!) Moved stats import inside to_prices() and group_returns() functions where it's actually needed. Fixes ranaroussi#499 🤖 Generated with Claude Code --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Hotfix release for circular import bug (ranaroussi#499) 🤖 Generated with Claude Code
- Implemented lazy imports in utils.py, reports.py, _plotting/core.py, _plotting/wrappers.py - Removed quantstats/stats.py from .gitignore (was incorrectly excluding it from builds) - All modules now defer stats/utils imports until actually needed Fixes ranaroussi#499, ranaroussi#501 🤖 Generated with Claude Code
Fix NameError in reports.full() caused by accidental find-and-replace during v0.0.80 lazy import refactoring. 🤖 Generated with Claude Code
…ranaroussi#502) - Fixed circular import errors that broke import quantstats - Fixed NameError in reports.full() - Fixed reports.html() to work without output file (opens in browser) - Fixed profit_ratio() DataFrame handling - Removed dark mode CSS from HTML report - Improved HTML report header (Compounded/matched dates conditionals) - Added new metrics to full report (UPI, RAR, Risk-Return Ratio, etc.) - Added terminal output parameters table - Added comprehensive test suite (125 tests)
Pass a `compounded` parameter through to the underlying CAGR calculation so that intraday and arithmetic return streams get the correct annualized return in the numerator instead of geometric CAGR. Fixes ranaroussi#507
eeae74e to
f76ef15
Compare
Author
|
Ping on this compounded flag feature for calmar(). Allows correct calculation for non-compounded returns. Ready for review! |
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.
Fixes #507
Problem
qs.stats.calmar()always uses geometric CAGR (compounded=True) as the numerator. This gives misleading results for intraday, per-trade PnL, or other non-compounded return streams where arithmetic annualized return is the correct numerator.Changes
compounded=Trueparameter tocalmar()inquantstats/stats.pycagr()call, which already supportscompounded=Falsereports.pyso thatmetrics(compounded=False)produces correct Calmar valuesFully backward-compatible -- default is
compounded=True, matching the existing behavior.Usage