Files
trading_bot_v4/docs/PYRAMIDING_IMPLEMENTATION_PLAN.md
mindesbunister b2ff3026c6 docs: Add Pyramiding/Position Stacking implementation plan
- Create comprehensive PYRAMIDING_IMPLEMENTATION_PLAN.md with:
  - Data-driven justification (100% WR for signals ≤72 bars apart)
  - User-selected parameters (4h window, 7x→14x leverage)
  - ENV variables, database schema, execute endpoint logic
  - Position manager updates, Telegram notifications
  - 7-phase implementation checklist
  - 4 expected behavior examples

- Add reference in copilot-instructions.md under Development Roadmap
  - Documents planned pyramiding system
  - Links to implementation plan for future agent
2026-01-09 12:00:51 +01:00

369 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.*