skillbase/hummingbot-risk-management
SkillRisk management for market making: P&L attribution (spread vs inventory), position limits, drawdown circuit breakers, exposure monitoring via get_portfolio_overview and search_history. Use when setting risk limits, analyzing MM P&L, monitoring portfolio exposure, or evaluating strategy risk.
SKILL.md
38
## Risk Controls in Hummingbot
39
40
Hummingbot has built-in risk controls. Use them — they are the automated last line of defense.
41
42
### Deploy-time limits (via `manage_bots`)
43
44
```
45
manage_bots(
46
action="deploy",
47
bot_name="...",
48
controllers_config=["..."],
49
max_global_drawdown_quote=500, # stop ALL controllers if total loss > $500
50
max_controller_drawdown_quote=200 # stop individual controller if its loss > $200
51
)
52
```
53
54
**How to size these limits:**
55
- `max_global_drawdown_quote` = maximum acceptable loss for this bot instance. Typically 5-10% of capital deployed to this bot.
56
- `max_controller_drawdown_quote` = per-strategy limit. Typically 2-5% of capital allocated to that strategy.
57
58
These are hard stops — when hit, Hummingbot automatically stops the affected controllers. This is non-negotiable: every bot deploys with both limits set.
59
60
### Strategy-level inventory controls
61
62
In controller configs (via `manage_controllers`):
63
- `inventory_skew_enabled` — widens spread on overweight side. Always enable.
64
- `inventory_target_base_pct` — target balance (50% = neutral)
65
- Order levels and amounts — implicitly limit max position
66
67
## P&L Attribution
68
69
Market making P&L must be decomposed to understand if the strategy actually works:
70
71
### Spread P&L (the intended profit)
72
```
73
spread_pnl = number_of_round_trips × effective_spread × avg_order_size
74
```
75
This should be consistently positive. If not, spreads are too tight or adverse selection is too high.
76
77
**How to calculate from MCP data:**
78
```
79
search_history(data_type="orders", status="filled", start_time=..., end_time=...)
80
```
81
Match buy fills with sell fills chronologically. Sum: (sell_price - buy_price) for matched pairs.
82
83
### Inventory P&L (the risk)
84
```
85
inventory_pnl = current_position × (current_price - avg_entry_price)
86
```
87
88
**How to calculate:**
89
```
90
get_portfolio_overview(include_balances=True) → current position
91
get_market_data(data_type="prices", ...) → current price
92
search_history(data_type="orders", ...) → reconstruct avg entry from fills
93
```
94
95
### Fee drag
96
```
97
total_fees = sum of all trading fees from order history
98
```
99
Include in every P&L analysis. High-frequency MM strategies can accumulate significant fee costs.
100
101
### The critical check
102
```
103
If |inventory_pnl| > spread_pnl consistently (over 3+ days):
104
→ The strategy is speculating, not market making
105
→ Action: stop, review parameters, reduce position size
106
```
107
108
## Exposure Monitoring
109
110
### Portfolio snapshot
111
```
112
get_portfolio_overview(
113
include_balances=True,
114
include_perp_positions=True,
115
include_active_orders=True,
116
as_distribution=True # see concentration %
117
)
118
```
119
120
### What to check
121
122
**Per-pair concentration:**
123
Any single pair > 30% of total deployed capital → over-concentrated. Reduce or diversify.
124
125
**Per-exchange concentration:**
126
Any single exchange > 40% of total capital → counterparty risk too high.
127
128
| Exchange tier | Max allocation |
129
|---|---|
130
| Top 5 by volume, regulated | Up to 40% |
131
| Top 20, established | Up to 25% |
132
| Smaller / less transparent | Up to 10% |
133
| DEX (non-custodial) | Based on smart contract audit status |
134
135
**Inventory balance per pair:**
136
```
137
get_portfolio_overview(include_balances=True)
138
```
139
Check base/quote ratio for each active pair. >70% one side for >1 hour = alert.
140
141
**Correlation risk:**
142
If running MM on ETH-USDT, SOL-USDT, and AVAX-USDT — these are all correlated with BTC. A 20% BTC drop affects ALL positions simultaneously. Treat correlated positions as one block for risk sizing.
143
144
## Stress Testing (before approving new strategy)
145
146
Calculate the impact of adverse scenarios using current portfolio data:
147
148
### Scenario 1: Flash crash (-30% in 1 hour)
149
```
150
max_loss = sum(position_size × 0.30) for all positions
151
```
152
Compare to total portfolio. If max_loss > 10% of total → reduce position sizes.
153
154
### Scenario 2: Exchange downtime (4 hours)
155
Orders sit on the book, market moves. Worst case: all orders on one side fill, market moves 10% against you.
156
```
157
exposure = sum(all_active_order_amounts)
158
max_loss = exposure × 0.10
159
```
160
161
### Scenario 3: Correlation shock
162
All crypto positions move together. Calculate total directional exposure:
163
```
164
net_exposure = sum(long_positions) - sum(short_positions)
165
max_loss_at_20pct = net_exposure × 0.20
166
```
167
168
### Scenario 4: Fee structure change
169
If maker fee doubles (exchange changes tiers), recalculate effective spread for all active strategies. Any that become negative effective spread → must stop.
170
171
## Risk Report Template
172
173
Produce periodically using MCP data:
174
175
```
176
## Risk Report: [Date]
177
178
### Data Sources
179
- Portfolio: get_portfolio_overview() at [timestamp]
180
- Recent orders: search_history(data_type="orders", last 24h)
181
182
### Portfolio Overview
183
| Metric | Value |
184
|--------|-------|
185
| Total deployed | $X |
186
| Net P&L (24h) | +/-$X |
187
| Spread P&L | +$X |
188
| Inventory P&L | +/-$X |
189
| Fees | -$X |
190
| Drawdown from peak | X% |
191
192
### Exposure
193
| Exchange | Pair | Position | Exposure $ | % of total |
194
|----------|------|----------|------------|------------|
195
196
### Alerts
197
| Condition | Status | Action needed |
198
|-----------|--------|---------------|
199
200
### Stress Test
201
| Scenario | Max loss | % of portfolio |
202
|----------|----------|---------------|
203
204
### Recommendations
205
- [Specific actions]
206
```
207
208
## Incident Analysis
209
210
After any loss event or circuit breaker trigger:
211
212
1. **Timeline**: `manage_bots(action="logs", ...)` + `search_history(data_type="orders", start_time=..., end_time=...)`
213
2. **Decompose**: was the loss from inventory (market move) or from spread (adverse selection)?
214
3. **Root cause**: strategy flaw, parameter issue, market regime change, or operational failure?
215
4. **Action**: parameter adjustment, strategy redesign, or resume with no changes?
216
217
Do not restart until the analysis is complete and documented.
223
- Every bot deploys with both drawdown limits set — this is non-negotiable
224
- Decompose P&L into spread + inventory + fees — aggregate P&L hides whether the strategy works
225
- When inventory P&L consistently exceeds spread P&L, the strategy is speculating — stop immediately
226
- Counterparty limits per exchange are hard caps — no exception for "great opportunity"
227
- Correlation between positions is the hidden risk — always assess portfolio-level exposure
228
- Stress test every new strategy before deployment — calculate what happens at -30% across correlated positions
229
- After any circuit breaker trigger: full analysis before restart, no exceptions