# Pyramiding / Signal Stacking Implementation Plan **Created:** January 9, 2026 **Status:** šŸ“‹ PLANNED - Ready for Implementation **Priority:** HIGH - User-requested feature based on backtested data --- ## šŸ“Š Background & Data-Driven Justification ### Analysis Results (Jan 9, 2026) From CSV analysis of ML v11.2 Long Only strategy on SOL/USDT 5-min chart: | Signal Spacing | Pairs | Win Rate | Avg Combined P&L | |----------------|-------|----------|------------------| | ≤72 bars (6h) | 9 | **100%** | +4.82% | | >72 bars | 34 | 67.6% | +1.94% | **Key Finding:** Signals within 72 bars (6 hours) of each other have **100% win rate** - these represent trend confirmation and are ideal for stacking. ### User-Selected Parameters - **Stacking Window:** 4 hours (48 bars on 5-min chart) - conservative vs 6h optimal - **Base Leverage:** 7x (down from previous 10x for safety) - **Stacked Leverage:** 14x total (7x + 7x) - **Max Pyramid Levels:** 2 (base + 1 stack) --- ## šŸ—ļø Implementation Components ### 1. Environment Variables (.env) ```bash # === PYRAMIDING / STACKING === ENABLE_PYRAMIDING=true BASE_LEVERAGE=7 STACK_LEVERAGE=7 MAX_LEVERAGE_TOTAL=14 STACKING_WINDOW_MINUTES=240 # 4 hours = 48 bars on 5-min chart MAX_PYRAMID_LEVELS=2 # Base + 1 additional stack # Per-symbol overrides (optional) SOLANA_BASE_LEVERAGE=7 SOLANA_MAX_LEVERAGE=14 SOLANA_STACKING_WINDOW_MINUTES=240 ``` ### 2. Configuration (config/trading.ts) Add to `TradingConfig` interface: ```typescript interface TradingConfig { // ... existing fields ... // Pyramiding settings enablePyramiding: boolean; baseLeverage: number; stackLeverage: number; maxLeverageTotal: number; stackingWindowMinutes: number; maxPyramidLevels: number; } ``` Add to `DEFAULT_TRADING_CONFIG`: ```typescript enablePyramiding: true, baseLeverage: 7, stackLeverage: 7, maxLeverageTotal: 14, stackingWindowMinutes: 240, // 4 hours maxPyramidLevels: 2, ``` Add to `getConfigFromEnv()`: ```typescript enablePyramiding: process.env.ENABLE_PYRAMIDING === 'true', baseLeverage: parseInt(process.env.BASE_LEVERAGE || '7'), stackLeverage: parseInt(process.env.STACK_LEVERAGE || '7'), maxLeverageTotal: parseInt(process.env.MAX_LEVERAGE_TOTAL || '14'), stackingWindowMinutes: parseInt(process.env.STACKING_WINDOW_MINUTES || '240'), maxPyramidLevels: parseInt(process.env.MAX_PYRAMID_LEVELS || '2'), ``` ### 3. Database Schema (prisma/schema.prisma) Add to Trade model: ```prisma model Trade { // ... existing fields ... // Pyramiding tracking pyramidLevel Int? @default(1) // 1 = base, 2 = first stack, etc. parentTradeId String? // Reference to base trade if stacked stackedAt DateTime? // When stack was added totalLeverageAtEntry Float? // Total leverage including stacks isStackedPosition Boolean @default(false) // True if this is a stack entry } ``` ### 4. Execute Endpoint (app/api/trading/execute/route.ts) #### A. Add Stacking Logic Check Before opening a new position, check if we should stack: ```typescript // Check for existing open position in same direction const existingOpenTrade = await prisma.trade.findFirst({ where: { symbol: driftSymbol, direction: direction, exitReason: null, // Still open }, orderBy: { createdAt: 'desc' } }); // Determine if this is a stack opportunity let isStackEntry = false; let effectiveLeverage = config.baseLeverage; let pyramidLevel = 1; if (existingOpenTrade && config.enablePyramiding) { const minutesSinceEntry = (Date.now() - new Date(existingOpenTrade.createdAt).getTime()) / 60000; const currentPyramidLevel = existingOpenTrade.pyramidLevel || 1; if (minutesSinceEntry <= config.stackingWindowMinutes && currentPyramidLevel < config.maxPyramidLevels) { // This is a valid stack opportunity isStackEntry = true; pyramidLevel = currentPyramidLevel + 1; effectiveLeverage = config.stackLeverage; // Add another 7x console.log(`šŸ“ˆ PYRAMID STACK: Signal within ${minutesSinceEntry.toFixed(0)} minutes`) console.log(` Level: ${pyramidLevel}/${config.maxPyramidLevels}`) console.log(` Adding: ${effectiveLeverage}x leverage`) console.log(` Total: ${currentPyramidLevel * config.baseLeverage + effectiveLeverage}x`) } else if (minutesSinceEntry > config.stackingWindowMinutes) { console.log(`ā° Stack window expired: ${minutesSinceEntry.toFixed(0)} min > ${config.stackingWindowMinutes} min`) console.log(` Treating as independent signal (not stacking)`) } else if (currentPyramidLevel >= config.maxPyramidLevels) { console.log(`šŸ”’ Max pyramid level reached: ${currentPyramidLevel}/${config.maxPyramidLevels}`) console.log(` Ignoring additional signal`) return NextResponse.json({ success: false, error: 'Max pyramid level reached', details: { currentLevel: currentPyramidLevel, maxLevel: config.maxPyramidLevels } }); } } ``` #### B. Modify Position Opening When opening position, use the determined leverage: ```typescript // Use effective leverage (base or stack) const positionParams = { symbol: driftSymbol, direction: direction, leverage: effectiveLeverage, // 7x for both base and stack // ... other params }; ``` #### C. Update Database Record Store pyramiding info in trade record: ```typescript const tradeData = { // ... existing fields ... pyramidLevel: pyramidLevel, parentTradeId: isStackEntry ? existingOpenTrade.id : null, stackedAt: isStackEntry ? new Date() : null, totalLeverageAtEntry: isStackEntry ? (existingOpenTrade.totalLeverageAtEntry || config.baseLeverage) + effectiveLeverage : effectiveLeverage, isStackedPosition: isStackEntry, }; ``` ### 5. Position Manager (lib/trading/position-manager.ts) #### A. Track Stacked Positions Together Modify `ActiveTrade` interface: ```typescript interface ActiveTrade { // ... existing fields ... pyramidLevel: number; parentTradeId?: string; isStackedPosition: boolean; totalLeverage: number; } ``` #### B. Unified Exit Logic When closing a position, close ALL pyramid levels: ```typescript async closePosition(tradeId: string, reason: string) { const trade = this.activeTrades.get(tradeId); // If this is a base position with stacks, close all if (trade && !trade.isStackedPosition) { const stackedTrades = Array.from(this.activeTrades.values()) .filter(t => t.parentTradeId === tradeId); for (const stackedTrade of stackedTrades) { console.log(`šŸ”— Closing stacked position: ${stackedTrade.id} (level ${stackedTrade.pyramidLevel})`); await this.executeClose(stackedTrade, reason); } } await this.executeClose(trade, reason); } ``` ### 6. Telegram Notifications (lib/notifications/telegram.ts) Update position notifications to show pyramid info: ```typescript // For stacked entries if (trade.isStackedPosition) { message += `\nšŸ“ˆ PYRAMID STACK (Level ${trade.pyramidLevel}/${config.maxPyramidLevels})`; message += `\nšŸ’Ŗ Total Leverage: ${trade.totalLeverageAtEntry}x`; message += `\nā±ļø Stacked ${Math.round((Date.now() - new Date(trade.parentTrade.createdAt).getTime()) / 60000)} min after base`; } ``` --- ## šŸ”’ Risk Management Safeguards ### Critical Safety Checks 1. **Max Leverage Guard** ```typescript if (totalLeverage > config.maxLeverageTotal) { console.error(`āŒ BLOCKED: Would exceed max leverage (${totalLeverage}x > ${config.maxLeverageTotal}x)`); return; } ``` 2. **Same Direction Only** - Only stack in same direction as existing position - Opposite signal should close existing position, not stack 3. **Time Window Enforcement** - Hard 4-hour (240 minute) window - Signals outside window treated as independent trades 4. **Max Levels Cap** - Maximum 2 pyramid levels (base + 1 stack = 14x max) - Additional signals beyond max are ignored with warning 5. **Quality Score Requirement** - Stacked entries should still pass quality score threshold - Don't stack low-quality confirmations --- ## šŸ“‹ Implementation Checklist ### Phase 1: Configuration - [ ] Add ENV variables to `.env` - [ ] Update `TradingConfig` interface in `config/trading.ts` - [ ] Add defaults to `DEFAULT_TRADING_CONFIG` - [ ] Add ENV parsing to `getConfigFromEnv()` ### Phase 2: Database - [ ] Add new fields to Trade model in `prisma/schema.prisma` - [ ] Run `npx prisma migrate dev --name add_pyramiding_fields` - [ ] Run `npx prisma generate` ### Phase 3: Execute Endpoint - [ ] Add existing position check logic - [ ] Add pyramid level calculation - [ ] Add stacking window validation - [ ] Modify position opening with effective leverage - [ ] Update trade record with pyramid info - [ ] Add logging for stack events ### Phase 4: Position Manager - [ ] Update ActiveTrade interface - [ ] Add stack tracking to position Map - [ ] Implement unified exit (close all levels together) - [ ] Update MAE/MFE tracking for combined position ### Phase 5: Notifications - [ ] Update Telegram entry notification with stack info - [ ] Update exit notification with combined P&L ### Phase 6: Testing - [ ] Test base entry (7x leverage) - [ ] Test stack entry within window (14x total) - [ ] Test signal outside window (independent trade) - [ ] Test max pyramid level blocking - [ ] Test unified exit closes all levels - [ ] Test opposite direction closes stacked position ### Phase 7: Documentation - [ ] Update copilot-instructions.md with pyramiding section - [ ] Add to Settings UI (optional) --- ## šŸ“Š Expected Behavior Examples ### Example 1: Successful Stack ``` 10:00 - BUY signal (quality 95) → Open LONG 7x leverage 12:30 - BUY signal (quality 92) → Stack! Within 4h window → Add 7x leverage → Total position: 14x leverage 14:00 - TP1 hit → Close entire stacked position → P&L calculated on 14x total leverage ``` ### Example 2: Outside Window ``` 10:00 - BUY signal → Open LONG 7x leverage 15:00 - BUY signal → 5 hours later, outside 4h window → Treated as independent trade → Close existing position, open new 7x position ``` ### Example 3: Max Level Reached ``` 10:00 - BUY signal → Open LONG 7x (level 1) 11:00 - BUY signal → Stack 7x (level 2, total 14x) 12:00 - BUY signal → Max level reached! → Log warning, ignore signal → Keep existing 14x position ``` ### Example 4: Opposite Signal ``` 10:00 - BUY signal → Open LONG 7x leverage 11:00 - SELL signal → Opposite direction! → Close LONG position entirely → Open new SHORT 7x position ``` --- ## šŸ”— References - **Analysis Source:** `/home/icke/traderv4/docs/PYRAMIDING_IMPLEMENTATION_PLAN.md` - **TradingView Strategy:** `/home/icke/traderv4/workflows/trading/moneyline_v11_2_strategy.pinescript` - **CSV Analysis Data:** `ML_v11.2_Strat_MEXC_SOLUSDT.P_2026-01-09.csv` - **Optimal Threshold Analysis:** 72 bars (6 hours) = 100% WR for stacked signals --- ## āš ļø Important Notes 1. **Conservative Window:** User chose 4 hours (48 bars) vs optimal 6 hours (72 bars) for safety 2. **Leverage Reduction:** Base leverage reduced from 10x to 7x to accommodate stacking safely 3. **Total Cap:** 14x maximum (7x + 7x) prevents over-leveraging 4. **Quality Gate:** Stack signals should still meet quality thresholds --- *This plan is ready for implementation. Reference this document when implementing pyramiding in the trading bot.*