diff --git a/app/api/trading/execute/route.ts b/app/api/trading/execute/route.ts index 7052579..e37a7aa 100644 --- a/app/api/trading/execute/route.ts +++ b/app/api/trading/execute/route.ts @@ -166,6 +166,14 @@ export async function POST(request: NextRequest): Promise = { pythPriceFeedId: '0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d', minOrderSize: 0.1, // 0.1 SOL minimum tickSize: 0.0001, + // Use default config values (positionSize: 50, leverage: 10) }, 'BTC-PERP': { symbol: 'BTC-PERP', @@ -115,6 +119,7 @@ export const SUPPORTED_MARKETS: Record = { pythPriceFeedId: '0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43', minOrderSize: 0.001, // 0.001 BTC minimum tickSize: 0.01, + // Use default config values }, 'ETH-PERP': { symbol: 'ETH-PERP', @@ -122,6 +127,9 @@ export const SUPPORTED_MARKETS: Record = { pythPriceFeedId: '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace', minOrderSize: 0.01, // 0.01 ETH minimum tickSize: 0.01, + // DATA COLLECTION MODE: Minimal risk + positionSize: 1, // $1 USD base capital only + leverage: 1, // 1x leverage = $1 position size total }, } @@ -147,6 +155,16 @@ export function getMarketConfig(symbol: string): MarketConfig { return config } +// Get position size for specific symbol (with market-specific overrides) +export function getPositionSizeForSymbol(symbol: string, baseConfig: TradingConfig): { size: number; leverage: number } { + const marketConfig = getMarketConfig(symbol) + + return { + size: marketConfig.positionSize ?? baseConfig.positionSize, + leverage: marketConfig.leverage ?? baseConfig.leverage + } +} + // Validate trading configuration export function validateTradingConfig(config: TradingConfig): void { if (config.positionSize <= 0) { diff --git a/docs/guides/SYMBOL_SPECIFIC_SIZING.md b/docs/guides/SYMBOL_SPECIFIC_SIZING.md new file mode 100644 index 0000000..3ee5e92 --- /dev/null +++ b/docs/guides/SYMBOL_SPECIFIC_SIZING.md @@ -0,0 +1,272 @@ +# 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 = { + '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)