526 行
无行尾
19 KiB
MQL5
526 行
无行尾
19 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| AISignalConfirmation.mqh |
|
|
//| AI-Powered Signal Confirmation System |
|
|
//| Combines OpenAI API + MQL5 Neural Network capabilities |
|
|
//| Validates signal clusters before trading |
|
|
//+------------------------------------------------------------------+
|
|
|
|
//================ AI CONFIRMATION STRUCTURE ==================//
|
|
struct AIConfirmation
|
|
{
|
|
bool approved; // Final decision
|
|
double confidence; // 0-100
|
|
string reasoning; // Why approved/rejected
|
|
string ai_bias; // "bullish", "bearish", "neutral"
|
|
string pattern_detected; // Pattern identified by AI
|
|
double risk_score; // 0-100 (higher = riskier)
|
|
string recommendation; // Specific trading advice
|
|
};
|
|
|
|
//================ GLOBAL AI STATE ==================//
|
|
AIConfirmation LastAIDecision;
|
|
datetime LastAICallTime = 0;
|
|
int AI_Call_Cooldown = 60; // 60 seconds between AI calls
|
|
string AI_Context_Memory = ""; // Stores recent market context
|
|
|
|
//================ NEURAL NETWORK VARIABLES ==================//
|
|
// These would connect to MQL5's neural network library
|
|
// For full implementation, see: https://www.mql5.com/en/neurobook
|
|
|
|
bool UseNeuralNetwork = false; // Enable when NN model is trained
|
|
string NeuralModelPath = ""; // Path to trained model
|
|
double NNConfidence = 0; // NN model confidence
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Initialize AI Confirmation System |
|
|
//+------------------------------------------------------------------+
|
|
void InitializeAIConfirmation()
|
|
{
|
|
LastAIDecision.approved = false;
|
|
LastAIDecision.confidence = 0;
|
|
|
|
// Check if we have a trained neural network model
|
|
NeuralModelPath = "Files\\TrainingModels\\QuarterTheory_NN.nnw";
|
|
if(FileIsExist(NeuralModelPath))
|
|
{
|
|
UseNeuralNetwork = true;
|
|
Print("✅ Neural Network model found: ", NeuralModelPath);
|
|
}
|
|
else
|
|
{
|
|
Print("ℹ️ No Neural Network model - using OpenAI only");
|
|
}
|
|
|
|
Print("✅ AI Signal Confirmation initialized");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Request AI Confirmation for Signal Cluster |
|
|
//+------------------------------------------------------------------+
|
|
AIConfirmation RequestAIConfirmation(SignalCluster &cluster)
|
|
{
|
|
AIConfirmation decision;
|
|
|
|
// Rate limiting - don't call AI too frequently
|
|
if(TimeCurrent() - LastAICallTime < AI_Call_Cooldown)
|
|
{
|
|
Print("⏱️ AI cooldown active - using last decision");
|
|
return LastAIDecision;
|
|
}
|
|
|
|
//==============================================================
|
|
// PHASE 1: PREPARE MARKET CONTEXT
|
|
//==============================================================
|
|
string context = BuildMarketContext(cluster);
|
|
|
|
//==============================================================
|
|
// PHASE 2: GET NEURAL NETWORK ANALYSIS (if available)
|
|
//==============================================================
|
|
double nn_confidence = 0;
|
|
string nn_pattern = "";
|
|
|
|
if(UseNeuralNetwork)
|
|
{
|
|
// This would call the trained NN model
|
|
// For now, placeholder
|
|
nn_confidence = AnalyzeWithNeuralNetwork(context);
|
|
nn_pattern = GetNNPatternPrediction();
|
|
|
|
Print("🧠 Neural Network Confidence: ", nn_confidence, "%");
|
|
Print("🧠 NN Pattern: ", nn_pattern);
|
|
}
|
|
|
|
//==============================================================
|
|
// PHASE 3: GET OPENAI ANALYSIS
|
|
//==============================================================
|
|
string ai_response = "";
|
|
|
|
if(Use_OpenAI && AI_Initialized)
|
|
{
|
|
ai_response = GetOpenAIAnalysis(context, cluster, nn_pattern);
|
|
Print("🤖 OpenAI Analysis received");
|
|
}
|
|
else
|
|
{
|
|
// Fallback to rule-based decision
|
|
Print("ℹ️ OpenAI not available - using rules-based decision");
|
|
decision = MakeRuleBasedDecision(cluster, nn_confidence);
|
|
LastAIDecision = decision;
|
|
LastAICallTime = TimeCurrent();
|
|
return decision;
|
|
}
|
|
|
|
//==============================================================
|
|
// PHASE 4: PARSE AI RESPONSE
|
|
//==============================================================
|
|
decision = ParseAIResponse(ai_response, cluster);
|
|
|
|
//==============================================================
|
|
// PHASE 5: COMBINE WITH NEURAL NETWORK (if available)
|
|
//==============================================================
|
|
if(UseNeuralNetwork && nn_confidence > 0)
|
|
{
|
|
// Weighted combination: 70% OpenAI, 30% Neural Network
|
|
double combined_confidence = (decision.confidence * 0.7) + (nn_confidence * 0.3);
|
|
decision.confidence = combined_confidence;
|
|
|
|
// Only approve if both agree on direction
|
|
if(decision.ai_bias != GetNNBias() && nn_confidence > 60)
|
|
{
|
|
decision.approved = false;
|
|
decision.reasoning = "OpenAI and Neural Network disagree on direction";
|
|
Print("⚠️ AI CONFLICT: OpenAI says ", decision.ai_bias,
|
|
" but NN says ", GetNNBias());
|
|
}
|
|
}
|
|
|
|
//==============================================================
|
|
// PHASE 6: FINAL DECISION LOGGING
|
|
//==============================================================
|
|
Print("========================================");
|
|
Print("🤖 AI CONFIRMATION RESULT:");
|
|
Print(" Decision: ", decision.approved ? "APPROVED ✅" : "REJECTED ❌");
|
|
Print(" Confidence: ", decision.confidence, "%");
|
|
Print(" AI Bias: ", decision.ai_bias);
|
|
Print(" Pattern: ", decision.pattern_detected);
|
|
Print(" Risk Score: ", decision.risk_score);
|
|
Print(" Reasoning: ", decision.reasoning);
|
|
Print(" Recommendation: ", decision.recommendation);
|
|
Print("========================================");
|
|
|
|
LastAIDecision = decision;
|
|
LastAICallTime = TimeCurrent();
|
|
|
|
return decision;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Build Comprehensive Market Context for AI |
|
|
//+------------------------------------------------------------------+
|
|
string BuildMarketContext(SignalCluster &cluster)
|
|
{
|
|
string context = "";
|
|
|
|
// Current market conditions
|
|
context += "MARKET CONDITIONS:\n";
|
|
context += "Symbol: " + _Symbol + "\n";
|
|
context += "Timeframe: " + EnumToString((ENUM_TIMEFRAMES)_Period) + "\n";
|
|
context += "Mode: " + CurrentMode + "\n";
|
|
context += "State: " + CurrentState + "\n";
|
|
context += "Price: " + DoubleToString(SymbolInfoDouble(_Symbol, SYMBOL_BID), 5) + "\n";
|
|
context += "\n";
|
|
|
|
// Signal cluster information
|
|
context += "SIGNAL CLUSTER:\n";
|
|
context += "Count: " + IntegerToString(cluster.count) + " signals\n";
|
|
context += "Direction: " + cluster.consensus_direction + "\n";
|
|
context += "Type: " + cluster.consensus_type + "\n";
|
|
context += "Strength: " + DoubleToString(cluster.combined_strength, 1) + "/100\n";
|
|
context += "Conflict Score: " + DoubleToString(cluster.conflict_score, 1) + "/100\n";
|
|
context += "\n";
|
|
|
|
// Individual signals
|
|
context += "ACTIVE SIGNALS:\n";
|
|
for(int i = 0; i < cluster.count; i++)
|
|
{
|
|
CoordinatedSignal sig = cluster.signals[i];
|
|
context += StringFormat("- %s: %s %s at %s (strength: %.0f)\n",
|
|
sig.source, sig.direction, sig.action,
|
|
sig.location, sig.strength);
|
|
}
|
|
context += "\n";
|
|
|
|
// Technical levels
|
|
context += "KEY LEVELS:\n";
|
|
context += "MFIB Levels:\n";
|
|
context += " 1.000: " + DoubleToString(MFIB_1000, 5) + "\n";
|
|
context += " 0.786: " + DoubleToString(MFIB_786, 5) + "\n";
|
|
context += " 0.618: " + DoubleToString(MFIB_618, 5) + "\n";
|
|
context += " 0.500: " + DoubleToString(MFIB_500, 5) + "\n";
|
|
context += " 0.382: " + DoubleToString(MFIB_382, 5) + "\n";
|
|
context += " 0.236: " + DoubleToString(MFIB_236, 5) + "\n";
|
|
context += "\n";
|
|
|
|
// Moving averages
|
|
context += "Moving Averages:\n";
|
|
context += " MA500: " + DoubleToString(MA_500_Value, 5) + "\n";
|
|
context += " MA230: " + DoubleToString(MA_230_Value, 5) + "\n";
|
|
context += " MA140: " + DoubleToString(MA_140_Value, 5) + "\n";
|
|
context += " MA50: " + DoubleToString(MA_50_Value, 5) + "\n";
|
|
context += " MA20: " + DoubleToString(MA_20_Value, 5) + "\n";
|
|
context += "\n";
|
|
|
|
// Recent patterns
|
|
if(PatternCount > 0)
|
|
{
|
|
context += "CANDLESTICK PATTERNS:\n";
|
|
for(int i = 0; i < MathMin(PatternCount, 5); i++)
|
|
{
|
|
PatternSignal pattern = ActivePatterns[i];
|
|
context += StringFormat("- %s at %s (strength: %.0f)\n",
|
|
pattern.name, pattern.location,
|
|
pattern.adjusted_strength);
|
|
}
|
|
context += "\n";
|
|
}
|
|
|
|
// Stochastic
|
|
context += "STOCHASTIC:\n";
|
|
context += " Main: " + DoubleToString(StochBuffer_Main[0], 1) + "\n";
|
|
context += " Signal: " + DoubleToString(StochBuffer_Signal[0], 1) + "\n";
|
|
context += "\n";
|
|
|
|
// Add context memory (recent AI insights)
|
|
if(AI_Context_Memory != "")
|
|
{
|
|
context += "RECENT AI INSIGHTS:\n";
|
|
context += AI_Context_Memory + "\n\n";
|
|
}
|
|
|
|
return context;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get OpenAI Analysis |
|
|
//+------------------------------------------------------------------+
|
|
string GetOpenAIAnalysis(string context, SignalCluster &cluster, string nn_pattern)
|
|
{
|
|
string prompt = "You are an expert forex trader analyzing the following market conditions.\n\n";
|
|
prompt += context;
|
|
|
|
if(nn_pattern != "")
|
|
{
|
|
prompt += "NEURAL NETWORK DETECTED PATTERN: " + nn_pattern + "\n\n";
|
|
}
|
|
|
|
prompt += "Based on this information, please provide:\n";
|
|
prompt += "1. Your directional bias (bullish/bearish/neutral)\n";
|
|
prompt += "2. Confidence level (0-100)\n";
|
|
prompt += "3. Approval (YES/NO) for taking this trade\n";
|
|
prompt += "4. Risk score (0-100, higher = riskier)\n";
|
|
prompt += "5. Key reasoning (2-3 sentences)\n";
|
|
prompt += "6. Specific recommendation\n\n";
|
|
prompt += "Format your response EXACTLY as:\n";
|
|
prompt += "BIAS: [bullish/bearish/neutral]\n";
|
|
prompt += "CONFIDENCE: [0-100]\n";
|
|
prompt += "APPROVAL: [YES/NO]\n";
|
|
prompt += "RISK: [0-100]\n";
|
|
prompt += "REASONING: [your reasoning]\n";
|
|
prompt += "RECOMMENDATION: [your recommendation]\n";
|
|
|
|
// Call OpenAI (from OpenAI.mqh)
|
|
string response = CallOpenAI(prompt);
|
|
|
|
return response;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Parse AI Response into Structured Decision |
|
|
//+------------------------------------------------------------------+
|
|
AIConfirmation ParseAIResponse(string response, SignalCluster &cluster)
|
|
{
|
|
AIConfirmation decision;
|
|
|
|
// Extract BIAS
|
|
int bias_pos = StringFind(response, "BIAS:");
|
|
if(bias_pos >= 0)
|
|
{
|
|
int bias_end = StringFind(response, "\n", bias_pos);
|
|
string bias_line = StringSubstr(response, bias_pos + 5, bias_end - bias_pos - 5);
|
|
StringTrimLeft(bias_line);
|
|
StringTrimRight(bias_line);
|
|
decision.ai_bias = StringToLower(bias_line);
|
|
}
|
|
else
|
|
{
|
|
decision.ai_bias = "neutral";
|
|
}
|
|
|
|
// Extract CONFIDENCE
|
|
int conf_pos = StringFind(response, "CONFIDENCE:");
|
|
if(conf_pos >= 0)
|
|
{
|
|
int conf_end = StringFind(response, "\n", conf_pos);
|
|
string conf_line = StringSubstr(response, conf_pos + 11, conf_end - conf_pos - 11);
|
|
StringTrimLeft(conf_line);
|
|
StringTrimRight(conf_line);
|
|
decision.confidence = StringToDouble(conf_line);
|
|
}
|
|
else
|
|
{
|
|
decision.confidence = 0;
|
|
}
|
|
|
|
// Extract APPROVAL
|
|
int appr_pos = StringFind(response, "APPROVAL:");
|
|
if(appr_pos >= 0)
|
|
{
|
|
int appr_end = StringFind(response, "\n", appr_pos);
|
|
string appr_line = StringSubstr(response, appr_pos + 9, appr_end - appr_pos - 9);
|
|
StringTrimLeft(appr_line);
|
|
StringTrimRight(appr_line);
|
|
decision.approved = (StringFind(StringToUpper(appr_line), "YES") >= 0);
|
|
}
|
|
else
|
|
{
|
|
decision.approved = false;
|
|
}
|
|
|
|
// Extract RISK
|
|
int risk_pos = StringFind(response, "RISK:");
|
|
if(risk_pos >= 0)
|
|
{
|
|
int risk_end = StringFind(response, "\n", risk_pos);
|
|
string risk_line = StringSubstr(response, risk_pos + 5, risk_end - risk_pos - 5);
|
|
StringTrimLeft(risk_line);
|
|
StringTrimRight(risk_line);
|
|
decision.risk_score = StringToDouble(risk_line);
|
|
}
|
|
else
|
|
{
|
|
decision.risk_score = 50;
|
|
}
|
|
|
|
// Extract REASONING
|
|
int reas_pos = StringFind(response, "REASONING:");
|
|
if(reas_pos >= 0)
|
|
{
|
|
int reas_end = StringFind(response, "RECOMMENDATION:", reas_pos);
|
|
if(reas_end < 0) reas_end = StringLen(response);
|
|
decision.reasoning = StringSubstr(response, reas_pos + 10, reas_end - reas_pos - 10);
|
|
StringTrimLeft(decision.reasoning);
|
|
StringTrimRight(decision.reasoning);
|
|
}
|
|
else
|
|
{
|
|
decision.reasoning = "No reasoning provided";
|
|
}
|
|
|
|
// Extract RECOMMENDATION
|
|
int rec_pos = StringFind(response, "RECOMMENDATION:");
|
|
if(rec_pos >= 0)
|
|
{
|
|
decision.recommendation = StringSubstr(response, rec_pos + 15);
|
|
StringTrimLeft(decision.recommendation);
|
|
StringTrimRight(decision.recommendation);
|
|
}
|
|
else
|
|
{
|
|
decision.recommendation = "Follow standard trade management";
|
|
}
|
|
|
|
// Validate that AI bias matches cluster direction
|
|
if(decision.ai_bias != cluster.consensus_direction &&
|
|
decision.ai_bias != "neutral")
|
|
{
|
|
Print("⚠️ AI DISAGREES: Cluster says ", cluster.consensus_direction,
|
|
" but AI says ", decision.ai_bias);
|
|
decision.approved = false;
|
|
decision.reasoning += " AI directional bias conflicts with signal cluster.";
|
|
}
|
|
|
|
return decision;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Fallback Rule-Based Decision (when AI not available) |
|
|
//+------------------------------------------------------------------+
|
|
AIConfirmation MakeRuleBasedDecision(SignalCluster &cluster, double nn_conf)
|
|
{
|
|
AIConfirmation decision;
|
|
|
|
// Use cluster consensus
|
|
decision.ai_bias = cluster.consensus_direction;
|
|
decision.confidence = cluster.combined_strength;
|
|
|
|
// Incorporate NN confidence if available
|
|
if(nn_conf > 0)
|
|
{
|
|
decision.confidence = (decision.confidence * 0.7) + (nn_conf * 0.3);
|
|
}
|
|
|
|
// Approval criteria
|
|
decision.approved = (cluster.conflict_score < 40 &&
|
|
decision.confidence >= 60 &&
|
|
cluster.consensus_direction != "neutral");
|
|
|
|
// Risk score (inverse of confidence, adjusted for conflict)
|
|
decision.risk_score = 100 - decision.confidence + cluster.conflict_score;
|
|
|
|
decision.reasoning = "Rule-based decision: " +
|
|
IntegerToString(cluster.count) + " signals, " +
|
|
DoubleToString(cluster.conflict_score, 1) + "% conflict";
|
|
|
|
decision.recommendation = decision.approved ?
|
|
"Proceed with standard position size" :
|
|
"Skip this setup";
|
|
|
|
return decision;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Neural Network Analysis (Placeholder for MQL5 NN implementation)|
|
|
//+------------------------------------------------------------------+
|
|
double AnalyzeWithNeuralNetwork(string context)
|
|
{
|
|
// This is a placeholder for the actual NN implementation
|
|
// Full implementation requires:
|
|
// 1. Training a model using MQL5's neural network library
|
|
// 2. Saving the model to file
|
|
// 3. Loading and running inference here
|
|
|
|
// See: https://www.mql5.com/en/neurobook for full implementation guide
|
|
|
|
// For now, return 0 (not implemented)
|
|
return 0;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get Neural Network Pattern Prediction |
|
|
//+------------------------------------------------------------------+
|
|
string GetNNPatternPrediction()
|
|
{
|
|
// Placeholder - would return pattern identified by NN
|
|
return "";
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get Neural Network Bias |
|
|
//+------------------------------------------------------------------+
|
|
string GetNNBias()
|
|
{
|
|
// Placeholder - would return directional bias from NN
|
|
return "neutral";
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Update AI Context Memory (for continuity between calls) |
|
|
//+------------------------------------------------------------------+
|
|
void UpdateAIContextMemory(string new_insight)
|
|
{
|
|
// Keep only last 3 insights
|
|
if(AI_Context_Memory != "")
|
|
{
|
|
int newline_count = 0;
|
|
for(int i = 0; i < StringLen(AI_Context_Memory); i++)
|
|
{
|
|
if(StringGetCharacter(AI_Context_Memory, i) == '\n')
|
|
newline_count++;
|
|
|
|
if(newline_count >= 3)
|
|
{
|
|
AI_Context_Memory = StringSubstr(AI_Context_Memory, 0, i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
AI_Context_Memory = new_insight + "\n" + AI_Context_Memory;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Calculate Defensive Multiplier Based on AI Risk Score |
|
|
//+------------------------------------------------------------------+
|
|
double GetAIRiskMultiplier(AIConfirmation &decision)
|
|
{
|
|
// Convert risk score to position size multiplier
|
|
// Low risk (0-30) = 1.2x multiplier
|
|
// Medium risk (31-60) = 1.0x multiplier
|
|
// High risk (61-100) = 0.7x multiplier
|
|
|
|
double multiplier = 1.0;
|
|
|
|
if(decision.risk_score <= 30)
|
|
multiplier = 1.2; // Low risk - can be aggressive
|
|
else if(decision.risk_score <= 60)
|
|
multiplier = 1.0; // Medium risk - standard size
|
|
else if(decision.risk_score <= 80)
|
|
multiplier = 0.8; // High risk - defensive
|
|
else
|
|
multiplier = 0.6; // Very high risk - very defensive
|
|
|
|
// Adjust based on confidence
|
|
if(decision.confidence >= 85)
|
|
multiplier += 0.2;
|
|
else if(decision.confidence < 60)
|
|
multiplier -= 0.1;
|
|
|
|
return MathMax(0.5, MathMin(multiplier, 1.5));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Get AI Decision Summary for Display |
|
|
//+------------------------------------------------------------------+
|
|
string GetAIDecisionSummary()
|
|
{
|
|
if(LastAIDecision.confidence == 0)
|
|
return "No AI decision yet";
|
|
|
|
string summary = "";
|
|
summary += LastAIDecision.approved ? "✅ APPROVED" : "❌ REJECTED";
|
|
summary += " | " + LastAIDecision.ai_bias;
|
|
summary += " | " + DoubleToString(LastAIDecision.confidence, 0) + "% conf";
|
|
summary += " | " + DoubleToString(LastAIDecision.risk_score, 0) + "% risk";
|
|
|
|
return summary;
|
|
} |