Skip to content

v2.3.0

Latest

Choose a tag to compare

@YichengYang-Ethan YichengYang-Ethan released this 17 Feb 16:03
· 49 commits to main since this release
04e0bd1

What's New in v2.3.0

Added

  • Sortino ratio (calculate_sortino_ratio()) — penalises only downside volatility, complementing Sharpe for leveraged-ETF portfolios.
  • CVaR / Expected Shortfall (calculate_cvar()) at 95% and 99% confidence — answers "how bad is it when VaR is breached?"
  • Portfolio RSIrsi_portfolio field now populated in analyze_risk() using the portfolio cumulative-return series.
  • Portfolio data export — new clawdfolio export CLI command with CSV and JSON output for portfolio, risk metrics, and alerts (output/export.py).
  • Dynamic trading calendar — algorithmic US holiday generation for any year (Easter via anonymous Gregorian algorithm, nth-weekday rules for MLK, Presidents, Memorial, Labor, Thanksgiving). Hardcoded 2024-2026 sets retained as fast-path cache.
  • Tests for previously untested modules: test_price_monitor.py, test_earnings_monitor.py, test_dca.py, test_json_output.py, test_export.py.
  • Python 3.13 added to CI matrix and pyproject.toml classifiers.
  • pip-audit security scanning step in CI.
  • Coverage enforcement: --cov-fail-under=48 in CI pytest step.

Changed

  • analyze_risk() fetches SPY and QQQ benchmarks in a single get_history_multi() call instead of two sequential get_history() calls.
  • Portfolio.get_position() now uses O(1) dict lookup via _ticker_index instead of O(n) linear scan.
  • calculate_ema() replaced Python for-loop with pd.Series.ewm() for better performance.

Fixed

  • calculate_dca_performance() no longer passes invalid period strings (e.g. "12mo") to yfinance; uses _months_to_period() mapping.
  • Position._weight attribute properly declared as a dataclass field, eliminating getattr fallback.
  • Cache TOCTOU race in _cached() — per-key locking prevents redundant expensive calls from concurrent threads.