- Extended MarketConfig with optional positionSize and leverage fields
- Configured ETH-PERP at @ 1x leverage for minimal-risk data collection
- Created getPositionSizeForSymbol() helper function in config/trading.ts
- Integrated symbol-specific sizing into execute endpoint
- Added comprehensive guide in docs/guides/SYMBOL_SPECIFIC_SIZING.md
Purpose: Enable ETH trading for faster signal quality data collection
while preserving SOL's profit-generation sizing (0 @ 10x)
Next: Create ETH alert in TradingView and restart bot
273 lines
7.4 KiB
Markdown
273 lines
7.4 KiB
Markdown
# Symbol-Specific Position Sizing Guide
|
||
|
||
## Overview
|
||
|
||
The bot now supports different position sizes and leverage for each trading symbol. This enables strategies like:
|
||
|
||
- **High-risk symbols (SOL):** $50 @ 10x leverage = $500 exposure (profit generation)
|
||
- **Low-risk symbols (ETH):** $1 @ 1x leverage = $1 exposure (data collection)
|
||
|
||
## Configuration
|
||
|
||
### 1. Market Configuration (`config/trading.ts`)
|
||
|
||
```typescript
|
||
export const SUPPORTED_MARKETS: Record<string, MarketConfig> = {
|
||
'SOL-PERP': {
|
||
driftMarketIndex: 0,
|
||
pythFeedId: '0xef0d...',
|
||
// Uses default config.positionSize and config.leverage
|
||
},
|
||
'ETH-PERP': {
|
||
driftMarketIndex: 1,
|
||
pythFeedId: '0xff61...',
|
||
// OVERRIDE: Data collection mode with minimal risk
|
||
positionSize: 1, // $1 base size
|
||
leverage: 1, // 1x leverage = $1 total exposure
|
||
},
|
||
'BTC-PERP': {
|
||
driftMarketIndex: 2,
|
||
pythFeedId: '0xe62d...',
|
||
// Uses default config.positionSize and config.leverage
|
||
},
|
||
}
|
||
```
|
||
|
||
### 2. Helper Function
|
||
|
||
```typescript
|
||
export function getPositionSizeForSymbol(
|
||
symbol: string,
|
||
baseConfig: TradingConfig
|
||
): { size: number; leverage: number } {
|
||
const marketConfig = SUPPORTED_MARKETS[symbol]
|
||
if (!marketConfig) {
|
||
throw new Error(`Unsupported symbol: ${symbol}`)
|
||
}
|
||
|
||
return {
|
||
size: marketConfig.positionSize ?? baseConfig.positionSize,
|
||
leverage: marketConfig.leverage ?? baseConfig.leverage,
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. Execute Endpoint Integration
|
||
|
||
The `app/api/trading/execute/route.ts` endpoint now:
|
||
|
||
1. Normalizes symbol (ETHUSDT → ETH-PERP)
|
||
2. Gets merged config via `getMergedConfig()`
|
||
3. **Calls `getPositionSizeForSymbol(symbol, config)`** to get symbol-specific sizing
|
||
4. Uses returned `{ size, leverage }` for position calculation
|
||
|
||
## Example: ETH Data Collection Setup
|
||
|
||
### Goal
|
||
Collect as many ETH signals as possible with minimal risk to improve signal quality analysis.
|
||
|
||
### Configuration
|
||
```typescript
|
||
'ETH-PERP': {
|
||
driftMarketIndex: 1,
|
||
pythFeedId: '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace',
|
||
positionSize: 1, // $1 base size
|
||
leverage: 1, // No leverage
|
||
}
|
||
```
|
||
|
||
### Expected Behavior
|
||
- TradingView sends: `ETHUSDT LONG` or `ETHUSDT SHORT`
|
||
- Bot normalizes to: `ETH-PERP`
|
||
- Bot loads sizing: `positionSize: 1, leverage: 1`
|
||
- Position size: `$1 × 1 = $1 total exposure`
|
||
- At ETH = $3,500: Opens ~0.00029 ETH position
|
||
- Risk: Maximum loss = ~$1 (if emergency stop hits)
|
||
|
||
### Console Output
|
||
```
|
||
📊 Normalized symbol: ETHUSDT → ETH-PERP
|
||
📐 Symbol-specific sizing for ETH-PERP:
|
||
Position size: $1
|
||
Leverage: 1x
|
||
💰 Opening LONG position:
|
||
Symbol: ETH-PERP
|
||
Base size: $1
|
||
Leverage: 1x
|
||
Total position: $1
|
||
```
|
||
|
||
## Testing
|
||
|
||
### 1. SOL Trade (Default Sizing)
|
||
Send webhook:
|
||
```json
|
||
{
|
||
"symbol": "SOLUSDT",
|
||
"direction": "LONG"
|
||
}
|
||
```
|
||
|
||
Expected logs:
|
||
```
|
||
📐 Symbol-specific sizing for SOL-PERP:
|
||
Position size: $50
|
||
Leverage: 10x
|
||
Total position: $500
|
||
```
|
||
|
||
### 2. ETH Trade (Override Sizing)
|
||
Send webhook:
|
||
```json
|
||
{
|
||
"symbol": "ETHUSDT",
|
||
"direction": "SHORT"
|
||
}
|
||
```
|
||
|
||
Expected logs:
|
||
```
|
||
📐 Symbol-specific sizing for ETH-PERP:
|
||
Position size: $1
|
||
Leverage: 1x
|
||
Total position: $1
|
||
```
|
||
|
||
### 3. Verify in Drift
|
||
Check open positions - ETH position should show ~$1 notional value.
|
||
|
||
## Strategy Rationale
|
||
|
||
### Why $1 @ 1x for ETH?
|
||
|
||
1. **Data Collection Priority:** ETH shows 2-3x more signals than SOL
|
||
2. **Risk Management:** Cross margin means ETH position uses shared collateral
|
||
3. **No Profit Pressure:** Not trying to make money on ETH, just gather quality scores
|
||
4. **Statistical Significance:** Need 20-50 trades with quality scores before Phase 2
|
||
5. **Collateral Preservation:** Current SOL long uses most collateral, can't risk large ETH positions
|
||
|
||
### When to Increase ETH Sizing?
|
||
|
||
Only after:
|
||
- ✅ Phase 1 complete (20-50 trades with quality scores)
|
||
- ✅ ETH signal quality proven ≥ SOL (win rate, profit factor)
|
||
- ✅ Sufficient collateral available (not at risk of liquidation)
|
||
- ✅ Phase 2 ATR-based targets implemented and validated
|
||
|
||
## Cross Margin Considerations
|
||
|
||
**Critical:** All positions (SOL, ETH, BTC) share the same collateral pool on Drift.
|
||
|
||
### Collateral Math
|
||
```
|
||
Total Collateral: $500
|
||
Current SOL position: ~$450 used
|
||
Free collateral: ~$50
|
||
|
||
Adding ETH @ $1:
|
||
- Maintenance margin: ~$0.05 (5%)
|
||
- Initial margin: ~$0.10 (10%)
|
||
- Impact: Minimal ✅
|
||
|
||
Adding ETH @ $50:
|
||
- Maintenance margin: ~$2.50
|
||
- Initial margin: ~$5
|
||
- Risk: Higher liquidation risk ⚠️
|
||
```
|
||
|
||
### Safety Buffer
|
||
Keep at least 30% free collateral at all times:
|
||
- Total: $500
|
||
- Max used: $350 (70%)
|
||
- Reserve: $150 (30%) for margin calls and new positions
|
||
|
||
## Future Enhancements
|
||
|
||
### Phase 2: Reserve-Based Sizing Module
|
||
|
||
Create `lib/trading/position-sizing.ts`:
|
||
|
||
```typescript
|
||
export interface PositionSizingParams {
|
||
symbol: string
|
||
direction: 'long' | 'short'
|
||
totalCollateral: number
|
||
usedCollateral: number
|
||
marketConfig: MarketConfig
|
||
baseConfig: TradingConfig
|
||
}
|
||
|
||
export function calculatePositionSize(params: PositionSizingParams): number {
|
||
const freeCollateral = params.totalCollateral - params.usedCollateral
|
||
const reservePercent = 0.30 // Keep 30% reserve
|
||
const availableForTrade = freeCollateral * (1 - reservePercent)
|
||
|
||
// Get base size from market config or default
|
||
const baseSize = params.marketConfig.positionSize ?? params.baseConfig.positionSize
|
||
const leverage = params.marketConfig.leverage ?? params.baseConfig.leverage
|
||
const requiredCollateral = baseSize * leverage * 0.10 // 10% initial margin
|
||
|
||
// If not enough collateral, reduce position size
|
||
if (requiredCollateral > availableForTrade) {
|
||
return availableForTrade / leverage / 0.10
|
||
}
|
||
|
||
return baseSize
|
||
}
|
||
```
|
||
|
||
**Benefits:**
|
||
- Prevents over-leveraging
|
||
- Maintains safety buffer
|
||
- Dynamic sizing based on account state
|
||
- Supports multiple concurrent positions
|
||
|
||
**When to implement:** After Phase 1 validation, before increasing ETH position sizes.
|
||
|
||
## Troubleshooting
|
||
|
||
### Issue: ETH still trading at $50
|
||
|
||
**Check:**
|
||
1. Restart bot after config changes: `docker restart trading-bot-v4`
|
||
2. Verify config loaded: Check console logs for "Symbol-specific sizing"
|
||
3. Ensure symbol normalization: ETHUSDT → ETH-PERP (not ETH-USD)
|
||
|
||
### Issue: Position Manager using wrong size
|
||
|
||
**Root cause:** Position Manager calculates position amounts from on-chain data, not config.
|
||
|
||
**Behavior:**
|
||
- Execute endpoint uses `positionSize` and `leverage` from config
|
||
- Position Manager reads actual position size from Drift
|
||
- They're independent systems (by design for safety)
|
||
|
||
### Issue: Database shows wrong positionSize
|
||
|
||
**Root cause:** Database stores actual executed size, not config size.
|
||
|
||
**Expected:**
|
||
- Config: `ETH-PERP positionSize: 1`
|
||
- Database: `positionSize: 1.0` (matches execution)
|
||
- Drift on-chain: ~0.00029 ETH (~$1 notional)
|
||
|
||
All three should align. If not, config didn't load properly.
|
||
|
||
## Summary
|
||
|
||
Symbol-specific sizing enables:
|
||
- ✅ Multi-asset trading with different risk profiles
|
||
- ✅ Data collection strategies (ETH @ $1)
|
||
- ✅ Profit generation strategies (SOL @ $50)
|
||
- ✅ Cross-margin safety (minimal ETH exposure)
|
||
- ✅ Faster signal quality validation (more trades)
|
||
|
||
**Next steps:**
|
||
1. ✅ Config updated (DONE)
|
||
2. ✅ Execute endpoint integrated (DONE)
|
||
3. ⏸️ Create ETH alert in TradingView (USER ACTION)
|
||
4. ⏸️ Restart bot: `docker restart trading-bot-v4`
|
||
5. ⏸️ Monitor first ETH trade for correct sizing
|
||
6. ⏸️ Collect 20-50 trades with quality scores
|
||
7. ⏸️ Proceed to Phase 2 (ATR-based dynamic targets)
|