0% found this document useful (0 votes)
27 views18 pages

Volatility Too High

Uploaded by

kanchanbd
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views18 pages

Volatility Too High

Uploaded by

kanchanbd
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 18

//+------------------------------------------------------------------+

//| ICT_Advanced_EA.mq5 |
//| Copyright 2024, ICT Trader |
//| Advanced ICT Concepts |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, ICT Trader"
#property link ""
#property version "1.30"
#property description "Advanced ICT Trading EA with Risk Management & DST-Aware
Sessions"

#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
#include <Indicators\Oscilators.mqh>

CTrade trade;
CPositionInfo position;
COrderInfo order;
CiATR atr_indicator;

//--- Input Parameters


input group "=== GENERAL SETTINGS ==="
input double LotSize = 0.01; // Base Lot Size
input int MagicNumber = 123456; // Magic Number
input double RiskPercent = 2.0; // Risk Percentage per Trade
input int MaxSpread = 30; // Maximum Spread (points)
input double TargetEquity = 0.0; // Target Equity (0=disabled)

input group "=== ICT TIMING SESSIONS ==="


input bool EnableLondonSession = true; // Enable London Session (3-4 AM
NY)
input bool EnableNYAMSession = true; // Enable NY AM Session (10-11 AM)
input bool EnableNYPMSession = true; // Enable NY PM Session (2-3 PM)
input int AsiaSessionStart = 18; // Asia session start (NY hour)
input int AsiaSessionEnd = 2; // Asia session end (NY hour)

input group "=== LIQUIDITY SETTINGS ==="


input int LiquidityLookback = 20; // Liquidity Lookback Periods
input double MinLiquidityDistance = 100; // Min Distance to Liquidity
(points)
input bool EnableMajorLiquidity = true; // Enable Major Liquidity
(Daily/Weekly)
input bool EnableMediumLiquidity = true; // Enable Medium Liquidity (4H/1H)

input group "=== FAIR VALUE GAP SETTINGS ==="


input double MinFVGSize = 50; // Minimum FVG Size (points)
input int MaxFVGAge = 10; // Maximum FVG Age (bars)
input bool EnableFVGMitigation = true; // Enable FVG Mitigation Entries

input group "=== MARKET STRUCTURE SETTINGS ==="


input int StructureLookback = 50; // Structure Lookback Periods
input double MinDisplacement = 200; // Minimum Displacement (points)
input bool EnableCHoCH = true; // Enable Change of Character
input int SwingStrength = 2; // Swing strength (1-5 bars)

input group "=== RISK MANAGEMENT ==="


input double MaxRiskRewardRatio = 3.0; // Maximum Risk:Reward Ratio
input double MinRiskRewardRatio = 1.5; // Minimum Risk:Reward Ratio
input bool UseTrailingStop = true; // Use Trailing Stop
input double TrailingDistance = 100; // Trailing Distance (points)
input double DailyLossLimit = 5.0; // Max Daily Loss (% of balance)
input double MaxATR = 150.0; // Max ATR (points) for trading
input int ATRPeriod = 14; // ATR Period for volatility filter

input group "=== SILVER BULLET SETTINGS ==="


input bool EnableSilverBullet = true; // Enable Silver Bullet Strategy
input double SilverBulletMinMove = 150; // Minimum Move for Silver Bullet
(points)

//--- Global Variables


datetime LastBarTime = 0;
double DailyHigh = 0, DailyLow = 0;
double WeeklyHigh = 0, WeeklyLow = 0;
double AsiaHigh = 0, AsiaLow = 0;
bool MarketStructureBullish = true;
double LastSwingHigh = 0, LastSwingLow = 0;
double DailyProfit = 0.0;
datetime LastTradeDay = 0;
int NYOffset = 5; // Default EST offset

enum ENTRY_TYPE {
ENTRY_NONE,
ENTRY_FVG_MITIGATION,
ENTRY_LIQUIDITY_REVERSAL,
ENTRY_SILVER_BULLET,
ENTRY_TRAP_REVERSAL
};

ENTRY_TYPE CurrentEntry = ENTRY_NONE;

struct LiquidityLevel {
double price;
datetime time;
bool isBuyLiquidity;
bool isSwept;
int strength; // 1=Minor, 2=Medium, 3=Major
};

struct FairValueGap {
double upperLevel;
double lowerLevel;
datetime time;
bool isBearish;
bool isMitigated;
int barsAge;
};

LiquidityLevel LiquidityLevels[];
FairValueGap FVGLevels[];

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
trade.SetExpertMagicNumber(MagicNumber);
trade.SetDeviationInPoints(10);
trade.SetTypeFilling(ORDER_FILLING_FOK);
ArrayResize(LiquidityLevels, 0);
ArrayResize(FVGLevels, 0);

// Calculate initial NY time offset


CalculateNYOffset();

// Initialize daily tracking


MqlDateTime today;
TimeToStruct(TimeCurrent(), today);
LastTradeDay = StructToTime(today);

// Initialize ATR indicator


if (!atr_indicator.Create(_Symbol, _Period, ATRPeriod)) {
Print("Failed to initialize ATR indicator");
return INIT_FAILED;
}

Print("ICT Advanced EA initialized successfully. NY Offset: ", NYOffset, "


hours");
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
CleanChartObjects();
Print("ICT Advanced EA deinitialized");
}

//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
// Check if new bar
if (LastBarTime != iTime(_Symbol, PERIOD_CURRENT, 0)) {
LastBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
OnNewBar();
}

// Update daily profit tracking


UpdateDailyProfit();

// Check if target equity reached


if (TargetEquity > 0 && AccountInfoDouble(ACCOUNT_EQUITY) >= TargetEquity) {
CloseAllPositions();
Print("Target equity reached. Trading halted.");
return;
}

// Check spread
double spread = (double)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
if (spread > MaxSpread) return;

// Check volatility
if (atr_indicator.Refresh() == 0) {
double atr_value = atr_indicator.Main(0);
if (atr_value > MaxATR * _Point) {
Print("Volatility too high. Skipping trading.");
return;
}
}

// Update liquidity levels


UpdateLiquidityLevels();

// Update Fair Value Gaps


UpdateFairValueGaps();

// Reset entry type


CurrentEntry = ENTRY_NONE;

// Check for trading opportunities


CheckTradingOpportunities();

// Manage existing positions


ManagePositions();

// Draw levels on chart


DrawLevels();
}

//+------------------------------------------------------------------+
//| Calculate NY time offset (DST-aware) |
//+------------------------------------------------------------------+
void CalculateNYOffset() {
MqlDateTime gmtTime;
TimeGMT(gmtTime);

// Simple DST approximation: April to October = DST (UTC-4)


if (gmtTime.mon >= 4 && gmtTime.mon <= 10) {
NYOffset = 4;
} else {
NYOffset = 5;
}
}

//+------------------------------------------------------------------+
//| Get current NY hour |
//+------------------------------------------------------------------+
int GetNYHour() {
MqlDateTime gmtTime;
TimeGMT(gmtTime);

int nyHour = gmtTime.hour - NYOffset;


if (nyHour < 0) nyHour += 24;

return nyHour;
}

//+------------------------------------------------------------------+
//| New bar processing |
//+------------------------------------------------------------------+
void OnNewBar() {
CalculateNYOffset(); // Update DST offset daily
UpdateSessionLevels();
UpdateMarketStructure();
CleanupOldLevels();
}

//+------------------------------------------------------------------+
//| Update daily profit tracking |
//+------------------------------------------------------------------+
void UpdateDailyProfit() {
MqlDateTime currentTime;
TimeToStruct(TimeCurrent(), currentTime);
datetime today = StructToTime(currentTime);

if (today != LastTradeDay) {
DailyProfit = 0.0;
LastTradeDay = today;
}

// Update from closed positions


HistorySelect(LastTradeDay, TimeCurrent());
int totalDeals = HistoryDealsTotal();
double dailyProfit = 0.0;

for (int i = 0; i < totalDeals; i++) {


ulong ticket = HistoryDealGetTicket(i);
if (HistoryDealGetInteger(ticket, DEAL_MAGIC) == MagicNumber) {
dailyProfit += HistoryDealGetDouble(ticket, DEAL_PROFIT);
}
}

// Update from open positions


for (int i = PositionsTotal() - 1; i >= 0; i--) {
if (PositionGetTicket(i) && PositionGetInteger(POSITION_MAGIC) ==
MagicNumber) {
dailyProfit += PositionGetDouble(POSITION_PROFIT);
}
}

DailyProfit = dailyProfit;
}

//+------------------------------------------------------------------+
//| Update session levels (Daily, Weekly, Asia) |
//+------------------------------------------------------------------+
void UpdateSessionLevels() {
int nyHour = GetNYHour();
MqlDateTime currentTime;
TimeCurrent(currentTime);

// Update daily levels at midnight NY time


if (nyHour == 0 && currentTime.min == 0) {
DailyHigh = iHigh(_Symbol, PERIOD_D1, 1);
DailyLow = iLow(_Symbol, PERIOD_D1, 1);

// Add to liquidity levels


AddLiquidityLevel(DailyHigh, TimeCurrent(), true, 3); // Major liquidity
AddLiquidityLevel(DailyLow, TimeCurrent(), false, 3);
}

// Update weekly levels on Monday


if (currentTime.day_of_week == 1 && nyHour == 0) {
WeeklyHigh = iHigh(_Symbol, PERIOD_W1, 1);
WeeklyLow = iLow(_Symbol, PERIOD_W1, 1);

AddLiquidityLevel(WeeklyHigh, TimeCurrent(), true, 3);


AddLiquidityLevel(WeeklyLow, TimeCurrent(), false, 3);
}

// Update Asia session levels


if (nyHour == AsiaSessionEnd && currentTime.min == 0) {
int hours = (AsiaSessionStart > AsiaSessionEnd) ?
(24 - AsiaSessionStart + AsiaSessionEnd) :
(AsiaSessionEnd - AsiaSessionStart);

int bars = hours * 60 / (int)PeriodSeconds(PERIOD_CURRENT);


bars = MathMin(bars, 100); // Safety limit

AsiaHigh = iHigh(_Symbol, PERIOD_CURRENT, iHighest(_Symbol, PERIOD_CURRENT,


MODE_HIGH, bars, 1));
AsiaLow = iLow(_Symbol, PERIOD_CURRENT, iLowest(_Symbol, PERIOD_CURRENT,
MODE_LOW, bars, 1));

AddLiquidityLevel(AsiaHigh, TimeCurrent(), true, 2); // Medium liquidity


AddLiquidityLevel(AsiaLow, TimeCurrent(), false, 2);
}
}

//+------------------------------------------------------------------+
//| Update market structure |
//+------------------------------------------------------------------+
void UpdateMarketStructure() {
double currentHigh = iHigh(_Symbol, PERIOD_CURRENT, 1);
double currentLow = iLow(_Symbol, PERIOD_CURRENT, 1);

// Find swing highs and lows


if (IsSwingHigh(1)) {
if (LastSwingHigh > 0) {
if (currentHigh > LastSwingHigh) {
// Higher high - bullish structure
MarketStructureBullish = true;
} else if (EnableCHoCH) {
// Lower high - potential bearish structure
MarketStructureBullish = false;
}
}
LastSwingHigh = currentHigh;
AddLiquidityLevel(currentHigh, iTime(_Symbol, PERIOD_CURRENT, 1), true, 1);
// Minor liquidity
}

if (IsSwingLow(1)) {
if (LastSwingLow > 0) {
if (currentLow < LastSwingLow) {
// Lower low - bearish structure
MarketStructureBullish = false;
} else if (EnableCHoCH) {
// Higher low - potential bullish structure
MarketStructureBullish = true;
}
}
LastSwingLow = currentLow;
AddLiquidityLevel(currentLow, iTime(_Symbol, PERIOD_CURRENT, 1), false, 1);
}
}

//+------------------------------------------------------------------+
//| Check if bar is swing high |
//+------------------------------------------------------------------+
bool IsSwingHigh(int bar) {
if (bar < SwingStrength || bar >= Bars(_Symbol, PERIOD_CURRENT) -
SwingStrength)
return false;

double high = iHigh(_Symbol, PERIOD_CURRENT, bar);

for (int i = 1; i <= SwingStrength; i++) {


if (high <= iHigh(_Symbol, PERIOD_CURRENT, bar + i)) return false;
if (high <= iHigh(_Symbol, PERIOD_CURRENT, bar - i)) return false;
}

return true;
}

//+------------------------------------------------------------------+
//| Check if bar is swing low |
//+------------------------------------------------------------------+
bool IsSwingLow(int bar) {
if (bar < SwingStrength || bar >= Bars(_Symbol, PERIOD_CURRENT) -
SwingStrength)
return false;

double low = iLow(_Symbol, PERIOD_CURRENT, bar);

for (int i = 1; i <= SwingStrength; i++) {


if (low >= iLow(_Symbol, PERIOD_CURRENT, bar + i)) return false;
if (low >= iLow(_Symbol, PERIOD_CURRENT, bar - i)) return false;
}

return true;
}

//+------------------------------------------------------------------+
//| Add liquidity level |
//+------------------------------------------------------------------+
void AddLiquidityLevel(double price, datetime time, bool isBuy, int strength) {
// Filter duplicates
for (int i = 0; i < ArraySize(LiquidityLevels); i++) {
if (MathAbs(LiquidityLevels[i].price - price) < 10 * _Point) {
return;
}
}

int size = ArraySize(LiquidityLevels);


ArrayResize(LiquidityLevels, size + 1);

LiquidityLevels[size].price = price;
LiquidityLevels[size].time = time;
LiquidityLevels[size].isBuyLiquidity = isBuy;
LiquidityLevels[size].isSwept = false;
LiquidityLevels[size].strength = strength;
}

//+------------------------------------------------------------------+
//| Update liquidity levels |
//+------------------------------------------------------------------+
void UpdateLiquidityLevels() {
double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

for (int i = ArraySize(LiquidityLevels) - 1; i >= 0; i--) {


if (LiquidityLevels[i].isSwept) continue;

// Check if liquidity is swept


if (LiquidityLevels[i].isBuyLiquidity) {
if (currentAsk >= LiquidityLevels[i].price) {
LiquidityLevels[i].isSwept = true;
OnLiquiditySweep(i, true);
}
} else {
if (currentBid <= LiquidityLevels[i].price) {
LiquidityLevels[i].isSwept = true;
OnLiquiditySweep(i, false);
}
}
}
}

//+------------------------------------------------------------------+
//| Handle liquidity sweep |
//+------------------------------------------------------------------+
void OnLiquiditySweep(int liquidityIndex, bool isBuySide) {
Print("Liquidity swept at ", LiquidityLevels[liquidityIndex].price,
" - ", isBuySide ? "Buy Side" : "Sell Side",
" - Strength: ", LiquidityLevels[liquidityIndex].strength);

// Look for reversal setup after liquidity sweep


CheckReversalSetup(liquidityIndex, isBuySide);
}

//+------------------------------------------------------------------+
//| Update Fair Value Gaps |
//+------------------------------------------------------------------+
void UpdateFairValueGaps() {
// Check for new FVGs in last 3 bars
for (int i = 1; i <= 3; i++) {
CheckForFVG(i);
}

// Update existing FVGs


for (int i = ArraySize(FVGLevels) - 1; i >= 0; i--) {
FVGLevels[i].barsAge++;

// Check if FVG is mitigated


if (!FVGLevels[i].isMitigated) {
double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);

if (FVGLevels[i].isBearish) {
if (currentPrice >= FVGLevels[i].lowerLevel) {
FVGLevels[i].isMitigated = true;
OnFVGMitigation(i);
}
} else {
if (currentPrice <= FVGLevels[i].upperLevel) {
FVGLevels[i].isMitigated = true;
OnFVGMitigation(i);
}
}
}
}
}

//+------------------------------------------------------------------+
//| Check for Fair Value Gap formation |
//+------------------------------------------------------------------+
void CheckForFVG(int bar) {
if (bar < 1 || bar >= Bars(_Symbol, PERIOD_CURRENT) - 2) return;

double high1 = iHigh(_Symbol, PERIOD_CURRENT, bar + 1);


double low1 = iLow(_Symbol, PERIOD_CURRENT, bar + 1);
double high2 = iHigh(_Symbol, PERIOD_CURRENT, bar);
double low2 = iLow(_Symbol, PERIOD_CURRENT, bar);
double high3 = iHigh(_Symbol, PERIOD_CURRENT, bar - 1);
double low3 = iLow(_Symbol, PERIOD_CURRENT, bar - 1);

// Bullish FVG: low of bar 3 > high of bar 1


if (low3 > high1) {
double gapSize = (low3 - high1) / _Point;
if (gapSize >= MinFVGSize) {
AddFVG(low3, high1, iTime(_Symbol, PERIOD_CURRENT, bar), false);
}
}

// Bearish FVG: high of bar 3 < low of bar 1


if (high3 < low1) {
double gapSize = (low1 - high3) / _Point;
if (gapSize >= MinFVGSize) {
AddFVG(low1, high3, iTime(_Symbol, PERIOD_CURRENT, bar), true);
}
}
}

//+------------------------------------------------------------------+
//| Add Fair Value Gap |
//+------------------------------------------------------------------+
void AddFVG(double upper, double lower, datetime time, bool bearish) {
// Filter duplicates
for (int i = 0; i < ArraySize(FVGLevels); i++) {
if (MathAbs(FVGLevels[i].upperLevel - upper) < 5 * _Point &&
MathAbs(FVGLevels[i].lowerLevel - lower) < 5 * _Point) {
return;
}
}

int size = ArraySize(FVGLevels);


ArrayResize(FVGLevels, size + 1);

FVGLevels[size].upperLevel = upper;
FVGLevels[size].lowerLevel = lower;
FVGLevels[size].time = time;
FVGLevels[size].isBearish = bearish;
FVGLevels[size].isMitigated = false;
FVGLevels[size].barsAge = 0;
}

//+------------------------------------------------------------------+
//| Handle FVG mitigation |
//+------------------------------------------------------------------+
void OnFVGMitigation(int fvgIndex) {
Print("FVG mitigated - ", FVGLevels[fvgIndex].isBearish ? "Bearish" :
"Bullish",
" at ", FVGLevels[fvgIndex].upperLevel, " - ",
FVGLevels[fvgIndex].lowerLevel);

if (EnableFVGMitigation && IsICTSession()) {


CheckFVGEntry(fvgIndex);
}
}

//+------------------------------------------------------------------+
//| Check for ICT session timing |
//+------------------------------------------------------------------+
bool IsICTSession() {
int nyHour = GetNYHour();

// London Session: 3-4 AM NY time


if (EnableLondonSession && nyHour == 3) return true;

// NY AM Session: 10-11 AM NY time


if (EnableNYAMSession && nyHour == 10) return true;

// NY PM Session: 2-3 PM NY time


if (EnableNYPMSession && nyHour == 14) return true;

return false;
}

//+------------------------------------------------------------------+
//| Check trading opportunities |
//+------------------------------------------------------------------+
void CheckTradingOpportunities() {
if (!IsICTSession()) return;

// Check risk limits


if (!RiskManagementCheck()) return;

// Silver Bullet Strategy


if (EnableSilverBullet && CurrentEntry == ENTRY_NONE) {
CurrentEntry = ENTRY_SILVER_BULLET;
CheckSilverBulletSetup();
}

// Liquidity Sweep Strategy


if (CurrentEntry == ENTRY_NONE) {
CurrentEntry = ENTRY_LIQUIDITY_REVERSAL;
CheckLiquiditySweepSetup();
}
}

//+------------------------------------------------------------------+
//| Check Silver Bullet setup |
//+------------------------------------------------------------------+
void CheckSilverBulletSetup() {
for (int i = 0; i < ArraySize(FVGLevels); i++) {
if (FVGLevels[i].isMitigated) continue;
if (FVGLevels[i].barsAge > MaxFVGAge) continue;

// Check alignment with market structure


bool validSetup = false;
if (MarketStructureBullish && !FVGLevels[i].isBearish) validSetup = true;
if (!MarketStructureBullish && FVGLevels[i].isBearish) validSetup = true;

if (validSetup) {
ExecuteSilverBulletTrade(i);
break;
}
}
}

//+------------------------------------------------------------------+
//| Execute Silver Bullet trade |
//+------------------------------------------------------------------+
void ExecuteSilverBulletTrade(int fvgIndex) {
if (HasOpenPosition()) return;

double entry, sl, tp;


ENUM_ORDER_TYPE orderType;
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

if (FVGLevels[fvgIndex].isBearish) {
entry = FVGLevels[fvgIndex].lowerLevel;
sl = FVGLevels[fvgIndex].upperLevel + 100 * point;
tp = entry - (sl - entry) * MinRiskRewardRatio;
orderType = ORDER_TYPE_SELL_LIMIT;
} else {
entry = FVGLevels[fvgIndex].upperLevel;
sl = FVGLevels[fvgIndex].lowerLevel - 100 * point;
tp = entry + (entry - sl) * MinRiskRewardRatio;
orderType = ORDER_TYPE_BUY_LIMIT;
}

double lotSize = CalculateLotSize(MathAbs(entry - sl));

if (trade.OrderOpen(_Symbol, orderType, lotSize, 0, entry, sl, tp,


ORDER_TIME_GTC, 0, "Silver Bullet")) {
Print("Silver Bullet order placed: ", EnumToString(orderType),
" at ", entry, " SL: ", sl, " TP: ", tp);
}
}

//+------------------------------------------------------------------+
//| Check liquidity sweep setup |
//+------------------------------------------------------------------+
void CheckLiquiditySweepSetup() {
for (int i = 0; i < ArraySize(LiquidityLevels); i++) {
if (!LiquidityLevels[i].isSwept) continue;
if (TimeCurrent() - LiquidityLevels[i].time > 3600) continue;

CheckReversalSetup(i, LiquidityLevels[i].isBuyLiquidity);
}
}

//+------------------------------------------------------------------+
//| Check reversal setup after liquidity sweep |
//+------------------------------------------------------------------+
void CheckReversalSetup(int liquidityIndex, bool wasBuySide) {
if (HasOpenPosition()) return;

double sweptPrice = LiquidityLevels[liquidityIndex].price;


double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

double displacement = MathAbs(currentPrice - sweptPrice) / point;


if (displacement < MinDisplacement) return;

int bestFVG = -1;


double bestDistance = DBL_MAX;

for (int i = 0; i < ArraySize(FVGLevels); i++) {


if (FVGLevels[i].isMitigated) continue;
if (FVGLevels[i].barsAge > MaxFVGAge) continue;

double fvgMid = (FVGLevels[i].upperLevel + FVGLevels[i].lowerLevel) / 2;


double distance = MathAbs(currentPrice - fvgMid);

if (distance < bestDistance) {


bestDistance = distance;
bestFVG = i;
}
}

if (bestFVG >= 0) {
ExecuteReversalTrade(bestFVG, !wasBuySide);
}
}

//+------------------------------------------------------------------+
//| Execute reversal trade |
//+------------------------------------------------------------------+
void ExecuteReversalTrade(int fvgIndex, bool isLong) {
double entry, sl, tp;
ENUM_ORDER_TYPE orderType;
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

if (isLong) {
entry = FVGLevels[fvgIndex].upperLevel;
sl = FVGLevels[fvgIndex].lowerLevel - 50 * point;
tp = entry + (entry - sl) * MinRiskRewardRatio;
orderType = ORDER_TYPE_BUY_LIMIT;
} else {
entry = FVGLevels[fvgIndex].lowerLevel;
sl = FVGLevels[fvgIndex].upperLevel + 50 * point;
tp = entry - (sl - entry) * MinRiskRewardRatio;
orderType = ORDER_TYPE_SELL_LIMIT;
}
double lotSize = CalculateLotSize(MathAbs(entry - sl));

if (trade.OrderOpen(_Symbol, orderType, lotSize, 0, entry, sl, tp,


ORDER_TIME_GTC, 0, "Liquidity Reversal")) {
Print("Reversal order placed: ", EnumToString(orderType),
" at ", entry, " SL: ", sl, " TP: ", tp);
}
}

//+------------------------------------------------------------------+
//| Check FVG entry |
//+------------------------------------------------------------------+
void CheckFVGEntry(int fvgIndex) {
if (HasOpenPosition()) return;
if (!IsICTSession()) return;

bool tradeDirection = !FVGLevels[fvgIndex].isBearish;


if (MarketStructureBullish != tradeDirection) return;

double entry = (FVGLevels[fvgIndex].upperLevel +


FVGLevels[fvgIndex].lowerLevel) / 2;
double sl, tp;
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

if (tradeDirection) {
sl = FVGLevels[fvgIndex].lowerLevel - 50 * point;
tp = entry + (entry - sl) * MinRiskRewardRatio;
} else {
sl = FVGLevels[fvgIndex].upperLevel + 50 * point;
tp = entry - (sl - entry) * MinRiskRewardRatio;
}

double lotSize = CalculateLotSize(MathAbs(entry - sl));

if (tradeDirection) {
trade.Buy(lotSize, _Symbol, 0, sl, tp, "FVG Mitigation");
} else {
trade.Sell(lotSize, _Symbol, 0, sl, tp, "FVG Mitigation");
}
}

//+------------------------------------------------------------------+
//| Calculate lot size based on risk |
//+------------------------------------------------------------------+
double CalculateLotSize(double slDistance) {
if (RiskPercent <= 0) return LotSize;

double balance = AccountInfoDouble(ACCOUNT_BALANCE);


double riskAmount = MathMin(
balance * RiskPercent / 100.0,
balance * 0.01 * DailyLossLimit // Cap risk by daily limit
);

double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);


double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

// Normalize for JPY pairs


if (tickValue == 0) return LotSize;
double pointValue = tickValue * (point / tickSize);

double lotSize = riskAmount / (slDistance * pointValue);

double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);


double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double stepLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

lotSize = MathMax(minLot, MathMin(maxLot, lotSize));


lotSize = MathFloor(lotSize / stepLot) * stepLot;

return lotSize;
}

//+------------------------------------------------------------------+
//| Manage existing positions |
//+------------------------------------------------------------------+
void ManagePositions() {
if (!HasOpenPosition()) return;

if (UseTrailingStop) {
ApplyTrailingStop();
}

// Check for break even move


double positionProfit = PositionGetDouble(POSITION_PROFIT);
double positionVolume = PositionGetDouble(POSITION_VOLUME);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

if (positionProfit > 0) {
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentPrice = PositionGetInteger(POSITION_TYPE) ==
POSITION_TYPE_BUY ?
SymbolInfoDouble(_Symbol, SYMBOL_BID) :
SymbolInfoDouble(_Symbol, SYMBOL_ASK);

double movePips = MathAbs(currentPrice - openPrice) / point;

// Move to break even after 50 pips profit


if (movePips >= 500) {
double currentSL = PositionGetDouble(POSITION_SL);
bool isLong = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY;

if ((isLong && currentSL < openPrice) || (!isLong && currentSL >


openPrice)) {
trade.PositionModify(_Symbol, openPrice,
PositionGetDouble(POSITION_TP));
Print("Position moved to break even");
}
}
}

// Check daily loss limit


if (DailyProfit < 0 && MathAbs(DailyProfit) >=
AccountInfoDouble(ACCOUNT_BALANCE) * DailyLossLimit / 100.0) {
CloseAllPositions();
Print("Daily loss limit reached. Closing all positions.");
}
}

//+------------------------------------------------------------------+
//| Apply trailing stop |
//+------------------------------------------------------------------+
void ApplyTrailingStop() {
double currentSL = PositionGetDouble(POSITION_SL);
bool isLong = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY;
double currentPrice = isLong ? SymbolInfoDouble(_Symbol, SYMBOL_BID) :
SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

double newSL = currentSL;

if (isLong) {
newSL = currentPrice - TrailingDistance * point;
if (newSL > currentSL && newSL > openPrice) {
trade.PositionModify(_Symbol, newSL, PositionGetDouble(POSITION_TP));
}
} else {
newSL = currentPrice + TrailingDistance * point;
if (newSL < currentSL && newSL < openPrice) {
trade.PositionModify(_Symbol, newSL, PositionGetDouble(POSITION_TP));
}
}
}

//+------------------------------------------------------------------+
//| Clean up old levels |
//+------------------------------------------------------------------+
void CleanupOldLevels() {
datetime currentTime = TimeCurrent();

// Clean up old liquidity levels (older than 7 days)


for (int i = ArraySize(LiquidityLevels) - 1; i >= 0; i--) {
if (currentTime - LiquidityLevels[i].time > 7 * 24 * 3600) {
ArrayRemove(LiquidityLevels, i, 1);
}
}

// Clean up old FVGs (older than MaxFVGAge bars or mitigated)


for (int i = ArraySize(FVGLevels) - 1; i >= 0; i--) {
if (FVGLevels[i].barsAge > MaxFVGAge || FVGLevels[i].isMitigated) {
ArrayRemove(FVGLevels, i, 1);
}
}
}

//+------------------------------------------------------------------+
//| Check for Change of Character (CHoCH) |
//+------------------------------------------------------------------+
bool CheckCHoCH() {
if (!EnableCHoCH) return false;

bool chochDetected = false;

if (MarketStructureBullish) {
if (LastSwingLow > 0) {
double currentLow = iLow(_Symbol, PERIOD_CURRENT, 0);
if (currentLow < LastSwingLow) {
chochDetected = true;
MarketStructureBullish = false;
}
}
} else {
if (LastSwingHigh > 0) {
double currentHigh = iHigh(_Symbol, PERIOD_CURRENT, 0);
if (currentHigh > LastSwingHigh) {
chochDetected = true;
MarketStructureBullish = true;
}
}
}

if (chochDetected) {
Print("Change of Character detected - New bias: ",
MarketStructureBullish ? "Bullish" : "Bearish");
}

return chochDetected;
}

//+------------------------------------------------------------------+
//| Draw levels on chart (for visualization) |
//+------------------------------------------------------------------+
void DrawLevels() {
// Draw liquidity levels
for (int i = 0; i < ArraySize(LiquidityLevels); i++) {
if (LiquidityLevels[i].isSwept) continue;

string objName = "Liquidity_" + IntegerToString(i);


color lineColor = LiquidityLevels[i].isBuyLiquidity ? clrBlue : clrRed;

ObjectCreate(0, objName, OBJ_HLINE, 0, 0, LiquidityLevels[i].price);


ObjectSetInteger(0, objName, OBJPROP_COLOR, lineColor);
ObjectSetInteger(0, objName, OBJPROP_STYLE, STYLE_DASH);
ObjectSetInteger(0, objName, OBJPROP_WIDTH, LiquidityLevels[i].strength);
}

// Draw Fair Value Gaps


for (int i = 0; i < ArraySize(FVGLevels); i++) {
if (FVGLevels[i].isMitigated) continue;

string objName = "FVG_" + IntegerToString(i);


color rectColor = FVGLevels[i].isBearish ? clrLightCoral : clrLightBlue;

ObjectCreate(0, objName, OBJ_RECTANGLE, 0,


FVGLevels[i].time, FVGLevels[i].upperLevel,
TimeCurrent() + 3600, FVGLevels[i].lowerLevel);
ObjectSetInteger(0, objName, OBJPROP_COLOR, rectColor);
ObjectSetInteger(0, objName, OBJPROP_FILL, true);
ObjectSetInteger(0, objName, OBJPROP_BACK, true);
}
}

//+------------------------------------------------------------------+
//| Clean chart objects |
//+------------------------------------------------------------------+
void CleanChartObjects() {
for (int i = ObjectsTotal(0) - 1; i >= 0; i--) {
string objName = ObjectName(0, i);
if (StringFind(objName, "Liquidity_") >= 0 || StringFind(objName, "FVG_")
>= 0) {
ObjectDelete(0, objName);
}
}
}

//+------------------------------------------------------------------+
//| Risk management check |
//+------------------------------------------------------------------+
bool RiskManagementCheck() {
// Check daily loss limit
if (DailyProfit < 0 && MathAbs(DailyProfit) >=
AccountInfoDouble(ACCOUNT_BALANCE) * DailyLossLimit / 100.0) {
Print("Daily loss limit reached. Trading suspended.");
return false;
}

// Check maximum open positions


if (PositionsTotal() >= 3) {
return false;
}

return true;
}

//+------------------------------------------------------------------+
//| Check for open position (magic number) |
//+------------------------------------------------------------------+
bool HasOpenPosition() {
for (int i = PositionsTotal() - 1; i >= 0; i--) {
if (PositionGetTicket(i) && PositionGetInteger(POSITION_MAGIC) ==
MagicNumber) {
return true;
}
}
return false;
}

//+------------------------------------------------------------------+
//| Close all positions |
//+------------------------------------------------------------------+
void CloseAllPositions() {
for (int i = PositionsTotal() - 1; i >= 0; i--) {
if (PositionGetTicket(i) && PositionGetInteger(POSITION_MAGIC) ==
MagicNumber) {
trade.PositionClose(PositionGetInteger(POSITION_TICKET));
}
}
}

//+------------------------------------------------------------------+
//| Calculate weekly displacement |
//+------------------------------------------------------------------+
double CalculateWeeklyDisplacement() {
double weeklyHigh = iHigh(_Symbol, PERIOD_W1, 0);
double weeklyLow = iLow(_Symbol, PERIOD_W1, 0);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

return (weeklyHigh - weeklyLow) / point;


}
//+------------------------------------------------------------------+

You might also like