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
This commit is contained in:
72
.github/copilot-instructions.md
vendored
72
.github/copilot-instructions.md
vendored
@@ -5947,6 +5947,78 @@ All technical improvements must align with current phase objectives (see top of
|
||||
- Comparison with executed trades at similar quality levels
|
||||
- Future automation of price tracking (would TP1/TP2/SL have hit?)
|
||||
|
||||
---
|
||||
|
||||
## 🔺 Pyramiding/Position Stacking System (Jan 6, 2026 - PLANNED)
|
||||
|
||||
**Status:** 📋 PLANNED - Implementation plan ready, awaiting development
|
||||
|
||||
**Purpose:** Scale into winning positions by adding to existing trades when confirmation signals arrive within a time window. Based on ML v11.2 backtesting analysis showing 100% win rate for signals ≤72 bars apart.
|
||||
|
||||
**Implementation Plan:** See `docs/PYRAMIDING_IMPLEMENTATION_PLAN.md` for complete details
|
||||
|
||||
**Key Parameters (User-Selected):**
|
||||
- **Stacking Window:** 4 hours (240 minutes / 48 bars on 5-min chart)
|
||||
- **Base Leverage:** 7x (first entry)
|
||||
- **Stack Leverage:** 7x (additional entry)
|
||||
- **Max Total Leverage:** 14x (7x + 7x = 2 pyramid levels)
|
||||
- **Max Pyramid Levels:** 2 (base + 1 stack)
|
||||
|
||||
**Data-Driven Justification:**
|
||||
- Backtesting analysis of ML v11.2 pyramiding trades
|
||||
- **≤72 bars (6 hours):** 100% win rate - signals close together confirm trend
|
||||
- **>72 bars:** 67.6% win rate - too far apart, trend may have reversed
|
||||
- User chose conservative 48-bar (4-hour) window for production
|
||||
|
||||
**Environment Variables (New):**
|
||||
```bash
|
||||
ENABLE_PYRAMIDING=true
|
||||
BASE_LEVERAGE=7
|
||||
STACK_LEVERAGE=7
|
||||
MAX_LEVERAGE_TOTAL=14
|
||||
MAX_PYRAMID_LEVELS=2
|
||||
STACKING_WINDOW_MINUTES=240
|
||||
```
|
||||
|
||||
**Database Schema Changes:**
|
||||
```prisma
|
||||
model Trade {
|
||||
// ... existing fields
|
||||
pyramidLevel Int? // 1 = base, 2 = first stack, etc.
|
||||
parentTradeId String? // Links stacked trades to base
|
||||
stackedAt DateTime? // When stack was added
|
||||
totalLeverageAtEntry Float? // Running total leverage
|
||||
isStackedPosition Boolean @default(false)
|
||||
}
|
||||
```
|
||||
|
||||
**Core Logic:**
|
||||
1. First signal → Open position with 7x leverage (pyramidLevel: 1)
|
||||
2. Second signal within 4 hours → Check if same direction + within window
|
||||
3. If valid → Add 7x position (pyramidLevel: 2), total leverage now 14x
|
||||
4. Position Manager tracks both as linked positions
|
||||
5. Exit → Close ALL pyramid levels together (unified exit)
|
||||
|
||||
**Safety Checks:**
|
||||
- ✅ Same direction only (no hedging)
|
||||
- ✅ Within stacking window (4 hours default)
|
||||
- ✅ Max leverage cap (14x)
|
||||
- ✅ Max pyramid levels (2)
|
||||
- ✅ Sufficient free collateral for additional position
|
||||
|
||||
**TradingView Strategy (Already Implemented):**
|
||||
- File: `workflows/trading/moneyline_v11_2_strategy.pinescript`
|
||||
- Has pyramiding=1 setting and barSpacingThreshold input
|
||||
- Debug table shows bar spacing and stacking decisions
|
||||
|
||||
**References:**
|
||||
- Implementation plan: `docs/PYRAMIDING_IMPLEMENTATION_PLAN.md`
|
||||
- TradingView strategy: `workflows/trading/moneyline_v11_2_strategy.pinescript`
|
||||
- Backtesting data: `backtester/dynamic_threshold_backtest_20251223_152614.csv`
|
||||
- Analysis document: `V11_COMPREHENSIVE_ANALYSIS_DEC17_2025.md`
|
||||
|
||||
---
|
||||
|
||||
## Telegram Notifications (Nov 16, 2025 - Enhanced Nov 20, 2025)
|
||||
|
||||
**Position Closure Notifications:** System sends direct Telegram messages for all position closures via `lib/notifications/telegram.ts`
|
||||
|
||||
368
docs/PYRAMIDING_IMPLEMENTATION_PLAN.md
Normal file
368
docs/PYRAMIDING_IMPLEMENTATION_PLAN.md
Normal file
@@ -0,0 +1,368 @@
|
||||
# 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.*
|
||||
Reference in New Issue
Block a user