Skip to content

Risk Model

Arye Kogan edited this page Sep 23, 2025 · 1 revision

Risk Model

The risk engine protects capital by applying deterministic rules to curated price data and the active holdings snapshot. This page documents each rule, how it is computed, and the configuration knobs you can tune.

Daily rules

The engine lives in src/trading_system/risk/__init__.py. For each holding and the configured benchmark it computes:

Single-day crash

  • Trigger: daily return ret_1drisk.crash_threshold_pct (default −8%).
  • Computation: ret_1d is derived during preprocessing as close_t / close_{t-1} - 1.
  • Alert payload: includes symbol, actual return, threshold, and a reason string for the report/notifications.
  • Tuning: set risk.crash_threshold_pct to match your risk appetite (e.g., −0.05 for a tighter leash).

Rolling drawdown

  • Trigger: drawdown ≤ risk.drawdown_threshold_pct (default −20%).
  • Computation: rolling_peak is the max close over preprocess.rolling_peak_window sessions (252 by default). Drawdown is (close / rolling_peak) - 1.
  • Window: adjust rolling_peak_window to target a 30-day, 90-day, or annual perspective.

Market filter

  • Trigger: user-defined expression evaluated on the benchmark (e.g., close > sma_200).
  • Effect: sets the global market_state (RISK_ON × RISK_OFF). The improvement engine can use it to halt new entries when the market is weak.
  • Configuration: risk.market_filter with benchmark and rule strings (parsed by RuleEvaluator).

Portfolio-level controls

While the current engine focuses on symbol-level alerts, the reports expose portfolio metrics you should monitor:

  • Portfolio drawdown: computed in the report performance section as (portfolio_value / rolling_peak) - 1 using aggregated holdings and cash. Surface it in notifications by extending ReportBuilder._build_performance_section.
  • Concentration: the report shows weights for each holding. Track max weight vs. your policy (e.g., ≤20%) and add automated alerts via rebalance constraints or report notes.
  • Turnover cap: configured via rebalance.turnover_cap_pct and enforced in the rebalance engine. When turnover exceeds the cap, the proposal is recomputed with reduced trades and notes explain the adjustment.

Risk-aware parameters in config

Section Field Purpose
risk crash_threshold_pct Crash sensitivity.
risk drawdown_threshold_pct Rolling drawdown tolerance.
risk.market_filter benchmark, rule Market regime guardrail.
preprocess rolling_peak_window Lookback for drawdown calculations.
rebalance cash_buffer Guaranteed cash reserve before sizing orders.
rebalance min_weight, max_positions Soft concentration limits via allocator constraints.
rebalance turnover_cap_pct Hard cap on trade volume per rebalance.

Beta, VaR, and Expected Shortfall

These measures originate from the learning plan PDF and are part of the risk roadmap:

  • Beta: compute slope of regression between holding returns and benchmark returns using curated data. Prototype code exists in research notebooks; productionisation will slot into a future risk evaluate extension.
  • Value at Risk / Expected Shortfall: planned for integration using historical simulation once higher-quality PIT data is available. For now they remain research metrics (see Roadmap).

Operational workflow

  1. Run poetry run ts risk evaluate --config ... --holdings ... whenever you need to sanity-check alerts without the full pipeline.
  2. Investigate any crash/drawdown alert immediately and annotate holdings.json if discretionary actions are taken.
  3. Use the report manifest and risk_alerts.json in version control to track how thresholds evolves over time.
  4. Keep an eye on concentration and turnover metrics in the report until automated alerting is implemented.

Questions? Check Troubleshooting for common error messages (missing curated data, NaN indicators, etc.).

Clone this wiki locally