docs: Major documentation reorganization + ENV variable reference
**Documentation Structure:** - Created docs/ subdirectory organization (analysis/, architecture/, bugs/, cluster/, deployments/, roadmaps/, setup/, archived/) - Moved 68 root markdown files to appropriate categories - Root directory now clean (only README.md remains) - Total: 83 markdown files now organized by purpose **New Content:** - Added comprehensive Environment Variable Reference to copilot-instructions.md - 100+ ENV variables documented with types, defaults, purpose, notes - Organized by category: Required (Drift/RPC/Pyth), Trading Config (quality/ leverage/sizing), ATR System, Runner System, Risk Limits, Notifications, etc. - Includes usage examples (correct vs wrong patterns) **File Distribution:** - docs/analysis/ - Performance analyses, blocked signals, profit projections - docs/architecture/ - Adaptive leverage, ATR trailing, indicator tracking - docs/bugs/ - CRITICAL_*.md, FIXES_*.md bug reports (7 files) - docs/cluster/ - EPYC setup, distributed computing docs (3 files) - docs/deployments/ - *_COMPLETE.md, DEPLOYMENT_*.md status (12 files) - docs/roadmaps/ - All *ROADMAP*.md strategic planning files (7 files) - docs/setup/ - TradingView guides, signal quality, n8n setup (8 files) - docs/archived/2025_pre_nov/ - Obsolete verification checklist (1 file) **Key Improvements:** - ENV variable reference: Single source of truth for all configuration - Common Pitfalls #68-71: Already complete, verified during audit - Better findability: Category-based navigation vs 68 files in root - Preserves history: All files git mv (rename), not copy/delete - Zero broken functionality: Only documentation moved, no code changes **Verification:** - 83 markdown files now in docs/ subdirectories - Root directory cleaned: 68 files → 0 files (except README.md) - Git history preserved for all moved files - Container running: trading-bot-v4 (no restart needed) **Next Steps:** - Create README.md files in each docs subdirectory - Add navigation index - Update main README.md with new structure - Consolidate duplicate deployment docs - Archive truly obsolete files (old SQL backups) See: docs/analysis/CLEANUP_PLAN.md for complete reorganization strategy
This commit is contained in:
310
docs/architecture/ADAPTIVE_LEVERAGE_SYSTEM.md
Normal file
310
docs/architecture/ADAPTIVE_LEVERAGE_SYSTEM.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# Adaptive Leverage System
|
||||
|
||||
**Implementation Date:** November 24, 2025
|
||||
**Status:** ✅ DEPLOYED - Container rebuilt and running
|
||||
**Commit:** bfdb0ba
|
||||
|
||||
## Overview
|
||||
|
||||
Adaptive leverage automatically adjusts position leverage based on signal quality score, providing risk-adjusted position sizing. High-confidence signals (quality 95+) use maximum leverage, while borderline signals (quality 90-94) use reduced leverage to preserve capital.
|
||||
|
||||
## Motivation
|
||||
|
||||
**Data-Driven Decision (Nov 24, 2025):**
|
||||
- v8 Money Line indicator shows perfect quality separation
|
||||
- Quality 95+ signals: 100% win rate (4/4 wins, +$253.35)
|
||||
- Quality 90-94 signals: More volatile performance
|
||||
- User requested: "adaptive leverage per quality score? like for every trade below the 95 threshold we only use a 10x and for every trade with 95 and more we use the full blast 15x?"
|
||||
- **Goal:** Maximize profits on best setups while reducing risk on borderline signals
|
||||
|
||||
## Configuration
|
||||
|
||||
### Quality-Based Leverage Tiers
|
||||
|
||||
```typescript
|
||||
// Default configuration (config/trading.ts)
|
||||
useAdaptiveLeverage: true // Enable adaptive leverage system
|
||||
highQualityLeverage: 15 // For signals >= 95 quality
|
||||
lowQualityLeverage: 10 // For signals 90-94 quality
|
||||
qualityLeverageThreshold: 95 // Threshold for high vs low leverage
|
||||
```
|
||||
|
||||
### ENV Variables
|
||||
|
||||
```bash
|
||||
# Adaptive Leverage Settings (Nov 24, 2025)
|
||||
USE_ADAPTIVE_LEVERAGE=true # Enable quality-based leverage tiers
|
||||
HIGH_QUALITY_LEVERAGE=15 # Maximum leverage for quality 95+
|
||||
LOW_QUALITY_LEVERAGE=10 # Reduced leverage for quality 90-94
|
||||
QUALITY_LEVERAGE_THRESHOLD=95 # Quality score threshold
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. Quality Score Calculation (Early in Execute Endpoint)
|
||||
|
||||
Quality score is now calculated **before position sizing** (moved from line 755 to line 172 in execute route):
|
||||
|
||||
```typescript
|
||||
// app/api/trading/execute/route.ts (lines 172-192)
|
||||
const qualityResult = await scoreSignalQuality({
|
||||
atr: body.atr || 0,
|
||||
adx: body.adx || 0,
|
||||
rsi: body.rsi || 0,
|
||||
volumeRatio: body.volumeRatio || 0,
|
||||
pricePosition: body.pricePosition || 0,
|
||||
direction: body.direction,
|
||||
symbol: driftSymbol,
|
||||
currentPrice: body.signalPrice || 0,
|
||||
timeframe: body.timeframe,
|
||||
})
|
||||
console.log(`📊 Signal quality score: ${qualityResult.score} (calculated early for adaptive leverage)`)
|
||||
```
|
||||
|
||||
### 2. Leverage Determination (Helper Function)
|
||||
|
||||
```typescript
|
||||
// config/trading.ts (lines 653-673)
|
||||
export function getLeverageForQualityScore(
|
||||
qualityScore: number,
|
||||
config: TradingConfig
|
||||
): number {
|
||||
// If adaptive leverage disabled, use fixed leverage
|
||||
if (!config.useAdaptiveLeverage) {
|
||||
return config.leverage
|
||||
}
|
||||
|
||||
// High quality signals get maximum leverage
|
||||
if (qualityScore >= config.qualityLeverageThreshold) {
|
||||
return config.highQualityLeverage // 15x for quality 95+
|
||||
}
|
||||
|
||||
// Lower quality signals get reduced leverage
|
||||
return config.lowQualityLeverage // 10x for quality 90-94
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Position Sizing Integration
|
||||
|
||||
```typescript
|
||||
// config/trading.ts (lines 327-384)
|
||||
export async function getActualPositionSizeForSymbol(
|
||||
symbol: string,
|
||||
baseConfig: TradingConfig,
|
||||
freeCollateral: number,
|
||||
qualityScore?: number // NEW: Optional quality score parameter
|
||||
): Promise<{ size: number; leverage: number; enabled: boolean; usePercentage: boolean }> {
|
||||
// ... symbol-specific size calculation ...
|
||||
|
||||
// NEW (Nov 24, 2025): Apply adaptive leverage based on quality score
|
||||
let finalLeverage = symbolSettings.leverage
|
||||
if (qualityScore !== undefined && baseConfig.useAdaptiveLeverage) {
|
||||
finalLeverage = getLeverageForQualityScore(qualityScore, baseConfig)
|
||||
console.log(`📊 Adaptive leverage: Quality ${qualityScore} → ${finalLeverage}x leverage (threshold: ${baseConfig.qualityLeverageThreshold})`)
|
||||
}
|
||||
|
||||
return {
|
||||
size: actualSize,
|
||||
leverage: finalLeverage, // Use adaptive leverage
|
||||
enabled: symbolSettings.enabled,
|
||||
usePercentage,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### High Quality Signal (Quality 95+)
|
||||
|
||||
```
|
||||
📊 Signal quality score: 100 (calculated early for adaptive leverage)
|
||||
📊 Adaptive leverage: Quality 100 → 15x leverage (threshold: 95)
|
||||
💰 Position: $540 × 15x = $8,100 notional
|
||||
✅ Maximum firepower for high-confidence setup
|
||||
```
|
||||
|
||||
### Borderline Quality Signal (Quality 90-94)
|
||||
|
||||
```
|
||||
📊 Signal quality score: 92 (calculated early for adaptive leverage)
|
||||
📊 Adaptive leverage: Quality 92 → 10x leverage (threshold: 95)
|
||||
💰 Position: $540 × 10x = $5,400 notional
|
||||
⚠️ Reduced exposure by $2,700 (33% less risk)
|
||||
```
|
||||
|
||||
### Below Threshold (Quality <90)
|
||||
|
||||
```
|
||||
📊 Signal quality score: 85
|
||||
❌ Blocked by direction-specific quality filter
|
||||
LONG threshold: 90
|
||||
SHORT threshold: 95
|
||||
🛑 Trade not executed
|
||||
```
|
||||
|
||||
## Risk Impact Analysis
|
||||
|
||||
### Capital Preservation on Borderline Signals
|
||||
|
||||
**Example: Quality 90 LONG signal**
|
||||
- Without adaptive: $540 × 15x = $8,100 position
|
||||
- With adaptive: $540 × 10x = $5,400 position
|
||||
- Risk reduction: $2,700 (33% less exposure)
|
||||
|
||||
**Profit trade-off:**
|
||||
- Hypothetical win at +0.77%: $62.37 vs $41.58
|
||||
- Profit reduction: $20.79 (33% less profit)
|
||||
- **But:** Borderline signals more likely to stop out
|
||||
- Net effect: Less painful losses on volatile setups
|
||||
|
||||
**Data-driven expectation:**
|
||||
- Quality 95+ signals: Proven 100% WR in v8 → deserve full leverage
|
||||
- Quality 90-94 signals: Volatile results → reduced leverage appropriate
|
||||
- Quality <90 signals: Blocked by filters (not executed)
|
||||
|
||||
## Integration Points
|
||||
|
||||
### Execute Endpoint
|
||||
|
||||
1. Quality score calculated early (line 172)
|
||||
2. Passed to `getActualPositionSizeForSymbol()` (line 196)
|
||||
3. Leverage determined by quality tier
|
||||
4. Position opened with adaptive leverage
|
||||
|
||||
### Test Endpoint
|
||||
|
||||
Test trades always use quality score 100 for maximum leverage:
|
||||
|
||||
```typescript
|
||||
const { size: positionSize, leverage, enabled, usePercentage } = await getActualPositionSizeForSymbol(
|
||||
driftSymbol,
|
||||
config,
|
||||
health.freeCollateral,
|
||||
100 // Test trades always use max leverage
|
||||
)
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### Log Messages
|
||||
|
||||
**Adaptive leverage determination:**
|
||||
```
|
||||
📊 Adaptive leverage: Quality 95 → 15x leverage (threshold: 95)
|
||||
📊 Adaptive leverage: Quality 92 → 10x leverage (threshold: 95)
|
||||
```
|
||||
|
||||
**Trade execution:**
|
||||
```
|
||||
💰 Opening LONG position:
|
||||
Symbol: SOL-PERP
|
||||
Base size: $534.60
|
||||
Leverage: 15x (adaptive - quality 100)
|
||||
Requested notional: $8,019.00
|
||||
```
|
||||
|
||||
### Analytics Dashboard
|
||||
|
||||
Future enhancement: Add "Leverage Tier" column to analytics showing which leverage was used per trade.
|
||||
|
||||
## Validation & Testing
|
||||
|
||||
### Pre-Deployment Checks
|
||||
|
||||
✅ TypeScript compilation: No errors
|
||||
✅ Docker build: Successful in 71.8s
|
||||
✅ Container startup: Clean, no errors
|
||||
✅ Log messages: Showing "Adaptive leverage: Quality X → Yx leverage"
|
||||
|
||||
### Post-Deployment Monitoring
|
||||
|
||||
**Track first 10 trades with adaptive leverage:**
|
||||
- Quality 95+ trades → Verify using 15x leverage
|
||||
- Quality 90-94 trades → Verify using 10x leverage
|
||||
- Compare P&L impact vs historical 15x-only results
|
||||
- Assess if risk reduction > profit reduction
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Additional Leverage Tiers
|
||||
|
||||
```typescript
|
||||
// Potential multi-tier system
|
||||
qualityScore >= 97: 20x leverage // Ultra-high confidence
|
||||
qualityScore >= 95: 15x leverage // High confidence (current)
|
||||
qualityScore >= 90: 10x leverage // Borderline (current)
|
||||
qualityScore >= 85: 5x leverage // Low confidence (currently blocked)
|
||||
qualityScore < 85: Blocked // Too low quality
|
||||
```
|
||||
|
||||
### Per-Direction Multipliers
|
||||
|
||||
```typescript
|
||||
// Example: SHORTS more conservative
|
||||
if (direction === 'short') {
|
||||
finalLeverage = finalLeverage * 0.8 // 15x → 12x, 10x → 8x
|
||||
}
|
||||
```
|
||||
|
||||
### Dynamic Adjustment Based on Streak
|
||||
|
||||
```typescript
|
||||
// Reduce leverage after losing streak
|
||||
if (lastThreeTradesLost()) {
|
||||
finalLeverage = Math.min(finalLeverage, 10) // Cap at 10x
|
||||
}
|
||||
```
|
||||
|
||||
## Files Changed
|
||||
|
||||
### Core Configuration
|
||||
- **config/trading.ts** (105 lines modified)
|
||||
- Added interface fields: `useAdaptiveLeverage`, `highQualityLeverage`, `lowQualityLeverage`, `qualityLeverageThreshold`
|
||||
- Added ENV variable parsing for adaptive leverage
|
||||
- Created helper function: `getLeverageForQualityScore()`
|
||||
- Modified `getActualPositionSizeForSymbol()` to accept optional `qualityScore` parameter
|
||||
|
||||
### API Endpoints
|
||||
- **app/api/trading/execute/route.ts** (32 lines modified)
|
||||
- Moved quality score calculation earlier (before position sizing)
|
||||
- Pass quality score to `getActualPositionSizeForSymbol()`
|
||||
- Removed duplicate quality scoring later in function
|
||||
|
||||
- **app/api/trading/test/route.ts** (3 lines modified)
|
||||
- Test trades use quality score 100 for maximum leverage
|
||||
|
||||
## Deployment Timeline
|
||||
|
||||
- **Nov 24, 2025 08:00 UTC:** User requested adaptive leverage
|
||||
- **Nov 24, 2025 08:15 UTC:** Implementation complete
|
||||
- **Nov 24, 2025 08:25 UTC:** Docker build successful (71.8s)
|
||||
- **Nov 24, 2025 08:28 UTC:** Container deployed and running
|
||||
- **Nov 24, 2025 08:30 UTC:** Git commit bfdb0ba pushed
|
||||
- **Status:** ✅ LIVE in production
|
||||
|
||||
## Expected Impact
|
||||
|
||||
### Capital Efficiency
|
||||
- Quality 95+ signals: Maximum leverage (15x) = maximum profit potential
|
||||
- Quality 90-94 signals: Reduced leverage (10x) = 33% less risk exposure
|
||||
- Net effect: Better risk-adjusted returns
|
||||
|
||||
### System Behavior Changes
|
||||
- Before: All signals used same leverage (15x fixed or per-symbol override)
|
||||
- After: Leverage adapts to signal confidence automatically
|
||||
- Trade-off: Slightly lower profits on borderline wins, significantly lower losses on borderline losses
|
||||
|
||||
### Success Metrics (After 50+ Trades)
|
||||
- Compare quality 95+ win rate and avg P&L (should be similar to before)
|
||||
- Compare quality 90-94 win rate and avg P&L (should be better risk-adjusted)
|
||||
- Calculate: (risk reduction on 90-94) > (profit reduction on 90-94 wins)?
|
||||
- If yes: System is net positive
|
||||
- If no: Adjust thresholds or disable adaptive leverage
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Adaptive leverage provides intelligent risk management by matching position size to signal confidence. High-quality signals (95+) earn full leverage for maximum profit, while borderline signals (90-94) use reduced leverage to preserve capital during volatile periods. This data-driven approach aligns position sizing with the proven performance characteristics of the v8 Money Line indicator, where quality 95+ signals have demonstrated 100% win rate.
|
||||
|
||||
**Next steps:** Monitor first 10-20 adaptive trades, validate leverage tiers are working as expected, collect performance data for threshold optimization.
|
||||
164
docs/architecture/ATR_TRAILING_STOP_FIX.md
Normal file
164
docs/architecture/ATR_TRAILING_STOP_FIX.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# ATR-Based Trailing Stop Fix - Nov 11, 2025
|
||||
|
||||
## Problem Identified
|
||||
|
||||
**Critical Bug:** Runner system was using FIXED 0.3% trailing stop, causing profitable runners to exit immediately.
|
||||
|
||||
**Evidence:**
|
||||
- Recent trades showing MFE of +7-9% but exiting for losses or minimal gains
|
||||
- Example: Entry $167.82, MFE +7.01%, exit $168.91 for **-$2.68 loss**
|
||||
- At $168 SOL price: 0.3% = only **$0.50 wiggle room** before stop hits
|
||||
- Normal price volatility easily triggers 0.3% retracement
|
||||
|
||||
**Documentation Claim vs Reality:**
|
||||
- Docs claimed "ATR-based trailing stop"
|
||||
- Code was using `this.config.trailingStopPercent` (fixed 0.3%)
|
||||
- Config already had `trailingStopAtrMultiplier` parameter but it wasn't being used!
|
||||
|
||||
## Solution Implemented
|
||||
|
||||
### 1. Position Manager Update (`lib/trading/position-manager.ts`)
|
||||
**Changed trailing stop calculation from fixed to ATR-based:**
|
||||
|
||||
```typescript
|
||||
// OLD (BROKEN):
|
||||
const trailingStopPrice = this.calculatePrice(
|
||||
trade.peakPrice,
|
||||
-this.config.trailingStopPercent, // Fixed 0.3%
|
||||
trade.direction
|
||||
)
|
||||
|
||||
// NEW (FIXED):
|
||||
if (trade.atrAtEntry && trade.atrAtEntry > 0) {
|
||||
// ATR-based: Use ATR% * multiplier
|
||||
const atrPercent = (trade.atrAtEntry / currentPrice) * 100
|
||||
const rawDistance = atrPercent * this.config.trailingStopAtrMultiplier
|
||||
|
||||
// Clamp between min and max
|
||||
trailingDistancePercent = Math.max(
|
||||
this.config.trailingStopMinPercent,
|
||||
Math.min(this.config.trailingStopMaxPercent, rawDistance)
|
||||
)
|
||||
} else {
|
||||
// Fallback to configured percent with clamping
|
||||
trailingDistancePercent = Math.max(
|
||||
this.config.trailingStopMinPercent,
|
||||
Math.min(this.config.trailingStopMaxPercent, this.config.trailingStopPercent)
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Added `atrAtEntry` to ActiveTrade Interface
|
||||
```typescript
|
||||
export interface ActiveTrade {
|
||||
// Entry details
|
||||
entryPrice: number
|
||||
entryTime: number
|
||||
positionSize: number
|
||||
leverage: number
|
||||
atrAtEntry?: number // NEW: ATR value at entry for ATR-based trailing stop
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Settings UI Updates (`app/settings/page.tsx`)
|
||||
Added new fields for ATR trailing configuration:
|
||||
- **ATR Trailing Multiplier** (1.0-3.0x, default 1.5x)
|
||||
- **Min Trailing Distance** (0.1-1.0%, default 0.25%)
|
||||
- **Max Trailing Distance** (0.5-2.0%, default 0.9%)
|
||||
- Changed "Trailing Stop Distance" label to "[FALLBACK]"
|
||||
|
||||
### 4. Environment Variables (`.env.example`)
|
||||
```bash
|
||||
# ATR-based Trailing Stop (for 25% runner after TP2)
|
||||
# Trailing distance = (ATR × multiplier)
|
||||
# Example: 0.5% ATR × 1.5 = 0.75% trailing (more room than fixed 0.3%)
|
||||
TRAILING_STOP_ATR_MULTIPLIER=1.5
|
||||
TRAILING_STOP_MIN_PERCENT=0.25
|
||||
TRAILING_STOP_MAX_PERCENT=0.9
|
||||
TRAILING_STOP_ACTIVATION=0.5
|
||||
```
|
||||
|
||||
## Expected Impact
|
||||
|
||||
### Before Fix (0.3% Fixed)
|
||||
- SOL at $168: 0.3% = $0.50 wiggle room
|
||||
- Normal 2-minute oscillation kills runner immediately
|
||||
- Runners with +7-9% MFE captured minimal profit or even lost money
|
||||
|
||||
### After Fix (ATR-based)
|
||||
**Recent ATR distribution from database:**
|
||||
```sql
|
||||
-- Most common ATR values: 0.25-0.52%
|
||||
-- At 1.5x multiplier:
|
||||
0.25% ATR × 1.5 = 0.375% trail
|
||||
0.37% ATR × 1.5 = 0.555% trail
|
||||
0.45% ATR × 1.5 = 0.675% trail
|
||||
0.52% ATR × 1.5 = 0.780% trail
|
||||
```
|
||||
|
||||
**Typical improvement:**
|
||||
- Old: $0.50 wiggle room ($168 × 0.3%)
|
||||
- New: $1.12 wiggle room ($168 × 0.67% avg)
|
||||
- **2.24x more room for runner to breathe!**
|
||||
|
||||
**Volatility adaptation:**
|
||||
- Low ATR (0.25%): 0.375% trail = $0.63 @ $168
|
||||
- High ATR (0.72%): 0.9% trail cap = $1.51 @ $168 (max cap)
|
||||
- Automatically adjusts to market conditions
|
||||
|
||||
## Verification Logs
|
||||
|
||||
When runner activates, you'll now see:
|
||||
```
|
||||
🎯 Trailing stop activated at +0.65%
|
||||
📊 ATR-based trailing: 0.0045 (0.52%) × 1.5x = 0.78%
|
||||
📈 Trailing SL updated: 168.50 → 167.20 (0.78% below peak $168.91)
|
||||
```
|
||||
|
||||
Instead of:
|
||||
```
|
||||
⚠️ No ATR data, using fallback: 0.30%
|
||||
📈 Trailing SL updated: 168.50 → 168.41 (0.30% below peak $168.91)
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
1. **Existing open trades:** Will use fallback 0.3% (no atrAtEntry yet)
|
||||
2. **New trades:** Will capture ATR at entry and use ATR-based trailing
|
||||
3. **Settings UI:** Update multiplier at http://localhost:3001/settings
|
||||
4. **Log verification:** Check for "📊 ATR-based trailing" messages
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. ✅ `lib/trading/position-manager.ts` - ATR-based trailing calculation + interface
|
||||
2. ✅ `app/settings/page.tsx` - UI for ATR multiplier controls
|
||||
3. ✅ `.env.example` - Documentation for new variables
|
||||
4. ✅ `config/trading.ts` - Already had the config (wasn't being used!)
|
||||
|
||||
## Deployment
|
||||
|
||||
```bash
|
||||
docker compose build trading-bot
|
||||
docker compose up -d --force-recreate trading-bot
|
||||
docker logs -f trading-bot-v4
|
||||
```
|
||||
|
||||
**Status:** ✅ **DEPLOYED AND RUNNING**
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Monitor next runner:** Watch for "📊 ATR-based trailing" in logs
|
||||
2. **Compare MFE vs realized P&L:** Should capture 50%+ of MFE (vs current 5-10%)
|
||||
3. **Adjust multiplier if needed:** May increase to 2.0x after seeing results
|
||||
4. **Update copilot-instructions.md:** Document this fix after validation
|
||||
|
||||
## Related Issues
|
||||
|
||||
- Fixes the morning's missed opportunity: $172→$162 drop would have been captured
|
||||
- Addresses "trades showing +7% MFE but -$2 loss" pattern
|
||||
- Makes the 25% runner system actually useful (vs broken 5% system)
|
||||
|
||||
## Key Insight
|
||||
|
||||
**The config system was already built for this!** The `trailingStopAtrMultiplier` parameter existed in DEFAULT_TRADING_CONFIG and getConfigFromEnv() since the TP2-as-runner redesign. The Position Manager just wasn't using it. This was a "90% done but not wired up" situation.
|
||||
225
docs/architecture/INDICATOR_VERSION_TRACKING.md
Normal file
225
docs/architecture/INDICATOR_VERSION_TRACKING.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# Indicator Version Tracking System
|
||||
|
||||
**Date:** November 11, 2025
|
||||
**Purpose:** Track which Pine Script version generated each signal for comparative analysis
|
||||
|
||||
## Changes Made
|
||||
|
||||
### 1. Database Schema (`prisma/schema.prisma`)
|
||||
Added `indicatorVersion` field to both tables:
|
||||
|
||||
```prisma
|
||||
model Trade {
|
||||
// ... existing fields ...
|
||||
indicatorVersion String? // Pine Script version (v5, v6, etc.)
|
||||
}
|
||||
|
||||
model BlockedSignal {
|
||||
// ... existing fields ...
|
||||
indicatorVersion String? // Pine Script version (v5, v6, etc.)
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Pine Script v6 (`moneyline_v6_improved.pinescript`)
|
||||
Added version identifier to alert messages:
|
||||
|
||||
```pinescript
|
||||
// Line 245-247
|
||||
indicatorVer = "v6"
|
||||
|
||||
// Alert messages now include: | IND:v6
|
||||
longAlertMsg = "SOL buy 5 | ATR:0.45 | ADX:28.3 | RSI:62.5 | VOL:1.45 | POS:75.3 | IND:v6"
|
||||
shortAlertMsg = "SOL sell 5 | ATR:0.45 | ADX:28.3 | RSI:62.5 | VOL:1.45 | POS:75.3 | IND:v6"
|
||||
```
|
||||
|
||||
### 3. n8n Workflow Update (REQUIRED)
|
||||
|
||||
**File:** `workflows/trading/Money_Machine.json`
|
||||
**Node:** `Parse Signal Enhanced` (JavaScript code)
|
||||
|
||||
**Add this code after the pricePosition extraction:**
|
||||
|
||||
```javascript
|
||||
// Extract indicator version (v5, v6, etc.)
|
||||
const indicatorMatch = body.match(/IND:([a-z0-9]+)/i);
|
||||
const indicatorVersion = indicatorMatch ? indicatorMatch[1] : 'v5'; // Default to v5 for old signals
|
||||
|
||||
return {
|
||||
rawMessage: body,
|
||||
symbol,
|
||||
direction,
|
||||
timeframe,
|
||||
// Context fields
|
||||
atr,
|
||||
adx,
|
||||
rsi,
|
||||
volumeRatio,
|
||||
pricePosition,
|
||||
// NEW: Indicator version
|
||||
indicatorVersion
|
||||
};
|
||||
```
|
||||
|
||||
**Then update the HTTP request nodes to include it:**
|
||||
|
||||
**Check Risk Request:**
|
||||
```json
|
||||
{
|
||||
"symbol": "{{ $('Parse Signal Enhanced').item.json.symbol }}",
|
||||
"direction": "{{ $('Parse Signal Enhanced').item.json.direction }}",
|
||||
"timeframe": "{{ $('Parse Signal Enhanced').item.json.timeframe }}",
|
||||
"atr": {{ $('Parse Signal Enhanced').item.json.atr }},
|
||||
"adx": {{ $('Parse Signal Enhanced').item.json.adx }},
|
||||
"rsi": {{ $('Parse Signal Enhanced').item.json.rsi }},
|
||||
"volumeRatio": {{ $('Parse Signal Enhanced').item.json.volumeRatio }},
|
||||
"pricePosition": {{ $('Parse Signal Enhanced').item.json.pricePosition }},
|
||||
"indicatorVersion": "{{ $('Parse Signal Enhanced').item.json.indicatorVersion }}"
|
||||
}
|
||||
```
|
||||
|
||||
**Execute Trade Request:** (same addition)
|
||||
|
||||
### 4. API Endpoints Update (REQUIRED)
|
||||
|
||||
**Files to update:**
|
||||
- `app/api/trading/check-risk/route.ts`
|
||||
- `app/api/trading/execute/route.ts`
|
||||
|
||||
**Add to request body interface:**
|
||||
```typescript
|
||||
interface RequestBody {
|
||||
symbol: string
|
||||
direction: 'long' | 'short'
|
||||
timeframe?: string
|
||||
atr?: number
|
||||
adx?: number
|
||||
rsi?: number
|
||||
volumeRatio?: number
|
||||
pricePosition?: number
|
||||
indicatorVersion?: string // NEW
|
||||
}
|
||||
```
|
||||
|
||||
**Pass to database functions:**
|
||||
```typescript
|
||||
await createTrade({
|
||||
// ... existing params ...
|
||||
indicatorVersion: body.indicatorVersion || 'v5'
|
||||
})
|
||||
|
||||
await createBlockedSignal({
|
||||
// ... existing params ...
|
||||
indicatorVersion: body.indicatorVersion || 'v5'
|
||||
})
|
||||
```
|
||||
|
||||
## Database Migration
|
||||
|
||||
Run this to apply schema changes:
|
||||
|
||||
```bash
|
||||
# Generate Prisma client with new fields
|
||||
npx prisma generate
|
||||
|
||||
# Push schema to database
|
||||
npx prisma db push
|
||||
|
||||
# Rebuild Docker container
|
||||
docker compose build trading-bot
|
||||
docker compose up -d trading-bot
|
||||
```
|
||||
|
||||
## Analysis Queries
|
||||
|
||||
### Compare v5 vs v6 Performance
|
||||
|
||||
```sql
|
||||
-- Executed trades by indicator version
|
||||
SELECT
|
||||
indicatorVersion,
|
||||
COUNT(*) as trades,
|
||||
ROUND(AVG(realizedPnL)::numeric, 2) as avg_pnl,
|
||||
ROUND(SUM(realizedPnL)::numeric, 2) as total_pnl,
|
||||
ROUND(100.0 * SUM(CASE WHEN realizedPnL > 0 THEN 1 ELSE 0 END) / COUNT(*)::numeric, 1) as win_rate
|
||||
FROM "Trade"
|
||||
WHERE exitReason IS NOT NULL
|
||||
AND indicatorVersion IS NOT NULL
|
||||
GROUP BY indicatorVersion
|
||||
ORDER BY indicatorVersion;
|
||||
```
|
||||
|
||||
### Blocked signals by version
|
||||
|
||||
```sql
|
||||
-- Blocked signals by indicator version
|
||||
SELECT
|
||||
indicatorVersion,
|
||||
COUNT(*) as blocked_count,
|
||||
ROUND(AVG(signalQualityScore)::numeric, 1) as avg_score,
|
||||
blockReason,
|
||||
COUNT(*) as count_per_reason
|
||||
FROM "BlockedSignal"
|
||||
WHERE indicatorVersion IS NOT NULL
|
||||
GROUP BY indicatorVersion, blockReason
|
||||
ORDER BY indicatorVersion, count_per_reason DESC;
|
||||
```
|
||||
|
||||
### v6 effectiveness check
|
||||
|
||||
```sql
|
||||
-- Did v6 reduce blocked signals at range extremes?
|
||||
SELECT
|
||||
indicatorVersion,
|
||||
CASE
|
||||
WHEN pricePosition < 15 OR pricePosition > 85 THEN 'Range Extreme'
|
||||
ELSE 'Normal Range'
|
||||
END as position_type,
|
||||
COUNT(*) as count
|
||||
FROM "BlockedSignal"
|
||||
WHERE indicatorVersion IN ('v5', 'v6')
|
||||
AND pricePosition IS NOT NULL
|
||||
GROUP BY indicatorVersion, position_type
|
||||
ORDER BY indicatorVersion, position_type;
|
||||
```
|
||||
|
||||
## Expected Results
|
||||
|
||||
**v5 signals:**
|
||||
- Should show more blocked signals at range extremes (< 15% or > 85%)
|
||||
- Higher percentage of signals blocked for QUALITY_SCORE_TOO_LOW
|
||||
|
||||
**v6 signals:**
|
||||
- Should show fewer/zero blocked signals at range extremes (filtered in Pine Script)
|
||||
- Higher average quality scores
|
||||
- Most signals should score 70+
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If v6 performs worse:
|
||||
|
||||
1. **Revert Pine Script:** Change `indicatorVer = "v5"` in v6 script
|
||||
2. **Or use v5 script:** Just switch back to `moneyline_v5_final.pinescript`
|
||||
3. **Database keeps working:** Old signals tagged as v5, new as v6
|
||||
4. **Analysis remains valid:** Can compare both versions historically
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Database schema updated (`npx prisma db push`)
|
||||
- [ ] Prisma client regenerated (`npx prisma generate`)
|
||||
- [ ] Docker container rebuilt
|
||||
- [ ] n8n workflow updated (Parse Signal Enhanced node)
|
||||
- [ ] n8n HTTP requests updated (Check Risk + Execute Trade)
|
||||
- [ ] v6 Pine Script deployed to TradingView
|
||||
- [ ] Test signal fires and `indicatorVersion` appears in database
|
||||
- [ ] SQL queries return v6 data correctly
|
||||
|
||||
## Notes
|
||||
|
||||
- **Backward compatible:** Old signals without version default to 'v5'
|
||||
- **No data loss:** Existing trades remain unchanged
|
||||
- **Immediate effect:** Once n8n updated, all new signals tagged with version
|
||||
- **Analysis ready:** Can compare v5 vs v6 after 10+ signals each
|
||||
|
||||
---
|
||||
|
||||
**Status:** Database and Pine Script updated. n8n workflow update REQUIRED before v6 tracking works.
|
||||
61
docs/architecture/POSITION_SYNC_QUICK_REF.md
Normal file
61
docs/architecture/POSITION_SYNC_QUICK_REF.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Position Sync - Quick Reference
|
||||
|
||||
## 🚨 When to Use
|
||||
- Position open on Drift but Position Manager shows 0 trades
|
||||
- Database says "closed" but Drift shows position still open
|
||||
- After manual Telegram trades with partial fills
|
||||
- Bot restart lost in-memory tracking
|
||||
- Rate limiting (429 errors) disrupted monitoring
|
||||
|
||||
## ✅ Three Ways to Sync
|
||||
|
||||
### 1. Settings UI (Easiest)
|
||||
1. Go to http://localhost:3001/settings
|
||||
2. Click the orange **"🔄 Sync Positions"** button (next to Restart Bot)
|
||||
3. View results in green success message
|
||||
|
||||
### 2. Terminal Script
|
||||
```bash
|
||||
cd /home/icke/traderv4
|
||||
bash scripts/sync-positions.sh
|
||||
```
|
||||
|
||||
### 3. Direct API Call
|
||||
```bash
|
||||
source /home/icke/traderv4/.env
|
||||
curl -X POST http://localhost:3001/api/trading/sync-positions \
|
||||
-H "Authorization: Bearer ${API_SECRET_KEY}"
|
||||
```
|
||||
|
||||
## 📊 What It Does
|
||||
|
||||
**Fetches** all open positions from Drift (SOL-PERP, BTC-PERP, ETH-PERP)
|
||||
|
||||
**Compares** against Position Manager's tracked trades
|
||||
|
||||
**Removes** tracking for positions closed externally
|
||||
|
||||
**Adds** tracking for unmonitored positions with:
|
||||
- Stop loss at configured %
|
||||
- TP1/TP2 at configured %
|
||||
- Emergency stop protection
|
||||
- Trailing stop (if TP2 hit)
|
||||
- MAE/MFE tracking
|
||||
|
||||
**Result**: Dual-layer protection restored ✅
|
||||
|
||||
## 🎯 Your Current Situation
|
||||
|
||||
- **Before Sync:** 4.93 SOL SHORT open, NO software protection
|
||||
- **After Sync:** Position Manager monitors it every 2s with full TP/SL system
|
||||
|
||||
## ⚠️ Limitations
|
||||
|
||||
- Entry time unknown (assumes 1 hour ago - doesn't affect TP/SL)
|
||||
- Signal quality metrics missing (only matters for scaling feature)
|
||||
- Uses current config (not original config from when trade opened)
|
||||
- Synthetic position ID (manual-{timestamp} instead of real TX)
|
||||
|
||||
## 📖 Full Documentation
|
||||
|
||||
See: `docs/guides/POSITION_SYNC_GUIDE.md`
|
||||
Reference in New Issue
Block a user