feat: Complete pyramiding/position stacking implementation (ALL 7 phases)

Phase 1: Configuration
- Added pyramiding config to trading.ts interface and defaults
- Added 6 ENV variables: ENABLE_PYRAMIDING, BASE_LEVERAGE, STACK_LEVERAGE,
  MAX_LEVERAGE_TOTAL, MAX_PYRAMID_LEVELS, STACKING_WINDOW_MINUTES

Phase 2: Database Schema
- Added 5 Trade fields: pyramidLevel, parentTradeId, stackedAt,
  totalLeverageAtEntry, isStackedPosition
- Added index on parentTradeId for pyramid group queries

Phase 3: Execute Endpoint
- Added findExistingPyramidBase() - finds active base trade within window
- Added canAddPyramidLevel() - validates pyramid conditions
- Stores pyramid metadata on new trades

Phase 4: Position Manager Core
- Added pyramidGroups Map for trade ID grouping
- Added addToPyramidGroup() - groups stacked trades by parent
- Added closeAllPyramidLevels() - unified exit for all levels
- Added getTotalPyramidLeverage() - calculates combined leverage
- All exit triggers now close entire pyramid group

Phase 5: Telegram Notifications
- Added sendPyramidStackNotification() - notifies on stack entry
- Added sendPyramidCloseNotification() - notifies on unified exit

Phase 6: Testing (25 tests, ALL PASSING)
- Pyramid Detection: 5 tests
- Pyramid Group Tracking: 4 tests
- Unified Exit: 4 tests
- Leverage Calculation: 4 tests
- Notification Context: 2 tests
- Edge Cases: 6 tests

Phase 7: Documentation
- Updated .github/copilot-instructions.md with full implementation details
- Updated docs/PYRAMIDING_IMPLEMENTATION_PLAN.md status to COMPLETE

Parameters: 4h window, 7x base/stack leverage, 14x max total, 2 max levels
Data-driven: 100% win rate for signals ≤72 bars apart in backtesting
This commit is contained in:
mindesbunister
2026-01-09 13:53:05 +01:00
parent b2ff3026c6
commit 96d1667ae6
17 changed files with 2384 additions and 56 deletions

View File

@@ -88,6 +88,16 @@ export interface TradingConfig {
minAdxIncrease: number // ADX must increase by this much for scaling
maxPricePositionForScale: number // Don't scale if price position above this %
// Pyramiding / Position Stacking (NEW - Jan 6, 2026)
// Stack positions when confirmation signals arrive within time window
// Data-driven: Signals ≤72 bars apart (6h) have 100% win rate
enablePyramiding: boolean // Enable position stacking on confirmation signals
baseLeverage: number // Leverage for first/base entry (e.g., 7x)
stackLeverage: number // Leverage for stack entries (e.g., 7x)
maxLeverageTotal: number // Maximum combined leverage (e.g., 14x for 2 levels)
maxPyramidLevels: number // Max pyramid entries (e.g., 2 = base + 1 stack)
stackingWindowMinutes: number // Time window for stacking (e.g., 240 = 4 hours)
// DEX specific
priceCheckIntervalMs: number // How often to check prices
slippageTolerance: number // Max acceptable slippage (%)
@@ -211,6 +221,15 @@ export const DEFAULT_TRADING_CONFIG: TradingConfig = {
minAdxIncrease: 5, // ADX must increase by 5+ points (trend strengthening)
maxPricePositionForScale: 70, // Don't scale if price >70% of range (near resistance)
// Pyramiding / Position Stacking (Jan 6, 2026 - DATA-DRIVEN)
// Signals ≤72 bars (6h) apart have 100% win rate - confirms trend momentum
enablePyramiding: true, // Enable position stacking on confirmation signals
baseLeverage: 7, // 7x leverage for first entry
stackLeverage: 7, // 7x leverage for additional entries
maxLeverageTotal: 14, // Max 14x combined (7x base + 7x stack)
maxPyramidLevels: 2, // Base entry + 1 stack = 2 levels max
stackingWindowMinutes: 240, // 4 hours (conservative vs 6h optimal from backtest)
// DEX settings
priceCheckIntervalMs: 2000, // Check every 2 seconds
slippageTolerance: 1.0, // 1% max slippage on market orders
@@ -734,6 +753,27 @@ export function getConfigFromEnv(): Partial<TradingConfig> {
maxPricePositionForScale: process.env.MAX_PRICE_POSITION_FOR_SCALE
? parseFloat(process.env.MAX_PRICE_POSITION_FOR_SCALE)
: undefined,
// Pyramiding / Position Stacking (Jan 6, 2026)
enablePyramiding: process.env.ENABLE_PYRAMIDING
? process.env.ENABLE_PYRAMIDING === 'true'
: undefined,
baseLeverage: process.env.BASE_LEVERAGE
? parseFloat(process.env.BASE_LEVERAGE)
: undefined,
stackLeverage: process.env.STACK_LEVERAGE
? parseFloat(process.env.STACK_LEVERAGE)
: undefined,
maxLeverageTotal: process.env.MAX_LEVERAGE_TOTAL
? parseFloat(process.env.MAX_LEVERAGE_TOTAL)
: undefined,
maxPyramidLevels: process.env.MAX_PYRAMID_LEVELS
? parseInt(process.env.MAX_PYRAMID_LEVELS)
: undefined,
stackingWindowMinutes: process.env.STACKING_WINDOW_MINUTES
? parseInt(process.env.STACKING_WINDOW_MINUTES)
: undefined,
maxDailyDrawdown: process.env.MAX_DAILY_DRAWDOWN
? parseFloat(process.env.MAX_DAILY_DRAWDOWN)
: undefined,