Initialize project in MT5 Experts directory
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Data/FibonacciEngine.mqh |
|
||||
//| Fibonacci Retracement & Extension Analysis |
|
||||
//| Identifies key S/R levels: 0.236, 0.382, 0.5, 0.618, 0.786 |
|
||||
//| Uses swing highs/lows for accurate level placement |
|
||||
//+------------------------------------------------------------------+
|
||||
#ifndef __FIBONACCI_ENGINE_MQH__
|
||||
#define __FIBONACCI_ENGINE_MQH__
|
||||
|
||||
#include "../Core/Config.mqh"
|
||||
#include "../Core/State.mqh"
|
||||
#include "../Data/PriceEngine.mqh"
|
||||
|
||||
class CFibonacciEngine
|
||||
{
|
||||
private:
|
||||
ENUM_TIMEFRAMES m_tf;
|
||||
double m_levels[7]; // 0.0, 0.236, 0.382, 0.5, 0.618, 0.786, 1.0
|
||||
double m_levelValues[7];
|
||||
bool m_levelsValid;
|
||||
double m_swingHigh;
|
||||
double m_swingLow;
|
||||
datetime m_swingHighTime;
|
||||
datetime m_swingLowTime;
|
||||
|
||||
public:
|
||||
CFibonacciEngine() : m_levelsValid(false), m_swingHigh(0), m_swingLow(0) {}
|
||||
|
||||
bool Init(ENUM_TIMEFRAMES tf)
|
||||
{
|
||||
m_tf = tf;
|
||||
m_levels[0] = 0.0;
|
||||
m_levels[1] = 0.236;
|
||||
m_levels[2] = 0.382;
|
||||
m_levels[3] = 0.500;
|
||||
m_levels[4] = 0.618;
|
||||
m_levels[5] = 0.786;
|
||||
m_levels[6] = 1.0;
|
||||
Print("[FibonacciEngine] Initialized on ", EnumToString(tf));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Calculate()
|
||||
{
|
||||
// Find significant swing high and low
|
||||
FindSwingPoints();
|
||||
|
||||
if(m_swingHigh <= m_swingLow || m_swingHigh == 0 || m_swingLow == 0)
|
||||
{
|
||||
m_levelsValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
double range = m_swingHigh - m_swingLow;
|
||||
for(int i = 0; i < 7; i++)
|
||||
{
|
||||
m_levelValues[i] = m_swingHigh - (range * m_levels[i]);
|
||||
}
|
||||
m_levelsValid = true;
|
||||
}
|
||||
|
||||
// Check if price is near a key fibonacci level (for entries)
|
||||
bool IsNearFibLevel(double price, double tolerance, int &nearestLevel)
|
||||
{
|
||||
if(!m_levelsValid) return false;
|
||||
|
||||
nearestLevel = -1;
|
||||
double minDist = DBL_MAX;
|
||||
|
||||
// Most important levels for entries: 0.382, 0.5, 0.618, 0.786
|
||||
int keyLevels[] = {2, 3, 4, 5};
|
||||
|
||||
for(int i = 0; i < ArraySize(keyLevels); i++)
|
||||
{
|
||||
int idx = keyLevels[i];
|
||||
double dist = MathAbs(price - m_levelValues[idx]);
|
||||
if(dist < minDist)
|
||||
{
|
||||
minDist = dist;
|
||||
nearestLevel = idx;
|
||||
}
|
||||
}
|
||||
|
||||
double atr = iATR(_Symbol, m_tf, 14);
|
||||
if(atr == 0) atr = _Point * 50;
|
||||
|
||||
return (minDist <= tolerance * atr);
|
||||
}
|
||||
|
||||
// Get the strongest level (0.618 golden ratio)
|
||||
double GetGoldenRatioLevel() const
|
||||
{
|
||||
if(!m_levelsValid) return 0;
|
||||
return m_levelValues[4]; // 0.618
|
||||
}
|
||||
|
||||
// Get 0.786 level (deep retracement - final support/resistance)
|
||||
double GetDeepLevel() const
|
||||
{
|
||||
if(!m_levelsValid) return 0;
|
||||
return m_levelValues[5]; // 0.786
|
||||
}
|
||||
|
||||
// Check if price broke a fib level (trend continuation signal)
|
||||
bool DidBreakLevel(double prevClose, double currClose, int levelIdx)
|
||||
{
|
||||
if(!m_levelsValid || levelIdx < 0 || levelIdx >= 7) return false;
|
||||
|
||||
double level = m_levelValues[levelIdx];
|
||||
return ((prevClose < level && currClose > level) ||
|
||||
(prevClose > level && currClose < level));
|
||||
}
|
||||
|
||||
// Get fibonacci extension for TP calculation
|
||||
double GetExtension(double multiplier)
|
||||
{
|
||||
if(!m_levelsValid) return 0;
|
||||
double range = m_swingHigh - m_swingLow;
|
||||
return m_swingHigh + (range * multiplier);
|
||||
}
|
||||
|
||||
string GetLevelName(int idx) const
|
||||
{
|
||||
if(idx < 0 || idx >= 7) return "Invalid";
|
||||
string names[] = {"0.0", "0.236", "0.382", "0.5", "0.618", "0.786", "1.0"};
|
||||
return names[idx];
|
||||
}
|
||||
|
||||
bool IsValid() const { return m_levelsValid; }
|
||||
double GetSwingHigh() const { return m_swingHigh; }
|
||||
double GetSwingLow() const { return m_swingLow; }
|
||||
|
||||
private:
|
||||
void FindSwingPoints()
|
||||
{
|
||||
MqlRates rates[];
|
||||
ArraySetAsSeries(rates, true);
|
||||
int copied = CopyRates(_Symbol, m_tf, 0, 100, rates);
|
||||
if(copied < 20) { m_levelsValid = false; return; }
|
||||
|
||||
// Find swing high (highest high in last 50 bars)
|
||||
m_swingHigh = 0;
|
||||
m_swingHighTime = 0;
|
||||
int highIdx = iHighest(_Symbol, m_tf, MODE_HIGH, 50, 1);
|
||||
if(highIdx >= 0)
|
||||
{
|
||||
m_swingHigh = iHigh(_Symbol, m_tf, highIdx);
|
||||
m_swingHighTime = iTime(_Symbol, m_tf, highIdx);
|
||||
}
|
||||
|
||||
// Find swing low (lowest low in last 50 bars)
|
||||
m_swingLow = DBL_MAX;
|
||||
m_swingLowTime = 0;
|
||||
int lowIdx = iLowest(_Symbol, m_tf, MODE_LOW, 50, 1);
|
||||
if(lowIdx >= 0)
|
||||
{
|
||||
m_swingLow = iLow(_Symbol, m_tf, lowIdx);
|
||||
m_swingLowTime = iTime(_Symbol, m_tf, lowIdx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __FIBONACCI_ENGINE_MQH__
|
||||
@@ -0,0 +1,306 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Data/LiquidityEngine.mqh |
|
||||
//| Smart Money Concepts: Order Blocks, Liquidity Sweeps, FVG |
|
||||
//| Identifies institutional levels for high-probability entries |
|
||||
//+------------------------------------------------------------------+
|
||||
#ifndef __LIQUIDITY_ENGINE_MQH__
|
||||
#define __LIQUIDITY_ENGINE_MQH__
|
||||
|
||||
#include "../Core/Config.mqh"
|
||||
#include "../Core/State.mqh"
|
||||
|
||||
struct OrderBlock
|
||||
{
|
||||
double high;
|
||||
double low;
|
||||
double open;
|
||||
double close;
|
||||
datetime time;
|
||||
bool isBullish; // true = bullish OB (buy zone)
|
||||
bool isValid;
|
||||
int strength; // 1-3 based on volume and follow-through
|
||||
};
|
||||
|
||||
struct LiquidityPool
|
||||
{
|
||||
double level;
|
||||
datetime time;
|
||||
bool isBuySide; // true = buy-side liquidity (equal highs)
|
||||
bool isSwept; // true = liquidity was swept/taken
|
||||
int touchCount; // how many times price touched this level
|
||||
};
|
||||
|
||||
class CLiquidityEngine
|
||||
{
|
||||
private:
|
||||
ENUM_TIMEFRAMES m_tf;
|
||||
OrderBlock m_bullishOBs[];
|
||||
OrderBlock m_bearishOBs[];
|
||||
LiquidityPool m_pools[];
|
||||
int m_maxOBs;
|
||||
int m_lookback;
|
||||
|
||||
public:
|
||||
CLiquidityEngine() : m_maxOBs(5), m_lookback(50) {}
|
||||
|
||||
bool Init(ENUM_TIMEFRAMES tf)
|
||||
{
|
||||
m_tf = tf;
|
||||
ArrayResize(m_bullishOBs, m_maxOBs);
|
||||
ArrayResize(m_bearishOBs, m_maxOBs);
|
||||
ArrayResize(m_pools, 10);
|
||||
Print("[LiquidityEngine] Initialized on ", EnumToString(tf));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
FindOrderBlocks();
|
||||
FindLiquidityPools();
|
||||
}
|
||||
|
||||
// Check if price is at a valid order block
|
||||
bool IsAtOrderBlock(double price, bool wantBullish, OrderBlock &outOB)
|
||||
{
|
||||
if(wantBullish)
|
||||
{
|
||||
for(int i = 0; i < ArraySize(m_bullishOBs); i++)
|
||||
{
|
||||
if(!m_bullishOBs[i].isValid) continue;
|
||||
if(price >= m_bullishOBs[i].low && price <= m_bullishOBs[i].high)
|
||||
{
|
||||
outOB = m_bullishOBs[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < ArraySize(m_bearishOBs); i++)
|
||||
{
|
||||
if(!m_bearishOBs[i].isValid) continue;
|
||||
if(price >= m_bearishOBs[i].low && price <= m_bearishOBs[i].high)
|
||||
{
|
||||
outOB = m_bearishOBs[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for liquidity sweep (stop hunt) - reversal signal
|
||||
bool WasLiquiditySwept(int barsBack, bool &sweptBuySide)
|
||||
{
|
||||
MqlRates rates[];
|
||||
ArraySetAsSeries(rates, true);
|
||||
if(CopyRates(_Symbol, m_tf, 0, barsBack + 5, rates) < barsBack + 5) return false;
|
||||
|
||||
// Check for sweep of equal highs/lows
|
||||
double recentHigh = 0, recentLow = DBL_MAX;
|
||||
for(int i = 1; i <= barsBack; i++)
|
||||
{
|
||||
if(rates[i].high > recentHigh) recentHigh = rates[i].high;
|
||||
if(rates[i].low < recentLow) recentLow = rates[i].low;
|
||||
}
|
||||
|
||||
// Buy-side liquidity sweep (swept highs then reversed down)
|
||||
if(rates[0].high > recentHigh && rates[0].close < rates[1].close)
|
||||
{
|
||||
sweptBuySide = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sell-side liquidity sweep (swept lows then reversed up)
|
||||
if(rates[0].low < recentLow && rates[0].close > rates[1].close)
|
||||
{
|
||||
sweptBuySide = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for Fair Value Gap (FVG) - imbalance zone
|
||||
bool HasFVG(int barsBack, bool &isBullishFVG, double &fvgTop, double &fvgBottom)
|
||||
{
|
||||
MqlRates rates[];
|
||||
ArraySetAsSeries(rates, true);
|
||||
if(CopyRates(_Symbol, m_tf, 0, barsBack + 3, rates) < barsBack + 3) return false;
|
||||
|
||||
for(int i = 1; i < barsBack; i++)
|
||||
{
|
||||
// Bullish FVG: current low > previous high (gap up)
|
||||
if(rates[i].low > rates[i+1].high)
|
||||
{
|
||||
isBullishFVG = true;
|
||||
fvgTop = rates[i].low;
|
||||
fvgBottom = rates[i+1].high;
|
||||
return true;
|
||||
}
|
||||
// Bearish FVG: current high < previous low (gap down)
|
||||
if(rates[i].high < rates[i+1].low)
|
||||
{
|
||||
isBullishFVG = false;
|
||||
fvgTop = rates[i+1].low;
|
||||
fvgBottom = rates[i].high;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the nearest untapped liquidity level
|
||||
double GetNearestLiquidity(double currentPrice, bool above)
|
||||
{
|
||||
double nearest = 0;
|
||||
double minDist = DBL_MAX;
|
||||
|
||||
for(int i = 0; i < ArraySize(m_pools); i++)
|
||||
{
|
||||
if(m_pools[i].isSwept) continue;
|
||||
|
||||
if(above && m_pools[i].level > currentPrice)
|
||||
{
|
||||
double dist = m_pools[i].level - currentPrice;
|
||||
if(dist < minDist) { minDist = dist; nearest = m_pools[i].level; }
|
||||
}
|
||||
else if(!above && m_pools[i].level < currentPrice)
|
||||
{
|
||||
double dist = currentPrice - m_pools[i].level;
|
||||
if(dist < minDist) { minDist = dist; nearest = m_pools[i].level; }
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
private:
|
||||
void FindOrderBlocks()
|
||||
{
|
||||
MqlRates rates[];
|
||||
ArraySetAsSeries(rates, true);
|
||||
int copied = CopyRates(_Symbol, m_tf, 0, m_lookback, rates);
|
||||
if(copied < 10) return;
|
||||
|
||||
int bullCount = 0, bearCount = 0;
|
||||
|
||||
for(int i = 2; i < copied - 1 && (bullCount < m_maxOBs || bearCount < m_maxOBs); i++)
|
||||
{
|
||||
// Bullish Order Block: bearish candle before strong bullish move
|
||||
if(rates[i].close < rates[i].open && rates[i-1].close > rates[i-1].open * 1.01)
|
||||
{
|
||||
// Strong bullish follow-through
|
||||
if(bullCount < m_maxOBs)
|
||||
{
|
||||
m_bullishOBs[bullCount].high = rates[i].high;
|
||||
m_bullishOBs[bullCount].low = rates[i].low;
|
||||
m_bullishOBs[bullCount].open = rates[i].open;
|
||||
m_bullishOBs[bullCount].close = rates[i].close;
|
||||
m_bullishOBs[bullCount].time = rates[i].time;
|
||||
m_bullishOBs[bullCount].isBullish = true;
|
||||
m_bullishOBs[bullCount].isValid = true;
|
||||
m_bullishOBs[bullCount].strength = CalculateStrength(rates, i);
|
||||
bullCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Bearish Order Block: bullish candle before strong bearish move
|
||||
if(rates[i].close > rates[i].open && rates[i-1].close < rates[i-1].open * 0.99)
|
||||
{
|
||||
// Strong bearish follow-through
|
||||
if(bearCount < m_maxOBs)
|
||||
{
|
||||
m_bearishOBs[bearCount].high = rates[i].high;
|
||||
m_bearishOBs[bearCount].low = rates[i].low;
|
||||
m_bearishOBs[bearCount].open = rates[i].open;
|
||||
m_bearishOBs[bearCount].close = rates[i].close;
|
||||
m_bearishOBs[bearCount].time = rates[i].time;
|
||||
m_bearishOBs[bearCount].isBullish = false;
|
||||
m_bearishOBs[bearCount].isValid = true;
|
||||
m_bearishOBs[bearCount].strength = CalculateStrength(rates, i);
|
||||
bearCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindLiquidityPools()
|
||||
{
|
||||
MqlRates rates[];
|
||||
ArraySetAsSeries(rates, true);
|
||||
int copied = CopyRates(_Symbol, m_tf, 0, m_lookback, rates);
|
||||
if(copied < 20) return;
|
||||
|
||||
int poolCount = 0;
|
||||
|
||||
// Find equal highs (buy-side liquidity)
|
||||
for(int i = 5; i < copied - 5 && poolCount < 10; i++)
|
||||
{
|
||||
double currHigh = rates[i].high;
|
||||
bool isEqualHigh = false;
|
||||
|
||||
for(int j = i + 2; j < i + 10 && j < copied; j++)
|
||||
{
|
||||
if(MathAbs(rates[j].high - currHigh) < _Point * 10)
|
||||
{
|
||||
isEqualHigh = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isEqualHigh)
|
||||
{
|
||||
m_pools[poolCount].level = currHigh;
|
||||
m_pools[poolCount].time = rates[i].time;
|
||||
m_pools[poolCount].isBuySide = true;
|
||||
m_pools[poolCount].isSwept = (rates[0].high > currHigh + _Point * 5);
|
||||
m_pools[poolCount].touchCount = 2;
|
||||
poolCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Find equal lows (sell-side liquidity)
|
||||
for(int i = 5; i < copied - 5 && poolCount < 10; i++)
|
||||
{
|
||||
double currLow = rates[i].low;
|
||||
bool isEqualLow = false;
|
||||
|
||||
for(int j = i + 2; j < i + 10 && j < copied; j++)
|
||||
{
|
||||
if(MathAbs(rates[j].low - currLow) < _Point * 10)
|
||||
{
|
||||
isEqualLow = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isEqualLow)
|
||||
{
|
||||
m_pools[poolCount].level = currLow;
|
||||
m_pools[poolCount].time = rates[i].time;
|
||||
m_pools[poolCount].isBuySide = false;
|
||||
m_pools[poolCount].isSwept = (rates[0].low < currLow - _Point * 5);
|
||||
m_pools[poolCount].touchCount = 2;
|
||||
poolCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CalculateStrength(MqlRates &rates[], int idx)
|
||||
{
|
||||
int strength = 1;
|
||||
|
||||
// Volume check
|
||||
double avgVol = 0;
|
||||
for(int i = idx; i < idx + 5 && i < ArraySize(rates); i++)
|
||||
avgVol += (double)rates[i].tick_volume;
|
||||
avgVol /= 5.0;
|
||||
|
||||
if(rates[idx].tick_volume > avgVol * 1.5) strength++;
|
||||
if(rates[idx].tick_volume > avgVol * 2.0) strength++;
|
||||
|
||||
return MathMin(strength, 3);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __LIQUIDITY_ENGINE_MQH__
|
||||
+185
-40
@@ -1,5 +1,7 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Logic/MicroTrigger.mqh |
|
||||
//| Enhanced LTF Entry Logic with Fibonacci, Liquidity, Price Action |
|
||||
//| Higher probability entries using multiple confluences |
|
||||
//+------------------------------------------------------------------+
|
||||
#ifndef __MICRO_TRIGGER_MQH__
|
||||
#define __MICRO_TRIGGER_MQH__
|
||||
@@ -8,6 +10,8 @@
|
||||
#include "../Core/State.mqh"
|
||||
#include "../Data/PriceEngine.mqh"
|
||||
#include "../Data/Volatility.mqh"
|
||||
#include "../Data/FibonacciEngine.mqh"
|
||||
#include "../Data/LiquidityEngine.mqh"
|
||||
#include "../Core/Logger.mqh"
|
||||
|
||||
extern CLogger g_logger;
|
||||
@@ -18,59 +22,176 @@ class CMicroTrigger
|
||||
private:
|
||||
ENUM_TIMEFRAMES m_ltf;
|
||||
CPriceEngine *m_price;
|
||||
CFibonacciEngine m_fib;
|
||||
CLiquidityEngine m_liquidity;
|
||||
|
||||
public:
|
||||
bool Init(ENUM_TIMEFRAMES ltf, CPriceEngine &price)
|
||||
{
|
||||
m_ltf = ltf; m_price = GetPointer(price);
|
||||
Print("[MicroTrigger] LTF entry logic initialized on ", EnumToString(ltf));
|
||||
m_ltf = ltf;
|
||||
m_price = GetPointer(price);
|
||||
|
||||
if(!m_fib.Init(ltf))
|
||||
{
|
||||
Print("[MicroTrigger] FibonacciEngine init failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!m_liquidity.Init(ltf))
|
||||
{
|
||||
Print("[MicroTrigger] LiquidityEngine init failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
Print("[MicroTrigger] LTF entry logic initialized on ", EnumToString(ltf), " (with Fib + Liquidity)");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Release() {}
|
||||
|
||||
void GenerateSignal(SignalData &signal, const EAState &state, CPriceEngine &price)
|
||||
{
|
||||
signal.isValid = false; signal.isBuy = false; signal.pattern = PATTERN_NONE;
|
||||
signal.rejectionReason = ""; signal.signalTime = TimeCurrent(); signal.atrValue = 0;
|
||||
signal.isValid = false;
|
||||
signal.isBuy = false;
|
||||
signal.pattern = PATTERN_NONE;
|
||||
signal.rejectionReason = "";
|
||||
signal.signalTime = TimeCurrent();
|
||||
signal.atrValue = 0;
|
||||
|
||||
// Update fibonacci and liquidity levels
|
||||
m_fib.Calculate();
|
||||
m_liquidity.Update();
|
||||
|
||||
// Check HTF bias validity
|
||||
if(state.currentBias == BIAS_NEUTRAL && state.currentRegime != REGIME_RANGE)
|
||||
{ signal.rejectionReason = "HTF Bias Neutral + Not Range Mode"; return; }
|
||||
{
|
||||
signal.rejectionReason = "HTF Bias Neutral + Not Range Mode";
|
||||
return;
|
||||
}
|
||||
|
||||
MqlRates bars[4];
|
||||
if(!price.GetClosedBar(m_ltf, 1, bars[1]) || !price.GetClosedBar(m_ltf, 2, bars[2]))
|
||||
{ signal.rejectionReason = "Failed to load LTF closed bars"; return; }
|
||||
{
|
||||
signal.rejectionReason = "Failed to load LTF closed bars";
|
||||
return;
|
||||
}
|
||||
|
||||
// === CONFLUENCE SCORING SYSTEM ===
|
||||
// Each confluence adds to score. Need minimum score for valid signal.
|
||||
int confluenceScore = 0;
|
||||
bool isBuy = false;
|
||||
ENUM_PATTERN detectedPattern = PATTERN_NONE;
|
||||
string patternName = "";
|
||||
|
||||
// 1. Check Price Action Patterns (0-3 points)
|
||||
if(CheckPinBar(bars[1], state))
|
||||
{
|
||||
signal.pattern = PATTERN_PIN_BAR; signal.patternName = "Pin Bar";
|
||||
signal.isBuy = (bars[1].close > bars[1].open);
|
||||
if(ValidateDirection(signal, state)) { CalculateLevels(signal, bars[1], state); return; }
|
||||
detectedPattern = PATTERN_PIN_BAR;
|
||||
patternName = "Pin Bar";
|
||||
isBuy = (bars[1].close > bars[1].open);
|
||||
confluenceScore += 2;
|
||||
}
|
||||
if(!price.GetClosedBar(m_ltf, 2, bars[2])) { signal.rejectionReason = "Failed to load bar[2]"; return; }
|
||||
if(CheckEngulfing(bars[1], bars[2]))
|
||||
else if(CheckEngulfing(bars[1], bars[2]))
|
||||
{
|
||||
signal.pattern = PATTERN_ENGULFING; signal.patternName = "Engulfing";
|
||||
signal.isBuy = (bars[1].close > bars[1].open);
|
||||
if(ValidateDirection(signal, state)) { CalculateLevels(signal, bars[1], state); return; }
|
||||
detectedPattern = PATTERN_ENGULFING;
|
||||
patternName = "Engulfing";
|
||||
isBuy = (bars[1].close > bars[1].open);
|
||||
confluenceScore += 2;
|
||||
}
|
||||
if(price.GetClosedBar(m_ltf, 3, bars[3]))
|
||||
else if(price.GetClosedBar(m_ltf, 3, bars[3]) && CheckInsideBarBreakout(bars[1], bars[2], bars[3]))
|
||||
{
|
||||
if(CheckInsideBarBreakout(bars[1], bars[2], bars[3]))
|
||||
detectedPattern = PATTERN_INSIDE_BAR;
|
||||
patternName = "Inside Bar Breakout";
|
||||
isBuy = (bars[1].close > bars[2].high);
|
||||
confluenceScore += 1;
|
||||
}
|
||||
|
||||
if(confluenceScore == 0)
|
||||
{
|
||||
signal.rejectionReason = "No valid price action pattern";
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Check Fibonacci Level (0-2 points)
|
||||
int fibLevel = -1;
|
||||
if(m_fib.IsNearFibLevel(bars[1].close, 0.5, fibLevel))
|
||||
{
|
||||
confluenceScore += 2;
|
||||
patternName += " + Fib" + m_fib.GetLevelName(fibLevel);
|
||||
}
|
||||
else if(m_fib.IsNearFibLevel(bars[1].close, 1.0, fibLevel))
|
||||
{
|
||||
confluenceScore += 1;
|
||||
patternName += " + Fib" + m_fib.GetLevelName(fibLevel);
|
||||
}
|
||||
|
||||
// 3. Check Order Block (0-2 points)
|
||||
OrderBlock ob;
|
||||
if(m_liquidity.IsAtOrderBlock(bars[1].close, isBuy, ob))
|
||||
{
|
||||
confluenceScore += ob.strength;
|
||||
patternName += " + OB";
|
||||
}
|
||||
|
||||
// 4. Check Liquidity Sweep (0-3 points) - STRONG signal
|
||||
bool sweptBuySide;
|
||||
if(m_liquidity.WasLiquiditySwept(3, sweptBuySide))
|
||||
{
|
||||
// If liquidity was swept and we're trading in opposite direction
|
||||
if((isBuy && !sweptBuySide) || (!isBuy && sweptBuySide))
|
||||
{
|
||||
signal.pattern = PATTERN_INSIDE_BAR; signal.patternName = "Inside Bar Breakout";
|
||||
signal.isBuy = (bars[1].close > bars[2].high);
|
||||
if(ValidateDirection(signal, state)) { CalculateLevels(signal, bars[1], state); return; }
|
||||
confluenceScore += 3;
|
||||
patternName += " + Liquidity Sweep";
|
||||
}
|
||||
}
|
||||
signal.rejectionReason = "No valid price action pattern";
|
||||
|
||||
// 5. Check FVG (Fair Value Gap) (0-1 points)
|
||||
bool isBullishFVG;
|
||||
double fvgTop, fvgBottom;
|
||||
if(m_liquidity.HasFVG(10, isBullishFVG, fvgTop, fvgBottom))
|
||||
{
|
||||
if((isBuy && isBullishFVG) || (!isBuy && !isBullishFVG))
|
||||
{
|
||||
confluenceScore += 1;
|
||||
patternName += " + FVG";
|
||||
}
|
||||
}
|
||||
|
||||
// === VALIDATION ===
|
||||
// Minimum confluence score required
|
||||
int minScore = (state.currentRegime == REGIME_TREND) ? 4 : 3;
|
||||
|
||||
if(confluenceScore < minScore)
|
||||
{
|
||||
signal.rejectionReason = StringFormat("Confluence score %d < minimum %d", confluenceScore, minScore);
|
||||
return;
|
||||
}
|
||||
|
||||
// Direction validation
|
||||
if(!ValidateDirection(isBuy, state))
|
||||
{
|
||||
signal.rejectionReason = isBuy ? "Bullish signal rejected (HTF Bias: BEAR)" : "Bearish signal rejected (HTF Bias: BULL)";
|
||||
return;
|
||||
}
|
||||
|
||||
// Build signal
|
||||
signal.isValid = true;
|
||||
signal.isBuy = isBuy;
|
||||
signal.pattern = detectedPattern;
|
||||
signal.patternName = patternName + StringFormat(" [Score:%d]", confluenceScore);
|
||||
|
||||
CalculateLevels(signal, bars[1], state);
|
||||
}
|
||||
|
||||
private:
|
||||
bool ValidateDirection(SignalData &signal, const EAState &state)
|
||||
bool ValidateDirection(bool isBuy, const EAState &state)
|
||||
{
|
||||
if(state.currentRegime == REGIME_RANGE) return true;
|
||||
if(state.currentBias == BIAS_BULL && !signal.isBuy)
|
||||
{ signal.isValid = false; signal.rejectionReason = "Bearish signal rejected (HTF Bias: BULL)"; return false; }
|
||||
if(state.currentBias == BIAS_BEAR && signal.isBuy)
|
||||
{ signal.isValid = false; signal.rejectionReason = "Bullish signal rejected (HTF Bias: BEAR)"; return false; }
|
||||
signal.isValid = true; return true;
|
||||
if(state.currentBias == BIAS_BULL && !isBuy) return false;
|
||||
if(state.currentBias == BIAS_BEAR && isBuy) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckPinBar(const MqlRates &bar, const EAState &state)
|
||||
{
|
||||
double body = MathAbs(bar.close - bar.open);
|
||||
@@ -78,6 +199,7 @@ private:
|
||||
double lowerWick = MathMin(bar.open, bar.close) - bar.low;
|
||||
double range = bar.high - bar.low;
|
||||
if(range == 0 || body == 0) return false;
|
||||
|
||||
bool bullish = (bar.close > bar.open);
|
||||
if(bullish)
|
||||
{
|
||||
@@ -94,6 +216,7 @@ private:
|
||||
return wickOK && closePos && atLevel;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckEngulfing(const MqlRates &curr, const MqlRates &prev)
|
||||
{
|
||||
bool bullish = (curr.close > prev.open && curr.open < prev.close);
|
||||
@@ -101,6 +224,7 @@ private:
|
||||
if(!bullish && !bearish) return false;
|
||||
return (curr.tick_volume >= prev.tick_volume * ENGULF_VOLUME_MULT);
|
||||
}
|
||||
|
||||
bool CheckInsideBarBreakout(const MqlRates &breakout, const MqlRates &inside, const MqlRates &mother)
|
||||
{
|
||||
bool isInside = (inside.high < mother.high && inside.low > mother.low);
|
||||
@@ -109,41 +233,61 @@ private:
|
||||
bool bearBreak = (breakout.close < inside.low);
|
||||
return (bullBreak || bearBreak);
|
||||
}
|
||||
|
||||
bool IsAtKeyLevel(const MqlRates &bar, const EAState &state, bool isBullish)
|
||||
{
|
||||
double proximity = state.assetProfile.atrMultiplierSL * g_volatility.GetATR() * 0.5;
|
||||
if(MathAbs(bar.close - state.vwapState.vwapValue) <= proximity) return true;
|
||||
if(isBullish && MathAbs(bar.low - state.swingLow) <= proximity) return true;
|
||||
if(!isBullish && MathAbs(bar.high - state.swingHigh) <= proximity) return true;
|
||||
int maHandle = iMA(_Symbol, m_ltf, 50, 0, MODE_EMA, PRICE_CLOSE);
|
||||
if(maHandle != INVALID_HANDLE)
|
||||
{
|
||||
double maBuf[]; ArraySetAsSeries(maBuf, true);
|
||||
if(CopyBuffer(maHandle, 0, 1, 1, maBuf) > 0)
|
||||
{
|
||||
double ema50 = maBuf[0];
|
||||
IndicatorRelease(maHandle);
|
||||
if(MathAbs(bar.close - ema50) <= proximity) return true;
|
||||
}
|
||||
IndicatorRelease(maHandle);
|
||||
}
|
||||
|
||||
// Check fibonacci levels
|
||||
int fibIdx;
|
||||
if(m_fib.IsNearFibLevel(bar.close, 0.3, fibIdx)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CalculateLevels(SignalData &signal, const MqlRates &bar, const EAState &state)
|
||||
{
|
||||
double atr = g_volatility.GetATR();
|
||||
if(atr <= 0) atr = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE) * 10;
|
||||
signal.atrValue = atr;
|
||||
|
||||
if(signal.isBuy) signal.entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
|
||||
else signal.entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
|
||||
|
||||
double slMult, tp1Mult, tp2Mult;
|
||||
if(state.currentRegime == REGIME_TREND)
|
||||
{ slMult = InpTrendATRMult; tp1Mult = InpTrendATRMult * 2.0; tp2Mult = InpTrendATRMult * 4.0; }
|
||||
{
|
||||
slMult = InpTrendATRMult;
|
||||
tp1Mult = InpTrendATRMult * 2.0;
|
||||
tp2Mult = InpTrendATRMult * 4.0;
|
||||
}
|
||||
else
|
||||
{ slMult = InpRangeATRMult; tp1Mult = InpRangeATRMult * 1.5; tp2Mult = InpRangeATRMult * 2.5; }
|
||||
{
|
||||
slMult = InpRangeATRMult;
|
||||
tp1Mult = InpRangeATRMult * 1.5;
|
||||
tp2Mult = InpRangeATRMult * 2.5;
|
||||
}
|
||||
|
||||
double slDist = atr * slMult;
|
||||
double tp1Dist = atr * tp1Mult;
|
||||
double tp2Dist = atr * tp2Mult;
|
||||
|
||||
// Adjust TP based on fibonacci extensions if available
|
||||
if(m_fib.IsValid())
|
||||
{
|
||||
double fibExtension = m_fib.GetExtension(1.618);
|
||||
if(fibExtension > 0)
|
||||
{
|
||||
if(signal.isBuy && fibExtension > signal.entryPrice + tp1Dist)
|
||||
tp2Dist = fibExtension - signal.entryPrice;
|
||||
else if(!signal.isBuy && fibExtension < signal.entryPrice - tp1Dist)
|
||||
tp2Dist = signal.entryPrice - fibExtension;
|
||||
}
|
||||
}
|
||||
|
||||
if(signal.isBuy)
|
||||
{
|
||||
signal.slPrice = signal.entryPrice - slDist;
|
||||
@@ -156,6 +300,7 @@ private:
|
||||
signal.tp1Price = signal.entryPrice - tp1Dist;
|
||||
signal.tp2Price = signal.entryPrice - tp2Dist;
|
||||
}
|
||||
|
||||
signal.isValid = true;
|
||||
}
|
||||
};
|
||||
|
||||
+29
-9
@@ -1,11 +1,16 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Risk/PositionSizer.mqh |
|
||||
//| ATR-based Position Sizing with Dynamic Risk Multiplier |
|
||||
//| Reduces size after losses, increases after wins |
|
||||
//+------------------------------------------------------------------+
|
||||
#ifndef __POSITION_SIZER_MQH__
|
||||
#define __POSITION_SIZER_MQH__
|
||||
|
||||
#include "../Core/Config.mqh"
|
||||
#include "../Core/State.mqh"
|
||||
#include "../Risk/Protection.mqh"
|
||||
|
||||
extern CProtection g_protection;
|
||||
|
||||
class CPositionSizer
|
||||
{
|
||||
@@ -16,21 +21,32 @@ private:
|
||||
public:
|
||||
bool Init(const AssetProfile &profile, double maxRisk)
|
||||
{
|
||||
m_profile = profile; m_maxRiskPercent = maxRisk;
|
||||
Print("[PositionSizer] Max risk per trade: ", maxRisk, "%");
|
||||
m_profile = profile;
|
||||
m_maxRiskPercent = maxRisk;
|
||||
Print("[PositionSizer] Max risk per trade: ", maxRisk, "% (with dynamic multiplier)");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Calculate(TradeParams ¶ms, const SignalData &signal, const EAState &state)
|
||||
{
|
||||
params.isValid = false; params.rejectReason = "";
|
||||
params.isValid = false;
|
||||
params.rejectReason = "";
|
||||
|
||||
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||
if(equity <= 0) { params.rejectReason = "Invalid account equity"; return; }
|
||||
double riskAmount = equity * (m_maxRiskPercent / 100.0);
|
||||
|
||||
// Apply dynamic risk multiplier based on recent performance
|
||||
double riskMultiplier = g_protection.GetRiskMultiplier();
|
||||
double adjustedRiskPercent = m_maxRiskPercent * riskMultiplier;
|
||||
|
||||
double riskAmount = equity * (adjustedRiskPercent / 100.0);
|
||||
double slDistance = MathAbs(signal.entryPrice - signal.slPrice);
|
||||
if(slDistance <= 0) { params.rejectReason = "Invalid SL distance"; return; }
|
||||
|
||||
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
|
||||
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
|
||||
if(tickValue <= 0 || tickSize <= 0) { params.rejectReason = "Invalid tick value/size"; return; }
|
||||
|
||||
double slTicks = slDistance / tickSize;
|
||||
double lotSize = riskAmount / (slTicks * tickValue);
|
||||
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
||||
@@ -56,13 +72,17 @@ public:
|
||||
double finalSlTicks = slDistance / tickSize;
|
||||
double finalRisk = lotSize * finalSlTicks * tickValue;
|
||||
double finalRiskPercent = (finalRisk / equity) * 100.0;
|
||||
if(finalRiskPercent > m_maxRiskPercent * 1.1)
|
||||
{ params.rejectReason = "Risk exceeds max"; return; }
|
||||
params.lotSize = lotSize; params.riskAmount = finalRisk;
|
||||
params.riskPercent = finalRiskPercent; params.slDistance = slDistance;
|
||||
if(finalRiskPercent > adjustedRiskPercent * 1.1)
|
||||
{ params.rejectReason = "Risk exceeds adjusted max"; return; }
|
||||
|
||||
params.lotSize = lotSize;
|
||||
params.riskAmount = finalRisk;
|
||||
params.riskPercent = finalRiskPercent;
|
||||
params.slDistance = slDistance;
|
||||
params.tp1Distance = MathAbs(signal.tp1Price - signal.entryPrice);
|
||||
params.tp2Distance = MathAbs(signal.tp2Price - signal.entryPrice);
|
||||
params.marginRequired = marginRequired; params.isValid = true;
|
||||
params.marginRequired = marginRequired;
|
||||
params.isValid = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+24
-7
@@ -1,7 +1,7 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Risk/Protection.mqh |
|
||||
//| Circuit Breakers: Daily/Weekly Loss, Consecutive Loss, Spread |
|
||||
//| MODIFIED: Completed UpdateState with live statistics tracking |
|
||||
//| Enhanced Circuit Breakers with Dynamic Risk Adjustment |
|
||||
//| Reduces position size after consecutive losses |
|
||||
//+------------------------------------------------------------------+
|
||||
#ifndef __PROTECTION_MQH__
|
||||
#define __PROTECTION_MQH__
|
||||
@@ -25,6 +25,7 @@ private:
|
||||
double m_lastEquity;
|
||||
int m_consecLossCounter;
|
||||
datetime m_lastTradeTime;
|
||||
double m_currentRiskMultiplier; // Dynamic risk reduction
|
||||
|
||||
public:
|
||||
bool Init(double dailyLoss, double weeklyLoss, int consecLoss, int maxPos, double maxRisk)
|
||||
@@ -39,6 +40,7 @@ public:
|
||||
m_lastEquity = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||
m_consecLossCounter = 0;
|
||||
m_lastTradeTime = 0;
|
||||
m_currentRiskMultiplier = 1.0;
|
||||
Print("[Protection] Circuit breakers active. Daily:", dailyLoss, "% Weekly:", weeklyLoss, "% Consec:", consecLoss);
|
||||
return true;
|
||||
}
|
||||
@@ -96,6 +98,12 @@ public:
|
||||
return (spreadPrice <= profile.maxSpreadPoints);
|
||||
}
|
||||
|
||||
// Get dynamic risk multiplier based on recent performance
|
||||
double GetRiskMultiplier() const
|
||||
{
|
||||
return m_currentRiskMultiplier;
|
||||
}
|
||||
|
||||
void UpdateState(EAState &state)
|
||||
{
|
||||
double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||
@@ -111,7 +119,14 @@ public:
|
||||
m_consecLossCounter++;
|
||||
state.consecutiveLosses = m_consecLossCounter;
|
||||
m_lastTradeTime = TimeCurrent();
|
||||
g_logger.LogEvent("PROTECTION", StringFormat("Loss detected. Consecutive: %d/%d", m_consecLossCounter, m_maxConsecLosses));
|
||||
|
||||
// Dynamic risk reduction after consecutive losses
|
||||
if(m_consecLossCounter == 1) m_currentRiskMultiplier = 0.75;
|
||||
else if(m_consecLossCounter == 2) m_currentRiskMultiplier = 0.50;
|
||||
else if(m_consecLossCounter >= 3) m_currentRiskMultiplier = 0.25;
|
||||
|
||||
g_logger.LogEvent("PROTECTION", StringFormat("Loss detected. Consecutive: %d/%d. Risk multiplier: %.2f",
|
||||
m_consecLossCounter, m_maxConsecLosses, m_currentRiskMultiplier));
|
||||
}
|
||||
}
|
||||
else if(equityChange > 0)
|
||||
@@ -120,15 +135,16 @@ public:
|
||||
{
|
||||
m_consecLossCounter = 0;
|
||||
state.consecutiveLosses = 0;
|
||||
g_logger.LogEvent("PROTECTION", "Profit detected. Consecutive loss counter reset.");
|
||||
m_currentRiskMultiplier = 1.0; // Reset to full risk
|
||||
g_logger.LogEvent("PROTECTION", "Profit detected. Risk multiplier reset to 1.0");
|
||||
}
|
||||
}
|
||||
}
|
||||
m_lastEquity = currentEquity;
|
||||
if(InpDebugMode)
|
||||
{
|
||||
g_logger.LogEvent("PROTECTION", StringFormat("State | Daily: %.2f | Weekly: %.2f | Consec: %d | Equity: %.2f",
|
||||
state.dailyPnL, state.weeklyPnL, state.consecutiveLosses, currentEquity));
|
||||
g_logger.LogEvent("PROTECTION", StringFormat("State | Daily: %.2f | Weekly: %.2f | Consec: %d | RiskMult: %.2f | Equity: %.2f",
|
||||
state.dailyPnL, state.weeklyPnL, state.consecutiveLosses, m_currentRiskMultiplier, currentEquity));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,10 +159,11 @@ public:
|
||||
state.totalTradesToday = 0;
|
||||
state.consecutiveLosses = 0;
|
||||
m_consecLossCounter = 0;
|
||||
m_currentRiskMultiplier = 1.0;
|
||||
m_lastDailyReset = todayStart;
|
||||
state.equityAtStart = AccountInfoDouble(ACCOUNT_EQUITY);
|
||||
m_lastEquity = state.equityAtStart;
|
||||
g_logger.LogEvent("PROTECTION", "Daily counters reset");
|
||||
g_logger.LogEvent("PROTECTION", "Daily counters reset. Risk multiplier reset to 1.0");
|
||||
}
|
||||
if(dt.day_of_week == 1 && todayStart > m_lastWeeklyReset)
|
||||
{
|
||||
|
||||
Binary file not shown.
+35
-14
@@ -1,20 +1,18 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| Universal_MTF_EA.mq5 |
|
||||
//| Universal Multi-Timeframe Expert Advisor v2.0 |
|
||||
//| Universal Multi-Timeframe Expert Advisor v2.1 |
|
||||
//| Enhanced: Fibonacci + Liquidity + Dynamic Risk + Confluence |
|
||||
//+------------------------------------------------------------------+
|
||||
#property strict
|
||||
#property copyright "Institutional Quantitative Systems"
|
||||
#property version "2.000"
|
||||
#property description "Universal MTF EA v2.0"
|
||||
#property version "2.100"
|
||||
#property description "Universal MTF EA v2.1 - Fibonacci + Liquidity + Smart Risk"
|
||||
|
||||
//--- Input for magic number
|
||||
//--- Input for magic number (ONLY in .mq5, not in any .mqh)
|
||||
input group "=== EA IDENTIFICATION ==="
|
||||
input ulong InpMagicNumber = 20250625;
|
||||
input string InpEALabel = "Universal_MTF";
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| MODULE INCLUDES |
|
||||
//+------------------------------------------------------------------+
|
||||
input group "=== RISK MANAGEMENT ==="
|
||||
input double InpMaxRiskPerTrade = 0.5;
|
||||
input double InpMaxDailyLoss = 2.0;
|
||||
@@ -63,6 +61,9 @@ input string InpLogPath = "Universal_MTF_EA/";
|
||||
input bool InpDebugMode = false;
|
||||
input int InpDashboardUpdateSec = 5;
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| MODULE INCLUDES |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "Core/Config.mqh"
|
||||
#include "Core/State.mqh"
|
||||
#include "Core/Logger.mqh"
|
||||
@@ -71,6 +72,8 @@ input int InpDashboardUpdateSec = 5;
|
||||
#include "Data/PriceEngine.mqh"
|
||||
#include "Data/VWAP_Engine.mqh"
|
||||
#include "Data/Volatility.mqh"
|
||||
#include "Data/FibonacciEngine.mqh"
|
||||
#include "Data/LiquidityEngine.mqh"
|
||||
#include "Execution/OrderManager.mqh"
|
||||
#include "Execution/TradeManager.mqh"
|
||||
#include "Logic/MacroAudit.mqh"
|
||||
@@ -91,6 +94,8 @@ CTelegramNotifier g_notifier;
|
||||
CPriceEngine g_priceEngine;
|
||||
CVWAPEngine g_vwapEngine;
|
||||
CVolatility g_volatility;
|
||||
CFibonacciEngine g_fibonacci;
|
||||
CLiquidityEngine g_liquidity;
|
||||
CMacroAudit g_macroAudit;
|
||||
CContextFilter g_contextFilter;
|
||||
CMicroTrigger g_microTrigger;
|
||||
@@ -108,7 +113,7 @@ CTradeManager g_tradeManager;
|
||||
int OnInit()
|
||||
{
|
||||
Print("============================================================");
|
||||
Print("[Universal_MTF_EA] Initializing v2.000...");
|
||||
Print("[Universal_MTF_EA] Initializing v2.100...");
|
||||
Print("============================================================");
|
||||
|
||||
if(!g_logger.Init(InpLogPath, InpEALabel, InpMagicNumber))
|
||||
@@ -116,7 +121,7 @@ int OnInit()
|
||||
Print("[CRITICAL] Logger init failed. EA halted.");
|
||||
return INIT_FAILED;
|
||||
}
|
||||
g_logger.LogEvent("SYSTEM", "EA Initialization started v2.0");
|
||||
g_logger.LogEvent("SYSTEM", "EA Initialization started v2.1 (Fib + Liquidity + Smart Risk)");
|
||||
|
||||
if(!g_session.Init())
|
||||
{
|
||||
@@ -149,6 +154,18 @@ int OnInit()
|
||||
return INIT_FAILED;
|
||||
}
|
||||
|
||||
if(!g_fibonacci.Init(InpMTF))
|
||||
{
|
||||
g_logger.LogError("OnInit", 0, "FibonacciEngine init failed", 0);
|
||||
return INIT_FAILED;
|
||||
}
|
||||
|
||||
if(!g_liquidity.Init(InpLTF))
|
||||
{
|
||||
g_logger.LogError("OnInit", 0, "LiquidityEngine init failed", 0);
|
||||
return INIT_FAILED;
|
||||
}
|
||||
|
||||
if(!g_macroAudit.Init(InpHTF, g_vwapEngine))
|
||||
{
|
||||
g_logger.LogError("OnInit", 0, "MacroAudit init failed", 0);
|
||||
@@ -231,17 +248,19 @@ int OnInit()
|
||||
g_priceEngine.RefreshAll();
|
||||
g_vwapEngine.Calculate(g_state.vwapState);
|
||||
g_volatility.Update();
|
||||
g_fibonacci.Calculate();
|
||||
g_liquidity.Update();
|
||||
g_macroAudit.Analyze(g_state);
|
||||
g_contextFilter.Analyze(g_state);
|
||||
|
||||
g_logger.LogEvent("SYSTEM", "EA Initialization completed successfully v2.0");
|
||||
g_logger.LogEvent("SYSTEM", "EA Initialization completed successfully v2.1");
|
||||
g_logger.LogEvent("SYSTEM", StringFormat("Symbol: %s | Class: %s | HTF: %s | MTF: %s | LTF: %s",
|
||||
_Symbol, g_state.assetProfile.description, EnumToString(InpHTF),
|
||||
EnumToString(InpMTF), EnumToString(InpLTF)));
|
||||
|
||||
if(InpAlertOnTrade)
|
||||
{
|
||||
g_notifier.SendMessage("*Universal MTF EA v2.0 Started*\n\nSymbol: " + _Symbol +
|
||||
g_notifier.SendMessage("*Universal MTF EA v2.1 Started*\n\nSymbol: " + _Symbol +
|
||||
"\nAsset: " + g_state.assetProfile.description +
|
||||
"\nTime: " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS));
|
||||
}
|
||||
@@ -269,7 +288,7 @@ void OnDeinit(const int reason)
|
||||
|
||||
if(InpAlertOnTrade)
|
||||
{
|
||||
g_notifier.SendMessage("*Universal MTF EA v2.0 Stopped*\n\nSymbol: " + _Symbol +
|
||||
g_notifier.SendMessage("*Universal MTF EA v2.1 Stopped*\n\nSymbol: " + _Symbol +
|
||||
"\nReason: " + IntegerToString(reason) +
|
||||
"\nDaily PnL: " + StringFormat("%.2f", g_state.dailyPnL) +
|
||||
"\nTime: " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS));
|
||||
@@ -353,6 +372,8 @@ void OnTimer()
|
||||
g_state.isBarClosedMTF = true;
|
||||
g_state.lastMTFBarTime = iTime(_Symbol, InpMTF, 0);
|
||||
g_volatility.Update();
|
||||
g_fibonacci.Calculate();
|
||||
g_liquidity.Update();
|
||||
g_contextFilter.Analyze(g_state);
|
||||
g_regimeEngine.UpdateState(g_state);
|
||||
}
|
||||
@@ -420,8 +441,8 @@ void ProcessSignal(const SignalData &signal)
|
||||
{
|
||||
g_state.openPositions++;
|
||||
g_logger.LogTradeOpen(signal, tradeParams, ticket);
|
||||
g_logger.LogEvent("EXECUTE", StringFormat("Order Ticket=%llu | %s | Lots: %.2f",
|
||||
ticket, signal.isBuy ? "BUY" : "SELL", tradeParams.lotSize));
|
||||
g_logger.LogEvent("EXECUTE", StringFormat("Order Ticket=%llu | %s | Lots: %.2f | RiskMult: %.2f",
|
||||
ticket, signal.isBuy ? "BUY" : "SELL", tradeParams.lotSize, g_protection.GetRiskMultiplier()));
|
||||
if(InpAlertOnTrade) g_notifier.SendTradeOpen(signal, tradeParams, ticket);
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user