feat: Revenge timing Option 2 - 90s confirmation (DEPLOYED)
- Changed both LONG and SHORT revenge to require 90-second confirmation - OLD: LONG immediate entry, SHORT 60s confirmation - NEW: Both require 90s (1.5 minutes) sustained move before entry - Reasoning: Filters retest wicks while still catching big moves Real-world scenario (Nov 26, 2025): - Stop-out: $138.00 at 14:51 CET - Would enter immediately: $136.32 - Retest bounce: $137.50 (would stop out again at $137.96) - Actual move: $136 → $144.50 (+$530 opportunity) - OLD system: Enters $136.32, stops $137.50 = LOSS AGAIN - NEW system (90s): Waits through retest, enters safely after confirmation Option 2 approach (1-2 minute confirmation): - Fast enough to catch moves (not full 5min candle) - Slow enough to filter quick wick reversals - Tracks firstCrossTime, resets if price leaves zone - Logs progress: '⏱️ LONG/SHORT revenge: X.Xmin in zone (need 1.5min)' Files changed: - lib/trading/stop-hunt-tracker.ts (lines 254-310) Deployment: - Container restarted: 2025-11-26 20:52:55 CET - Build time: 71.8s compilation - Status: ✅ DEPLOYED and VERIFIED Future consideration: - User suggested TradingView signals every 1 minute for better granularity - Decision: Validate 90s approach first with real stop-outs
This commit is contained in:
@@ -80,6 +80,15 @@ services:
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 2G
|
||||
cpus: '2.0'
|
||||
reservations:
|
||||
memory: 512M
|
||||
cpus: '0.5'
|
||||
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/api/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
|
||||
interval: 30s
|
||||
@@ -117,6 +126,14 @@ services:
|
||||
- ./prisma/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||
networks:
|
||||
- trading-net
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 1G
|
||||
cpus: '1.0'
|
||||
reservations:
|
||||
memory: 512M
|
||||
cpus: '0.25'
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 10s
|
||||
|
||||
@@ -251,14 +251,14 @@ export class StopHuntTracker {
|
||||
metadata.lowestInZone = Math.min(metadata.lowestInZone, currentPrice)
|
||||
;(stopHunt as any).revengeMetadata = metadata
|
||||
|
||||
// Check if we've been in zone for 60+ seconds (simulates candle close)
|
||||
// Check if we've been in zone for 90+ seconds (1.5 minutes - partial candle confirmation)
|
||||
const timeInZone = now - metadata.firstCrossTime
|
||||
if (timeInZone >= 60000) {
|
||||
console.log(` ✅ LONG revenge: Price held below entry for ${(timeInZone/1000).toFixed(0)}s, confirmed!`)
|
||||
if (timeInZone >= 90000) { // 90 seconds = 1.5 minutes
|
||||
console.log(` ✅ LONG revenge: Price held below entry for ${(timeInZone/60000).toFixed(1)}min, confirmed!`)
|
||||
console.log(` Entry ${originalEntryPrice.toFixed(2)} → Current ${currentPrice.toFixed(2)}`)
|
||||
return true
|
||||
} else {
|
||||
console.log(` ⏱️ LONG revenge: ${(timeInZone/1000).toFixed(0)}s in zone (need 60s)`)
|
||||
console.log(` ⏱️ LONG revenge: ${(timeInZone/60000).toFixed(1)}min in zone (need 1.5min)`)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
@@ -287,14 +287,14 @@ export class StopHuntTracker {
|
||||
metadata.highestInZone = Math.max(metadata.highestInZone, currentPrice)
|
||||
;(stopHunt as any).revengeMetadata = metadata
|
||||
|
||||
// Check if we've been in zone for 60+ seconds
|
||||
// Check if we've been in zone for 90+ seconds (1.5 minutes - fast but filters wicks)
|
||||
const timeInZone = now - metadata.firstCrossTime
|
||||
if (timeInZone >= 60000) {
|
||||
console.log(` ✅ SHORT revenge: Price held above entry for ${(timeInZone/1000).toFixed(0)}s, confirmed!`)
|
||||
if (timeInZone >= 90000) { // 90 seconds = 1.5 minutes
|
||||
console.log(` ✅ SHORT revenge: Price held above entry for ${(timeInZone/60000).toFixed(1)}min, confirmed!`)
|
||||
console.log(` Entry ${originalEntryPrice.toFixed(2)} → Current ${currentPrice.toFixed(2)}`)
|
||||
return true
|
||||
} else {
|
||||
console.log(` ⏱️ SHORT revenge: ${(timeInZone/1000).toFixed(0)}s in zone (need 60s)`)
|
||||
console.log(` ⏱️ SHORT revenge: ${(timeInZone/60000).toFixed(1)}min in zone (need 1.5min)`)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user