EA_SMC_Mql5/Include/CChartDrawer.mqh

290 lines
22 KiB
MQL5
Raw Permalink Normal View History

2025-07-03 23:37:34 +07:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| CChartDrawer.mqh |
//| v5.0 - Dynamic Zone Drawing Logic |
//+------------------------------------------------------------------+
#ifndef CCHARTDRAWER_MQH
#define CCHARTDRAWER_MQH
#include <Arrays/ArrayString.mqh>
#include "CEnumSharing.mqh"
#include "SMC_DataStructures.mqh"
2025-07-03 23:38:38 +07:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CChartDrawer
{
2025-07-03 23:37:34 +07:00
private:
2025-07-03 23:38:38 +07:00
long m_chart_id;
string m_prefix;
2025-07-03 23:37:34 +07:00
public:
2025-07-03 23:38:38 +07:00
CChartDrawer(long chart_id, long magic_number)
{
m_chart_id = chart_id;
m_prefix = StringFormat("EASMC_%d_", magic_number);
}
~CChartDrawer() {}
// --- 1L
2025-07-03 23:37:34 +07:00
15ID!HDIC
IA%I' AH@GD'I@7H-#5 8@ 4 ---
2025-07-03 23:38:38 +07:00
void ClearAllDrawings()
{
ObjectsDeleteAll(m_chart_id, 0, -1, m_prefix);
}
void SynchronizeDrawings(CArrayObj* all_zones, CArrayObj* all_swings)
{
CArrayString* valid_object_names = new CArrayString();
if(all_zones != NULL)
{
for(int i=0; i<all_zones.Total(); i++)
{
CSignalZone* zone = all_zones.At(i);
if(zone != NULL)
{
valid_object_names.Add(zone.object_name);
valid_object_names.Add(zone.object_name + "_Text");
}
}
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
if(all_swings != NULL)
{
for(int i=0; i<all_swings.Total(); i++)
{
SwingPoint* swing = all_swings.At(i);
if(swing != NULL && swing.status != STATUS_NOISE && swing.status != STATUS_UNCONFIRMED)
{
valid_object_names.Add(m_prefix + "Swing_" + (string)swing.time);
if(swing.status == STATUS_INDUCEMENT && swing.linked_major_index >=0)
{
valid_object_names.Add(m_prefix + "Link_" + (string)swing.time);
}
if(swing.status == STATUS_MAJOR && swing.bos_confirmation_time > 0)
{
valid_object_names.Add(m_prefix + "BOS_" + (string)swing.time);
}
}
}
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
for(int i = ObjectsTotal(m_chart_id) - 1; i >= 0; i--)
{
string name = ObjectName(m_chart_id, i);
if(StringFind(name, m_prefix) == 0)
{
if(valid_object_names.Search(name) < 0)
{
ObjectDelete(m_chart_id, name);
}
}
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
delete valid_object_names;
}
void DrawZone(CSignalZone* zone, CDataContext &context)
{
if(zone == NULL)
return;
string obj_name = zone.object_name;
// 1. 3+*5A%0*D%L2!*20-B 
color box_color = clrWhite;
ENUM_LINE_STYLE box_style = (zone.zone_type == ZONE_FVG) ? STYLE_DOT : STYLE_SOLID;
bool fill_box = (zone.zone_type != ZONE_FVG);
switch(zone.state)
{
case STATE_FRESH:
box_color = (zone.direction == DIRECTION_BULLISH ? clrDarkGreen : clrMaroon);
if(zone.zone_type==ZONE_FVG)
box_color=clrGold;
break;
if(zone.zone_type == ZONE_FLIP)
box_color = clrAqua;
else
if(zone.zone_type == ZONE_BREAKOUT_RETEST)
box_color = clrDodgerBlue;
case STATE_ACTIVE:
box_color = (zone.direction == DIRECTION_BULLISH ? clrGreen : clrTomato);
break;
case STATE_MITIGATED:
box_color = (zone.direction == DIRECTION_BULLISH ? clrForestGreen : clrIndianRed);
break;
//case STATE_CONFIRMED: box_color = (zone.direction == DIRECTION_BULLISH ? clrLime : clrRed); break;
case STATE_INVALIDATED:
box_color = clrDimGray;
fill_box = false;
break;
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
// 2. +28*4I*8-2#'2B 
datetime end_time;
int start_idx = iBarShift(_Symbol, PERIOD_CURRENT, zone.time);
if(start_idx < 0 || start_idx >= context.bars_to_load)
{
// ObjectDelete(m_chart_id, zone.object_name); // -20% object @H24II2!5
return;
}
// +2AH@5"5H "3%2"" +#7- "1" B 
int end_idx = -1;
for(int i = start_idx - 1; i >= 0; i--)
{
// *3+#1B  Demand, +2AH5H Low H3'H2-%H2-B 
if(zone.direction == DIRECTION_BULLISH && context.rates[i].low < zone.bottom)
{
end_idx = i;
break;
}
// *3+#1B  Supply, +2AH5H High *9'H2--B 
if(zone.direction == DIRECTION_BEARISH && context.rates[i].high > zone.top)
{
end_idx = i;
break;
}
}
// 3. 3+@'%2*4I*8
if(end_idx != -1)
{
// I2@-AH5H3%2"B  C+I2#'25HAH1I
end_time = context.rates[end_idx].time;
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
else
{
// I2D!H@- C+I%2"2'D6-2@%GI-" (-'2*8--)
end_time = context.rates[0].time + PeriodSeconds() * 10;
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
// I2"1D!H!5 Object 5I C+I*#I2C+!H
if(ObjectFind(m_chart_id, obj_name) < 0)
{
ObjectCreate(m_chart_id, obj_name, OBJ_RECTANGLE, 0, zone.time, zone.top, end_time, zone.bottom);
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
// I2!5-"9HA%I' C+I-1@@ 20*4H5H-2@%5H"A%
else
{
ObjectSetInteger(m_chart_id, obj_name, OBJPROP_TIME, 1, end_time);
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
// -1@8*!14-7HF 8#1I @7H-!52#@%5H"A%
ObjectSetInteger(m_chart_id, obj_name, OBJPROP_COLOR, box_color);
ObjectSetInteger(m_chart_id, obj_name, OBJPROP_STYLE, box_style);
ObjectSetInteger(m_chart_id, obj_name, OBJPROP_FILL, fill_box);
ObjectSetInteger(m_chart_id, obj_name, OBJPROP_BACK, true);
// '2/-1@ Text Label
string text_name = obj_name + "_Text";
string text = EnumToString(zone.zone_type) + " " + EnumToString(zone.state);
if(zone.mitigation_count > 0)
text += " T:" + (string)zone.mitigation_count;
if(ObjectFind(m_chart_id, text_name) < 0)
2025-07-03 23:37:34 +07:00
{
2025-07-03 23:38:38 +07:00
ObjectCreate(m_chart_id, text_name, OBJ_TEXT, 0, zone.time, zone.top);
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
ObjectSetString(m_chart_id, text_name, OBJPROP_TEXT, text);
ObjectSetInteger(m_chart_id, text_name, OBJPROP_COLOR, box_color);
ObjectSetInteger(m_chart_id, text_name, OBJPROP_FONTSIZE, 8);
ObjectSetInteger(m_chart_id, text_name, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
}
void DrawSwing(SwingPoint* swing, CArrayObj* all_swings, CDataContext &context)
{
if(swing == NULL || swing.status == STATUS_NOISE || swing.status == STATUS_UNCONFIRMED)
return;
string obj_name = m_prefix + "Swing_" + (string)swing.time;
color symbol_color = clrWhite;
int symbol_code = 0;
int symbol_size = 1;
switch(swing.status)
{
case STATUS_MAJOR:
symbol_color = (swing.type == SWING_HIGH) ? clrRed : clrLimeGreen;
symbol_size = 3;
// FIXED: Use character codes for Wingdings font
symbol_code = (swing.type == SWING_HIGH) ? 159 : 159;
break;
case STATUS_INDUCEMENT:
symbol_color = clrGold;
symbol_size = 2;
symbol_code = 159; // '$' sign
break;
case STATUS_MINOR:
symbol_color = clrDimGray;
symbol_size = 1;
symbol_code = 159; // Solid Circle
break;
2025-07-03 23:37:34 +07:00
2025-07-03 23:38:38 +07:00
default:
return;
}
/*double atr_val = (swing.bar_index < context.bars_to_load) ? context.atr_buffer[swing.bar_index] : 0;
double price_offset = atr_val * 0.2;*/
double draw_price = (swing.type == SWING_HIGH) ? swing.price + 12 : swing.price ;
// '2/-1@ *1 %1)L+%1
if(ObjectFind(m_chart_id, obj_name) < 0)
{
ObjectCreate(m_chart_id, obj_name, OBJ_ARROW, 0, swing.time, draw_price);
}
else
{
ObjectSetDouble(m_chart_id, obj_name, OBJPROP_PRICE, 0, draw_price);
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
ObjectSetInteger(m_chart_id, obj_name, OBJPROP_ARROWCODE, symbol_code);
ObjectSetInteger(m_chart_id, obj_name, OBJPROP_COLOR, symbol_color);
ObjectSetInteger(m_chart_id, obj_name, OBJPROP_WIDTH, symbol_size);
ObjectSetInteger(m_chart_id, obj_name, OBJPROP_BACK, true);
2025-07-03 23:37:34 +07:00
2025-07-03 23:38:38 +07:00
// '2/-1@ @*I@
2025-07-03 23:37:34 +07:00
7H-! Inducement . Major
2025-07-03 23:38:38 +07:00
/*string link_name = m_prefix + "Link_" + (string)swing.time;
if(swing.status == STATUS_INDUCEMENT && swing.linked_major_index >= 0 && swing.linked_major_index < all_swings.Total()) {
SwingPoint *major_swing = all_swings.At(swing.linked_major_index);
if(major_swing != NULL) {
if(ObjectFind(m_chart_id, link_name) < 0) {
ObjectCreate(m_chart_id, link_name, OBJ_TREND, 0, swing.time, swing.price, major_swing.time, major_swing.price);
}
ObjectSetInteger(m_chart_id, link_name, OBJPROP_COLOR, clrGoldenrod);
ObjectSetInteger(m_chart_id, link_name, OBJPROP_STYLE, STYLE_DOT);
}
}*/
// '2/-1@ I2" "BOS"
if(swing.status == STATUS_MAJOR && swing.bos_confirmation_time > 0)
{
string bos_name = m_prefix + "BOS_" + (string)swing.time;
datetime bos_time = swing.bos_confirmation_time;
int bos_idx = iBarShift(_Symbol, PERIOD_CURRENT, bos_time);
if(bos_idx >= 0 && bos_idx < context.bars_to_load)
2025-07-03 23:37:34 +07:00
{
2025-07-03 23:38:38 +07:00
double bos_atr_val = context.atr_buffer[bos_idx];
double bos_price_offset = bos_atr_val * 0.5;
double bos_price = (swing.type == SWING_LOW) ? context.rates[bos_idx].high + bos_price_offset : context.rates[bos_idx].low - bos_price_offset;
ObjectCreate(m_chart_id, bos_name, OBJ_TEXT, 0, bos_time, bos_price);
ObjectSetString(m_chart_id, bos_name, OBJPROP_TEXT, "BOS");
ObjectSetInteger(m_chart_id, bos_name, OBJPROP_COLOR, clrAqua);
ObjectSetInteger(m_chart_id, bos_name, OBJPROP_FONTSIZE, 8);
ObjectSetInteger(m_chart_id, bos_name, OBJPROP_BACK, true);
if(swing.type == SWING_LOW)
ObjectSetInteger(m_chart_id, bos_name, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER);
else
ObjectSetInteger(m_chart_id, bos_name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
}
2025-07-03 23:37:34 +07:00
}
2025-07-03 23:38:38 +07:00
}
};
#endif
//+------------------------------------------------------------------+