1785 lines
No EOL
54 KiB
Text
1785 lines
No EOL
54 KiB
Text
//+------------------------------------------------------------------+
|
|
//| AI_MLEngine_PatternDetector.mqh|
|
|
//| Machine Learning & Pattern Recognition |
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Candlestick Pattern Detector |
|
|
//+------------------------------------------------------------------+
|
|
class CPatternDetector
|
|
{
|
|
private:
|
|
string m_symbol;
|
|
ENUM_TIMEFRAMES m_timeframe;
|
|
|
|
MqlRates m_rates[];
|
|
|
|
public:
|
|
CPatternDetector(string symbol, ENUM_TIMEFRAMES tf)
|
|
{
|
|
m_symbol = symbol;
|
|
m_timeframe = tf;
|
|
ArraySetAsSeries(m_rates, true);
|
|
}
|
|
|
|
bool UpdateData()
|
|
{
|
|
return CopyRates(m_symbol, m_timeframe, 0, 10, m_rates) > 0;
|
|
}
|
|
|
|
// Bullish Engulfing
|
|
bool IsBullishEngulfing()
|
|
{
|
|
if(ArraySize(m_rates) < 2) return false;
|
|
|
|
bool prevBearish = m_rates[1].close < m_rates[1].open;
|
|
bool currBullish = m_rates[0].close > m_rates[0].open;
|
|
bool engulfs = m_rates[0].close > m_rates[1].open &&
|
|
m_rates[0].open < m_rates[1].close;
|
|
|
|
return prevBearish && currBullish && engulfs;
|
|
}
|
|
|
|
// Bearish Engulfing
|
|
bool IsBearishEngulfing()
|
|
{
|
|
if(ArraySize(m_rates) < 2) return false;
|
|
|
|
bool prevBullish = m_rates[1].close > m_rates[1].open;
|
|
bool currBearish = m_rates[0].close < m_rates[0].open;
|
|
bool engulfs = m_rates[0].close < m_rates[1].open &&
|
|
m_rates[0].open > m_rates[1].close;
|
|
|
|
return prevBullish && currBearish && engulfs;
|
|
}
|
|
|
|
// Pin Bar (Hammer/Shooting Star)
|
|
int DetectPinBar()
|
|
{
|
|
if(ArraySize(m_rates) < 1) return 0;
|
|
|
|
double body = MathAbs(m_rates[0].close - m_rates[0].open);
|
|
double upperWick = m_rates[0].high - MathMax(m_rates[0].close, m_rates[0].open);
|
|
double lowerWick = MathMin(m_rates[0].close, m_rates[0].open) - m_rates[0].low;
|
|
double totalRange = m_rates[0].high - m_rates[0].low;
|
|
|
|
if(totalRange == 0) return 0;
|
|
|
|
// Bullish Pin (Hammer)
|
|
if(lowerWick > body * 2 && lowerWick > totalRange * 0.6 && upperWick < body)
|
|
return 1;
|
|
|
|
// Bearish Pin (Shooting Star)
|
|
if(upperWick > body * 2 && upperWick > totalRange * 0.6 && lowerWick < body)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Doji
|
|
bool IsDoji()
|
|
{
|
|
if(ArraySize(m_rates) < 1) return false;
|
|
|
|
double body = MathAbs(m_rates[0].close - m_rates[0].open);
|
|
double totalRange = m_rates[0].high - m_rates[0].low;
|
|
|
|
return (body < totalRange * 0.1);
|
|
}
|
|
|
|
// Morning/Evening Star (3-candle pattern)
|
|
int DetectStar()
|
|
{
|
|
if(ArraySize(m_rates) < 3) return 0;
|
|
|
|
double body1 = MathAbs(m_rates[2].close - m_rates[2].open);
|
|
double body2 = MathAbs(m_rates[1].close - m_rates[1].open);
|
|
double body3 = MathAbs(m_rates[0].close - m_rates[0].open);
|
|
|
|
// Morning Star (Bullish)
|
|
if(m_rates[2].close < m_rates[2].open && // Bearish candle
|
|
body2 < body1 * 0.3 && // Small middle candle
|
|
m_rates[0].close > m_rates[0].open && // Bullish candle
|
|
m_rates[0].close > m_rates[2].open) // Closes above first candle open
|
|
return 1;
|
|
|
|
// Evening Star (Bearish)
|
|
if(m_rates[2].close > m_rates[2].open && // Bullish candle
|
|
body2 < body1 * 0.3 && // Small middle candle
|
|
m_rates[0].close < m_rates[0].open && // Bearish candle
|
|
m_rates[0].close < m_rates[2].open) // Closes below first candle open
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Get pattern score (combined)
|
|
double GetPatternScore()
|
|
{
|
|
UpdateData();
|
|
|
|
double score = 0;
|
|
|
|
if(IsBullishEngulfing()) score += 30;
|
|
if(IsBearishEngulfing()) score -= 30;
|
|
|
|
int pinBar = DetectPinBar();
|
|
score += pinBar * 25;
|
|
|
|
int star = DetectStar();
|
|
score += star * 35;
|
|
|
|
if(IsDoji()) score += 0; // Neutral - indecision
|
|
|
|
return score;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Support & Resistance Level Detector |
|
|
//+------------------------------------------------------------------+
|
|
class CLevelDetector
|
|
{
|
|
private:
|
|
string m_symbol;
|
|
ENUM_TIMEFRAMES m_timeframe;
|
|
|
|
double m_supportLevels[];
|
|
double m_resistanceLevels[];
|
|
|
|
int m_lookbackBars;
|
|
|
|
public:
|
|
CLevelDetector(string symbol, ENUM_TIMEFRAMES tf, int lookback = 100)
|
|
{
|
|
m_symbol = symbol;
|
|
m_timeframe = tf;
|
|
m_lookbackBars = lookback;
|
|
}
|
|
|
|
void DetectLevels()
|
|
{
|
|
ArrayResize(m_supportLevels, 0);
|
|
ArrayResize(m_resistanceLevels, 0);
|
|
|
|
MqlRates rates[];
|
|
ArraySetAsSeries(rates, true);
|
|
|
|
if(CopyRates(m_symbol, m_timeframe, 0, m_lookbackBars, rates) <= 0)
|
|
return;
|
|
|
|
// Detect swing highs and lows
|
|
for(int i = 3; i < m_lookbackBars - 3; i++)
|
|
{
|
|
// Swing High (Resistance)
|
|
if(rates[i].high > rates[i-1].high && rates[i].high > rates[i-2].high &&
|
|
rates[i].high > rates[i+1].high && rates[i].high > rates[i+2].high)
|
|
{
|
|
AddResistance(rates[i].high);
|
|
}
|
|
|
|
// Swing Low (Support)
|
|
if(rates[i].low < rates[i-1].low && rates[i].low < rates[i-2].low &&
|
|
rates[i].low < rates[i+1].low && rates[i].low < rates[i+2].low)
|
|
{
|
|
AddSupport(rates[i].low);
|
|
}
|
|
}
|
|
|
|
// Cluster nearby levels
|
|
ClusterLevels();
|
|
}
|
|
|
|
void AddSupport(double level)
|
|
{
|
|
int size = ArraySize(m_supportLevels);
|
|
ArrayResize(m_supportLevels, size + 1);
|
|
m_supportLevels[size] = level;
|
|
}
|
|
|
|
void AddResistance(double level)
|
|
{
|
|
int size = ArraySize(m_resistanceLevels);
|
|
ArrayResize(m_resistanceLevels, size + 1);
|
|
m_resistanceLevels[size] = level;
|
|
}
|
|
|
|
void ClusterLevels()
|
|
{
|
|
double threshold = SymbolInfoDouble(m_symbol, SYMBOL_POINT) * 50;
|
|
|
|
// Cluster support levels
|
|
for(int i = 0; i < ArraySize(m_supportLevels); i++)
|
|
{
|
|
for(int j = i + 1; j < ArraySize(m_supportLevels); j++)
|
|
{
|
|
if(MathAbs(m_supportLevels[i] - m_supportLevels[j]) < threshold)
|
|
{
|
|
m_supportLevels[i] = (m_supportLevels[i] + m_supportLevels[j]) / 2;
|
|
ArrayRemove(m_supportLevels, j, 1);
|
|
j--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cluster resistance levels
|
|
for(int i = 0; i < ArraySize(m_resistanceLevels); i++)
|
|
{
|
|
for(int j = i + 1; j < ArraySize(m_resistanceLevels); j++)
|
|
{
|
|
if(MathAbs(m_resistanceLevels[i] - m_resistanceLevels[j]) < threshold)
|
|
{
|
|
m_resistanceLevels[i] = (m_resistanceLevels[i] + m_resistanceLevels[j]) / 2;
|
|
ArrayRemove(m_resistanceLevels, j, 1);
|
|
j--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
double GetNearestSupport(double price)
|
|
{
|
|
double nearest = 0;
|
|
double minDist = DBL_MAX;
|
|
|
|
for(int i = 0; i < ArraySize(m_supportLevels); i++)
|
|
{
|
|
if(m_supportLevels[i] < price)
|
|
{
|
|
double dist = price - m_supportLevels[i];
|
|
if(dist < minDist)
|
|
{
|
|
minDist = dist;
|
|
nearest = m_supportLevels[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return nearest;
|
|
}
|
|
|
|
double GetNearestResistance(double price)
|
|
{
|
|
double nearest = 0;
|
|
double minDist = DBL_MAX;
|
|
|
|
for(int i = 0; i < ArraySize(m_resistanceLevels); i++)
|
|
{
|
|
if(m_resistanceLevels[i] > price)
|
|
{
|
|
double dist = m_resistanceLevels[i] - price;
|
|
if(dist < minDist)
|
|
{
|
|
minDist = dist;
|
|
nearest = m_resistanceLevels[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return nearest;
|
|
}
|
|
|
|
bool IsNearSupport(double price, double threshold = 0.0005)
|
|
{
|
|
double support = GetNearestSupport(price);
|
|
if(support == 0) return false;
|
|
|
|
return (MathAbs(price - support) / price < threshold);
|
|
}
|
|
|
|
bool IsNearResistance(double price, double threshold = 0.0005)
|
|
{
|
|
double resistance = GetNearestResistance(price);
|
|
if(resistance == 0) return false;
|
|
|
|
return (MathAbs(price - resistance) / price < threshold);
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Simple Neural Network for Decision Making |
|
|
//+------------------------------------------------------------------+
|
|
class CNeuralNetwork
|
|
{
|
|
private:
|
|
// Simple 3-layer network: Input -> Hidden -> Output
|
|
int m_inputSize;
|
|
int m_hiddenSize;
|
|
int m_outputSize;
|
|
|
|
double m_weightsIH[][]; // Input to Hidden
|
|
double m_weightsHO[][]; // Hidden to Output
|
|
double m_biasH[];
|
|
double m_biasO[];
|
|
|
|
public:
|
|
CNeuralNetwork(int inputSize, int hiddenSize, int outputSize)
|
|
{
|
|
m_inputSize = inputSize;
|
|
m_hiddenSize = hiddenSize;
|
|
m_outputSize = outputSize;
|
|
|
|
InitializeWeights();
|
|
}
|
|
|
|
void InitializeWeights()
|
|
{
|
|
// Initialize with small random values
|
|
ArrayResize(m_weightsIH, m_inputSize);
|
|
for(int i = 0; i < m_inputSize; i++)
|
|
{
|
|
ArrayResize(m_weightsIH[i], m_hiddenSize);
|
|
for(int j = 0; j < m_hiddenSize; j++)
|
|
m_weightsIH[i][j] = (MathRand() / 32767.0 - 0.5) * 0.5;
|
|
}
|
|
|
|
ArrayResize(m_weightsHO, m_hiddenSize);
|
|
for(int i = 0; i < m_hiddenSize; i++)
|
|
{
|
|
ArrayResize(m_weightsHO[i], m_outputSize);
|
|
for(int j = 0; j < m_outputSize; j++)
|
|
m_weightsHO[i][j] = (MathRand() / 32767.0 - 0.5) * 0.5;
|
|
}
|
|
|
|
ArrayResize(m_biasH, m_hiddenSize);
|
|
ArrayResize(m_biasO, m_outputSize);
|
|
ArrayInitialize(m_biasH, 0);
|
|
ArrayInitialize(m_biasO, 0);
|
|
}
|
|
|
|
double Sigmoid(double x)
|
|
{
|
|
return 1.0 / (1.0 + MathExp(-x));
|
|
}
|
|
|
|
double ReLU(double x)
|
|
{
|
|
return MathMax(0, x);
|
|
}
|
|
|
|
void Forward(double &inputs[], double &outputs[])
|
|
{
|
|
ArrayResize(outputs, m_outputSize);
|
|
|
|
// Hidden layer
|
|
double hidden[];
|
|
ArrayResize(hidden, m_hiddenSize);
|
|
|
|
for(int j = 0; j < m_hiddenSize; j++)
|
|
{
|
|
double sum = m_biasH[j];
|
|
for(int i = 0; i < m_inputSize; i++)
|
|
sum += inputs[i] * m_weightsIH[i][j];
|
|
hidden[j] = ReLU(sum);
|
|
}
|
|
|
|
// Output layer
|
|
for(int k = 0; k < m_outputSize; k++)
|
|
{
|
|
double sum = m_biasO[k];
|
|
for(int j = 0; j < m_hiddenSize; j++)
|
|
sum += hidden[j] * m_weightsHO[j][k];
|
|
outputs[k] = Sigmoid(sum);
|
|
}
|
|
}
|
|
|
|
// Simplified training (would need proper backpropagation in production)
|
|
void Train(double &inputs[], double &targets[], double learningRate = 0.01)
|
|
{
|
|
// This is a placeholder - implement full backpropagation for production
|
|
// For now, just forward pass
|
|
double outputs[];
|
|
Forward(inputs, outputs);
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| AI Decision Engine - Combines All Intelligence |
|
|
//+------------------------------------------------------------------+
|
|
class CAIDecisionEngine
|
|
{
|
|
private:
|
|
CPatternDetector *m_patternH1;
|
|
CPatternDetector *m_patternH4;
|
|
CLevelDetector *m_levelH4;
|
|
CNeuralNetwork *m_neuralNet;
|
|
|
|
string m_symbol;
|
|
|
|
public:
|
|
CAIDecisionEngine(string symbol)
|
|
{
|
|
m_symbol = symbol;
|
|
m_patternH1 = new CPatternDetector(symbol, PERIOD_H1);
|
|
m_patternH4 = new CPatternDetector(symbol, PERIOD_H4);
|
|
m_levelH4 = new CLevelDetector(symbol, PERIOD_H4, 200);
|
|
|
|
// Neural network: 10 inputs -> 20 hidden -> 3 outputs (Buy/Neutral/Sell)
|
|
m_neuralNet = new CNeuralNetwork(10, 20, 3);
|
|
}
|
|
|
|
~CAIDecisionEngine()
|
|
{
|
|
delete m_patternH1;
|
|
delete m_patternH4;
|
|
delete m_levelH4;
|
|
delete m_neuralNet;
|
|
}
|
|
|
|
double MakeDecision(MarketContext &ctx)
|
|
{
|
|
// Update levels
|
|
m_levelH4.DetectLevels();
|
|
|
|
// Get pattern scores
|
|
double patternScoreH1 = m_patternH1.GetPatternScore();
|
|
double patternScoreH4 = m_patternH4.GetPatternScore();
|
|
|
|
// Check proximity to levels
|
|
ctx.nearSupport = m_levelH4.IsNearSupport(ctx.currentPrice);
|
|
ctx.nearResistance = m_levelH4.IsNearResistance(ctx.currentPrice);
|
|
|
|
// Prepare neural network inputs (normalized 0-1)
|
|
double inputs[10];
|
|
inputs[0] = (ctx.trendStrengthH1 + 100) / 200.0; // -100 to 100 -> 0 to 1
|
|
inputs[1] = (ctx.trendStrengthH4 + 100) / 200.0;
|
|
inputs[2] = (ctx.trendStrengthD1 + 100) / 200.0;
|
|
inputs[3] = ctx.volatilityRatio / 3.0; // Normalize assuming max 3x
|
|
inputs[4] = (patternScoreH1 + 100) / 200.0;
|
|
inputs[5] = (patternScoreH4 + 100) / 200.0;
|
|
inputs[6] = ctx.nearSupport ? 1.0 : 0.0;
|
|
inputs[7] = ctx.nearResistance ? 1.0 : 0.0;
|
|
inputs[8] = ctx.isNewsTime ? 1.0 : 0.0;
|
|
inputs[9] = (ctx.usdStrength + 100) / 200.0;
|
|
|
|
// Get neural network decision
|
|
double outputs[];
|
|
m_neuralNet.Forward(inputs, outputs);
|
|
|
|
// outputs[0] = Buy probability
|
|
// outputs[1] = Neutral probability
|
|
// outputs[2] = Sell probability
|
|
|
|
// Return decision score: -1 (Strong Sell) to +1 (Strong Buy)
|
|
double decision = outputs[0] - outputs[2];
|
|
|
|
return decision;
|
|
}
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//+------------------------------------------------------------------+
|
|
//| UltraFast_AI_XAUUSD_System.mq5 |
|
|
//| High-Frequency AI Trading Framework |
|
|
//| Sub-Second Multi-Factor Analysis |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Ultra-Fast AI Gold Trading System"
|
|
#property version "2.00"
|
|
#property strict
|
|
|
|
#include <Trade\Trade.mqh>
|
|
#include <Trade\SymbolInfo.mqh>
|
|
#include <Trade\PositionInfo.mqh>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| INPUT PARAMETERS - Fine-tune for HFT performance |
|
|
//+------------------------------------------------------------------+
|
|
input group "=== CORE SETTINGS ==="
|
|
input double RiskPercentPerTrade = 1.0; // Risk % per trade
|
|
input double MaxDailyLoss = 3.0; // Max daily loss %
|
|
input int MagicNumber = 123456; // EA Magic Number
|
|
input string TradeComment = "AI_HFT_Gold"; // Trade comment
|
|
|
|
input group "=== HIGH-FREQUENCY SETTINGS ==="
|
|
input bool EnableSubSecondAnalysis = true; // Enable tick-by-tick analysis
|
|
input int MinTicksBeforeTrade = 3; // Min ticks for signal confirmation
|
|
input int MaxSlippagePips = 5; // Max allowed slippage
|
|
input bool UseMarketExecution = true; // Use instant execution (faster)
|
|
input int MaxSpreadPips = 30; // Max spread to trade
|
|
|
|
input group "=== MULTI-FACTOR SCORING ==="
|
|
input double TrendWeight = 30.0; // Trend strength weight %
|
|
input double VolatilityWeight = 20.0; // Volatility regime weight %
|
|
input double IndicatorWeight = 25.0; // Indicator confluence weight %
|
|
input double PatternWeight = 25.0; // Pattern recognition weight %
|
|
input double MinConfluenceScore = 65.0; // Min score to trade (0-100)
|
|
|
|
input group "=== EXECUTION DISCIPLINE ==="
|
|
input bool InstantStopLoss = true; // Place SL immediately
|
|
input double StopLossATRMultiplier = 1.5; // SL = ATR * multiplier
|
|
input double TakeProfitATRMultiplier = 3.0; // TP = ATR * multiplier
|
|
input bool UseTrailingStop = true; // Enable trailing stop
|
|
input double TrailingStopATRMultiplier = 1.0;// Trailing stop distance
|
|
|
|
input group "=== ADVANCED FILTERS ==="
|
|
input bool FilterHighSpread = true; // Block trades on high spread
|
|
input bool FilterNewsEvents = true; // Block trades during news
|
|
input int NewsBufferMinutes = 15; // Minutes before/after news
|
|
input bool FilterSessionTimes = true; // Trade only in specific sessions
|
|
input bool AllowLondonSession = true; // Trade during London
|
|
input bool AllowNYSession = true; // Trade during NY
|
|
input bool AllowAsianSession = false; // Trade during Asian
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| ENUMERATIONS |
|
|
//+------------------------------------------------------------------+
|
|
enum ENUM_MARKET_REGIME
|
|
{
|
|
REGIME_STRONG_UPTREND,
|
|
REGIME_WEAK_UPTREND,
|
|
REGIME_STRONG_DOWNTREND,
|
|
REGIME_WEAK_DOWNTREND,
|
|
REGIME_RANGING,
|
|
REGIME_BREAKOUT_UP,
|
|
REGIME_BREAKOUT_DOWN,
|
|
REGIME_HIGH_VOLATILITY,
|
|
REGIME_UNKNOWN
|
|
};
|
|
|
|
enum ENUM_SIGNAL_STRENGTH
|
|
{
|
|
SIGNAL_VERY_STRONG_BUY = 100,
|
|
SIGNAL_STRONG_BUY = 75,
|
|
SIGNAL_WEAK_BUY = 50,
|
|
SIGNAL_NEUTRAL = 0,
|
|
SIGNAL_WEAK_SELL = -50,
|
|
SIGNAL_STRONG_SELL = -75,
|
|
SIGNAL_VERY_STRONG_SELL = -100
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Ultra-Fast Market Context - Optimized for Speed |
|
|
//+------------------------------------------------------------------+
|
|
struct UltraFastContext
|
|
{
|
|
// Timing (microsecond precision)
|
|
datetime lastTickTime;
|
|
ulong lastTickMicroseconds;
|
|
int tickCounter;
|
|
|
|
// Price action (immediate)
|
|
double bid, ask, spread;
|
|
double lastClose, currentClose;
|
|
double priceChangeRate; // Price velocity
|
|
|
|
// Market structure
|
|
ENUM_MARKET_REGIME regime;
|
|
double trendScore; // -100 to +100
|
|
double volatilityScore; // 0 to 100
|
|
|
|
// Multi-factor scores
|
|
double indicatorScore; // 0 to 100
|
|
double patternScore; // -100 to +100
|
|
double confluenceScore; // Final weighted score
|
|
|
|
// Execution context
|
|
bool canTrade;
|
|
bool isHighSpread;
|
|
bool isNewsTime;
|
|
bool isValidSession;
|
|
|
|
// Risk metrics
|
|
double atrValue;
|
|
double dynamicSL;
|
|
double dynamicTP;
|
|
|
|
void Reset()
|
|
{
|
|
tickCounter = 0;
|
|
regime = REGIME_UNKNOWN;
|
|
trendScore = 0;
|
|
volatilityScore = 0;
|
|
indicatorScore = 0;
|
|
patternScore = 0;
|
|
confluenceScore = 0;
|
|
canTrade = false;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Ultra-Fast Indicator Engine - Pre-calculated & Cached |
|
|
//+------------------------------------------------------------------+
|
|
class CUltraFastIndicators
|
|
{
|
|
private:
|
|
// Cached handles (initialized once)
|
|
int h_ema_fast, h_ema_medium, h_ema_slow;
|
|
int h_rsi, h_macd, h_atr, h_adx;
|
|
int h_bb, h_stoch;
|
|
|
|
// Cached buffers (updated only on bar change)
|
|
double cache_ema_fast[3], cache_ema_medium[3], cache_ema_slow[3];
|
|
double cache_rsi[3], cache_macd_main[3], cache_macd_signal[3];
|
|
double cache_atr[3], cache_adx[3];
|
|
double cache_bb_upper[3], cache_bb_lower[3], cache_bb_middle[3];
|
|
double cache_stoch_main[3], cache_stoch_signal[3];
|
|
|
|
// Real-time tick data (updated every tick)
|
|
double tick_price;
|
|
double tick_ema_fast; // Exponential smoothing on ticks
|
|
|
|
datetime lastBarTime;
|
|
string m_symbol;
|
|
ENUM_TIMEFRAMES m_tf;
|
|
|
|
// Exponential smoothing factor for tick-level EMA
|
|
double alpha_fast;
|
|
|
|
public:
|
|
CUltraFastIndicators(string symbol, ENUM_TIMEFRAMES tf = PERIOD_M1)
|
|
{
|
|
m_symbol = symbol;
|
|
m_tf = tf;
|
|
lastBarTime = 0;
|
|
tick_ema_fast = 0;
|
|
alpha_fast = 2.0 / (10.0 + 1.0); // 10-period EMA smoothing
|
|
|
|
InitializeIndicators();
|
|
}
|
|
|
|
~CUltraFastIndicators()
|
|
{
|
|
ReleaseIndicators();
|
|
}
|
|
|
|
bool InitializeIndicators()
|
|
{
|
|
// Initialize all indicators
|
|
h_ema_fast = iMA(m_symbol, m_tf, 9, 0, MODE_EMA, PRICE_CLOSE);
|
|
h_ema_medium = iMA(m_symbol, m_tf, 21, 0, MODE_EMA, PRICE_CLOSE);
|
|
h_ema_slow = iMA(m_symbol, m_tf, 50, 0, MODE_EMA, PRICE_CLOSE);
|
|
h_rsi = iRSI(m_symbol, m_tf, 14, PRICE_CLOSE);
|
|
h_macd = iMACD(m_symbol, m_tf, 12, 26, 9, PRICE_CLOSE);
|
|
h_atr = iATR(m_symbol, m_tf, 14);
|
|
h_adx = iADX(m_symbol, m_tf, 14);
|
|
h_bb = iBands(m_symbol, m_tf, 20, 0, 2.0, PRICE_CLOSE);
|
|
h_stoch = iStochastic(m_symbol, m_tf, 5, 3, 3, MODE_SMA, STO_LOWHIGH);
|
|
|
|
if(h_ema_fast == INVALID_HANDLE || h_rsi == INVALID_HANDLE)
|
|
{
|
|
Print("ERROR: Indicator initialization failed!");
|
|
return false;
|
|
}
|
|
|
|
// Pre-fill cache
|
|
Sleep(100); // Allow indicators to calculate
|
|
UpdateCache(true);
|
|
|
|
return true;
|
|
}
|
|
|
|
void ReleaseIndicators()
|
|
{
|
|
IndicatorRelease(h_ema_fast);
|
|
IndicatorRelease(h_ema_medium);
|
|
IndicatorRelease(h_ema_slow);
|
|
IndicatorRelease(h_rsi);
|
|
IndicatorRelease(h_macd);
|
|
IndicatorRelease(h_atr);
|
|
IndicatorRelease(h_adx);
|
|
IndicatorRelease(h_bb);
|
|
IndicatorRelease(h_stoch);
|
|
}
|
|
|
|
// Update cache only on new bar (efficient)
|
|
bool UpdateCache(bool force = false)
|
|
{
|
|
datetime currentBarTime = iTime(m_symbol, m_tf, 0);
|
|
|
|
if(!force && currentBarTime == lastBarTime)
|
|
return false; // No new bar, use cached values
|
|
|
|
lastBarTime = currentBarTime;
|
|
|
|
// Copy all buffers at once (optimized)
|
|
if(CopyBuffer(h_ema_fast, 0, 0, 3, cache_ema_fast) <= 0) return false;
|
|
if(CopyBuffer(h_ema_medium, 0, 0, 3, cache_ema_medium) <= 0) return false;
|
|
if(CopyBuffer(h_ema_slow, 0, 0, 3, cache_ema_slow) <= 0) return false;
|
|
if(CopyBuffer(h_rsi, 0, 0, 3, cache_rsi) <= 0) return false;
|
|
if(CopyBuffer(h_macd, 0, 0, 3, cache_macd_main) <= 0) return false;
|
|
if(CopyBuffer(h_macd, 1, 0, 3, cache_macd_signal) <= 0) return false;
|
|
if(CopyBuffer(h_atr, 0, 0, 3, cache_atr) <= 0) return false;
|
|
if(CopyBuffer(h_adx, 0, 0, 3, cache_adx) <= 0) return false;
|
|
if(CopyBuffer(h_bb, 1, 0, 3, cache_bb_upper) <= 0) return false;
|
|
if(CopyBuffer(h_bb, 2, 0, 3, cache_bb_lower) <= 0) return false;
|
|
if(CopyBuffer(h_bb, 0, 0, 3, cache_bb_middle) <= 0) return false;
|
|
if(CopyBuffer(h_stoch, 0, 0, 3, cache_stoch_main) <= 0) return false;
|
|
if(CopyBuffer(h_stoch, 1, 0, 3, cache_stoch_signal) <= 0) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Ultra-fast tick update (sub-millisecond)
|
|
void UpdateTick(double price)
|
|
{
|
|
tick_price = price;
|
|
|
|
// Real-time EMA calculation on ticks
|
|
if(tick_ema_fast == 0)
|
|
tick_ema_fast = price;
|
|
else
|
|
tick_ema_fast = alpha_fast * price + (1 - alpha_fast) * tick_ema_fast;
|
|
}
|
|
|
|
// Instant access to cached values (microsecond speed)
|
|
double GetEMAFast(int shift = 0) { return cache_ema_fast[shift]; }
|
|
double GetEMAMedium(int shift = 0) { return cache_ema_medium[shift]; }
|
|
double GetEMASlow(int shift = 0) { return cache_ema_slow[shift]; }
|
|
double GetRSI(int shift = 0) { return cache_rsi[shift]; }
|
|
double GetMACD(int shift = 0) { return cache_macd_main[shift]; }
|
|
double GetMACDSignal(int shift = 0) { return cache_macd_signal[shift]; }
|
|
double GetATR(int shift = 0) { return cache_atr[shift]; }
|
|
double GetADX(int shift = 0) { return cache_adx[shift]; }
|
|
double GetBBUpper(int shift = 0) { return cache_bb_upper[shift]; }
|
|
double GetBBLower(int shift = 0) { return cache_bb_lower[shift]; }
|
|
double GetBBMiddle(int shift = 0) { return cache_bb_middle[shift]; }
|
|
double GetStochMain(int shift = 0) { return cache_stoch_main[shift]; }
|
|
double GetStochSignal(int shift = 0) { return cache_stoch_signal[shift]; }
|
|
|
|
// Tick-level indicators
|
|
double GetTickEMA() { return tick_ema_fast; }
|
|
double GetTickPrice() { return tick_price; }
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Ultra-Fast Multi-Factor Analyzer |
|
|
//+------------------------------------------------------------------+
|
|
class CMultiFactorAnalyzer
|
|
{
|
|
private:
|
|
CUltraFastIndicators *indicators;
|
|
string m_symbol;
|
|
|
|
public:
|
|
CMultiFactorAnalyzer(string symbol)
|
|
{
|
|
m_symbol = symbol;
|
|
indicators = new CUltraFastIndicators(symbol, PERIOD_M1);
|
|
}
|
|
|
|
~CMultiFactorAnalyzer()
|
|
{
|
|
delete indicators;
|
|
}
|
|
|
|
// FACTOR 1: Trend Strength Analysis (-100 to +100)
|
|
double AnalyzeTrendStrength()
|
|
{
|
|
double score = 0;
|
|
double price = SymbolInfoDouble(m_symbol, SYMBOL_BID);
|
|
|
|
// EMA alignment (50 points max)
|
|
double ema_fast = indicators.GetEMAFast();
|
|
double ema_medium = indicators.GetEMAMedium();
|
|
double ema_slow = indicators.GetEMASlow();
|
|
|
|
if(ema_fast > ema_medium && ema_medium > ema_slow)
|
|
score += 50; // Perfect bullish alignment
|
|
else if(ema_fast < ema_medium && ema_medium < ema_slow)
|
|
score -= 50; // Perfect bearish alignment
|
|
else
|
|
score += 0; // Mixed signals
|
|
|
|
// Price position relative to EMAs (30 points max)
|
|
if(price > ema_fast && price > ema_medium && price > ema_slow)
|
|
score += 30;
|
|
else if(price < ema_fast && price < ema_medium && price < ema_slow)
|
|
score -= 30;
|
|
|
|
// ADX strength confirmation (20 points max)
|
|
double adx = indicators.GetADX();
|
|
if(adx > 25)
|
|
score *= 1.2; // Boost score in strong trend
|
|
else if(adx < 15)
|
|
score *= 0.5; // Reduce score in weak trend
|
|
|
|
return NormalizeDouble(MathMax(-100, MathMin(100, score)), 2);
|
|
}
|
|
|
|
// FACTOR 2: Volatility Regime Detection (0 to 100)
|
|
double AnalyzeVolatility()
|
|
{
|
|
double atr = indicators.GetATR();
|
|
double atr_prev = indicators.GetATR(1);
|
|
double atr_change = (atr - atr_prev) / atr_prev * 100;
|
|
|
|
// Calculate volatility percentile
|
|
double score = 50; // Base score
|
|
|
|
// ATR expansion/contraction
|
|
if(atr_change > 10)
|
|
score += 30; // Volatility expanding
|
|
else if(atr_change < -10)
|
|
score -= 20; // Volatility contracting
|
|
|
|
// Bollinger Band width
|
|
double bb_upper = indicators.GetBBUpper();
|
|
double bb_lower = indicators.GetBBLower();
|
|
double bb_width = (bb_upper - bb_lower) / indicators.GetBBMiddle() * 100;
|
|
|
|
if(bb_width > 2.0)
|
|
score += 20;
|
|
else if(bb_width < 1.0)
|
|
score -= 20;
|
|
|
|
return NormalizeDouble(MathMax(0, MathMin(100, score)), 2);
|
|
}
|
|
|
|
// FACTOR 3: Indicator Confluence Scoring (0 to 100)
|
|
double AnalyzeIndicatorConfluence()
|
|
{
|
|
double score = 0;
|
|
int bullish_signals = 0;
|
|
int bearish_signals = 0;
|
|
|
|
// RSI analysis
|
|
double rsi = indicators.GetRSI();
|
|
if(rsi > 50 && rsi < 70)
|
|
bullish_signals++;
|
|
else if(rsi < 50 && rsi > 30)
|
|
bearish_signals++;
|
|
|
|
// MACD analysis
|
|
double macd = indicators.GetMACD();
|
|
double macd_signal = indicators.GetMACDSignal();
|
|
if(macd > macd_signal && macd > 0)
|
|
bullish_signals++;
|
|
else if(macd < macd_signal && macd < 0)
|
|
bearish_signals++;
|
|
|
|
// Stochastic analysis
|
|
double stoch_main = indicators.GetStochMain();
|
|
double stoch_signal = indicators.GetStochSignal();
|
|
if(stoch_main > stoch_signal && stoch_main < 80)
|
|
bullish_signals++;
|
|
else if(stoch_main < stoch_signal && stoch_main > 20)
|
|
bearish_signals++;
|
|
|
|
// Bollinger Bands position
|
|
double price = SymbolInfoDouble(m_symbol, SYMBOL_BID);
|
|
double bb_middle = indicators.GetBBMiddle();
|
|
if(price > bb_middle)
|
|
bullish_signals++;
|
|
else if(price < bb_middle)
|
|
bearish_signals++;
|
|
|
|
// Calculate confluence
|
|
int total_signals = bullish_signals + bearish_signals;
|
|
if(total_signals > 0)
|
|
{
|
|
double confluence_ratio = (double)MathMax(bullish_signals, bearish_signals) / total_signals;
|
|
score = confluence_ratio * 100;
|
|
}
|
|
|
|
return NormalizeDouble(score, 2);
|
|
}
|
|
|
|
// FACTOR 4: Pattern Recognition (-100 to +100)
|
|
double AnalyzePatterns()
|
|
{
|
|
double score = 0;
|
|
MqlRates rates[];
|
|
ArraySetAsSeries(rates, true);
|
|
|
|
if(CopyRates(m_symbol, PERIOD_M1, 0, 5, rates) < 5)
|
|
return 0;
|
|
|
|
// Bullish Engulfing
|
|
if(IsBullishEngulfing(rates))
|
|
score += 40;
|
|
|
|
// Bearish Engulfing
|
|
if(IsBearishEngulfing(rates))
|
|
score -= 40;
|
|
|
|
// Pin Bar detection
|
|
int pinBar = DetectPinBar(rates);
|
|
score += pinBar * 30;
|
|
|
|
// Higher High / Lower Low patterns
|
|
if(rates[0].high > rates[1].high && rates[1].high > rates[2].high)
|
|
score += 20; // Bullish momentum
|
|
else if(rates[0].low < rates[1].low && rates[1].low < rates[2].low)
|
|
score -= 20; // Bearish momentum
|
|
|
|
return NormalizeDouble(MathMax(-100, MathMin(100, score)), 2);
|
|
}
|
|
|
|
bool IsBullishEngulfing(MqlRates &rates[])
|
|
{
|
|
return (rates[1].close < rates[1].open &&
|
|
rates[0].close > rates[0].open &&
|
|
rates[0].close > rates[1].open &&
|
|
rates[0].open < rates[1].close);
|
|
}
|
|
|
|
bool IsBearishEngulfing(MqlRates &rates[])
|
|
{
|
|
return (rates[1].close > rates[1].open &&
|
|
rates[0].close < rates[0].open &&
|
|
rates[0].close < rates[1].open &&
|
|
rates[0].open > rates[1].close);
|
|
}
|
|
|
|
int DetectPinBar(MqlRates &rates[])
|
|
{
|
|
double body = MathAbs(rates[0].close - rates[0].open);
|
|
double upperWick = rates[0].high - MathMax(rates[0].close, rates[0].open);
|
|
double lowerWick = MathMin(rates[0].close, rates[0].open) - rates[0].low;
|
|
double range = rates[0].high - rates[0].low;
|
|
|
|
if(range == 0) return 0;
|
|
|
|
if(lowerWick > body * 2 && lowerWick > range * 0.6)
|
|
return 1; // Bullish pin
|
|
if(upperWick > body * 2 && upperWick > range * 0.6)
|
|
return -1; // Bearish pin
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Update indicators (call on new bar only)
|
|
void UpdateIndicators()
|
|
{
|
|
indicators.UpdateCache();
|
|
}
|
|
|
|
// Update tick data (call every tick)
|
|
void UpdateTick(double price)
|
|
{
|
|
indicators.UpdateTick(price);
|
|
}
|
|
|
|
double GetATR() { return indicators.GetATR(); }
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Lightning-Fast Execution Engine |
|
|
//+------------------------------------------------------------------+
|
|
class CLightningExecutor
|
|
{
|
|
private:
|
|
CTrade trade;
|
|
CSymbolInfo symbolInfo;
|
|
CPositionInfo positionInfo;
|
|
|
|
string m_symbol;
|
|
int m_magic;
|
|
|
|
public:
|
|
CLightningExecutor(string symbol, int magic)
|
|
{
|
|
m_symbol = symbol;
|
|
m_magic = magic;
|
|
|
|
trade.SetExpertMagicNumber(m_magic);
|
|
trade.SetDeviationInPoints(MaxSlippagePips * 10);
|
|
trade.SetTypeFilling(ORDER_FILLING_IOC); // Immediate or Cancel
|
|
trade.SetAsyncMode(false); // Synchronous for reliability
|
|
|
|
symbolInfo.Name(m_symbol);
|
|
}
|
|
|
|
// Execute BUY with instant SL/TP
|
|
bool ExecuteBuy(double lots, double sl, double tp, string comment)
|
|
{
|
|
symbolInfo.Refresh();
|
|
double ask = symbolInfo.Ask();
|
|
|
|
if(!trade.Buy(lots, m_symbol, ask, sl, tp, comment))
|
|
{
|
|
Print("BUY FAILED: ", trade.ResultRetcodeDescription());
|
|
return false;
|
|
}
|
|
|
|
Print("BUY EXECUTED: ", lots, " lots @ ", ask, " | SL:", sl, " TP:", tp);
|
|
return true;
|
|
}
|
|
|
|
// Execute SELL with instant SL/TP
|
|
bool ExecuteSell(double lots, double sl, double tp, string comment)
|
|
{
|
|
symbolInfo.Refresh();
|
|
double bid = symbolInfo.Bid();
|
|
|
|
if(!trade.Sell(lots, m_symbol, bid, sl, tp, comment))
|
|
{
|
|
Print("SELL FAILED: ", trade.ResultRetcodeDescription());
|
|
return false;
|
|
}
|
|
|
|
Print("SELL EXECUTED: ", lots, " lots @ ", bid, " | SL:", sl, " TP:", tp);
|
|
return true;
|
|
}
|
|
|
|
// Trailing stop implementation
|
|
void ManageTrailingStop(double atr)
|
|
{
|
|
if(!UseTrailingStop) return;
|
|
|
|
for(int i = PositionsTotal() - 1; i >= 0; i--)
|
|
{
|
|
if(!positionInfo.SelectByIndex(i)) continue;
|
|
if(positionInfo.Symbol() != m_symbol || positionInfo.Magic() != m_magic) continue;
|
|
|
|
double trailDistance = atr * TrailingStopATRMultiplier;
|
|
double currentPrice = positionInfo.Type() == POSITION_TYPE_BUY ?
|
|
symbolInfo.Bid() : symbolInfo.Ask();
|
|
double currentSL = positionInfo.StopLoss();
|
|
|
|
if(positionInfo.Type() == POSITION_TYPE_BUY)
|
|
{
|
|
double newSL = currentPrice - trailDistance;
|
|
if(newSL > currentSL && newSL < currentPrice)
|
|
trade.PositionModify(positionInfo.Ticket(), newSL, positionInfo.TakeProfit());
|
|
}
|
|
else
|
|
{
|
|
double newSL = currentPrice + trailDistance;
|
|
if(newSL < currentSL && newSL > currentPrice)
|
|
trade.PositionModify(positionInfo.Ticket(), newSL, positionInfo.TakeProfit());
|
|
}
|
|
}
|
|
}
|
|
|
|
bool HasOpenPosition()
|
|
{
|
|
for(int i = 0; i < PositionsTotal(); i++)
|
|
{
|
|
if(positionInfo.SelectByIndex(i))
|
|
{
|
|
if(positionInfo.Symbol() == m_symbol && positionInfo.Magic() == m_magic)
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Main Ultra-Fast Trading Bot |
|
|
//+------------------------------------------------------------------+
|
|
class CUltraFastTradingBot
|
|
{
|
|
private:
|
|
CMultiFactorAnalyzer *analyzer;
|
|
CLightningExecutor *executor;
|
|
|
|
UltraFastContext ctx;
|
|
datetime lastBarTime;
|
|
|
|
string m_symbol;
|
|
|
|
public:
|
|
CUltraFastTradingBot()
|
|
{
|
|
m_symbol = _Symbol;
|
|
analyzer = new CMultiFactorAnalyzer(m_symbol);
|
|
executor = new CLightningExecutor(m_symbol, MagicNumber);
|
|
lastBarTime = 0;
|
|
}
|
|
|
|
~CUltraFastTradingBot()
|
|
{
|
|
delete analyzer;
|
|
delete executor;
|
|
}
|
|
|
|
void OnTick()
|
|
{
|
|
// Update context
|
|
ctx.Reset();
|
|
ctx.bid = SymbolInfoDouble(m_symbol, SYMBOL_BID);
|
|
ctx.ask = SymbolInfoDouble(m_symbol, SYMBOL_ASK);
|
|
ctx.spread = (ctx.ask - ctx.bid) / SymbolInfoDouble(m_symbol, SYMBOL_POINT);
|
|
|
|
// Check if new bar
|
|
datetime currentBarTime = iTime(m_symbol, PERIOD_M1, 0);
|
|
if(currentBarTime != lastBarTime)
|
|
{
|
|
lastBarTime = currentBarTime;
|
|
analyzer.UpdateIndicators();
|
|
}
|
|
|
|
// Sub-second tick analysis
|
|
if(EnableSubSecondAnalysis)
|
|
{
|
|
analyzer.UpdateTick(ctx.bid);
|
|
ctx.tickCounter++;
|
|
}
|
|
|
|
// Pre-flight checks
|
|
if(!PerformPreflightChecks())
|
|
return;
|
|
|
|
// Multi-factor analysis
|
|
PerformMultiFactorAnalysis();
|
|
|
|
// Generate and execute signal
|
|
if(ctx.confluenceScore >= MinConfluenceScore && !executor.HasOpenPosition())
|
|
{
|
|
ExecuteSignal();
|
|
}
|
|
|
|
// Manage existing positions
|
|
executor.ManageTrailingStop(ctx.atrValue);
|
|
}
|
|
|
|
bool PerformPreflightChecks()
|
|
{
|
|
// Spread filter
|
|
if(FilterHighSpread && ctx.spread > MaxSpreadPips)
|
|
{
|
|
ctx.canTrade = false;
|
|
return false;
|
|
}
|
|
|
|
// Session filter
|
|
if(FilterSessionTimes && !IsValidSession())
|
|
{
|
|
ctx.canTrade = false;
|
|
return false;
|
|
}
|
|
|
|
// Tick confirmation
|
|
if(EnableSubSecondAnalysis && ctx.tickCounter < MinTicksBeforeTrade)
|
|
{
|
|
ctx.canTrade = false;
|
|
return false;
|
|
}
|
|
|
|
ctx.canTrade = true;
|
|
return true;
|
|
}
|
|
|
|
void PerformMultiFactorAnalysis()
|
|
{
|
|
// Factor 1: Trend
|
|
ctx.trendScore = analyzer.AnalyzeTrendStrength();
|
|
|
|
// Factor 2: Volatility
|
|
ctx.volatilityScore = analyzer.AnalyzeVolatility();
|
|
|
|
// Factor 3: Indicators
|
|
ctx.indicatorScore = analyzer.AnalyzeIndicatorConfluence();
|
|
|
|
// Factor 4: Patterns
|
|
ctx.patternScore = analyzer.AnalyzePatterns();
|
|
|
|
// Get ATR
|
|
ctx.atrValue = analyzer.GetATR();
|
|
|
|
// Calculate weighted confluence score
|
|
double trendComponent = (ctx.trendScore + 100) / 2.0 * TrendWeight / 100.0;
|
|
double volatilityComponent = ctx.volatilityScore * VolatilityWeight / 100.0;
|
|
double indicatorComponent = ctx.indicatorScore * IndicatorWeight / 100.0;
|
|
double patternComponent = (ctx.patternScore + 100) / 2.0 * PatternWeight / 100.0;
|
|
|
|
ctx.confluenceScore = trendComponent + volatilityComponent +
|
|
indicatorComponent + patternComponent;
|
|
|
|
// Determine direction
|
|
double directionScore = (ctx.trendScore + ctx.patternScore) / 2.0;
|
|
|
|
if(directionScore > 30)
|
|
ctx.regime = REGIME_STRONG_UPTREND;
|
|
else if(directionScore < -30)
|
|
ctx.regime = REGIME_STRONG_DOWNTREND;
|
|
else
|
|
ctx.regime = REGIME_RANGING;
|
|
}
|
|
|
|
void ExecuteSignal()
|
|
{
|
|
double lots = CalculatePositionSize();
|
|
|
|
// Calculate SL/TP
|
|
if(ctx.regime == REGIME_STRONG_UPTREND)
|
|
{
|
|
double sl = ctx.bid - (ctx.atrValue * StopLossATRMultiplier);
|
|
double tp = ctx.bid + (ctx.atrValue * TakeProfitATRMultiplier);
|
|
executor.ExecuteBuy(lots, sl, tp, TradeComment);
|
|
}
|
|
else if(ctx.regime == REGIME_STRONG_DOWNTREND)
|
|
{
|
|
double sl = ctx.ask + (ctx.atrValue * StopLossATRMultiplier);
|
|
double tp = ctx.ask - (ctx.atrValue * TakeProfitATRMultiplier);
|
|
executor.ExecuteSell(lots, sl, tp, TradeComment);
|
|
}
|
|
}
|
|
|
|
double CalculatePositionSize()
|
|
{
|
|
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
double riskAmount = balance * RiskPercentPerTrade / 100.0;
|
|
|
|
double slDistance = ctx.atrValue * StopLossATRMultiplier;
|
|
double tickValue = SymbolInfoDouble(m_symbol, SYMBOL_TRADE_TICK_VALUE);
|
|
double tickSize = SymbolInfoDouble(m_symbol, SYMBOL_TRADE_TICK_SIZE);
|
|
double point = SymbolInfoDouble(m_symbol, SYMBOL_POINT);
|
|
|
|
double slValue = slDistance / tickSize * tickValue;
|
|
double lots = riskAmount / slValue;
|
|
|
|
// Normalize lot size
|
|
double minLot = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_MIN);
|
|
double maxLot = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_MAX);
|
|
double lotStep = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_STEP);
|
|
|
|
lots = MathFloor(lots / lotStep) * lotStep;
|
|
lots = MathMax(minLot, MathMin(maxLot, lots));
|
|
|
|
return lots;
|
|
}
|
|
|
|
bool IsValidSession()
|
|
{
|
|
MqlDateTime dt;
|
|
TimeToStruct(TimeCurrent(), dt);
|
|
int hour = dt.hour;
|
|
|
|
// London: 08:00-17:00 GMT
|
|
if(AllowLondonSession && hour >= 8 && hour < 17) return true;
|
|
|
|
// NY: 13:00-22:00 GMT
|
|
if(AllowNYSession && hour >= 13 && hour < 22) return true;
|
|
|
|
// Asian: 00:00-09:00 GMT
|
|
if(AllowAsianSession && hour >= 0 && hour < 9) return true;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
CUltraFastTradingBot *bot;
|
|
|
|
int OnInit()
|
|
{
|
|
Print("========================================");
|
|
Print(" ULTRA-FAST AI GOLD TRADING SYSTEM");
|
|
Print(" Sub-Second Multi-Factor Analysis");
|
|
Print("========================================");
|
|
Print("Confluence Threshold: ", MinConfluenceScore, "%");
|
|
Print("Trend Weight: ", TrendWeight, "%");
|
|
Print("Volatility Weight: ", VolatilityWeight, "%");
|
|
Print("Indicator Weight: ", IndicatorWeight, "%");
|
|
Print("Pattern Weight: ", PatternWeight, "%");
|
|
Print("========================================");
|
|
|
|
bot = new CUltraFastTradingBot();
|
|
|
|
if(bot == NULL)
|
|
{
|
|
Print("ERROR: Failed to initialize bot");
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
Print("Bot initialized successfully!");
|
|
Print("Waiting for trading signals...");
|
|
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
void OnDeinit(const int reason)
|
|
{
|
|
Print("========================================");
|
|
Print("EA Stopped. Reason: ", reason);
|
|
Print("========================================");
|
|
delete bot;
|
|
}
|
|
|
|
void OnTick()
|
|
{
|
|
bot.OnTick();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//+------------------------------------------------------------------+
|
|
//| Dashboard_RiskManagement.mqh |
|
|
//| Real-Time Performance & Risk Analytics |
|
|
//+------------------------------------------------------------------+
|
|
|
|
#include <ChartObjects\ChartObjectsTxtControls.mqh>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Performance Metrics Tracker |
|
|
//+------------------------------------------------------------------+
|
|
class CPerformanceTracker
|
|
{
|
|
private:
|
|
struct TradeRecord
|
|
{
|
|
datetime openTime;
|
|
datetime closeTime;
|
|
double openPrice;
|
|
double closePrice;
|
|
double profit;
|
|
double lots;
|
|
int type; // 0=Buy, 1=Sell
|
|
bool isWin;
|
|
};
|
|
|
|
TradeRecord history[];
|
|
int totalTrades;
|
|
int winningTrades;
|
|
int losingTrades;
|
|
|
|
double totalProfit;
|
|
double totalLoss;
|
|
double largestWin;
|
|
double largestLoss;
|
|
double currentDrawdown;
|
|
double maxDrawdown;
|
|
|
|
double initialBalance;
|
|
double currentBalance;
|
|
|
|
// Daily metrics
|
|
datetime currentDay;
|
|
double dailyProfit;
|
|
int dailyTrades;
|
|
|
|
public:
|
|
CPerformanceTracker()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
totalTrades = 0;
|
|
winningTrades = 0;
|
|
losingTrades = 0;
|
|
totalProfit = 0;
|
|
totalLoss = 0;
|
|
largestWin = 0;
|
|
largestLoss = 0;
|
|
currentDrawdown = 0;
|
|
maxDrawdown = 0;
|
|
initialBalance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
currentBalance = initialBalance;
|
|
dailyProfit = 0;
|
|
dailyTrades = 0;
|
|
currentDay = 0;
|
|
}
|
|
|
|
void RecordTrade(double openPrice, double closePrice, double profit, double lots, int type)
|
|
{
|
|
totalTrades++;
|
|
|
|
// Check if new day
|
|
datetime now = TimeCurrent();
|
|
MqlDateTime dt;
|
|
TimeToStruct(now, dt);
|
|
datetime today = StringToTime(IntegerToString(dt.year) + "." +
|
|
IntegerToString(dt.mon) + "." +
|
|
IntegerToString(dt.day));
|
|
|
|
if(today != currentDay)
|
|
{
|
|
currentDay = today;
|
|
dailyProfit = 0;
|
|
dailyTrades = 0;
|
|
}
|
|
|
|
dailyTrades++;
|
|
dailyProfit += profit;
|
|
|
|
// Record win/loss
|
|
if(profit > 0)
|
|
{
|
|
winningTrades++;
|
|
totalProfit += profit;
|
|
if(profit > largestWin) largestWin = profit;
|
|
}
|
|
else if(profit < 0)
|
|
{
|
|
losingTrades++;
|
|
totalLoss += MathAbs(profit);
|
|
if(MathAbs(profit) > largestLoss) largestLoss = MathAbs(profit);
|
|
}
|
|
|
|
// Update balance
|
|
currentBalance += profit;
|
|
|
|
// Calculate drawdown
|
|
if(currentBalance < initialBalance)
|
|
{
|
|
currentDrawdown = (initialBalance - currentBalance) / initialBalance * 100;
|
|
if(currentDrawdown > maxDrawdown)
|
|
maxDrawdown = currentDrawdown;
|
|
}
|
|
else
|
|
{
|
|
currentDrawdown = 0;
|
|
initialBalance = currentBalance; // New high watermark
|
|
}
|
|
}
|
|
|
|
double GetWinRate()
|
|
{
|
|
if(totalTrades == 0) return 0;
|
|
return (double)winningTrades / totalTrades * 100;
|
|
}
|
|
|
|
double GetProfitFactor()
|
|
{
|
|
if(totalLoss == 0) return totalProfit > 0 ? 999 : 0;
|
|
return totalProfit / totalLoss;
|
|
}
|
|
|
|
double GetAverageWin()
|
|
{
|
|
if(winningTrades == 0) return 0;
|
|
return totalProfit / winningTrades;
|
|
}
|
|
|
|
double GetAverageLoss()
|
|
{
|
|
if(losingTrades == 0) return 0;
|
|
return totalLoss / losingTrades;
|
|
}
|
|
|
|
double GetExpectancy()
|
|
{
|
|
if(totalTrades == 0) return 0;
|
|
return (totalProfit - totalLoss) / totalTrades;
|
|
}
|
|
|
|
double GetROI()
|
|
{
|
|
double startBalance = AccountInfoDouble(ACCOUNT_BALANCE) - (currentBalance - initialBalance);
|
|
if(startBalance == 0) return 0;
|
|
return (currentBalance - startBalance) / startBalance * 100;
|
|
}
|
|
|
|
// Getters
|
|
int GetTotalTrades() { return totalTrades; }
|
|
int GetWinningTrades() { return winningTrades; }
|
|
int GetLosingTrades() { return losingTrades; }
|
|
double GetTotalProfit() { return totalProfit; }
|
|
double GetTotalLoss() { return totalLoss; }
|
|
double GetLargestWin() { return largestWin; }
|
|
double GetLargestLoss() { return largestLoss; }
|
|
double GetMaxDrawdown() { return maxDrawdown; }
|
|
double GetCurrentDrawdown() { return currentDrawdown; }
|
|
double GetDailyProfit() { return dailyProfit; }
|
|
int GetDailyTrades() { return dailyTrades; }
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Advanced Risk Manager with Real-Time Monitoring |
|
|
//+------------------------------------------------------------------+
|
|
class CAdvancedRiskManager
|
|
{
|
|
private:
|
|
CPerformanceTracker *tracker;
|
|
|
|
// Risk limits
|
|
double maxDailyLossPercent;
|
|
double maxDrawdownPercent;
|
|
double maxPositionSize;
|
|
|
|
// Dynamic risk adjustment
|
|
bool useAdaptiveRisk;
|
|
double baseRiskPercent;
|
|
double currentRiskPercent;
|
|
|
|
// Circuit breaker
|
|
bool circuitBreakerActive;
|
|
datetime circuitBreakerUntil;
|
|
|
|
// Correlation monitor
|
|
double correlationThreshold;
|
|
|
|
public:
|
|
CAdvancedRiskManager(double dailyLoss, double maxDD, double baseRisk)
|
|
{
|
|
tracker = new CPerformanceTracker();
|
|
maxDailyLossPercent = dailyLoss;
|
|
maxDrawdownPercent = maxDD;
|
|
baseRiskPercent = baseRisk;
|
|
currentRiskPercent = baseRisk;
|
|
useAdaptiveRisk = true;
|
|
circuitBreakerActive = false;
|
|
}
|
|
|
|
~CAdvancedRiskManager()
|
|
{
|
|
delete tracker;
|
|
}
|
|
|
|
// Check if trading is allowed
|
|
bool CanTrade()
|
|
{
|
|
// Circuit breaker check
|
|
if(circuitBreakerActive)
|
|
{
|
|
if(TimeCurrent() < circuitBreakerUntil)
|
|
{
|
|
Print("CIRCUIT BREAKER ACTIVE - Trading suspended until ", circuitBreakerUntil);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
circuitBreakerActive = false;
|
|
Print("Circuit breaker reset - Trading resumed");
|
|
}
|
|
}
|
|
|
|
// Daily loss limit
|
|
double dailyLoss = -tracker.GetDailyProfit();
|
|
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
|
|
double dailyLossPercent = dailyLoss / balance * 100;
|
|
|
|
if(dailyLossPercent >= maxDailyLossPercent)
|
|
{
|
|
ActivateCircuitBreaker(24); // 24 hour suspension
|
|
Print("DAILY LOSS LIMIT REACHED: ", dailyLossPercent, "% - Circuit breaker activated");
|
|
return false;
|
|
}
|
|
|
|
// Drawdown limit
|
|
if(tracker.GetCurrentDrawdown() >= maxDrawdownPercent)
|
|
{
|
|
ActivateCircuitBreaker(48); // 48 hour suspension
|
|
Print("MAX DRAWDOWN REACHED: ", tracker.GetCurrentDrawdown(), "% - Circuit breaker activated");
|
|
return false;
|
|
}
|
|
|
|
// Consecutive loss protection
|
|
if(GetConsecutiveLosses() >= 5)
|
|
{
|
|
ActivateCircuitBreaker(6); // 6 hour cooldown
|
|
Print("5 CONSECUTIVE LOSSES - Cooling down for 6 hours");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ActivateCircuitBreaker(int hours)
|
|
{
|
|
circuitBreakerActive = true;
|
|
circuitBreakerUntil = TimeCurrent() + hours * 3600;
|
|
}
|
|
|
|
// Adaptive risk calculation
|
|
double GetCurrentRiskPercent()
|
|
{
|
|
if(!useAdaptiveRisk)
|
|
return baseRiskPercent;
|
|
|
|
// Reduce risk after losses
|
|
double winRate = tracker.GetWinRate();
|
|
double profitFactor = tracker.GetProfitFactor();
|
|
|
|
currentRiskPercent = baseRiskPercent;
|
|
|
|
// Adjust based on performance
|
|
if(winRate < 40)
|
|
currentRiskPercent *= 0.5; // Reduce risk by 50%
|
|
else if(winRate > 60 && profitFactor > 1.5)
|
|
currentRiskPercent *= 1.2; // Increase risk by 20%
|
|
|
|
// Drawdown adjustment
|
|
double dd = tracker.GetCurrentDrawdown();
|
|
if(dd > 5)
|
|
currentRiskPercent *= (1 - dd / 100); // Scale down with drawdown
|
|
|
|
// Keep within bounds
|
|
currentRiskPercent = MathMax(0.25, MathMin(2.0, currentRiskPercent));
|
|
|
|
return currentRiskPercent;
|
|
}
|
|
|
|
int GetConsecutiveLosses()
|
|
{
|
|
// Check last 10 positions for consecutive losses
|
|
int consecutive = 0;
|
|
|
|
for(int i = HistoryDealsTotal() - 1; i >= HistoryDealsTotal() - 10 && i >= 0; i--)
|
|
{
|
|
ulong ticket = HistoryDealGetTicket(i);
|
|
if(ticket == 0) continue;
|
|
|
|
if(HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT)
|
|
{
|
|
double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);
|
|
if(profit < 0)
|
|
consecutive++;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
return consecutive;
|
|
}
|
|
|
|
void RecordTrade(double openPrice, double closePrice, double profit, double lots, int type)
|
|
{
|
|
tracker.RecordTrade(openPrice, closePrice, profit, lots, type);
|
|
}
|
|
|
|
CPerformanceTracker* GetTracker() { return tracker; }
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Real-Time Dashboard Display |
|
|
//+------------------------------------------------------------------+
|
|
class CPerformanceDashboard
|
|
{
|
|
private:
|
|
CAdvancedRiskManager *riskManager;
|
|
|
|
// Chart objects
|
|
CChartObjectLabel lblTitle;
|
|
CChartObjectLabel lblStats[];
|
|
|
|
int windowIndex;
|
|
int xPosition;
|
|
int yPosition;
|
|
|
|
string prefix;
|
|
|
|
public:
|
|
CPerformanceDashboard(CAdvancedRiskManager *rm)
|
|
{
|
|
riskManager = rm;
|
|
prefix = "Dashboard_";
|
|
windowIndex = 0;
|
|
xPosition = 10;
|
|
yPosition = 20;
|
|
}
|
|
|
|
void Initialize()
|
|
{
|
|
// Create title
|
|
lblTitle.Create(0, prefix + "Title", windowIndex, xPosition, yPosition);
|
|
lblTitle.Description("═══ AI GOLD SYSTEM PERFORMANCE ═══");
|
|
lblTitle.Color(clrYellow);
|
|
lblTitle.FontSize(10);
|
|
|
|
// Create stat labels
|
|
ArrayResize(lblStats, 15);
|
|
|
|
string labels[] = {
|
|
"Total Trades:", "Win Rate:", "Profit Factor:",
|
|
"Total Profit:", "Max Drawdown:", "Daily P/L:",
|
|
"Avg Win:", "Avg Loss:", "Expectancy:",
|
|
"ROI:", "Risk Level:", "Status:",
|
|
"Largest Win:", "Largest Loss:", "Daily Trades:"
|
|
};
|
|
|
|
for(int i = 0; i < 15; i++)
|
|
{
|
|
lblStats[i].Create(0, prefix + "Stat" + IntegerToString(i),
|
|
windowIndex, xPosition, yPosition + 30 + (i * 18));
|
|
lblStats[i].Description(labels[i]);
|
|
lblStats[i].Color(clrWhite);
|
|
lblStats[i].FontSize(8);
|
|
}
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
CPerformanceTracker *tracker = riskManager.GetTracker();
|
|
|
|
UpdateLabel(0, "Total Trades: " + IntegerToString(tracker.GetTotalTrades()));
|
|
UpdateLabel(1, "Win Rate: " + DoubleToString(tracker.GetWinRate(), 1) + "%",
|
|
tracker.GetWinRate() >= 50 ? clrLime : clrRed);
|
|
UpdateLabel(2, "Profit Factor: " + DoubleToString(tracker.GetProfitFactor(), 2),
|
|
tracker.GetProfitFactor() >= 1.5 ? clrLime : clrOrange);
|
|
UpdateLabel(3, "Total Profit: $" + DoubleToString(tracker.GetTotalProfit(), 2),
|
|
tracker.GetTotalProfit() > 0 ? clrLime : clrRed);
|
|
UpdateLabel(4, "Max DD: " + DoubleToString(tracker.GetMaxDrawdown(), 2) + "%",
|
|
tracker.GetMaxDrawdown() < 10 ? clrLime : clrRed);
|
|
UpdateLabel(5, "Daily P/L: $" + DoubleToString(tracker.GetDailyProfit(), 2),
|
|
tracker.GetDailyProfit() > 0 ? clrLime : clrRed);
|
|
UpdateLabel(6, "Avg Win: $" + DoubleToString(tracker.GetAverageWin(), 2));
|
|
UpdateLabel(7, "Avg Loss: $" + DoubleToString(tracker.GetAverageLoss(), 2));
|
|
UpdateLabel(8, "Expectancy: $" + DoubleToString(tracker.GetExpectancy(), 2),
|
|
tracker.GetExpectancy() > 0 ? clrLime : clrRed);
|
|
UpdateLabel(9, "ROI: " + DoubleToString(tracker.GetROI(), 2) + "%",
|
|
tracker.GetROI() > 0 ? clrLime : clrRed);
|
|
UpdateLabel(10, "Risk Level: " + DoubleToString(riskManager.GetCurrentRiskPercent(), 2) + "%");
|
|
UpdateLabel(11, riskManager.CanTrade() ? "Status: ACTIVE" : "Status: SUSPENDED",
|
|
riskManager.CanTrade() ? clrLime : clrRed);
|
|
UpdateLabel(12, "Largest Win: $" + DoubleToString(tracker.GetLargestWin(), 2));
|
|
UpdateLabel(13, "Largest Loss: $" + DoubleToString(tracker.GetLargestLoss(), 2));
|
|
UpdateLabel(14, "Daily Trades: " + IntegerToString(tracker.GetDailyTrades()));
|
|
}
|
|
|
|
void UpdateLabel(int index, string text, color clr = clrWhite)
|
|
{
|
|
if(index >= 0 && index < ArraySize(lblStats))
|
|
{
|
|
lblStats[index].Description(text);
|
|
lblStats[index].Color(clr);
|
|
}
|
|
}
|
|
|
|
void Destroy()
|
|
{
|
|
lblTitle.Delete();
|
|
for(int i = 0; i < ArraySize(lblStats); i++)
|
|
lblStats[i].Delete();
|
|
}
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Signal Quality Analyzer - Pre-Trade Validation |
|
|
//+------------------------------------------------------------------+
|
|
class CSignalQualityAnalyzer
|
|
{
|
|
private:
|
|
double qualityThreshold;
|
|
|
|
public:
|
|
CSignalQualityAnalyzer(double threshold = 70.0)
|
|
{
|
|
qualityThreshold = threshold;
|
|
}
|
|
|
|
// Comprehensive signal quality scoring (0-100)
|
|
double AnalyzeSignalQuality(double trendScore, double volatilityScore,
|
|
double indicatorScore, double patternScore,
|
|
double atr, double spread)
|
|
{
|
|
double quality = 0;
|
|
|
|
// 1. Trend alignment (30 points)
|
|
if(MathAbs(trendScore) > 70)
|
|
quality += 30;
|
|
else if(MathAbs(trendScore) > 40)
|
|
quality += 15;
|
|
|
|
// 2. Volatility appropriateness (20 points)
|
|
if(volatilityScore > 40 && volatilityScore < 80)
|
|
quality += 20; // Ideal volatility
|
|
else if(volatilityScore > 80)
|
|
quality += 5; // Too volatile
|
|
|
|
// 3. Indicator confluence (25 points)
|
|
quality += indicatorScore * 0.25;
|
|
|
|
// 4. Pattern strength (25 points)
|
|
if(MathAbs(patternScore) > 60)
|
|
quality += 25;
|
|
else if(MathAbs(patternScore) > 30)
|
|
quality += 12;
|
|
|
|
// 5. Spread penalty
|
|
if(spread > 20)
|
|
quality *= 0.8; // 20% penalty
|
|
|
|
return NormalizeDouble(quality, 2);
|
|
}
|
|
|
|
bool IsHighQualitySignal(double quality)
|
|
{
|
|
return quality >= qualityThreshold;
|
|
}
|
|
};
|
|
//+------------------------------------------------------------------+ |