- 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
7.4 KiB
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)
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
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:
- Normalizes symbol (ETHUSDT → ETH-PERP)
- Gets merged config via
getMergedConfig() - Calls
getPositionSizeForSymbol(symbol, config)to get symbol-specific sizing - 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
'ETH-PERP': {
driftMarketIndex: 1,
pythFeedId: '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace',
positionSize: 1, // $1 base size
leverage: 1, // No leverage
}
Expected Behavior
- TradingView sends:
ETHUSDT LONGorETHUSDT 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:
{
"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:
{
"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?
- Data Collection Priority: ETH shows 2-3x more signals than SOL
- Risk Management: Cross margin means ETH position uses shared collateral
- No Profit Pressure: Not trying to make money on ETH, just gather quality scores
- Statistical Significance: Need 20-50 trades with quality scores before Phase 2
- 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:
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:
- Restart bot after config changes:
docker restart trading-bot-v4 - Verify config loaded: Check console logs for "Symbol-specific sizing"
- 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
positionSizeandleveragefrom 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:
- ✅ Config updated (DONE)
- ✅ Execute endpoint integrated (DONE)
- ⏸️ Create ETH alert in TradingView (USER ACTION)
- ⏸️ Restart bot:
docker restart trading-bot-v4 - ⏸️ Monitor first ETH trade for correct sizing
- ⏸️ Collect 20-50 trades with quality scores
- ⏸️ Proceed to Phase 2 (ATR-based dynamic targets)