From db52299b55dbe55a3ce10dfd9653aeff3917d6b2 Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Thu, 27 Nov 2025 08:26:45 +0100 Subject: [PATCH] feat: Enhancement #6 data collection + #1 implementation plan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhancement #6 - SL Distance Validation (Data Collection Phase): - Added slDistanceAtEntry field to StopHunt schema - Calculates distance from revenge entry to stop zone (LONG vs SHORT logic) - Logs distance in dollars + × ATR multiplier - Purpose: Collect 20+ revenge trade samples for optimal multiplier analysis - Created comprehensive analysis guide with SQL queries - Decision deferred until empirical data collected Enhancement #1 - ADX Confirmation (Implementation Plan): - Documented complete 1-minute TradingView alert strategy - Storage analysis: 19.44 MB/month for 3 symbols (negligible) - Two-phase approach: Cache-only MVP → Optional DB persistence - Provided TradingView Pine Script (ready to use) - Cost breakdown: Pro subscription $49.95/month required - Benefits: Real-time ADX, pattern recognition, ML features - Implementation checklist with validation phases Files Changed: - prisma/schema.prisma: +1 field (slDistanceAtEntry) - lib/trading/stop-hunt-tracker.ts: +10 lines (distance calculation + logging) - docs/1MIN_MARKET_DATA_IMPLEMENTATION.md: NEW (comprehensive plan) - docs/ENHANCEMENT_6_ANALYSIS_GUIDE.md: NEW (SQL queries + decision matrix) Status: Enhancement #4 and #10 deployed (previous commit) Enhancement #6 data collection enabled (this commit) Awaiting 20+ revenge trades for Enhancement #6 decision --- docs/1MIN_MARKET_DATA_IMPLEMENTATION.md | 379 ++++++++++++++++++++++++ docs/ENHANCEMENT_6_ANALYSIS_GUIDE.md | 326 ++++++++++++++++++++ lib/trading/stop-hunt-tracker.ts | 7 + prisma/schema.prisma | 1 + 4 files changed, 713 insertions(+) create mode 100644 docs/1MIN_MARKET_DATA_IMPLEMENTATION.md create mode 100644 docs/ENHANCEMENT_6_ANALYSIS_GUIDE.md diff --git a/docs/1MIN_MARKET_DATA_IMPLEMENTATION.md b/docs/1MIN_MARKET_DATA_IMPLEMENTATION.md new file mode 100644 index 0000000..a77e64c --- /dev/null +++ b/docs/1MIN_MARKET_DATA_IMPLEMENTATION.md @@ -0,0 +1,379 @@ +# 1-Minute Market Data Collection - Implementation Plan + +**Status:** READY TO IMPLEMENT (Nov 27, 2025) +**Purpose:** Enable real-time ADX validation for revenge system (Enhancement #1) + +--- + +## Current State + +**TradingView Alerts:** +- Send data ONLY when trend changes (bullish/bearish transitions) +- Timeframes: 5min, 15min, 1H, Daily +- Problem: No fresh data between trend changes = stale cache for revenge ADX checks + +**Market Data Cache:** +- 5-minute expiry +- Fields: ADX, ATR, RSI, volumeRatio, pricePosition, currentPrice +- Used by: Re-entry analytics, soon revenge system + +--- + +## Proposed Solution: 1-Minute Market Data Alerts + +### Database Impact Analysis + +**Current schema:** +```sql +-- No separate table, data flows through cache only +-- Cache: In-memory Map, expires after 5 minutes +-- Zero database storage currently +``` + +**Proposed: Add MarketDataSnapshot table** (OPTIONAL) +```sql +model MarketDataSnapshot { + id String @id @default(cuid()) + timestamp DateTime @default(now()) + symbol String + timeframe String // "1", "5", "15", "60", "D" + + -- Metrics + atr Float + adx Float + rsi Float + volumeRatio Float + pricePosition Float + currentPrice Float + + -- Metadata + indicatorVersion String? // e.g., "v9" + + @@index([symbol, timestamp]) + @@index([symbol, timeframe, timestamp]) +} +``` + +**Storage Calculation:** +``` +Per record: ~150 bytes (8 fields × 8-20 bytes each) +Per minute: 150 bytes × 1 symbol = 150 bytes +Per hour: 150 × 60 = 9 KB +Per day: 9 KB × 24 = 216 KB +Per month: 216 KB × 30 = 6.48 MB +Per year: 6.48 MB × 12 = 77.76 MB + +With 3 symbols (SOL, ETH, BTC): +Per month: 6.48 MB × 3 = 19.44 MB +Per year: 77.76 MB × 3 = 233.28 MB + +CONCLUSION: Negligible storage impact (<1 GB/year for 3 symbols) +``` + +--- + +## Implementation Options + +### Option A: Cache-Only (RECOMMENDED for MVP) + +**Pros:** +- ✅ Zero database changes required +- ✅ Existing infrastructure (market-data-cache.ts) +- ✅ Fast implementation (just TradingView alert) +- ✅ No storage overhead + +**Cons:** +- ❌ No historical analysis (can't backtest ADX patterns) +- ❌ Lost on container restart (cache clears) +- ❌ 5-minute window only (recent data) + +**Use Case:** +- Revenge system ADX validation (real-time only) +- Re-entry analytics (already working) +- Good for Phase 1 validation + +**Implementation Steps:** +1. Create TradingView 1-minute alert (15 lines of Pine Script) +2. Point to existing `/api/trading/market-data` endpoint +3. Cache handles the rest automatically +4. Test with revenge system + +--- + +### Option B: Cache + Database Persistence + +**Pros:** +- ✅ Historical analysis (backtest ADX-based filters) +- ✅ Survives container restarts +- ✅ Enables future ML models (train on historical patterns) +- ✅ Audit trail for debugging + +**Cons:** +- ❌ Requires schema migration +- ❌ Need cleanup policy (auto-delete old data) +- ❌ Slightly more complex + +**Use Case:** +- Long-term data science projects +- Pattern recognition (what ADX patterns precede stop hunts?) +- System optimization with historical validation + +**Implementation Steps:** +1. Add MarketDataSnapshot model to schema +2. Update `/api/trading/market-data` to save to DB +3. Add cleanup job (delete data >30 days old) +4. Create TradingView 1-minute alert +5. Build analytics queries + +--- + +## Recommended Approach: Hybrid (Start with A, Add B Later) + +### Phase 1: Cache-Only (This Week) +``` +1. Create 1-min TradingView alert +2. Point to /api/trading/market-data +3. Test revenge ADX validation +4. Monitor cache hit rate +5. Validate revenge outcomes improve +``` + +### Phase 2: Add Persistence (After 10+ Revenge Trades) +``` +1. Add MarketDataSnapshot table +2. Save historical data +3. Backtest: "Would ADX filter have helped?" +4. Optimize thresholds based on data +``` + +--- + +## TradingView Alert Setup (1-Minute Data) + +### Pine Script Code +```pinescript +//@version=5 +indicator("Market Data Feed (1min)", overlay=true) + +// Calculate metrics +atr = ta.atr(14) +adx = ta.dmi(14, 14) +rsi = ta.rsi(close, 14) +volumeRatio = volume / ta.sma(volume, 20) +pricePosition = (close - ta.lowest(low, 100)) / (ta.highest(high, 100) - ta.lowest(low, 100)) * 100 + +// Alert condition: Every bar close (1 minute) +alertcondition(true, title="1min Data Feed", message=' +{ + "action": "market_data", + "symbol": "{{ticker}}", + "timeframe": "1", + "atr": ' + str.tostring(atr) + ', + "adx": ' + str.tostring(adx) + ', + "rsi": ' + str.tostring(rsi) + ', + "volumeRatio": ' + str.tostring(volumeRatio) + ', + "pricePosition": ' + str.tostring(pricePosition) + ', + "currentPrice": ' + str.tostring(close) + ', + "indicatorVersion": "v9" +} +') +``` + +### Alert Configuration +- **Condition:** "Once Per Bar Close" +- **Timeframe:** 1 minute chart +- **Frequency:** Every 1 minute (24/7) +- **Webhook URL:** `https://your-domain.com/api/trading/market-data` +- **Symbol:** SOL-PERP (start with one, add more later) + +### Expected Alert Volume +``` +Per symbol: 60 alerts/hour = 1,440 alerts/day +With 3 symbols: 4,320 alerts/day +TradingView free tier: 400 alerts/month (NOT ENOUGH) +TradingView Pro tier: Unlimited alerts ✅ + +User needs: Pro or Premium plan ($14.95-$59.95/month) +``` + +--- + +## Benefits Beyond Revenge System + +### 1. Improved Re-Entry Analytics +- Current: Uses stale data or historical fallback +- With 1-min: Always fresh data (<1 minute old) +- Effect: Better manual trade validation + +### 2. Pattern Recognition +- Track ADX behavior before/after stop hunts +- Identify "fake-out" patterns (ADX spikes then drops) +- Optimize entry timing (ADX crossing 20 upward) + +### 3. Market Regime Detection +- Real-time: Is market trending or chopping? +- Use case: Disable trading during low-ADX periods +- Implementation: `if (cache.get('SOL-PERP')?.adx < 15) return 'Market too choppy, skip trade'` + +### 4. Signal Quality Evolution +- Compare 1-min vs 5-min ADX at signal time +- Question: Does fresher data improve quality scores? +- A/B test: 5-min alerts vs 1-min alerts performance + +### 5. Future ML Models +- Features: ADX_1min_ago, ADX_5min_ago, ADX_15min_ago +- Predict: Will this signal hit TP1 or SL? +- Training data: Historical 1-min snapshots + trade outcomes + +--- + +## API Endpoint Impact + +### Current `/api/trading/market-data` Endpoint +```typescript +// app/api/trading/market-data/route.ts +export async function POST(request: Request) { + const body = await request.json() + + // Update cache (already handles this) + const cache = getMarketDataCache() + cache.set(body.symbol, { + atr: body.atr, + adx: body.adx, + rsi: body.rsi, + volumeRatio: body.volumeRatio, + pricePosition: body.pricePosition, + currentPrice: body.currentPrice, + timestamp: Date.now() + }) + + // NEW (Phase 2): Save to database + if (process.env.STORE_MARKET_DATA === 'true') { + await prisma.marketDataSnapshot.create({ + data: { + symbol: body.symbol, + timeframe: body.timeframe, + atr: body.atr, + adx: body.adx, + rsi: body.rsi, + volumeRatio: body.volumeRatio, + pricePosition: body.pricePosition, + currentPrice: body.currentPrice, + indicatorVersion: body.indicatorVersion + } + }) + } + + return NextResponse.json({ success: true }) +} +``` + +**Rate Limit Considerations:** +- 1 alert/minute = 1,440 requests/day per symbol +- With 3 symbols = 4,320 requests/day +- Current bot handles 10,000+ Position Manager checks/day +- **Impact: Negligible** (0.04% increase in total requests) + +--- + +## Implementation Checklist + +### Phase 1: Cache-Only (Immediate) +- [ ] Create 1-min TradingView alert on SOL-PERP +- [ ] Configure webhook to `/api/trading/market-data` +- [ ] Verify cache updates every minute: `curl http://localhost:3001/api/trading/market-data` +- [ ] Test revenge system ADX validation with fresh data +- [ ] Monitor for 24 hours, check cache staleness +- [ ] Add ETH-PERP and BTC-PERP alerts if successful + +### Phase 2: Database Persistence (After Validation) +- [ ] Add MarketDataSnapshot model to schema +- [ ] Update API to save snapshots (feature flag controlled) +- [ ] Add cleanup job (delete data >30 days) +- [ ] Create analytics queries (ADX patterns before stop hunts) +- [ ] Build historical backtest: "Would ADX filter help?" + +### Phase 3: Revenge System Integration +- [ ] Implement Enhancement #1 Option A (fetch fresh ADX) +- [ ] Add logging: ADX at stop-out vs ADX at revenge entry +- [ ] Track: revenge_with_adx_confirmation vs revenge_without +- [ ] After 20 trades: Compare win rates + +--- + +## Cost Analysis + +### TradingView Subscription +- **Current:** Essential ($14.95/month) - 400 alerts/month (NOT ENOUGH) +- **Required:** Pro ($49.95/month) - Unlimited alerts ✅ +- **Alternative:** Premium ($59.95/month) - More indicators + features + +### Database Storage (Phase 2 Only) +- **Monthly:** ~20 MB with 3 symbols +- **Annual:** ~240 MB +- **Cost:** Free (within PostgreSQL disk allocation) + +### Server Resources +- **CPU:** Negligible (cache write = microseconds) +- **Memory:** +60 KB per symbol in cache (180 KB total for 3 symbols) +- **Network:** 150 bytes × 4,320 alerts/day = 648 KB/day = 19.4 MB/month + +**Total Additional Cost:** ~$35/month (TradingView Pro upgrade) + +--- + +## Risk Mitigation + +### What If Alerts Fail? +**Problem:** TradingView alert service down, network issue, rate limiting + +**Solution:** +```typescript +// In revenge system, check data freshness +const cache = getMarketDataCache() +const freshData = cache.get(stopHunt.symbol) + +if (!freshData) { + console.log('⚠️ No market data in cache, using fallback') + // Option 1: Use originalADX as proxy + // Option 2: Skip ADX validation (fail-open) + // Option 3: Block revenge (fail-closed) +} + +const dataAge = Date.now() - freshData.timestamp +if (dataAge > 300000) { // >5 minutes old + console.log(`⚠️ Stale data (${(dataAge/60000).toFixed(1)}min old)`) + // Apply same fallback logic +} +``` + +### What If Cache Overflows? +**Not an issue:** Map with 3 symbols = 180 KB memory (negligible) + +### What If Database Grows Too Large? +**Solution (Phase 2):** +```typescript +// Daily cleanup job +async function cleanupOldMarketData() { + const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) + + await prisma.marketDataSnapshot.deleteMany({ + where: { timestamp: { lt: thirtyDaysAgo } } + }) + + console.log('🗑️ Cleaned up market data older than 30 days') +} +``` + +--- + +## Next Steps + +1. **User Decision:** Start with Phase 1 (cache-only) or implement both phases? +2. **TradingView Upgrade:** Confirm Pro/Premium subscription for unlimited alerts +3. **Symbol Priority:** Start with SOL-PERP only or all 3 symbols? +4. **Create Alert:** I'll provide exact Pine Script + webhook config +5. **Deploy:** Test for 24 hours before revenge system integration + +**Recommendation:** Start with Phase 1 (cache-only) on SOL-PERP, validate for 1 week, then expand. + diff --git a/docs/ENHANCEMENT_6_ANALYSIS_GUIDE.md b/docs/ENHANCEMENT_6_ANALYSIS_GUIDE.md new file mode 100644 index 0000000..3b033f9 --- /dev/null +++ b/docs/ENHANCEMENT_6_ANALYSIS_GUIDE.md @@ -0,0 +1,326 @@ +# Enhancement #6 - SL Distance Analysis Guide + +**Status:** DATA COLLECTION ENABLED (Nov 27, 2025) +**Purpose:** Gather revenge trade data to determine optimal SL distance multiplier + +--- + +## What We're Tracking Now + +### Database Fields Added +```sql +-- In StopHunt table: +slDistanceAtEntry Float? -- Distance from entry to stop zone (absolute value) +revengeOutcome String? -- "TP1", "TP2", "SL", "TRAILING_SL" +revengePnL Float? -- Actual P&L from revenge trade +revengeFailedReason String? -- "stopped_again" if re-stopped +originalATR Float? -- ATR at original stop-out +``` + +### What Gets Calculated +```typescript +// When revenge trade executes: +const slDistance = direction === 'long' + ? currentPrice - stopHuntPrice // LONG: Room below entry + : stopHuntPrice - currentPrice // SHORT: Room above entry + +// Stored: Math.abs(slDistance) +// Logged: Distance in $ and in ATR multiples +// Example: "$1.48 distance (2.47× ATR)" +``` + +--- + +## Analysis Queries (After 20+ Revenge Trades) + +### Query 1: SL Distance vs Outcome +```sql +-- Do tighter entries get re-stopped more often? +SELECT + CASE + WHEN "slDistanceAtEntry" / "originalATR" < 1.0 THEN '<1× ATR (Very Tight)' + WHEN "slDistanceAtEntry" / "originalATR" < 1.5 THEN '1-1.5× ATR (Tight)' + WHEN "slDistanceAtEntry" / "originalATR" < 2.0 THEN '1.5-2× ATR (Moderate)' + WHEN "slDistanceAtEntry" / "originalATR" < 2.5 THEN '2-2.5× ATR (Safe)' + ELSE '2.5×+ ATR (Very Safe)' + END as distance_tier, + + COUNT(*) as total_trades, + + -- Win rate + ROUND(100.0 * SUM(CASE + WHEN "revengeOutcome" IN ('TP1', 'TP2', 'TRAILING_SL') THEN 1 + ELSE 0 + END) / COUNT(*), 1) as win_rate, + + -- Re-stopped rate + ROUND(100.0 * SUM(CASE + WHEN "revengeFailedReason" = 'stopped_again' THEN 1 + ELSE 0 + END) / COUNT(*), 1) as restopped_rate, + + -- Average P&L + ROUND(AVG("revengePnL"), 2) as avg_pnl, + + -- Total P&L + ROUND(SUM("revengePnL"), 2) as total_pnl + +FROM "StopHunt" +WHERE "revengeExecuted" = true + AND "slDistanceAtEntry" IS NOT NULL + AND "originalATR" IS NOT NULL +GROUP BY distance_tier +ORDER BY MIN("slDistanceAtEntry" / "originalATR"); +``` + +**Expected Output:** +``` +distance_tier | total | win_rate | restopped_rate | avg_pnl | total_pnl +-----------------------+-------+----------+----------------+---------+----------- +<1× ATR (Very Tight) | 5 | 40.0 | 60.0 | -25.50 | -127.50 +1-1.5× ATR (Tight) | 8 | 62.5 | 25.0 | 15.25 | 122.00 +1.5-2× ATR (Moderate) | 12 | 75.0 | 16.7 | 42.30 | 507.60 +2-2.5× ATR (Safe) | 7 | 85.7 | 14.3 | 68.45 | 479.15 +2.5×+ ATR (Very Safe) | 3 | 100.0 | 0.0 | 92.30 | 276.90 +``` + +**Decision Logic:** +- If <1× ATR has high re-stop rate (>50%): Filter needed +- If 1.5-2× ATR has best risk/reward: Use 1.5× multiplier +- If 2-2.5× ATR has highest win rate: Use 2.0× multiplier +- If Very Safe (2.5×+) rarely happens: Lower multiplier to catch more + +--- + +### Query 2: Missed Opportunities +```sql +-- How many revenge opportunities didn't execute because reversal wasn't deep enough? +SELECT + COUNT(*) as total_stop_hunts, + + -- How many reversed but didn't enter + SUM(CASE + WHEN "revengeExecuted" = false + AND "revengeWindowExpired" = true + AND ("lowestPriceAfterStop" < "originalEntryPrice" -- LONG reversed + OR "highestPriceAfterStop" > "originalEntryPrice") -- SHORT reversed + THEN 1 ELSE 0 + END) as missed_reversals, + + -- Average distance of missed reversals + ROUND(AVG(CASE + WHEN "revengeExecuted" = false + AND "revengeWindowExpired" = true + THEN ABS("lowestPriceAfterStop" - "stopHuntPrice") + END), 2) as avg_missed_distance + +FROM "StopHunt" +WHERE "originalATR" IS NOT NULL; +``` + +**Tells us:** If we filter too strictly (e.g., 3× ATR), how many opportunities do we lose? + +--- + +### Query 3: Time to Re-Stop +```sql +-- How quickly do re-stopped revenge trades fail? +SELECT + CASE + WHEN EXTRACT(EPOCH FROM ("Trade"."exitTime" - "StopHunt"."revengeTime")) < 300 THEN '<5min (Instant)' + WHEN EXTRACT(EPOCH FROM ("Trade"."exitTime" - "StopHunt"."revengeTime")) < 900 THEN '5-15min (Fast)' + WHEN EXTRACT(EPOCH FROM ("Trade"."exitTime" - "StopHunt"."revengeTime")) < 1800 THEN '15-30min (Moderate)' + ELSE '30min+ (Slow)' + END as time_to_restop, + + COUNT(*) as count, + + ROUND(AVG("StopHunt"."slDistanceAtEntry" / "StopHunt"."originalATR"), 2) as avg_atr_multiple + +FROM "StopHunt" +INNER JOIN "Trade" ON "StopHunt"."revengeTradeId" = "Trade"."id" +WHERE "StopHunt"."revengeFailedReason" = 'stopped_again' +GROUP BY time_to_restop +ORDER BY MIN(EXTRACT(EPOCH FROM ("Trade"."exitTime" - "StopHunt"."revengeTime"))); +``` + +**Insight:** If most re-stops happen <5min, they're wicks. Wider SL distance helps. + +--- + +### Query 4: Direction-Specific Analysis +```sql +-- Do LONGs vs SHORTs need different SL distances? +SELECT + "direction", + + COUNT(*) as total, + + ROUND(AVG("slDistanceAtEntry" / "originalATR"), 2) as avg_atr_multiple, + + ROUND(100.0 * SUM(CASE + WHEN "revengeFailedReason" = 'stopped_again' THEN 1 ELSE 0 + END) / COUNT(*), 1) as restopped_rate, + + ROUND(AVG("revengePnL"), 2) as avg_pnl + +FROM "StopHunt" +WHERE "revengeExecuted" = true + AND "slDistanceAtEntry" IS NOT NULL +GROUP BY "direction"; +``` + +**Possible outcome:** SHORTs need wider distance (more volatile reversals) + +--- + +## Decision Matrix (After 20+ Trades) + +### Scenario A: Tight Entries Work +**Data shows:** 1-1.5× ATR has 70%+ win rate, low re-stop rate +**Decision:** Use 1.5× ATR multiplier (or no filter at all) +**Trade-off:** More revenge opportunities, slightly higher re-stop risk + +### Scenario B: Moderate Distance Optimal +**Data shows:** 1.5-2× ATR has best risk/reward +**Decision:** Use 1.75× or 2.0× ATR multiplier +**Trade-off:** Balanced approach (recommended starting point) + +### Scenario C: Wide Distance Required +**Data shows:** <2× ATR has >40% re-stop rate +**Decision:** Use 2.5× or 3.0× ATR multiplier +**Trade-off:** Fewer opportunities, but much higher win rate + +### Scenario D: Direction-Specific +**Data shows:** LONGs work at 1.5×, SHORTs need 2.5× +**Decision:** Implement separate multipliers per direction +**Trade-off:** More complex but optimized + +--- + +## Implementation Plan (After Data Collection) + +### Step 1: Review Data (After 20 Revenge Trades) +```bash +# Run Query 1 in database +docker exec trading-bot-postgres psql -U postgres -d trading_bot_v4 -c " +[Query 1 from above] +" + +# Save results to CSV +# Analyze in spreadsheet or share with me +``` + +### Step 2: Calculate Optimal Multiplier +```python +# Simple calculation: +optimal_multiplier = ( + sum(distance * pnl for each tier) / + sum(pnl for each tier) +) + +# Weight by win rate: +optimal_multiplier_weighted = ( + sum(distance * win_rate * count for each tier) / + sum(win_rate * count for each tier) +) +``` + +### Step 3: Implement Filter +```typescript +// In stop-hunt-tracker.ts shouldExecuteRevenge() +const slDistance = stopHunt.direction === 'long' + ? currentPrice - stopHunt.stopHuntPrice + : stopHunt.stopHuntPrice - currentPrice + +const minSafeDistance = stopHunt.originalATR * 2.0 // Use data-driven value + +if (Math.abs(slDistance) < minSafeDistance) { + console.log(`⚠️ SL distance too tight: ${Math.abs(slDistance).toFixed(2)} < ${minSafeDistance.toFixed(2)}`) + return false +} +``` + +### Step 4: A/B Test (Optional) +```typescript +// Randomly assign filter on/off +const useFilter = Math.random() > 0.5 + +if (useFilter && Math.abs(slDistance) < minSafeDistance) { + await prisma.stopHunt.update({ + where: { id: stopHunt.id }, + data: { + notes: 'Would have been filtered by SL distance check', + filterTestGroup: 'A' + } + }) + return false +} + +// Compare groups after 40 trades (20 each) +``` + +--- + +## Monitoring Dashboard + +### Key Metrics to Track +1. **Re-Stop Rate:** % of revenge trades that hit SL immediately +2. **Average SL Distance:** Median ATR multiple at entry +3. **Win Rate by Distance:** Scatterplot (x=distance, y=outcome) +4. **Missed Opportunities:** Reversals that didn't execute + +### Alert Thresholds +- **High re-stop rate:** >30% revenge trades fail = tighten filter +- **Low execution rate:** <50% stop hunts execute = loosen filter +- **Negative total P&L:** Sum of revenge P&L < 0 = pause system + +--- + +## Timeline + +**Week 1-2:** Data collection (first 5-10 revenge trades) +**Week 3:** Preliminary analysis (spot obvious patterns) +**Week 4:** Full analysis (20+ trades, statistical significance) +**Week 5:** Implement optimal filter based on data +**Week 6+:** Monitor improvement, adjust if needed + +**Current Status:** ✅ Data collection enabled, awaiting first revenge trades + +--- + +## Example Real-World Analysis + +### Hypothetical Results After 25 Revenge Trades +``` +Distance Tier | Trades | Win Rate | Avg P&L | Total P&L +---------------------|--------|----------|---------|---------- +<1× ATR | 3 | 33% | -$45 | -$135 +1-1.5× ATR | 7 | 57% | $12 | $84 +1.5-2× ATR | 9 | 78% | $58 | $522 +2-2.5× ATR | 4 | 75% | $62 | $248 +2.5×+ ATR | 2 | 100% | $89 | $178 +``` + +**Conclusion from data:** +- <1× ATR: High failure rate, negative P&L → FILTER OUT +- 1-1.5× ATR: Break-even, mediocre win rate → QUESTIONABLE +- 1.5-2× ATR: **SWEET SPOT** - 9 trades, 78% WR, +$522 +- 2-2.5× ATR: Good but fewer opportunities +- 2.5×+ ATR: Perfect WR but rarely happens + +**Optimal setting:** 1.5× ATR minimum distance +**Expected impact:** Block 10 bad trades, keep 15 good trades = +$606 net improvement + +--- + +## Questions for Future AI Agents + +1. **What's the optimal multiplier?** → Check Query 1 results +2. **Are we missing too many opportunities?** → Check Query 2 results +3. **Do re-stops happen instantly or slowly?** → Check Query 3 results +4. **Do LONGs vs SHORTs need different filters?** → Check Query 4 results +5. **Should we implement the filter?** → If re-stop rate >30%, YES + +**Remember:** Data > theory. Don't implement filter until data proves it helps. + diff --git a/lib/trading/stop-hunt-tracker.ts b/lib/trading/stop-hunt-tracker.ts index cad6a54..1ac1653 100644 --- a/lib/trading/stop-hunt-tracker.ts +++ b/lib/trading/stop-hunt-tracker.ts @@ -392,6 +392,11 @@ export class StopHuntTracker { const result = await response.json() if (result.success) { + // Calculate SL distance at entry (for Enhancement #6 analysis) + const slDistance = stopHunt.direction === 'long' + ? currentPrice - stopHunt.stopHuntPrice // LONG: Room below entry + : stopHunt.stopHuntPrice - currentPrice // SHORT: Room above entry + // Mark revenge as executed await this.prisma.stopHunt.update({ where: { id: stopHunt.id }, @@ -400,10 +405,12 @@ export class StopHuntTracker { revengeTradeId: result.trade?.id, revengeEntryPrice: currentPrice, revengeTime: new Date(), + slDistanceAtEntry: Math.abs(slDistance), // Store absolute distance } }) console.log(`✅ REVENGE TRADE EXECUTED: ${result.trade?.id}`) + console.log(`📊 SL Distance: $${Math.abs(slDistance).toFixed(2)} (${stopHunt.originalATR ? `${(Math.abs(slDistance) / stopHunt.originalATR).toFixed(2)}× ATR` : 'no ATR'})`) console.log(`🔥 LET'S GET OUR MONEY BACK!`) // Send special Telegram notification diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 0f5f67e..ce9ef48 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -237,6 +237,7 @@ model StopHunt { revengeTime DateTime? // When revenge executed revengeWindowExpired Boolean @default(false) revengeExpiresAt DateTime // 4 hours after stop hunt + slDistanceAtEntry Float? // Distance from entry to stop zone (for Enhancement #6 analysis) // Monitoring state highestPriceAfterStop Float? // Track if stop hunt reverses