@@ -123,13 +123,15 @@ class SimpleAutomation {
console . log ( 'MODE: ' + ( config . mode || 'SIMULATION' ) ) ;
// Start dynamic monitoring cycle with risk-based intervals
this . currentInterval = 10 * 60 * 1000 ; // Start with 10 minutes
console . log ( '🚀 STARTING: Dynamic monitoring with scalping optimization' ) ;
this . currentInterval = 30 * 1000 ; // Start with 30 seconds for immediate analysis
this . startDynamicMonitoring ( ) ;
// First cycle after 30 seconds
// First cycle after 5 seconds (immediate for scalping)
setTimeout ( ( ) => {
console . log ( '🔥 IMMEDIATE CYCLE: Starting first analysis cycle' ) ;
this . runCycle ( ) ;
} , 30 000) ;
} , 5 000) ;
return {
success : true ,
@@ -189,26 +191,50 @@ class SimpleAutomation {
this . intervalId = setTimeout ( runMonitoringCycle , this . currentInterval ) ;
}
// Determine next interval based on risk level
// Determine next interval based on risk level and position status
async getNextInterval ( ) {
try {
// Check position monitor for current risk level
const baseUrl = process . env . INTERNAL _API _URL || 'http://localhost:9 001 ' ;
const response = await fetch ( ` ${ baseUrl } /api/automation/position-monitor ` ) ; if ( response . ok ) {
// Check position monitor for current risk level AND position status
const baseUrl = process . env . INTERNAL _API _URL || 'http://localhost:30 00' ;
const response = await fetch ( ` ${ baseUrl } /api/automation/position-monitor ` ) ;
if ( response . ok ) {
const data = await response . json ( ) ;
const riskLevel = data . monitor ? . riskLevel || 'NONE' ;
const hasPosition = data . monitor ? . hasPosition ;
const recommendation = data . monitor ? . recommendation ;
// Get timeframe-based intervals (scalping needs faster analysis)
const baseInterval = this . getTimeframeBasedIntervals ( ) ;
// Risk-based multipliers for fine-tu ning
// 🚨 SCALPING LOGIC: No position = IMMEDIATE re-entry scan ning
if ( ! hasPosition && recommendation === 'START_TRADING' ) {
const isScalping = this . config . selectedTimeframes ? . includes ( '5m' ) ||
this . config . selectedTimeframes ? . includes ( '15m' ) ;
if ( isScalping ) {
// Ultra-fast intervals for scalping when no position
const scalpingInterval = 2 * 60 * 1000 ; // 2 minutes for immediate re-entry
console . log ( '🏃♂️ SCALPING ALERT: No position - scanning every 2 minutes for re-entry' ) ;
this . currentInterval = scalpingInterval ;
return scalpingInterval ;
} else {
// Fast intervals for day trading when no position
const dayTradingInterval = 5 * 60 * 1000 ; // 5 minutes for day trading
console . log ( '⚡ DAY TRADING: No position - scanning every 5 minutes for re-entry' ) ;
this . currentInterval = dayTradingInterval ;
return dayTradingInterval ;
}
}
// Risk-based multipliers for existing positions
let riskMultiplier ;
switch ( riskLevel ) {
case 'CRITICAL' :
riskMultiplier = 0.5 ; // 50% faster when critical (5min→2.5min for scalping)
riskMultiplier = 0.5 ; // 50% faster when critical
break ;
case 'HIGH' :
riskMultiplier = 0.7 ; // 30% faster when high risk (10min→7min for scalping)
riskMultiplier = 0.7 ; // 30% faster when high risk
break ;
case 'MEDIUM' :
riskMultiplier = 1.0 ; // Normal speed
@@ -218,18 +244,19 @@ class SimpleAutomation {
break ;
case 'NONE' :
default :
riskMultiplier = 1.0 ; // Normal speed when no positio n
// For NONE risk (no position), use base interval but don't slow dow n
riskMultiplier = hasPosition ? 1.0 : 0.8 ; // Slightly faster when no position
}
const finalInterval = Math . round ( baseInterval * riskMultiplier ) ;
const finalMinutes = finalInterval / ( 60 * 1000 ) ;
console . log ( ` 📊 Risk: ${ riskLevel } | Strategy: ${ this . detectStrategy ( ) } | Interval: ${ finalMinutes } min ` ) ;
console . log ( ` 📊 Risk: ${ riskLevel } | Position: ${ hasPosition ? 'YES' : 'NO' } | Interval: ${ finalMinutes } min ` ) ;
console . log ( ` ⚡ Optimized for ${ this . getSelectedTimeframes ( ) . join ( ',' ) || 'default' } timeframes ` ) ;
const intervalMs = finalInterval ;
console . log ( ` 📊 DYNAMIC INTERVAL: Risk level ${ riskLevel } → Next analysis in ${ interv alMinutes } minutes ` ) ;
console . log ( ` 📊 DYNAMIC INTERVAL: Risk level ${ riskLevel } → Next analysis in ${ f inalMinutes} minutes ` ) ;
this . currentInterval = intervalMs ;
return intervalMs ;
@@ -291,66 +318,139 @@ class SimpleAutomation {
}
async performAnalysis ( ) {
console . log ( ` 📊 TRUE PARALLEL ANALYSIS: Starting simultaneous analysis for ${ this . config . selectedTimeframes . length } timeframes... ` ) ;
console . log ( ` 🚀 This will capture ${ this . config . selectedTimeframes . length * 2 } screenshots in parallel ( ${ this . config . selectedTimeframes . length } timeframes × 2 layouts) ` ) ;
console . log ( ` 📊 ANALYSIS CYCLE : Starting analysis for ${ this . config . selectedTimeframes . length } timeframes... ` ) ;
try {
// Use correct internal port for server-side API call s
const baseUrl = process . env . INTERNAL _API _URL || 'http://localhost:9 001 ' ;
const response = await fetch ( ` ${ baseUrl } /api/batch-analysis ` , {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' } ,
body : JSON . stringify ( {
symbol : this . config . symbol ,
timeframes : this . config . selectedTimeframes , // All timeframes at once!
layouts : [ 'ai' , 'diy' ] ,
analyze : true
} )
} ) ;
if ( ! response . ok ) {
console . warn ( ` ⚠️ BATCH API ERROR: ${ response . status } , falling back to sequential... ` ) ;
return this . performSequentialAnalysis ( ) ;
}
const result = await response . json ( ) ;
// 🚨 STEP 1: Check position monitor FIRST to determine market statu s
const baseUrl = process . env . INTERNAL _API _URL || 'http://localhost:30 00' ;
if ( result . success && result . analysis ) {
// Reset consecutive error counter on success
this . stats . consecutiveErro rs = 0 ;
let hasPosition = false ;
let recommendation = 'HOLD' ;
let activeOrde rs = 0 ;
try {
console . log ( '🔍 Checking position monitor status...' ) ;
const monitorResponse = await fetch ( ` ${ baseUrl } /api/automation/position-monitor ` ) ;
console . log ( ` ✅ PARALLEL ANALYSIS COMPLETE: ${ result . totalScreenshots } screenshots captured ` ) ;
console . log ( ` 📊 COMBINED Recommendation: ${ result . analysis . recommendation } ` ) ;
console . log ( ` 🎯 COMBINED Confidence: ${ result . analysis . confidence } % ` ) ;
console . log ( ` ⏰ Timeframes analyzed: ${ result . timeframes . join ( ', ' ) } ` ) ;
// Check if we should execute a trade based on combined analysis
if ( this . shouldExecuteTrade ( result . analysis ) ) {
console . log ( '💰 TRADE SIGNAL: Executing trade...' ) ;
await this . executeTrade ( result . analysis ) ;
if ( monitorResponse . ok ) {
const monitorData = await monitorResponse . json ( ) ;
hasPosition = monitorData . monitor ? . hasPosition || false ;
recommendation = monitorData . monitor ? . recommendation || 'HOLD' ;
activeOrders = monitorData . monitor ? . orphanedOrderCleanup ? . summary ? . activeOrders || 0 ;
console . log ( ` 📍 POSITION STATUS: ${ hasPosition ? 'ACTIVE POSITION' : 'NO POSITION' } ` ) ;
console . log ( ` 🎯 MONITOR RECOMMENDATION: ${ recommendation } ` ) ;
console . log ( ` 📋 ACTIVE ORDERS: ${ activeOrders } ` ) ;
} else {
console . log ( '📈 SIGNAL: Combined analysis complete, no trade executed' ) ;
console . warn ( ` ⚠️ Position monitor API error: ${ monitorResponse . status } ` ) ;
}
} catch ( monitorError ) {
console . warn ( '⚠️ Could not fetch position monitor, using defaults:' , monitorError . message ) ;
}
// 🚨 NO POSITION SCENARIO - SCALPING MODE
if ( ! hasPosition ) {
console . log ( '🏃♂️ SCALPING MODE: No position detected - aggressive re-entry needed' ) ;
// Clean up any remaining orders first
if ( activeOrders > 0 ) {
console . log ( '🧹 CLEANUP: Canceling remaining orders before new entry...' ) ;
try {
const cleanupResponse = await fetch ( ` ${ baseUrl } /api/drift/cleanup-orders ` , {
method : 'POST'
} ) ;
if ( cleanupResponse . ok ) {
const cleanupResult = await cleanupResponse . json ( ) ;
console . log ( ` ✅ CLEANUP COMPLETE: ${ cleanupResult . summary ? . totalCanceled || 0 } orders canceled ` ) ;
} else {
console . warn ( ` ⚠️ Cleanup API error: ${ cleanupResponse . status } ` ) ;
}
} catch ( cleanupError ) {
console . warn ( '⚠️ Order cleanup failed:' , cleanupError . message ) ;
}
}
return ;
// For scalping, if no position, we ALWAYS analyze for immediate re-entry
if ( recommendation === 'START_TRADING' || ! hasPosition ) {
console . log ( '🚀 IMMEDIATE ANALYSIS: Market is clear, scanning for entry opportunities...' ) ;
// Continue with analysis below
}
} else {
console . warn ( '⚠️ BATCH ANALYSIS: No valid data, falling back to sequential... ' ) ;
console . log ( '📊 POSITION MONITORING: Existing position detected, normal analysis ' ) ;
}
// 🚨 STEP 2: Perform parallel analysis with better error handling
console . log ( ` 🚀 PARALLEL SCREENSHOTS: ${ this . config . selectedTimeframes . length * 2 } captures starting... ` ) ;
try {
const response = await fetch ( ` ${ baseUrl } /api/batch-analysis ` , {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' } ,
body : JSON . stringify ( {
symbol : this . config . symbol ,
timeframes : this . config . selectedTimeframes ,
layouts : [ 'ai' , 'diy' ] ,
analyze : true
} )
} ) ;
if ( ! response . ok ) {
console . warn ( ` ⚠️ BATCH API ERROR: ${ response . status } , falling back to sequential... ` ) ;
return this . performSequentialAnalysis ( ) ;
}
const result = await response . json ( ) ;
if ( result . success && result . analysis ) {
// Reset consecutive error counter on success
this . stats . consecutiveErrors = 0 ;
console . log ( ` ✅ PARALLEL ANALYSIS COMPLETE: ${ result . totalScreenshots } screenshots captured ` ) ;
console . log ( ` 📊 COMBINED Recommendation: ${ result . analysis . recommendation } ` ) ;
console . log ( ` 🎯 COMBINED Confidence: ${ result . analysis . confidence } % ` ) ;
console . log ( ` ⏰ Timeframes analyzed: ${ result . timeframes . join ( ', ' ) } ` ) ;
// Check if we should execute a trade based on combined analysis
if ( this . shouldExecuteTrade ( result . analysis ) ) {
console . log ( '💰 TRADE SIGNAL: Executing trade...' ) ;
await this . executeTrade ( result . analysis ) ;
} else {
console . log ( '📈 SIGNAL: Combined analysis complete, no trade executed' ) ;
}
return ;
} else {
console . warn ( '⚠️ BATCH ANALYSIS: No valid data, falling back to sequential...' ) ;
return this . performSequentialAnalysis ( ) ;
}
} catch ( batchError ) {
// Track network errors
this . stats . networkErrors ++ ;
this . stats . consecutiveErrors ++ ;
console . error ( ` ❌ PARALLEL ANALYSIS FAILED (Network Error # ${ this . stats . networkErrors } ): ` , batchError . message ) ;
// If too many consecutive errors, slow down
if ( this . stats . consecutiveErrors >= 3 ) {
console . warn ( ` ⚠️ HIGH NETWORK ERROR COUNT: ${ this . stats . consecutiveErrors } consecutive failures. System will continue but may slow down. ` ) ;
}
console . log ( ` 🔄 FALLBACK: Using sequential analysis... ` ) ;
return this . performSequentialAnalysis ( ) ;
}
} catch ( error ) {
// Track network errors
this . stats . networkErrors ++ ;
// Main try-catch for the entire performAnalysis method
this . stats . consecutiveErrors ++ ;
console . error ( '❌ ANALYSIS ERROR:' , error . message ) ;
console . error ( ` ❌ PARALLEL ANALYSIS FAILED (Network Error # ${ this . stats . networkErrors } ): ` , error . message ) ;
// If too many consecutive err ors, slow down
if ( this . stats . consecutiveErrors >= 3 ) {
console . warn ( ` ⚠️ HIGH NETWORK ERROR COUNT: ${ this . stats . consecutiveErrors } consecutive failures. System will continue but may slow down. ` ) ;
// Fallback to sequential if all else fails
try {
return this . p erf ormSequentialAnalysis ( ) ;
} catch ( fallbackError ) {
console . error ( '❌ SEQUENTIAL ANALYSIS ALSO FAILED:' , fallbackError . message ) ;
}
console . log ( ` 🔄 FALLBACK: Using sequential analysis... ` ) ;
return this . performSequentialAnalysis ( ) ;
}
}
@@ -366,7 +466,7 @@ class SimpleAutomation {
console . log ( ` 📊 ANALYZING: ${ timeframe } timeframe... ` ) ;
// Use the enhanced screenshot API for each timeframe
const baseUrl = process . env . INTERNAL _API _URL || 'http://localhost:9 001 ' ;
const baseUrl = process . env . INTERNAL _API _URL || 'http://localhost:30 00' ;
const response = await fetch ( ` ${ baseUrl } /api/enhanced-screenshot ` , {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' } ,
@@ -457,28 +557,63 @@ class SimpleAutomation {
}
shouldExecuteTrade ( analysis ) {
// Always allow trade execution - the useRealDEX flag determines if it's real or simulated
console . log ( ` <EFBFBD> TRADE MODE: ${ this . config . mode || 'SIMULATION' } - Trading ${ this . config . enableTrading ? 'ENABLED' : 'DISABLED' } ` ) ;
console . log ( ` 🎯 TRADE MODE: ${ this . config . mode || 'SIMULATION' } - Trading ${ this . config . enableTrading ? 'ENABLED' : 'DISABLED' } ` ) ;
const recommendation = analysis . recommendation ? . toLowerCase ( ) || '' ;
const confidence = analysis . confidence || 0 ;
// Strategy-specific confidence requirements
let minConfidence = 75 ;
if ( this . config . selectedTimeframes ? . includes ( '5' ) || this . config . selectedTimeframes ? . includes ( '15' ) ) {
minConfidence = 80 ; // Higher confidence for scalping
// 🚨 DYNAMIC CONFIDENCE BASED ON POSITION STATUS
// Check if we have an active position
let hasActivePosition = false ;
try {
// This will be updated by the position monitor check in performAnalysis
// For now, assume no position if we're running scalping analysis
const isScalping = this . config . selectedTimeframes ? . includes ( '5m' ) ||
this . config . selectedTimeframes ? . includes ( '15m' ) ;
hasActivePosition = false ; // Will be properly detected in position monitor
} catch ( error ) {
console . warn ( '⚠️ Could not determine position status for confidence adjustment' ) ;
}
// 🎯 AGGRESSIVE SCALPING CONFIDENCE when NO POSITION
let minConfidence = 75 ; // Default confidence
if ( ! hasActivePosition ) {
// NO POSITION = Lower confidence threshold for faster re-entry
if ( this . config . selectedTimeframes ? . includes ( '5m' ) ) {
minConfidence = 65 ; // Very aggressive for 5m scalping
console . log ( '🏃♂️ SCALPING MODE: Using aggressive 65% confidence (no position)' ) ;
} else if ( this . config . selectedTimeframes ? . includes ( '15m' ) ) {
minConfidence = 70 ; // Aggressive for 15m scalping
console . log ( '⚡ SCALPING MODE: Using aggressive 70% confidence (no position)' ) ;
} else {
minConfidence = 72 ; // Slightly lower for day trading
console . log ( '📈 DAY TRADING: Using 72% confidence (no position)' ) ;
}
} else {
// EXISTING POSITION = Higher confidence threshold for additional entries
if ( this . config . selectedTimeframes ? . includes ( '5m' ) || this . config . selectedTimeframes ? . includes ( '15m' ) ) {
minConfidence = 80 ; // Higher confidence for scalping with existing position
console . log ( '⚖️ POSITION EXISTS: Using conservative 80% confidence' ) ;
} else {
minConfidence = 75 ; // Standard confidence for day trading
console . log ( '📊 POSITION EXISTS: Using standard 75% confidence' ) ;
}
}
const isHighConfidence = confidence >= minConfidence ;
const isClearDirection = recommendation . includes ( 'buy' ) || recommendation . includes ( 'sell' ) ;
const isClearDirection = recommendation . includes ( 'buy' ) || recommendation . includes ( 'sell' ) ||
recommendation . includes ( 'long' ) || recommendation . includes ( 'short' ) ;
console . log ( ' 🎯 TRADE DECISION: ' + recommendation + ' (' + confidence + '%) - Min: ' + minConfidence + '%' ) ;
console . log ( ` 🎯 TRADE DECISION: ${ recommendation } ( ${ confidence } %) vs Required: ${ minConfidence } % ` ) ;
console . log ( ` ✅ Will Execute: ${ isHighConfidence && isClearDirection ? 'YES' : 'NO' } ` ) ;
// 🧠 RECORD AI DECISION FOR LEARNING
this . recordAIDecisionForLearning ( analysis , {
recommendation ,
confidence ,
minConfidenceRequired : minConfidence ,
hasActivePosition ,
willExecute : isHighConfidence && isClearDirection
} ) ;
@@ -488,11 +623,12 @@ class SimpleAutomation {
recommendation : analysis . recommendation || 'HOLD' ,
confidence : confidence ,
minConfidenceRequired : minConfidence ,
hasActivePosition : hasActivePosition ,
reasoning : analysis . reasoning || analysis . summary || 'No detailed reasoning available' ,
executed : false , // Will be updated if trade is executed
executed : false ,
executionDetails : null ,
executionError : null ,
learningRecorded : true // Indicate learning system recorded this
learningRecorded : true
} ;
return isHighConfidence && isClearDirection ;
@@ -504,7 +640,7 @@ class SimpleAutomation {
console . log ( '📊 Analysis data:' , JSON . stringify ( analysis , null , 2 ) ) ;
// Check if we already have a position to prevent fragmentation
const apiBaseUrl = process . env . INTERNAL _API _URL || 'http://localhost:9 001 ' ;
const apiBaseUrl = process . env . INTERNAL _API _URL || 'http://localhost:30 00' ;
const existingPositions = await fetch ( ` ${ apiBaseUrl } /api/drift/positions ` ) ;
const positionsData = await existingPositions . json ( ) ;
@@ -623,9 +759,8 @@ class SimpleAutomation {
let availableBalance = 49 ; // fallback
try {
const baseUrl = process . env . INTERNAL _API _URL || 'http://localhost:9001' ;
console . log ( '🔧 DEBUG: Fetching balance from:' , baseUrl ) ;
const balanceResponse = await fetch ( ` ${ baseUrl } /api/drift/balance ` ) ;
console . log ( '🔧 DEBUG: Fetching balance from:' , apiBaseUrl ) ;
const balanceResponse = await fetch ( ` ${ apiBaseUrl } /api/drift/balance ` ) ;
const balanceData = await balanceResponse . json ( ) ;
if ( balanceData . success ) {
accountValue = balanceData . accountValue ;
@@ -680,8 +815,7 @@ class SimpleAutomation {
console . log ( '📊 TRADE PAYLOAD:' , tradePayload ) ;
const baseUrl = process . env . INTERNAL _API _URL || 'http://localhost:9001' ;
const response = await fetch ( ` ${ baseUrl } /api/trading/execute-drift ` , {
const response = await fetch ( ` ${ apiBaseUrl } /api/trading/execute-drift ` , {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' } ,
body : JSON . stringify ( tradePayload )
@@ -743,7 +877,7 @@ class SimpleAutomation {
console . log ( ` 💰 Adding $ ${ dcaAmount } to existing position with AI-calculated levels ` ) ;
// Use the position scaling API
const baseUrl = process . env . INTERNAL _API _URL || 'http://localhost:9 001 ' ;
const baseUrl = process . env . INTERNAL _API _URL || 'http://localhost:30 00' ;
const response = await fetch ( ` ${ baseUrl } /api/drift/scale-position ` , {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' } ,