Skip to content

Commit 67ce939

Browse files
authored
Merge pull request #42 from AKKI0511/implement-drawdown-protection-system
feat(trading): add drawdown guard risk management
2 parents fec5dda + e985a09 commit 67ce939

File tree

12 files changed

+538
-63
lines changed

12 files changed

+538
-63
lines changed

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919
## Key Features
2020

2121
- 📊 Data: YFinance/AlphaVantage loaders, caching, validation
22-
- 🧪 Features: technical indicators, custom signals, optional LLM sentiment
23-
- 🤖 Models: ensemble VotingClassifier (LR, RF, XGBoost) with Optuna tuning
22+
- 🧪 Features: technical indicators, custom signals, optional LLM sentiment
23+
- 🤖 Models: ensemble VotingClassifier (LR, RF, XGBoost) with Optuna tuning
2424
- 📈 Backtesting: execution costs, slippage, liquidity limits, market impact modeling, portfolio helpers
25-
- 🛠️ CLI: end‑to‑end pipeline, evaluation, and model backtest in one place
25+
- 🛡️ Risk management: drawdown and turnover guards
26+
- 🛠️ CLI: end‑to‑end pipeline, evaluation, and model backtest in one place
2627

2728
## Quickstart
2829

@@ -61,10 +62,11 @@ Artifacts are written to:
6162

6263
## Configuration
6364

64-
- `config/model_config.yaml`: symbols, date ranges, caching, training, trading
65-
- `config/features_config.yaml`: pipeline steps, indicators, selection, sentiment
66-
- `config/backtest_config.yaml`: execution costs, slippage, liquidity
67-
- `config/streaming.yaml`: providers, auth, subscriptions (optional)
65+
- `config/model_config.yaml`: symbols, date ranges, caching, training, trading
66+
- `config/features_config.yaml`: pipeline steps, indicators, selection, sentiment
67+
- `config/backtest_config.yaml`: execution costs, slippage, liquidity
68+
- `config/risk_config.yaml`: drawdown protection and turnover limits
69+
- `config/streaming.yaml`: providers, auth, subscriptions (optional)
6870

6971
Time‑aware evaluation rules:
7072
- If `data.test_start` and `data.test_end` set: train = dates < `test_start`; test = `test_start` ≤ dates ≤ `test_end`

config/risk_config.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
risk_management:
2+
drawdown_protection:
3+
enabled: true
4+
max_drawdown_pct: 0.15
5+
max_drawdown_absolute: 50000
6+
warning_threshold: 0.8
7+
soft_stop_threshold: 0.9
8+
hard_stop_threshold: 1.0
9+
emergency_stop_threshold: 1.1
10+
lookback_periods: [1, 7, 30]
11+
turnover_limits:
12+
daily_max: 2.0
13+
weekly_max: 5.0
14+
monthly_max: 15.0

docs/README.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ The [Quick Reference Guide](quick-reference.md) includes:
5656
- **Common Patterns** - Data loading, feature engineering, model training, backtesting
5757
- **Technical Indicators** - Usage examples for all technical indicators
5858
- **Custom Features** - Momentum score and volatility breakout functions
59-
- **Risk Management** - Stop-loss, take-profit, and position sizing
59+
- **Risk Management** - Stop-loss, take-profit, drawdown guard, and position sizing
6060
- **Performance Metrics** - Classification and trading metrics
6161
- **Visualization** - Price charts and performance plots
6262
- **Configuration Examples** - Model and feature configuration templates
@@ -83,15 +83,18 @@ QuantTradeAI/
8383
│ │ └── classifier.py # Voting classifier
8484
│ ├── backtest/ # Backtesting
8585
│ │ └── backtester.py # Trade simulation
86-
│ ├── trading/ # Trading utilities
87-
│ │ └── risk.py # Risk management
86+
│ ├── trading/ # Trading utilities
87+
│ │ ├── drawdown_guard.py # Drawdown protection
88+
│ │ ├── portfolio.py # Portfolio operations
89+
│ │ └── risk_manager.py # Risk coordination
8890
│ └── utils/ # Utilities
8991
│ ├── metrics.py # Performance metrics
9092
│ ├── visualization.py # Plotting functions
9193
│ └── config_schemas.py # Configuration validation
92-
├── config/ # Configuration files
93-
│ ├── model_config.yaml # Model parameters
94-
│ └── features_config.yaml # Feature engineering settings
94+
├── config/ # Configuration files
95+
│ ├── model_config.yaml # Model parameters
96+
│ ├── features_config.yaml # Feature engineering settings
97+
│ └── risk_config.yaml # Drawdown and turnover limits
9598
└── docs/ # Documentation
9699
├── api/ # API documentation
97100
├── quick-reference.md # Quick reference guide
@@ -134,11 +137,11 @@ QuantTradeAI/
134137
- **Market impact modeling** for execution cost realism
135138
- **Position sizing** based on risk parameters
136139

137-
### Risk Management
138-
- **Stop-loss and take-profit** rules
139-
- **Position sizing** calculations
140-
- **Risk-adjusted returns** analysis
141-
- **Drawdown monitoring**
140+
### Risk Management
141+
- **Stop-loss and take-profit** rules
142+
- **Position sizing** calculations
143+
- **Risk-adjusted returns** analysis
144+
- **Drawdown and turnover guards**
142145

143146
## 📊 Supported Assets
144147

docs/configuration.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ The framework uses several configuration files:
1010
- **`config/features_config.yaml`** - Feature engineering settings
1111
- **`config/backtest_config.yaml`** - Execution settings for backtests
1212
- **`config/impact_config.yaml`** - Market impact parameters by asset class
13+
- **`config/risk_config.yaml`** - Drawdown protection and turnover limits
1314

1415
## 🔧 Model Configuration
1516

@@ -89,7 +90,7 @@ trading:
8990
transaction_cost: 0.001
9091
```
9192
92-
### Backtest Execution
93+
### Backtest Execution
9394
9495
```yaml
9596
execution:
@@ -130,7 +131,7 @@ parameter sets per asset class can be defined in `config/impact_config.yaml`.
130131
price_features:
131132
sma_periods: [5, 10, 20, 50, 200]
132133
ema_periods: [5, 10, 20, 50, 200]
133-
```
134+
```
134135

135136
### Momentum Features
136137

@@ -230,8 +231,28 @@ pipeline:
230231
- handle_missing_values
231232
- remove_outliers
232233
- scale_features
233-
- select_features
234-
```
234+
- select_features
235+
```
236+
237+
## 🛡️ Risk Management
238+
239+
```yaml
240+
risk_management:
241+
drawdown_protection:
242+
enabled: true
243+
max_drawdown_pct: 0.15
244+
warning_threshold: 0.8
245+
soft_stop_threshold: 0.9
246+
hard_stop_threshold: 1.0
247+
turnover_limits:
248+
daily_max: 2.0
249+
weekly_max: 5.0
250+
monthly_max: 15.0
251+
```
252+
253+
**Key Parameters:**
254+
- `drawdown_protection`: monitors portfolio equity and halts trading at specified levels
255+
- `turnover_limits`: caps how frequently positions may change over each period
235256

236257
## 🎯 Common Configurations
237258

docs/quick-reference.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -116,25 +116,26 @@ stoch_df = ta.stochastic(df['High'], df['Low'], df['Close'])
116116

117117
## 🛡️ Risk Management
118118

119-
```python
120-
from quanttradeai import apply_stop_loss_take_profit, position_size
119+
```python
120+
from quanttradeai import apply_stop_loss_take_profit, position_size
121121

122122
# Apply risk rules
123123
df_with_risk = apply_stop_loss_take_profit(df, stop_loss_pct=0.02, take_profit_pct=0.04)
124124

125125
# Calculate position size
126-
qty = position_size(capital=10000, risk_per_trade=0.02, stop_loss_pct=0.05, price=150.0)
127-
```
128-
129-
```python
130-
from quanttradeai import PortfolioManager
131-
132-
# Allocate capital across multiple symbols
133-
pm = PortfolioManager(10000)
134-
pm.open_position('AAPL', price=150, stop_loss_pct=0.05)
135-
pm.open_position('TSLA', price=250, stop_loss_pct=0.05)
136-
print(f"Portfolio exposure: {pm.risk_exposure:.2%}")
137-
```
126+
qty = position_size(capital=10000, risk_per_trade=0.02, stop_loss_pct=0.05, price=150.0)
127+
```
128+
129+
```python
130+
from quanttradeai.trading import DrawdownGuard, PortfolioManager
131+
132+
# Allocate capital across multiple symbols with drawdown protection
133+
guard = DrawdownGuard(config_path="config/risk_config.yaml")
134+
pm = PortfolioManager(10000, drawdown_guard=guard)
135+
pm.open_position('AAPL', price=150, stop_loss_pct=0.05)
136+
pm.open_position('TSLA', price=250, stop_loss_pct=0.05)
137+
print(f"Portfolio exposure: {pm.risk_exposure:.2%}")
138+
```
138139

139140
## 📈 Performance Metrics
140141

quanttradeai/backtest/backtester.py

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717
```
1818
"""
1919

20-
import pandas as pd
21-
from quanttradeai.utils.metrics import sharpe_ratio, max_drawdown
22-
from quanttradeai.trading.risk import apply_stop_loss_take_profit
23-
from quanttradeai.trading.portfolio import PortfolioManager
20+
import pandas as pd
21+
from quanttradeai.utils.metrics import sharpe_ratio, max_drawdown
22+
from quanttradeai.trading.risk import apply_stop_loss_take_profit
23+
from quanttradeai.trading.portfolio import PortfolioManager
24+
from quanttradeai.trading.drawdown_guard import DrawdownGuard
2425

2526

2627
def _simulate_single(
@@ -190,13 +191,14 @@ def _simulate_single(
190191

191192
def simulate_trades(
192193
df: pd.DataFrame | dict[str, pd.DataFrame],
193-
stop_loss_pct: float | None = None,
194-
take_profit_pct: float | None = None,
195-
transaction_cost: float = 0.0,
196-
slippage: float = 0.0,
197-
execution: dict | None = None,
198-
portfolio: PortfolioManager | None = None,
199-
) -> pd.DataFrame | dict[str, pd.DataFrame]:
194+
stop_loss_pct: float | None = None,
195+
take_profit_pct: float | None = None,
196+
transaction_cost: float = 0.0,
197+
slippage: float = 0.0,
198+
execution: dict | None = None,
199+
portfolio: PortfolioManager | None = None,
200+
drawdown_guard: DrawdownGuard | None = None,
201+
) -> pd.DataFrame | dict[str, pd.DataFrame]:
200202
"""Simulate trades using label signals.
201203
202204
Parameters
@@ -270,14 +272,23 @@ def simulate_trades(
270272
results["portfolio"] = pd.DataFrame(
271273
{"strategy_return": combined, "equity_curve": portfolio_curve}
272274
)
273-
return results
274-
else:
275-
return _simulate_single(
276-
df,
277-
stop_loss_pct=stop_loss_pct,
278-
take_profit_pct=take_profit_pct,
279-
execution=exec_cfg,
280-
)
275+
if drawdown_guard is not None:
276+
curve = results["portfolio"]["equity_curve"]
277+
for t, v in zip(curve.index, curve):
278+
drawdown_guard.update_portfolio_value(float(v), t)
279+
return results
280+
else:
281+
res = _simulate_single(
282+
df,
283+
stop_loss_pct=stop_loss_pct,
284+
take_profit_pct=take_profit_pct,
285+
execution=exec_cfg,
286+
)
287+
if drawdown_guard is not None:
288+
curve = res["equity_curve"]
289+
for t, v in zip(curve.index, curve):
290+
drawdown_guard.update_portfolio_value(float(v), t)
291+
return res
281292

282293

283294
def compute_metrics(data: pd.DataFrame, risk_free_rate: float = 0.0) -> dict:

quanttradeai/trading/__init__.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,15 @@
1414
```
1515
"""
1616

17-
from .portfolio import PortfolioManager
18-
from .risk import apply_stop_loss_take_profit, position_size
19-
20-
__all__ = ["PortfolioManager", "apply_stop_loss_take_profit", "position_size"]
17+
from .portfolio import PortfolioManager
18+
from .risk import apply_stop_loss_take_profit, position_size
19+
from .drawdown_guard import DrawdownGuard
20+
from .risk_manager import RiskManager
21+
22+
__all__ = [
23+
"PortfolioManager",
24+
"apply_stop_loss_take_profit",
25+
"position_size",
26+
"DrawdownGuard",
27+
"RiskManager",
28+
]

0 commit comments

Comments
 (0)