Bugfixes for 0.0.78 release
-
Fixed circular import errors that broke
import quantstats(#499, #501) -
Fixed
NameError: name 'dd_get_stats' is not definedinreports.full()(#502) -
Fixed
reports.html()to work without specifying output file (opens in browser) -
Fixed
profit_ratio()to handle DataFrame inputs properly -
Removed dark mode CSS from HTML report template
-
Suppressed pandas FutureWarning for callable resampler.apply()
-
Improved HTML report header:
- Title shows "(Compounded)" only when compounded=True
- Date range shows "(matched dates)" only when match_dates=True with benchmark
- Parameters now always show Benchmark, Periods/Year, and RF rate
-
Added new metrics to full HTML report:
- Ulcer Performance Index, Risk-Adjusted Return, Risk-Return Ratio
- Avg. Return, Avg. Win, Avg. Loss, Win/Loss Ratio, Profit Ratio
-
Added terminal output parameters table for
reports.full()andreports.basic() -
Added comprehensive test suite (125 tests):
- Tests for stats, reports, utils, plots, compat, extend_pandas, and Monte Carlo
2026 Modernization Update
-
Added comprehensive type hints to stats.py functions:
- All major public functions now have full type annotations
- Uses Python 3.10+ union syntax (
X | Yinstead ofUnion[X, Y]) - Added
Returnstype alias forpd.Series | pd.DataFrame - Functions typed include:
ghpr(),outliers(),remove_outliers(),best(),worst(),consecutive_wins(),consecutive_losses(),exposure(),win_rate(),avg_return(),avg_win(),avg_loss(),rolling_volatility(),implied_volatility(),autocorr_penalty(),smart_sharpe(),rolling_sharpe(),smart_sortino(),rolling_sortino(),adjusted_sortino(),probabilistic_ratio(),probabilistic_sharpe_ratio(), and more
-
Simplified compatibility layers for Python 3.10+/pandas 2.0+/numpy 1.24+:
- _compat.py: Removed obsolete pandas < 1.0.0 and < 1.4.0 version checks
- _numpy_compat.py: Removed obsolete numpy < 1.17.0, < 1.21.0, and < 1.22.0 version checks
- Cleaner, more maintainable codebase for modern dependency versions
-
Fixed issue #467 - CVaR calculation returning NaN for DataFrame inputs:
- The conditional_value_at_risk() function now properly handles DataFrame inputs
- When filtering DataFrames, NaN values are now correctly removed before calculating the mean
- CVaR calculations are now consistent between Series and DataFrame inputs
- This fix ensures accurate risk metrics in HTML reports when using benchmarks
-
Confirmed issue #468 is already resolved:
- The "mode.use_inf_as_null" pandas option error reported in v0.0.64 no longer occurs
- This issue was resolved in a previous version through updates to pandas compatibility
-
Fixed issue #457 - Inconsistent benchmark EOY returns in reports:
- Benchmark yearly returns now remain consistent regardless of strategy's trading calendar
- HTML reports preserve original benchmark data for accurate EOY calculations
- Previously, benchmark returns would change when aligned to different strategies' trading days
- Added comprehensive tests to verify benchmark consistency across different comparisons
-
Improved timezone handling for cross-market comparisons:
- All resampling operations now normalize timezones to prevent comparison errors
- Mixed timezone-aware and timezone-naive data can now be compared without errors
- Data is converted to UTC then made timezone-naive for consistent comparisons
- Fixes "Cannot compare dtypes datetime64[ns] and datetime64[ns, UTC]" errors
-
Fixed FutureWarning for pandas pct_change():
- Updated all pct_change() calls to use fill_method=None parameter
- Prevents "fill_method='pad' is deprecated" warnings in pandas 2.x
- Ensures compatibility with future pandas versions
- Fixed FutureWarning for deprecated pandas frequency aliases:
- Updated make_index default rebalance parameter from "1M" to "1ME"
- Ensures compatibility with pandas 2.2.0+ without warnings
- The _compat module already handles conversion for older pandas versions
- Completed fix for issue #463 - DataFrame handling in qs.reports functions:
- kelly_criterion: Fixed improper use of 'or' operator with Series values
- Now properly detects Series vs scalar inputs
- Handles zero and NaN values correctly for DataFrames
- recovery_factor: Added proper DataFrame input handling
- Detects when max_dd is a Series and handles accordingly
- Prevents "truth value of Series is ambiguous" errors
- All functions now tested with qs.reports.html() and qs.reports.metrics() with benchmarks
- Verified working with exact code examples from issue reporters
- kelly_criterion: Fixed improper use of 'or' operator with Series values
- Fixed payoff_ratio to handle DataFrame inputs properly (fixes issue #463)
- When using qs.reports.html with a benchmark, payoff_ratio receives a DataFrame
- Previously caused "ValueError: truth value of Series is ambiguous"
- Now properly handles both Series and scalar avg_loss values
- Returns Series for DataFrame inputs, scalar for Series inputs
- Fixed ValueError "truth value of Series is ambiguous" for DataFrame inputs in multiple stats functions:
- sortino: Properly handles Series downside deviation from DataFrame inputs
- outlier_win_ratio: Handles Series positive_mean calculations correctly
- outlier_loss_ratio: Handles Series negative_mean calculations correctly
- risk_return_ratio: Handles Series standard deviation properly
- ulcer_performance_index: Handles Series ulcer index values
- serenity_index: Handles Series std and denominator calculations
- gain_to_pain_ratio: Handles Series downside calculations
- All functions now properly return Series for DataFrame inputs and scalars for Series inputs
-
Fixed RuntimeWarnings in tail_ratio function by properly handling edge cases:
- Handle divide by zero when lower quantile is 0
- Handle invalid values when quantiles return NaN
- Handle DataFrame inputs that return Series from quantile operations
- Return NaN gracefully instead of triggering warnings
-
Added comprehensive divide by zero protection across multiple stats functions:
- gain_to_pain_ratio: Returns NaN when no negative returns (downside = 0)
- recovery_factor: Returns NaN when no drawdown (max_dd = 0)
- sortino: Returns NaN when downside deviation is 0
- calmar: Returns NaN when max drawdown is 0
- ulcer_performance_index: Returns NaN when ulcer index is 0
- serenity_index: Returns NaN when std or denominator is 0
- payoff_ratio: Returns NaN when average loss is 0
- outlier_win_ratio: Returns NaN when no positive returns
- outlier_loss_ratio: Returns NaN when no negative returns
- risk_return_ratio: Returns NaN when standard deviation is 0
- kelly_criterion: Returns NaN when win/loss ratio is 0 or NaN
- greeks: Returns NaN for beta when benchmark variance is 0
- rolling_greeks: Handles zero benchmark std gracefully
- All functions now return NaN instead of triggering RuntimeWarnings
- Fixed chart naming inconsistency: renamed "Daily Active Returns" to "Daily Active Returns (Cumulative Sum)" and "Daily Returns" to "Daily Returns (Cumulative Sum)" to accurately reflect that charts show cumulative values (fixes issue #454)
- Fixed CAGR calculation bug where years were incorrectly calculated using calendar days instead of trading periods, causing drastically reduced CAGR values (fixes issue #458)
- Fixed inconsistent EOY returns for benchmarks by preserving original benchmark data for aggregation while aligning to strategy index for other calculations (fixes issue #457)
- Added
periodsparameter tocalmar()function to support custom annualization periods (fixes issue #455) - Updated reports.py to pass periods parameter to Calmar ratio calculation for consistency with other metrics
- Fixed ValueError when comparing Series with scalar in _get_baseline_value() function (fixes issue #448)
- Properly handle both DataFrame and Series inputs in drawdown calculations
- Added support for NumPy 2.0.0+ (fixes issue #445)
- Fixed bug with calculating drawdowns when first return is < 0
- Misc bug fixes
MAJOR RELEASE - Comprehensive Compatibility and Performance Improvements
🔧 Major Fixes:
- Fixed pandas resampling compatibility issues (UnsupportedFunctionCall errors)
- Added yfinance proxy configuration compatibility layer for all versions
- Implemented comprehensive pandas compatibility layer with frequency alias mapping (M→ME, Q→QE, A→YE)
- Fixed all pandas FutureWarnings related to chained assignment operations
- Added numpy compatibility layer for deprecated functions (np.product → np.prod)
- Replaced broad exception handling with specific exception types throughout codebase
📈 Performance Improvements:
- Implemented LRU caching for _prepare_returns function (10-100x faster for repeated operations)
- Optimized autocorrelation calculations with vectorized numpy operations
- Improved rolling Sortino calculation performance and memory usage
- Optimized multi_shift memory usage with incremental concatenation
- Eliminated redundant dropna operations with intelligent caching
- Replaced inefficient iterrows usage with vectorized operations
🛡️ Reliability Improvements:
- Added comprehensive input validation to public functions
- Implemented safe_resample compatibility function for all pandas versions
- Created robust error handling with custom exception classes
- Added safe_yfinance_download function handling proxy configuration changes
- Fixed matplotlib/seaborn compatibility issues and deprecation warnings
🎨 Visualization Fixes:
- Updated seaborn compatibility (sns.set() → sns.set_theme())
- Fixed legend handling in plotting functions
- Improved chart rendering with better error handling
- Fixed monthly heatmap display issues
📊 Technical Improvements:
- Created comprehensive compatibility layer in _compat.py module
- Implemented frequency alias mapping for pandas version compatibility
- Added version detection and handling for pandas/numpy changes
- Enhanced data preparation pipeline with caching and validation
🚀 Overall Impact:
- 10-100x performance improvement for large datasets
- 5-10x memory usage reduction
- Eliminated all pandas/numpy compatibility warnings
- Future-proofed against dependency updates
- Maintained full backward compatibility
This release addresses 23+ community-reported issues and PRs, making QuantStats significantly faster, more reliable, and compatible with modern pandas/numpy versions.
- Misc pd/np compatibility stuff
- Changed
serenity_indexandrecovery_factorto use simple sum instead of compounded sum - Reports passing the
compoundedparam to all supporting methods - Fixed a bug related to monthly_heatmap display
- Fixed positional arguments passed to cagr()
- Multi-strategy reports! You can now pass a dataframe with a column for each strategy to get a unified, single report for all
- Support request proxy with yfinance
- Added custom periods to CAGR
- Correct drawdown days calculation when last day is a drawdown
- Write report in correct file path
- IPython 7+ compatibility
- Pandas 2.0 compatibility
- Fix for benchmark name when supplied by the user
- Handles tz-native and tz-aware comparisson issue
- Adding benchmark name to html report
- Update README ticker to META :)
- Many pull requests merged
- Fixed EOY compounded return calculation
- Run fillna(0) on plot's beta (issue #193)
- Fixed
sigmacalculation instats.probabilistic_ratio()
- Added option to explicitly provide the benchmark title via
benchmark_title=...
- Fix for benchmark name in html report when supplied by the user
- Fixed dependency name in requirements.txt
- Added information ratio to reports
- Added Treynor ratio
- Added max consecutive wins/losses to full report
- Added “correlation to benchmark” to report
- Cleanup inf/nan from reports
- Added benchmark name to stats column and html report
- Added probabilistic sharpe/sortino ratios
- Fix relative dates calculations
- Fixed a bug when reporting the max drawdown
- Fixed an issue with saving the HTML report as a file
- Fixed RF display bug
- Fixed average DD display bug
- Misc bug fixes and speedups
- Fixed
stats.rolling_sharpe()parameter mismatch
- Match dates logic on
utils.make_index()
- Fixed
stats.rolling_sortino()calculations - Added
match_datesflag to reports to make strategy and benchmark comparible by syncing their dates and frequency - Added
prepare_returnsflag toutils._prepare_benchmark() - Misc code cleanup and speedups
- Usability improvements
- Typos fixed
- Added rebalance option to
utils.make_index() - Added option to add
log_scale=True/False` toplots.snapshot()``
- Fixed
plots.rolling_volatility()benchmark display (bug introduced in 0.0.37)
- Added
stats.smart_sharpe()andstats.smart_sortino()
- added
stats.rolling_sharpe(),stats.rolling_sortino(),stats.and rolling_volatility() - Added
stats.distribution() - Added Omega ratio
- BREAKING CHANGE: Eenamed
trading_year_daysparam toperiods_per_year - Misc code cleanup and speedups
- Added
as_pctparams toreports.metrics()for when you need display data as DataFrame
- Passing correct rolling windows in
rolling_beta() - Added Serenity Index
- Passing
trading_year_daysto methodmetrics - Fixed "day is out of range for month" error
- Fixed bug in
stats.consecutive_wins()andstats.consecutive_losses() - Fixed seaborn's depreated
distplotwarning - Improved annualization by passing
trading_year_days
- Added option to pass the number of days per year in reports, so you can now use
trading_year_days=365if you're trading crypto, or any other number for intl. markets.
- Fixed bug in
plot_histogram()(issues 94+95)
- Enable period setting for adjusted sortino
- Added
utils.make_index()for easy "etf" creation
- Fixed PIP installer
- Minor code refactoring
gain_to_painrenamed togain_to_pain_ratio- Minor code refactoring
- Added Sortino/√2 and Gain/Pain ratio to report
- Merged PRs to fix some bugs
- Misc bug fixes and code improvements
- Fixed
conditional_value_at_risk() - Fixed
%matplotlib inlineissue notebooks
- Added mtd/qtd/ytd methods for panda (usage:
df.mtd()) - Fixed Pandas deprecation warning
- Fixed Matplotlib deprecation warning
- Try setting
%matplotlib inlineautomatic in notebooks
- Fixed profit Factor formula
- Misc bug fixes
- Fixed chart EOY chart's
xtickswhen charting data with 10+ years - Fixed issue where daily return >= 100%
- Fixed Snapshot plot
- Removed duplicaated code
- Added conda installer
- Misc code refactoring and optimizations
- Misc bugfixes
- Cleaning up data before calculations (replaces inf/-inf/-0 with 0)
- Removed usage of
pandas.compound()for futurepandasversion compatibility - Auto conversion of price-to-returns and returns-to-data as needed
- Fixed issue when last date in data is in the past (issue #4)
- Fixed issue when data has less than 5 drawdown periods (issue #4)
- Fixed CAGR calculation for more accuracy
- Handles drawdowns better in live trading mode when currently in drawdown
- Handles no drawdowns better
- Better report formatting
- Code cleanup
- Fixed calculation for rolling sharpe and rolling sortino charts
- Nicer CSS when printing html reports
- Fixed non-compounded plots in reports when using
compounded=False
- Option to add
compounded=True/Falseto reports (default isTrue)
- Minor bug fixes
- Updated to install and use
yfinanceinstead offix_yahoo_finance
- Added support for 3 modes (cumulative, compounded, fixed amount) in
plots.earnings()andutils.make_portfolio() - Added two DataFrame utilities:
df.curr_month()anddf.date(date) - Misc bug fixes and code refactoring
- Better calculations for cagr, var, cvar, avg win/loss and payoff_ratio
- Removed unused param from
to_plotly() - Added risk free param to
log_returns()+ renamed it toto_log_returns() - Misc bug fixes and code improvements
- Plots returns figure if
showis set to False
- Minor bug fix
- Added
plots.to_plotly()method - Added Ulcer Index to metrics report
- Better returns/price detection
- Bug fixes and code refactoring
- Added
pct_rank()method to stats - Added
multi_shift()method to utils
- Better VaR/cVaR calculation
- Fixed calculation of
to_drawdown_series() - Changed VaR/cVaR default confidence to 95%
- Improved Sortino formula
- Fixed conversion of returns to prices (
to_prices())
- Initial release
- Pre-release placeholder