Vizion-Trading-EA/Shared Projects/VizionAI-Trading/VizionAI-Trading-Repo/VizionAI-EA/ChartStructure.mqh
2026-02-19 23:19:25 -06:00

198 lines
4.8 KiB
MQL5

#ifndef CHART_STRUCTURE_MQH
#define CHART_STRUCTURE_MQH
enum ENUM_SWING_TYPE
{
SWING_HIGH,
SWING_LOW
};
enum ENUM_MARKET_STRUCTURE
{
STRUCTURE_UPTREND,
STRUCTURE_DOWNTREND,
STRUCTURE_RANGING,
STRUCTURE_BREAKING
};
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;
};
SwingPoint g_SwingPoints[];
int g_SwingCount = 0;
const int MAX_SWINGS = 50;
ENUM_MARKET_STRUCTURE g_CurrentStructure = STRUCTURE_RANGING;
bool InitializeChartStructure()
{
ArrayResize(g_SwingPoints, MAX_SWINGS);
g_SwingCount = 0;
return true;
}
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 t = g_SwingPoints[j];
g_SwingPoints[j] = g_SwingPoints[j + 1];
g_SwingPoints[j + 1] = t;
}
}
}
}
void IdentifySwingPoints(const MqlRates &rates[])
{
g_SwingCount = 0;
const int swing_bars = 5;
for(int i = swing_bars; i < ArraySize(rates) - swing_bars && g_SwingCount < MAX_SWINGS; ++i)
{
bool is_high = true;
bool is_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_high = false;
if(rates[i].low >= rates[i - j].low || rates[i].low >= rates[i + j].low) is_low = false;
}
if(is_high)
{
SwingPoint s;
s.type = SWING_HIGH;
s.price = rates[i].high;
s.time = rates[i].time;
s.bar_index = i;
s.is_higher_high = false;
s.is_lower_low = false;
s.is_higher_low = false;
s.is_lower_high = false;
g_SwingPoints[g_SwingCount++] = s;
}
if(is_low && g_SwingCount < MAX_SWINGS)
{
SwingPoint s2;
s2.type = SWING_LOW;
s2.price = rates[i].low;
s2.time = rates[i].time;
s2.bar_index = i;
s2.is_higher_high = false;
s2.is_lower_low = false;
s2.is_higher_low = false;
s2.is_lower_high = false;
g_SwingPoints[g_SwingCount++] = s2;
}
}
SortSwingsByTime();
}
void ClassifySwingRelationships()
{
if(g_SwingCount < 2) return;
for(int i = 0; i < g_SwingCount; ++i)
{
for(int j = i + 1; j < g_SwingCount; ++j)
{
if(g_SwingPoints[i].type != g_SwingPoints[j].type)
continue;
if(g_SwingPoints[i].type == SWING_HIGH)
{
if(g_SwingPoints[i].price > g_SwingPoints[j].price) g_SwingPoints[i].is_higher_high = true;
else g_SwingPoints[i].is_lower_high = true;
}
else
{
if(g_SwingPoints[i].price > g_SwingPoints[j].price) g_SwingPoints[i].is_higher_low = true;
else g_SwingPoints[i].is_lower_low = true;
}
break;
}
}
}
void DetermineMarketStructure()
{
int hh = 0, hl = 0, lh = 0, ll = 0;
int lookback = MathMin(10, g_SwingCount);
for(int i = 0; i < lookback; ++i)
{
if(g_SwingPoints[i].is_higher_high) hh++;
if(g_SwingPoints[i].is_higher_low) hl++;
if(g_SwingPoints[i].is_lower_high) lh++;
if(g_SwingPoints[i].is_lower_low) ll++;
}
if(hh >= 2 && hl >= 1) g_CurrentStructure = STRUCTURE_UPTREND;
else if(lh >= 2 && ll >= 1) g_CurrentStructure = STRUCTURE_DOWNTREND;
else g_CurrentStructure = STRUCTURE_RANGING;
}
void DetectMarketStructure()
{
MqlRates rates[];
ArraySetAsSeries(rates, true);
int copied = CopyRates(_Symbol, _Period, 0, 220, rates);
if(copied < 60) return;
IdentifySwingPoints(rates);
ClassifySwingRelationships();
DetermineMarketStructure();
}
string GetStructureString()
{
if(g_CurrentStructure == STRUCTURE_UPTREND) return "UPTREND";
if(g_CurrentStructure == STRUCTURE_DOWNTREND) return "DOWNTREND";
if(g_CurrentStructure == STRUCTURE_BREAKING) return "BREAKING";
return "RANGING";
}
int GetStructureStrength()
{
int hh = 0, hl = 0, lh = 0, ll = 0;
int lookback = MathMin(8, g_SwingCount);
for(int i = 0; i < lookback; ++i)
{
if(g_SwingPoints[i].is_higher_high) hh++;
if(g_SwingPoints[i].is_higher_low) hl++;
if(g_SwingPoints[i].is_lower_high) lh++;
if(g_SwingPoints[i].is_lower_low) ll++;
}
if(g_CurrentStructure == STRUCTURE_UPTREND) return MathMin(100, hh * 20 + hl * 15);
if(g_CurrentStructure == STRUCTURE_DOWNTREND) return MathMin(100, lh * 20 + ll * 15);
return 35;
}
void CleanupStructureObjects()
{
for(int i = ObjectsTotal(0) - 1; i >= 0; --i)
{
string name = ObjectName(0, i);
if(StringFind(name, "STRUCTURE_") == 0)
ObjectDelete(0, name);
}
}
#endif