@gaberoo/kalshitools 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +249 -12
- package/dist/commands/markets/scan.d.ts +18 -0
- package/dist/commands/markets/scan.js +237 -0
- package/dist/commands/portfolio/analytics.d.ts +12 -0
- package/dist/commands/portfolio/analytics.js +192 -0
- package/dist/commands/portfolio/history.d.ts +14 -0
- package/dist/commands/portfolio/history.js +245 -0
- package/dist/commands/portfolio/risk.d.ts +11 -0
- package/dist/commands/portfolio/risk.js +206 -0
- package/dist/lib/analytics.d.ts +64 -0
- package/dist/lib/analytics.js +236 -0
- package/dist/lib/risk.d.ts +51 -0
- package/dist/lib/risk.js +153 -0
- package/dist/lib/scanner.d.ts +58 -0
- package/dist/lib/scanner.js +160 -0
- package/docs/TRADING_STRATEGIES.md +538 -0
- package/oclif.manifest.json +486 -188
- package/package.json +1 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Market scanning and opportunity detection utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Calculate total liquidity from an orderbook
|
|
6
|
+
*/
|
|
7
|
+
export function calculateOrderbookLiquidity(orderbook) {
|
|
8
|
+
const yesTotal = orderbook.yes.reduce((sum, level) => sum + level.count * level.price, 0);
|
|
9
|
+
const noTotal = orderbook.no.reduce((sum, level) => sum + level.count * level.price, 0);
|
|
10
|
+
return {
|
|
11
|
+
noTotal,
|
|
12
|
+
total: yesTotal + noTotal,
|
|
13
|
+
yesTotal,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Calculate bid-ask spread from an orderbook
|
|
18
|
+
*
|
|
19
|
+
* In Kalshi orderbooks:
|
|
20
|
+
* - Lower prices in the yes array are bids (buyers)
|
|
21
|
+
* - Higher prices in the yes array are asks (sellers)
|
|
22
|
+
* - Spread = ask - bid
|
|
23
|
+
*/
|
|
24
|
+
export function calculateSpread(orderbook) {
|
|
25
|
+
if (orderbook.yes.length === 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const prices = orderbook.yes.map(level => level.price).sort((a, b) => a - b);
|
|
29
|
+
// Best bid is the lowest price (buyers)
|
|
30
|
+
const yesBid = prices[0];
|
|
31
|
+
// Best ask is the highest price (sellers)
|
|
32
|
+
const yesAsk = prices.at(-1);
|
|
33
|
+
if (!yesAsk || !yesBid) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
// If bid and ask are the same, there's no spread
|
|
37
|
+
const spreadCents = yesAsk - yesBid;
|
|
38
|
+
const midPrice = (yesBid + yesAsk) / 2;
|
|
39
|
+
const spreadPct = midPrice > 0 ? (spreadCents / midPrice) * 100 : 0;
|
|
40
|
+
return {
|
|
41
|
+
spreadCents,
|
|
42
|
+
spreadPct,
|
|
43
|
+
yesAsk,
|
|
44
|
+
yesBid,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const DEFAULT_WEIGHTS = {
|
|
48
|
+
liquidity: 40,
|
|
49
|
+
spread: 30,
|
|
50
|
+
volume: 30,
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Score a market based on liquidity, spread, and volume
|
|
54
|
+
* Returns score from 0-100
|
|
55
|
+
*/
|
|
56
|
+
export function scoreMarket(market, orderbook, weights = DEFAULT_WEIGHTS) {
|
|
57
|
+
let score = 0;
|
|
58
|
+
// Liquidity score (0-40 points)
|
|
59
|
+
const liquidity = calculateOrderbookLiquidity(orderbook);
|
|
60
|
+
const liquidityScore = Math.min(weights.liquidity, (liquidity.total / 5000) * weights.liquidity);
|
|
61
|
+
score += liquidityScore;
|
|
62
|
+
// Spread score (0-30 points) - wider spreads are better for market making
|
|
63
|
+
const spread = calculateSpread(orderbook);
|
|
64
|
+
if (spread) {
|
|
65
|
+
// Spread between 0.03 (3 cents) and 0.20 (20 cents) is ideal
|
|
66
|
+
const { spreadCents } = spread;
|
|
67
|
+
let spreadScore = 0;
|
|
68
|
+
if (spreadCents >= 0.03 && spreadCents <= 0.2) {
|
|
69
|
+
spreadScore = weights.spread;
|
|
70
|
+
}
|
|
71
|
+
else if (spreadCents > 0.2) {
|
|
72
|
+
// Too wide - gradually decrease score
|
|
73
|
+
spreadScore = Math.max(0, weights.spread * (1 - (spreadCents - 0.2) / 0.3));
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// Too narrow - gradually decrease score
|
|
77
|
+
spreadScore = (spreadCents / 0.03) * weights.spread;
|
|
78
|
+
}
|
|
79
|
+
score += spreadScore;
|
|
80
|
+
}
|
|
81
|
+
// Volume score (0-30 points)
|
|
82
|
+
const volume = market.volume_24h || market.volume || 0;
|
|
83
|
+
const volumeScore = Math.min(weights.volume, (volume / 10_000) * weights.volume);
|
|
84
|
+
score += volumeScore;
|
|
85
|
+
return Math.round(score);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Classify the type of opportunity a market presents
|
|
89
|
+
*/
|
|
90
|
+
export function classifyOpportunity(spread, liquidity, volume) {
|
|
91
|
+
const hasWideSpread = spread >= 0.05;
|
|
92
|
+
const hasHighLiquidity = liquidity >= 2000;
|
|
93
|
+
const hasHighVolume = volume >= 5000;
|
|
94
|
+
// Check combinations
|
|
95
|
+
if (hasWideSpread && hasHighLiquidity && hasHighVolume) {
|
|
96
|
+
return 'balanced';
|
|
97
|
+
}
|
|
98
|
+
if (hasWideSpread) {
|
|
99
|
+
return 'wide_spread';
|
|
100
|
+
}
|
|
101
|
+
if (hasHighLiquidity) {
|
|
102
|
+
return 'high_liquidity';
|
|
103
|
+
}
|
|
104
|
+
if (hasHighVolume) {
|
|
105
|
+
return 'high_volume';
|
|
106
|
+
}
|
|
107
|
+
// Default to balanced if none of the above
|
|
108
|
+
return 'balanced';
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Generate human-readable reason for opportunity
|
|
112
|
+
*/
|
|
113
|
+
export function generateOpportunityReason(type, spread, liquidity, volume) {
|
|
114
|
+
const spreadCents = Math.round(spread * 100);
|
|
115
|
+
switch (type) {
|
|
116
|
+
case 'balanced': {
|
|
117
|
+
return `Balanced opportunity: ${spreadCents} cent spread, $${Math.round(liquidity)} liquidity, $${Math.round(volume)} volume`;
|
|
118
|
+
}
|
|
119
|
+
case 'high_liquidity': {
|
|
120
|
+
return `Strong liquidity ($${Math.round(liquidity).toLocaleString()})`;
|
|
121
|
+
}
|
|
122
|
+
case 'high_volume': {
|
|
123
|
+
return `High trading volume ($${Math.round(volume).toLocaleString()} 24h)`;
|
|
124
|
+
}
|
|
125
|
+
case 'wide_spread': {
|
|
126
|
+
return `High liquidity with ${spreadCents} cent spread`;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Filter markets based on criteria
|
|
132
|
+
*/
|
|
133
|
+
export function filterMarketsByCriteria(markets, criteria) {
|
|
134
|
+
return markets.filter(m => {
|
|
135
|
+
// Liquidity check
|
|
136
|
+
if (criteria.minLiquidity && m.liquidity < criteria.minLiquidity) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
// Spread checks
|
|
140
|
+
if (m.spread === null) {
|
|
141
|
+
// No spread data - exclude if spread filters are specified
|
|
142
|
+
if (criteria.minSpread || criteria.maxSpread) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
if (criteria.minSpread && m.spread < criteria.minSpread) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
if (criteria.maxSpread && m.spread > criteria.maxSpread) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Volume check
|
|
155
|
+
if (criteria.minVolume && m.volume < criteria.minVolume) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
return true;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
# Trading Strategies Guide for AI Agents
|
|
2
|
+
|
|
3
|
+
This guide demonstrates how to use kalshitools' advanced analytics and scanning features to implement automated trading strategies. All examples use JSON output for programmatic integration.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Portfolio Analytics](#portfolio-analytics)
|
|
8
|
+
- [Risk Management](#risk-management)
|
|
9
|
+
- [Market Discovery](#market-discovery)
|
|
10
|
+
- [Strategy Examples](#strategy-examples)
|
|
11
|
+
- [Best Practices](#best-practices)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Portfolio Analytics
|
|
16
|
+
|
|
17
|
+
### Understanding Performance Metrics
|
|
18
|
+
|
|
19
|
+
Get comprehensive portfolio analytics:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
kalshitools portfolio analytics --period 30 --json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Key Metrics:**
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"success": true,
|
|
30
|
+
"data": {
|
|
31
|
+
"trades": {
|
|
32
|
+
"total": 45,
|
|
33
|
+
"winning": 28,
|
|
34
|
+
"losing": 17,
|
|
35
|
+
"win_rate": 0.622
|
|
36
|
+
},
|
|
37
|
+
"pnl": {
|
|
38
|
+
"total_pnl": 1250.50,
|
|
39
|
+
"realized_pnl": 980.30,
|
|
40
|
+
"unrealized_pnl": 270.20,
|
|
41
|
+
"avg_win": 85.20,
|
|
42
|
+
"avg_loss": -42.30,
|
|
43
|
+
"total_return_pct": 12.51
|
|
44
|
+
},
|
|
45
|
+
"portfolio": {
|
|
46
|
+
"current_value": 11250.50,
|
|
47
|
+
"exposure": 2750.50,
|
|
48
|
+
"exposure_ratio": 0.244
|
|
49
|
+
},
|
|
50
|
+
"risk": {
|
|
51
|
+
"largest_position_pct": 15.2
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Strategy Evaluation
|
|
58
|
+
|
|
59
|
+
**Assessing Strategy Effectiveness:**
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Get 7-day performance
|
|
63
|
+
kalshitools portfolio analytics --period 7 --json | jq '.data.trades.win_rate'
|
|
64
|
+
|
|
65
|
+
# Get 30-day performance
|
|
66
|
+
kalshitools portfolio analytics --period 30 --json | jq '.data.trades.win_rate'
|
|
67
|
+
|
|
68
|
+
# Compare to determine if strategy is improving
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Key Questions to Answer:**
|
|
72
|
+
|
|
73
|
+
1. **Is the win rate acceptable?** Target: > 55% for market-making, > 60% for directional
|
|
74
|
+
2. **Is the average win > average loss?** Positive expectancy requires this
|
|
75
|
+
3. **Is exposure ratio appropriate?** < 50% for conservative, < 80% for aggressive
|
|
76
|
+
4. **Are fees eating into profits?** Monitor `fee_impact_pct`
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Risk Management
|
|
81
|
+
|
|
82
|
+
### Real-Time Risk Assessment
|
|
83
|
+
|
|
84
|
+
Check portfolio risk before adding new positions:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
kalshitools portfolio risk --threshold 20 --json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Response:**
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"success": true,
|
|
95
|
+
"data": {
|
|
96
|
+
"risk_score": 45,
|
|
97
|
+
"risk_level": "MEDIUM",
|
|
98
|
+
"total_exposure": 2750.50,
|
|
99
|
+
"exposure_ratio": 0.244,
|
|
100
|
+
"concentrations": {
|
|
101
|
+
"by_ticker": [
|
|
102
|
+
{
|
|
103
|
+
"ticker": "MARKET-A",
|
|
104
|
+
"exposure": 1710.00,
|
|
105
|
+
"pct_of_portfolio": 15.2,
|
|
106
|
+
"alert": false
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
"alerts": [],
|
|
111
|
+
"recommendations": {
|
|
112
|
+
"max_new_position_size": 2250.00
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Position Sizing Strategy
|
|
119
|
+
|
|
120
|
+
**Before Opening a Position:**
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# Check recommended max position size
|
|
124
|
+
MAX_SIZE=$(kalshitools portfolio risk --json | jq -r '.data.recommendations.max_new_position_size')
|
|
125
|
+
|
|
126
|
+
# Use this to size your order
|
|
127
|
+
kalshitools orders create \
|
|
128
|
+
--ticker MARKET-A \
|
|
129
|
+
--action buy \
|
|
130
|
+
--side yes \
|
|
131
|
+
--quantity $(echo "$MAX_SIZE / 0.50" | bc) \
|
|
132
|
+
--type limit \
|
|
133
|
+
--price 0.50
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Correlation Monitoring
|
|
137
|
+
|
|
138
|
+
Detect correlated positions (multiple positions in same event):
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
kalshitools portfolio risk --group-by event --json | jq '.data.correlations'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Use Case:**
|
|
145
|
+
- Avoid over-exposure to single events
|
|
146
|
+
- Diversify across uncorrelated markets
|
|
147
|
+
- Reduce systematic risk
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Market Discovery
|
|
152
|
+
|
|
153
|
+
### Finding Trading Opportunities
|
|
154
|
+
|
|
155
|
+
Scan markets for high-quality opportunities:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
kalshitools markets scan \
|
|
159
|
+
--min-liquidity 200 \
|
|
160
|
+
--min-spread 0.05 \
|
|
161
|
+
--max-spread 0.20 \
|
|
162
|
+
--min-volume 1000 \
|
|
163
|
+
--sort-by score \
|
|
164
|
+
--limit 20 \
|
|
165
|
+
--json
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Response:**
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"success": true,
|
|
173
|
+
"data": {
|
|
174
|
+
"markets": [
|
|
175
|
+
{
|
|
176
|
+
"ticker": "MARKET-A",
|
|
177
|
+
"score": 85.5,
|
|
178
|
+
"spread": {
|
|
179
|
+
"yes_bid": 0.62,
|
|
180
|
+
"yes_ask": 0.68,
|
|
181
|
+
"spread_cents": 0.06
|
|
182
|
+
},
|
|
183
|
+
"liquidity": {
|
|
184
|
+
"total": 2430.00
|
|
185
|
+
},
|
|
186
|
+
"volume": {
|
|
187
|
+
"volume_24h": 8500.00
|
|
188
|
+
},
|
|
189
|
+
"opportunity_type": "wide_spread"
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Market-Making Strategy
|
|
197
|
+
|
|
198
|
+
**Criteria for Market-Making:**
|
|
199
|
+
- Wide spreads (> 0.05): Room for profit
|
|
200
|
+
- High liquidity (> 200): Can enter/exit easily
|
|
201
|
+
- Active volume (> 1000): Market is moving
|
|
202
|
+
|
|
203
|
+
**Implementation:**
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# Find markets with wide spreads
|
|
207
|
+
MARKETS=$(kalshitools markets scan \
|
|
208
|
+
--min-spread 0.05 \
|
|
209
|
+
--min-liquidity 300 \
|
|
210
|
+
--sort-by spread \
|
|
211
|
+
--json | jq -r '.data.markets[].ticker')
|
|
212
|
+
|
|
213
|
+
# For each market, place limit orders on both sides
|
|
214
|
+
for TICKER in $MARKETS; do
|
|
215
|
+
# Get current orderbook
|
|
216
|
+
ORDERBOOK=$(kalshitools markets orderbook $TICKER --json)
|
|
217
|
+
|
|
218
|
+
# Calculate fair value and place orders
|
|
219
|
+
# (implementation depends on your pricing model)
|
|
220
|
+
done
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Arbitrage Scanner
|
|
224
|
+
|
|
225
|
+
Look for mispriced markets within the same event:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# Get all markets in an event
|
|
229
|
+
EVENT_MARKETS=$(kalshitools markets list \
|
|
230
|
+
--event-ticker EVENT-2024 \
|
|
231
|
+
--status active \
|
|
232
|
+
--json)
|
|
233
|
+
|
|
234
|
+
# Scan for opportunities
|
|
235
|
+
kalshitools markets scan \
|
|
236
|
+
--event-ticker EVENT-2024 \
|
|
237
|
+
--min-liquidity 100 \
|
|
238
|
+
--json | jq '.data.markets[] | select(.spread.spread_cents > 0.10)'
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Strategy Examples
|
|
244
|
+
|
|
245
|
+
### 1. Mean Reversion Strategy
|
|
246
|
+
|
|
247
|
+
**Goal:** Buy when price drops below historical average, sell when it rises above.
|
|
248
|
+
|
|
249
|
+
**Implementation:**
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
# Step 1: Get historical performance for a ticker
|
|
253
|
+
HISTORY=$(kalshitools portfolio history \
|
|
254
|
+
--ticker MARKET-A \
|
|
255
|
+
--group-by day \
|
|
256
|
+
--json)
|
|
257
|
+
|
|
258
|
+
# Step 2: Calculate average price (pseudocode)
|
|
259
|
+
AVG_PRICE=$(echo "$HISTORY" | jq '[.data.time_series.daily[].avg_price] | add / length')
|
|
260
|
+
|
|
261
|
+
# Step 3: Get current price
|
|
262
|
+
CURRENT_PRICE=$(kalshitools markets show MARKET-A --json | jq '.data.yes_bid')
|
|
263
|
+
|
|
264
|
+
# Step 4: Trade if deviation > threshold
|
|
265
|
+
if (( $(echo "$CURRENT_PRICE < $AVG_PRICE * 0.9" | bc -l) )); then
|
|
266
|
+
# Price is 10% below average - buy
|
|
267
|
+
kalshitools orders create --ticker MARKET-A --action buy --side yes ...
|
|
268
|
+
fi
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### 2. Momentum Strategy
|
|
272
|
+
|
|
273
|
+
**Goal:** Follow trends by trading in the direction of recent price movement.
|
|
274
|
+
|
|
275
|
+
**Implementation:**
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
# Get recent trading activity
|
|
279
|
+
HISTORY=$(kalshitools portfolio history \
|
|
280
|
+
--ticker MARKET-A \
|
|
281
|
+
--group-by day \
|
|
282
|
+
--limit 10 \
|
|
283
|
+
--json)
|
|
284
|
+
|
|
285
|
+
# Calculate momentum indicators
|
|
286
|
+
# - Volume trend (increasing = strong momentum)
|
|
287
|
+
# - Price trend (rising = bullish, falling = bearish)
|
|
288
|
+
|
|
289
|
+
# Trade with the trend
|
|
290
|
+
# (implementation depends on your momentum calculation)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### 3. Portfolio Rebalancing
|
|
294
|
+
|
|
295
|
+
**Goal:** Maintain target exposure levels and concentration limits.
|
|
296
|
+
|
|
297
|
+
**Implementation:**
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
# Step 1: Check current risk
|
|
301
|
+
RISK=$(kalshitools portfolio risk --threshold 15 --json)
|
|
302
|
+
|
|
303
|
+
# Step 2: Identify over-concentrated positions
|
|
304
|
+
OVER_LIMIT=$(echo "$RISK" | jq -r '.data.concentrations.by_ticker[] | select(.alert == true) | .name')
|
|
305
|
+
|
|
306
|
+
# Step 3: Reduce positions that exceed threshold
|
|
307
|
+
for TICKER in $OVER_LIMIT; do
|
|
308
|
+
# Get current position
|
|
309
|
+
POSITION=$(kalshitools portfolio positions --json | \
|
|
310
|
+
jq -r ".data[] | select(.ticker == \"$TICKER\") | .position")
|
|
311
|
+
|
|
312
|
+
# Calculate amount to sell to reach target (15%)
|
|
313
|
+
TARGET_SIZE=$(echo "$RISK" | jq -r '.data.recommendations.max_new_position_size')
|
|
314
|
+
|
|
315
|
+
# Place sell order to reduce position
|
|
316
|
+
kalshitools orders create \
|
|
317
|
+
--ticker $TICKER \
|
|
318
|
+
--action sell \
|
|
319
|
+
--side yes \
|
|
320
|
+
--quantity $REDUCE_BY \
|
|
321
|
+
--type market
|
|
322
|
+
done
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### 4. Statistical Arbitrage
|
|
326
|
+
|
|
327
|
+
**Goal:** Exploit pricing inefficiencies between correlated markets.
|
|
328
|
+
|
|
329
|
+
**Implementation:**
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
# Step 1: Find correlated markets in same event
|
|
333
|
+
kalshitools markets list --event-ticker EVENT-2024 --json
|
|
334
|
+
|
|
335
|
+
# Step 2: Compare prices and liquidity
|
|
336
|
+
kalshitools markets scan --event-ticker EVENT-2024 --json
|
|
337
|
+
|
|
338
|
+
# Step 3: Identify spread > expected
|
|
339
|
+
# If Market A + Market B should sum to 1.00, but sum to 1.10:
|
|
340
|
+
# - Sell the overpriced side
|
|
341
|
+
# - Buy the underpriced side
|
|
342
|
+
# - Profit from convergence
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Best Practices
|
|
348
|
+
|
|
349
|
+
### 1. Pre-Trade Risk Checks
|
|
350
|
+
|
|
351
|
+
**Always check risk before trading:**
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
# Create a pre-trade checklist function
|
|
355
|
+
pre_trade_check() {
|
|
356
|
+
TICKER=$1
|
|
357
|
+
SIZE=$2
|
|
358
|
+
|
|
359
|
+
# Check 1: Portfolio risk
|
|
360
|
+
RISK_SCORE=$(kalshitools portfolio risk --json | jq -r '.data.risk_score')
|
|
361
|
+
if (( $(echo "$RISK_SCORE > 70" | bc -l) )); then
|
|
362
|
+
echo "ERROR: Portfolio risk too high ($RISK_SCORE/100)"
|
|
363
|
+
return 1
|
|
364
|
+
fi
|
|
365
|
+
|
|
366
|
+
# Check 2: Position size limit
|
|
367
|
+
MAX_SIZE=$(kalshitools portfolio risk --json | jq -r '.data.recommendations.max_new_position_size')
|
|
368
|
+
if (( $(echo "$SIZE > $MAX_SIZE" | bc -l) )); then
|
|
369
|
+
echo "ERROR: Position size exceeds limit ($SIZE > $MAX_SIZE)"
|
|
370
|
+
return 1
|
|
371
|
+
fi
|
|
372
|
+
|
|
373
|
+
# Check 3: Market liquidity
|
|
374
|
+
LIQUIDITY=$(kalshitools markets orderbook $TICKER --json | jq -r '.data.liquidity')
|
|
375
|
+
if (( $(echo "$LIQUIDITY < 100" | bc -l) )); then
|
|
376
|
+
echo "ERROR: Insufficient liquidity ($LIQUIDITY)"
|
|
377
|
+
return 1
|
|
378
|
+
fi
|
|
379
|
+
|
|
380
|
+
echo "Pre-trade checks passed"
|
|
381
|
+
return 0
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
# Use before every trade
|
|
385
|
+
if pre_trade_check "MARKET-A" 500; then
|
|
386
|
+
kalshitools orders create --ticker MARKET-A ...
|
|
387
|
+
fi
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### 2. Performance Monitoring
|
|
391
|
+
|
|
392
|
+
**Regular strategy evaluation:**
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
# Daily: Check win rate and P&L
|
|
396
|
+
kalshitools portfolio analytics --period 1 --json > daily_analytics.json
|
|
397
|
+
|
|
398
|
+
# Weekly: Compare to baseline
|
|
399
|
+
kalshitools portfolio analytics --period 7 --json > weekly_analytics.json
|
|
400
|
+
|
|
401
|
+
# Monthly: Full performance review
|
|
402
|
+
kalshitools portfolio analytics --period 30 --json > monthly_analytics.json
|
|
403
|
+
|
|
404
|
+
# Track metrics over time
|
|
405
|
+
echo "$(date),$(jq -r '.data.trades.win_rate' daily_analytics.json)" >> performance_log.csv
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### 3. Diversification
|
|
409
|
+
|
|
410
|
+
**Spread risk across multiple markets:**
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# Target: No single position > 20% of portfolio
|
|
414
|
+
kalshitools portfolio risk --threshold 20 --json
|
|
415
|
+
|
|
416
|
+
# Target: Max 3 positions per event
|
|
417
|
+
kalshitools portfolio risk --group-by event --json | \
|
|
418
|
+
jq '.data.concentrations.by_event[] | select(.markets | length > 3)'
|
|
419
|
+
|
|
420
|
+
# Rebalance if limits exceeded
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### 4. Fee Optimization
|
|
424
|
+
|
|
425
|
+
**Prefer maker orders to minimize fees:**
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
# Check maker vs taker ratio
|
|
429
|
+
kalshitools portfolio history --json | jq '.data.maker_taker'
|
|
430
|
+
|
|
431
|
+
# Target: > 70% maker fills for optimal fee structure
|
|
432
|
+
# Maker fee: 0.5%, Taker fee: 1.5%
|
|
433
|
+
# Use limit orders instead of market orders when possible
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### 5. Rate Limiting
|
|
437
|
+
|
|
438
|
+
**Respect API rate limits (20 req/sec for reads, 10 req/sec for writes):**
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# Use sleep between API calls
|
|
442
|
+
for TICKER in $TICKERS; do
|
|
443
|
+
kalshitools markets show $TICKER --json
|
|
444
|
+
sleep 0.1 # 100ms delay = max 10 req/sec
|
|
445
|
+
done
|
|
446
|
+
|
|
447
|
+
# Batch requests when possible
|
|
448
|
+
kalshitools markets list --tickers "TICKER1,TICKER2,TICKER3" --json
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Integration with OpenClaw
|
|
454
|
+
|
|
455
|
+
kalshitools is designed for seamless integration with AI trading agents:
|
|
456
|
+
|
|
457
|
+
```python
|
|
458
|
+
import subprocess
|
|
459
|
+
import json
|
|
460
|
+
|
|
461
|
+
class KalshiAgent:
|
|
462
|
+
def get_analytics(self, period=30):
|
|
463
|
+
"""Get portfolio analytics"""
|
|
464
|
+
result = subprocess.run(
|
|
465
|
+
['kalshitools', 'portfolio', 'analytics',
|
|
466
|
+
'--period', str(period), '--json'],
|
|
467
|
+
capture_output=True, text=True
|
|
468
|
+
)
|
|
469
|
+
return json.loads(result.stdout)
|
|
470
|
+
|
|
471
|
+
def check_risk(self, threshold=20):
|
|
472
|
+
"""Check portfolio risk"""
|
|
473
|
+
result = subprocess.run(
|
|
474
|
+
['kalshitools', 'portfolio', 'risk',
|
|
475
|
+
'--threshold', str(threshold), '--json'],
|
|
476
|
+
capture_output=True, text=True
|
|
477
|
+
)
|
|
478
|
+
return json.loads(result.stdout)
|
|
479
|
+
|
|
480
|
+
def scan_markets(self, min_liquidity=200, min_spread=0.05):
|
|
481
|
+
"""Scan for opportunities"""
|
|
482
|
+
result = subprocess.run(
|
|
483
|
+
['kalshitools', 'markets', 'scan',
|
|
484
|
+
'--min-liquidity', str(min_liquidity),
|
|
485
|
+
'--min-spread', str(min_spread),
|
|
486
|
+
'--json'],
|
|
487
|
+
capture_output=True, text=True
|
|
488
|
+
)
|
|
489
|
+
return json.loads(result.stdout)
|
|
490
|
+
|
|
491
|
+
def make_decision(self):
|
|
492
|
+
"""Example trading decision logic"""
|
|
493
|
+
# Get current portfolio state
|
|
494
|
+
analytics = self.get_analytics(period=7)
|
|
495
|
+
risk = self.check_risk(threshold=20)
|
|
496
|
+
|
|
497
|
+
# Check if we should trade
|
|
498
|
+
if analytics['data']['trades']['win_rate'] < 0.5:
|
|
499
|
+
return "SKIP", "Win rate too low"
|
|
500
|
+
|
|
501
|
+
if risk['data']['risk_score'] > 70:
|
|
502
|
+
return "SKIP", "Portfolio risk too high"
|
|
503
|
+
|
|
504
|
+
# Find opportunities
|
|
505
|
+
opportunities = self.scan_markets()
|
|
506
|
+
|
|
507
|
+
if len(opportunities['data']['markets']) == 0:
|
|
508
|
+
return "SKIP", "No opportunities found"
|
|
509
|
+
|
|
510
|
+
# Take best opportunity
|
|
511
|
+
best = opportunities['data']['markets'][0]
|
|
512
|
+
max_size = risk['data']['recommendations']['max_new_position_size']
|
|
513
|
+
|
|
514
|
+
return "TRADE", {
|
|
515
|
+
'ticker': best['ticker'],
|
|
516
|
+
'size': max_size,
|
|
517
|
+
'reason': best['reason']
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## Summary
|
|
524
|
+
|
|
525
|
+
kalshitools provides four key capabilities for automated trading:
|
|
526
|
+
|
|
527
|
+
1. **Portfolio Analytics**: Measure strategy performance
|
|
528
|
+
2. **Risk Management**: Control exposure and concentration
|
|
529
|
+
3. **Historical Analysis**: Learn from past trades
|
|
530
|
+
4. **Market Scanner**: Discover opportunities systematically
|
|
531
|
+
|
|
532
|
+
All commands output structured JSON for easy integration with AI agents and automated systems.
|
|
533
|
+
|
|
534
|
+
**Next Steps:**
|
|
535
|
+
- Start with manual exploration using the CLI
|
|
536
|
+
- Build analytics dashboards using the JSON output
|
|
537
|
+
- Implement automated strategies with proper risk controls
|
|
538
|
+
- Monitor performance and iterate on your approach
|