RSI-Stoch-MA-EA/Chartstructure.mqh

492 lines
13 KiB
MQL5
Raw Permalink Normal View History

2026-01-21 08:14:25 +00:00
//+------------------------------------------------------------------+
//| ChartStructure.mqh |
//| Market Structure Analysis: HH, HL, LH, LL |
//| STANDALONE VERSION - No external dependencies |
//+------------------------------------------------------------------+
#property copyright "QuarterTheory x VIZION"
#property version "1.00"
#property strict
//================ STRUCTURE ENUMS ==================//
enum ENUM_SWING_TYPE
{
SWING_HIGH,
SWING_LOW
};
enum ENUM_MARKET_STRUCTURE
{
STRUCTURE_UPTREND,
STRUCTURE_DOWNTREND,
STRUCTURE_RANGING,
STRUCTURE_BREAKING
};
//================ STRUCTURE CLASSES ==================//
struct SwingPoint
{
ENUM_SWING_TYPE type;
double price;
datetime time;
int bar_index;
bool is_higher_high;
bool is_lower_low;
bool is_higher_low;
bool is_lower_high;
bool is_structure_break;
};
//================ GLOBAL VARIABLES ==================//
SwingPoint g_SwingPoints[];
int g_SwingCount = 0;
const int MAX_SWINGS = 50;
ENUM_MARKET_STRUCTURE g_CurrentStructure = STRUCTURE_RANGING;
double g_LastHighHigh = 0;
double g_LastHighLow = 0;
double g_LastLowHigh = 0;
double g_LastLowLow = 0;
int g_ConsecutiveHH = 0;
int g_ConsecutiveHL = 0;
int g_ConsecutiveLH = 0;
int g_ConsecutiveLL = 0;
bool g_BullishStructureBreak = false;
bool g_BearishStructureBreak = false;
//+------------------------------------------------------------------+
//| Initialize Chart Structure System |
//+------------------------------------------------------------------+
bool InitializeChartStructure()
{
ArrayResize(g_SwingPoints, MAX_SWINGS);
g_SwingCount = 0;
Print("✅ Chart Structure Analysis Initialized");
return true;
}
//+------------------------------------------------------------------+
//| Main Structure Detection |
//+------------------------------------------------------------------+
void DetectMarketStructure()
{
MqlRates rates[];
ArraySetAsSeries(rates, true);
int copied = CopyRates(_Symbol, _Period, 0, 200, rates);
if(copied < 50) return;
IdentifySwingPoints(rates);
ClassifySwingRelationships();
DetermineMarketStructure();
DetectStructureBreaks(rates);
UpdateStructureCounters();
}
//+------------------------------------------------------------------+
//| Identify Swing Highs and Lows |
//+------------------------------------------------------------------+
void IdentifySwingPoints(const MqlRates &rates[])
{
g_SwingCount = 0;
const int swing_bars = 5;
for(int i = swing_bars; i < ArraySize(rates) - swing_bars; i++)
{
bool is_swing_high = true;
bool is_swing_low = true;
for(int j = 1; j <= swing_bars; j++)
{
if(rates[i].high <= rates[i-j].high || rates[i].high <= rates[i+j].high)
{
is_swing_high = false;
break;
}
}
for(int j = 1; j <= swing_bars; j++)
{
if(rates[i].low >= rates[i-j].low || rates[i].low >= rates[i+j].low)
{
is_swing_low = false;
break;
}
}
if(is_swing_high && g_SwingCount < MAX_SWINGS)
{
SwingPoint swing;
swing.type = SWING_HIGH;
swing.price = rates[i].high;
swing.time = rates[i].time;
swing.bar_index = i;
swing.is_higher_high = false;
swing.is_lower_high = false;
swing.is_structure_break = false;
g_SwingPoints[g_SwingCount] = swing;
g_SwingCount++;
}
if(is_swing_low && g_SwingCount < MAX_SWINGS)
{
SwingPoint swing;
swing.type = SWING_LOW;
swing.price = rates[i].low;
swing.time = rates[i].time;
swing.bar_index = i;
swing.is_higher_low = false;
swing.is_lower_low = false;
swing.is_structure_break = false;
g_SwingPoints[g_SwingCount] = swing;
g_SwingCount++;
}
}
SortSwingsByTime();
}
//+------------------------------------------------------------------+
//| Sort Swings by Time |
//+------------------------------------------------------------------+
void SortSwingsByTime()
{
for(int i = 0; i < g_SwingCount - 1; i++)
{
for(int j = 0; j < g_SwingCount - i - 1; j++)
{
if(g_SwingPoints[j].time < g_SwingPoints[j+1].time)
{
SwingPoint temp = g_SwingPoints[j];
g_SwingPoints[j] = g_SwingPoints[j+1];
g_SwingPoints[j+1] = temp;
}
}
}
}
//+------------------------------------------------------------------+
//| Classify Swing Relationships |
//+------------------------------------------------------------------+
void ClassifySwingRelationships()
{
if(g_SwingCount < 2) return;
for(int i = 0; i < g_SwingCount; i++)
{
SwingPoint curr = g_SwingPoints[i];
for(int j = i + 1; j < g_SwingCount; j++)
{
SwingPoint previous = g_SwingPoints[j];
if(curr.type == previous.type)
{
if(curr.type == SWING_HIGH)
{
if(curr.price > previous.price)
{
g_SwingPoints[i].is_higher_high = true;
g_LastHighHigh = curr.price;
}
else
{
g_SwingPoints[i].is_lower_high = true;
g_LastLowHigh = curr.price;
}
}
else
{
if(curr.price > previous.price)
{
g_SwingPoints[i].is_higher_low = true;
g_LastHighLow = curr.price;
}
else
{
g_SwingPoints[i].is_lower_low = true;
g_LastLowLow = curr.price;
}
}
break;
}
}
}
}
//+------------------------------------------------------------------+
//| Determine Overall Market Structure |
//+------------------------------------------------------------------+
void DetermineMarketStructure()
{
int hh_count = 0, hl_count = 0;
int lh_count = 0, ll_count = 0;
int lookback = MathMin(10, g_SwingCount);
for(int i = 0; i < lookback; i++)
{
if(g_SwingPoints[i].is_higher_high) hh_count++;
if(g_SwingPoints[i].is_higher_low) hl_count++;
if(g_SwingPoints[i].is_lower_high) lh_count++;
if(g_SwingPoints[i].is_lower_low) ll_count++;
}
ENUM_MARKET_STRUCTURE prev_structure = g_CurrentStructure;
if(hh_count >= 2 && hl_count >= 1)
{
g_CurrentStructure = STRUCTURE_UPTREND;
}
else if(lh_count >= 2 && ll_count >= 1)
{
g_CurrentStructure = STRUCTURE_DOWNTREND;
}
else
{
g_CurrentStructure = STRUCTURE_RANGING;
}
if(prev_structure != g_CurrentStructure && prev_structure != STRUCTURE_RANGING)
{
if(prev_structure == STRUCTURE_UPTREND && g_CurrentStructure == STRUCTURE_DOWNTREND)
{
g_BearishStructureBreak = true;
Print("📉 BEARISH STRUCTURE BREAK");
}
else if(prev_structure == STRUCTURE_DOWNTREND && g_CurrentStructure == STRUCTURE_UPTREND)
{
g_BullishStructureBreak = true;
Print("📈 BULLISH STRUCTURE BREAK");
}
}
}
//+------------------------------------------------------------------+
//| Detect Structure Breaks |
//+------------------------------------------------------------------+
void DetectStructureBreaks(const MqlRates &rates[])
{
if(g_SwingCount < 4) return;
double current_price = rates[0].close;
if(g_CurrentStructure == STRUCTURE_UPTREND)
{
for(int i = 0; i < g_SwingCount; i++)
{
if(g_SwingPoints[i].type == SWING_HIGH)
{
if(current_price > g_SwingPoints[i].price)
{
Print("⚡ BOS - Bullish structure continues");
break;
}
}
}
}
if(g_CurrentStructure == STRUCTURE_DOWNTREND)
{
for(int i = 0; i < g_SwingCount; i++)
{
if(g_SwingPoints[i].type == SWING_LOW)
{
if(current_price < g_SwingPoints[i].price)
{
Print("⚡ BOS - Bearish structure continues");
break;
}
}
}
}
}
//+------------------------------------------------------------------+
//| Update Structure Counters |
//+------------------------------------------------------------------+
void UpdateStructureCounters()
{
g_ConsecutiveHH = 0;
g_ConsecutiveHL = 0;
g_ConsecutiveLH = 0;
g_ConsecutiveLL = 0;
int lookback = MathMin(6, g_SwingCount);
for(int i = 0; i < lookback; i++)
{
if(g_SwingPoints[i].is_higher_high) g_ConsecutiveHH++;
if(g_SwingPoints[i].is_higher_low) g_ConsecutiveHL++;
if(g_SwingPoints[i].is_lower_high) g_ConsecutiveLH++;
if(g_SwingPoints[i].is_lower_low) g_ConsecutiveLL++;
}
}
//+------------------------------------------------------------------+
//| Get Structure Information Functions |
//+------------------------------------------------------------------+
ENUM_MARKET_STRUCTURE GetCurrentStructure()
{
return g_CurrentStructure;
}
string GetStructureString()
{
switch(g_CurrentStructure)
{
case STRUCTURE_UPTREND: return "UPTREND (HH+HL)";
case STRUCTURE_DOWNTREND: return "DOWNTREND (LH+LL)";
case STRUCTURE_RANGING: return "RANGING";
case STRUCTURE_BREAKING: return "BREAKING";
default: return "UNKNOWN";
}
}
bool IsUptrend()
{
return g_CurrentStructure == STRUCTURE_UPTREND;
}
bool IsDowntrend()
{
return g_CurrentStructure == STRUCTURE_DOWNTREND;
}
bool IsRanging()
{
return g_CurrentStructure == STRUCTURE_RANGING;
}
int GetConsecutiveHH()
{
return g_ConsecutiveHH;
}
int GetConsecutiveHL()
{
return g_ConsecutiveHL;
}
int GetConsecutiveLH()
{
return g_ConsecutiveLH;
}
int GetConsecutiveLL()
{
return g_ConsecutiveLL;
}
bool IsBullishStructureBreak()
{
bool result = g_BullishStructureBreak;
g_BullishStructureBreak = false;
return result;
}
bool IsBearishStructureBreak()
{
bool result = g_BearishStructureBreak;
g_BearishStructureBreak = false;
return result;
}
double GetNearestSwingHigh()
{
for(int i = 0; i < g_SwingCount; i++)
{
if(g_SwingPoints[i].type == SWING_HIGH)
return g_SwingPoints[i].price;
}
return 0;
}
double GetNearestSwingLow()
{
for(int i = 0; i < g_SwingCount; i++)
{
if(g_SwingPoints[i].type == SWING_LOW)
return g_SwingPoints[i].price;
}
return 0;
}
int GetStructureStrength()
{
int strength = 0;
if(g_CurrentStructure == STRUCTURE_UPTREND)
{
strength = (g_ConsecutiveHH * 20) + (g_ConsecutiveHL * 15);
}
else if(g_CurrentStructure == STRUCTURE_DOWNTREND)
{
strength = (g_ConsecutiveLH * 20) + (g_ConsecutiveLL * 15);
}
return MathMin(strength, 100);
}
//+------------------------------------------------------------------+
//| Draw Structure on Chart |
//+------------------------------------------------------------------+
void DrawStructureOnChart()
{
ObjectsDeleteAll(0, "STRUCTURE_");
for(int i = 0; i < MathMin(20, g_SwingCount); i++)
{
string name = "STRUCTURE_SWING_" + IntegerToString(i);
if(g_SwingPoints[i].type == SWING_HIGH)
{
if(g_SwingPoints[i].is_higher_high)
{
ObjectCreate(0, name, OBJ_ARROW_DOWN, 0, g_SwingPoints[i].time,
g_SwingPoints[i].price);
ObjectSetInteger(0, name, OBJPROP_COLOR, clrLime);
ObjectSetString(0, name, OBJPROP_TEXT, "HH");
}
else if(g_SwingPoints[i].is_lower_high)
{
ObjectCreate(0, name, OBJ_ARROW_DOWN, 0, g_SwingPoints[i].time,
g_SwingPoints[i].price);
ObjectSetInteger(0, name, OBJPROP_COLOR, clrOrange);
ObjectSetString(0, name, OBJPROP_TEXT, "LH");
}
}
else
{
if(g_SwingPoints[i].is_higher_low)
{
ObjectCreate(0, name, OBJ_ARROW_UP, 0, g_SwingPoints[i].time,
g_SwingPoints[i].price);
ObjectSetInteger(0, name, OBJPROP_COLOR, clrLime);
ObjectSetString(0, name, OBJPROP_TEXT, "HL");
}
else if(g_SwingPoints[i].is_lower_low)
{
ObjectCreate(0, name, OBJ_ARROW_UP, 0, g_SwingPoints[i].time,
g_SwingPoints[i].price);
ObjectSetInteger(0, name, OBJPROP_COLOR, clrRed);
ObjectSetString(0, name, OBJPROP_TEXT, "LL");
}
}
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 8);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_CENTER);
}
}
void CleanupStructureObjects()
{
ObjectsDeleteAll(0, "STRUCTURE_");
}