mirror of
https://github.com/softwaredevelop/mql5.git
synced 2026-11-02 11:16:15 +00:00
refactor: Dual State-Guards (Zero GDI overhead on live ticks)
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
//| PivotPoints_Pro.mq5 |
|
||||
//| Copyright 2026, xxxxxxxx|
|
||||
//+------------------------------------------------------------------+
|
||||
#property copyright "Copyright 2026, xxxxxxxx"
|
||||
#property version "3.30" // Streamlined: Permanent Extended Workspace Support
|
||||
#property copyright "Copyright 2026, xxxxxxxx"
|
||||
#property version "3.40" // Enterprise Refactor: Dual State-Guards (Zero GDI overhead on live ticks)
|
||||
#property description "Professional Pivot Points with Native Workspace & Chart Shift Support."
|
||||
#property description "Optimized for massive multi-window execution with zero tick latency."
|
||||
|
||||
#property indicator_chart_window
|
||||
#property indicator_buffers 13
|
||||
@@ -13,40 +14,28 @@
|
||||
//--- Plot definitions (Data Window Registration)
|
||||
#property indicator_label1 "Pivot Point"
|
||||
#property indicator_type1 DRAW_NONE
|
||||
|
||||
#property indicator_label2 "R1"
|
||||
#property indicator_type2 DRAW_NONE
|
||||
|
||||
#property indicator_label3 "S1"
|
||||
#property indicator_type3 DRAW_NONE
|
||||
|
||||
#property indicator_label4 "R2"
|
||||
#property indicator_type4 DRAW_NONE
|
||||
|
||||
#property indicator_label5 "S2"
|
||||
#property indicator_type5 DRAW_NONE
|
||||
|
||||
#property indicator_label6 "R3"
|
||||
#property indicator_type6 DRAW_NONE
|
||||
|
||||
#property indicator_label7 "S3"
|
||||
#property indicator_type7 DRAW_NONE
|
||||
|
||||
#property indicator_label8 "S1-S2"
|
||||
#property indicator_type8 DRAW_NONE
|
||||
|
||||
#property indicator_label9 "PP-S1"
|
||||
#property indicator_type9 DRAW_NONE
|
||||
|
||||
#property indicator_label10 "PP-R1"
|
||||
#property indicator_type10 DRAW_NONE
|
||||
|
||||
#property indicator_label11 "R1-R2"
|
||||
#property indicator_type11 DRAW_NONE
|
||||
|
||||
#property indicator_label12 "R2-R3"
|
||||
#property indicator_type12 DRAW_NONE
|
||||
|
||||
#property indicator_label13 "S2-S3"
|
||||
#property indicator_type13 DRAW_NONE
|
||||
|
||||
@@ -93,16 +82,33 @@ double BufferR2[], BufferS2[];
|
||||
double BufferR3[], BufferS3[];
|
||||
double BufferM1[], BufferM2[], BufferM3[], BufferM4[], BufferM5[], BufferM6[];
|
||||
|
||||
//--- Global Objects & Constants
|
||||
CPivotPointCalculator *g_calculator = NULL;
|
||||
const string g_prefix_line = "PivotLine_";
|
||||
const string g_prefix_lbl = "PivotLabel_";
|
||||
//--- Static Global Engine Instance (Zero heap allocation)
|
||||
CPivotPointCalculator g_calculator;
|
||||
|
||||
//--- State Guards for Zero-Lag Execution
|
||||
datetime g_last_rendered_period = 0;
|
||||
datetime g_last_bar_time = 0;
|
||||
|
||||
string g_prefix_line = "";
|
||||
string g_prefix_lbl = "";
|
||||
|
||||
// Forward declarations
|
||||
void UpdateExtendedLevels(const PivotLevels &levels);
|
||||
void UpdateLabels(const PivotLevels &levels, const datetime current_time);
|
||||
void SetLevelRay(const string name, const double price, const datetime t1, const datetime t2, const color col, const ENUM_LINE_STYLE style, const int width);
|
||||
void CreateLabel(const string name, const double price, const color col, const datetime target_time, const bool small=false);
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| OnInit |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
g_last_rendered_period = 0;
|
||||
g_last_bar_time = 0;
|
||||
|
||||
g_prefix_line = StringFormat("PivLine_%I64d_", ChartID());
|
||||
g_prefix_lbl = StringFormat("PivLbl_%I64d_", ChartID());
|
||||
|
||||
SetIndexBuffer(0, BufferPP, INDICATOR_DATA);
|
||||
SetIndexBuffer(1, BufferR1, INDICATOR_DATA);
|
||||
SetIndexBuffer(2, BufferS1, INDICATOR_DATA);
|
||||
@@ -118,7 +124,7 @@ int OnInit()
|
||||
SetIndexBuffer(11, BufferM5, INDICATOR_DATA);
|
||||
SetIndexBuffer(12, BufferM6, INDICATOR_DATA);
|
||||
|
||||
// Chronological Safety (0 = Oldest bar)
|
||||
// Chronological Safety
|
||||
ArraySetAsSeries(BufferPP, false);
|
||||
ArraySetAsSeries(BufferR1, false);
|
||||
ArraySetAsSeries(BufferS1, false);
|
||||
@@ -133,24 +139,10 @@ int OnInit()
|
||||
ArraySetAsSeries(BufferM5, false);
|
||||
ArraySetAsSeries(BufferM6, false);
|
||||
|
||||
ArrayInitialize(BufferPP, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferR1, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferS1, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferR2, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferS2, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferR3, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferS3, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferM1, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferM2, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferM3, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferM4, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferM5, EMPTY_VALUE);
|
||||
ArrayInitialize(BufferM6, EMPTY_VALUE);
|
||||
|
||||
// Configure all plots to DRAW_NONE to delegate rendering to the ray object engine
|
||||
for(int i = 0; i < 13; i++)
|
||||
{
|
||||
PlotIndexSetInteger(i, PLOT_DRAW_TYPE, DRAW_NONE);
|
||||
PlotIndexSetDouble(i, PLOT_EMPTY_VALUE, EMPTY_VALUE);
|
||||
}
|
||||
|
||||
if(InpTimeframe < Period())
|
||||
@@ -159,8 +151,7 @@ int OnInit()
|
||||
return INIT_PARAMETERS_INCORRECT;
|
||||
}
|
||||
|
||||
g_calculator = new CPivotPointCalculator();
|
||||
if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPivotType, InpSourceType))
|
||||
if(!g_calculator.Init(InpPivotType, InpSourceType))
|
||||
return INIT_FAILED;
|
||||
|
||||
string label = StringFormat("PivotPro(%s)", EnumToString(InpTimeframe));
|
||||
@@ -175,12 +166,6 @@ int OnInit()
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
if(CheckPointer(g_calculator) != POINTER_INVALID)
|
||||
{
|
||||
delete g_calculator;
|
||||
g_calculator = NULL;
|
||||
}
|
||||
|
||||
ObjectsDeleteAll(0, g_prefix_line);
|
||||
ObjectsDeleteAll(0, g_prefix_lbl);
|
||||
ChartRedraw(0);
|
||||
@@ -204,19 +189,38 @@ int OnCalculate(const int rates_total,
|
||||
return 0;
|
||||
|
||||
ArraySetAsSeries(time, false);
|
||||
|
||||
datetime current_time = time[rates_total - 1];
|
||||
|
||||
PivotLevels levels;
|
||||
if(!g_calculator.CalculateLevels(current_time, InpTimeframe, levels))
|
||||
return 0;
|
||||
|
||||
// 1. Maintain Buffers for Data Window & iCustom compatibility
|
||||
int limit = (prev_calculated == 0) ? 0 : prev_calculated - 1;
|
||||
|
||||
for(int i = limit; i < rates_total; i++)
|
||||
// 1. Maintain Buffers for Data Window & iCustom compatibility (O(1) on live ticks!)
|
||||
if(prev_calculated == 0)
|
||||
{
|
||||
if(time[i] >= levels.period_start)
|
||||
// Efficient initial pass: Find start of active period in O(log N)
|
||||
int period_start_bar = ArrayBsearch(time, levels.period_start);
|
||||
if(period_start_bar < 0)
|
||||
period_start_bar = 0;
|
||||
|
||||
for(int i = 0; i < period_start_bar; i++)
|
||||
{
|
||||
BufferPP[i] = EMPTY_VALUE;
|
||||
BufferR1[i] = EMPTY_VALUE;
|
||||
BufferS1[i] = EMPTY_VALUE;
|
||||
BufferR2[i] = EMPTY_VALUE;
|
||||
BufferS2[i] = EMPTY_VALUE;
|
||||
BufferR3[i] = EMPTY_VALUE;
|
||||
BufferS3[i] = EMPTY_VALUE;
|
||||
BufferM1[i] = EMPTY_VALUE;
|
||||
BufferM2[i] = EMPTY_VALUE;
|
||||
BufferM3[i] = EMPTY_VALUE;
|
||||
BufferM4[i] = EMPTY_VALUE;
|
||||
BufferM5[i] = EMPTY_VALUE;
|
||||
BufferM6[i] = EMPTY_VALUE;
|
||||
}
|
||||
|
||||
for(int i = period_start_bar; i < rates_total; i++)
|
||||
{
|
||||
BufferPP[i] = levels.PP;
|
||||
BufferR1[i] = levels.R1;
|
||||
@@ -228,42 +232,61 @@ int OnCalculate(const int rates_total,
|
||||
|
||||
if(InpShowMedians && levels.PP != EMPTY_VALUE)
|
||||
{
|
||||
BufferM1[i] = (levels.S1 != EMPTY_VALUE && levels.S2 != EMPTY_VALUE) ? (levels.S1 + levels.S2) / 2.0 : EMPTY_VALUE;
|
||||
BufferM2[i] = (levels.S1 != EMPTY_VALUE) ? (levels.S1 + levels.PP) / 2.0 : EMPTY_VALUE;
|
||||
BufferM3[i] = (levels.R1 != EMPTY_VALUE) ? (levels.PP + levels.R1) / 2.0 : EMPTY_VALUE;
|
||||
BufferM4[i] = (levels.R1 != EMPTY_VALUE && levels.R2 != EMPTY_VALUE) ? (levels.R1 + levels.R2) / 2.0 : EMPTY_VALUE;
|
||||
BufferM5[i] = (levels.R2 != EMPTY_VALUE && levels.R3 != EMPTY_VALUE) ? (levels.R2 + levels.R3) / 2.0 : EMPTY_VALUE;
|
||||
BufferM6[i] = (levels.S2 != EMPTY_VALUE && levels.S3 != EMPTY_VALUE) ? (levels.S2 + levels.S3) / 2.0 : EMPTY_VALUE;
|
||||
BufferM1[i] = (levels.S1 != EMPTY_VALUE && levels.S2 != EMPTY_VALUE) ? (levels.S1 + levels.S2) * 0.5 : EMPTY_VALUE;
|
||||
BufferM2[i] = (levels.S1 != EMPTY_VALUE) ? (levels.S1 + levels.PP) * 0.5 : EMPTY_VALUE;
|
||||
BufferM3[i] = (levels.R1 != EMPTY_VALUE) ? (levels.PP + levels.R1) * 0.5 : EMPTY_VALUE;
|
||||
BufferM4[i] = (levels.R1 != EMPTY_VALUE && levels.R2 != EMPTY_VALUE) ? (levels.R1 + levels.R2) * 0.5 : EMPTY_VALUE;
|
||||
BufferM5[i] = (levels.R2 != EMPTY_VALUE && levels.R3 != EMPTY_VALUE) ? (levels.R2 + levels.R3) * 0.5 : EMPTY_VALUE;
|
||||
BufferM6[i] = (levels.S2 != EMPTY_VALUE && levels.S3 != EMPTY_VALUE) ? (levels.S2 + levels.S3) * 0.5 : EMPTY_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferPP[i] = EMPTY_VALUE;
|
||||
BufferR1[i] = EMPTY_VALUE;
|
||||
BufferS1[i] = EMPTY_VALUE;
|
||||
BufferR2[i] = EMPTY_VALUE;
|
||||
BufferS2[i] = EMPTY_VALUE;
|
||||
BufferR3[i] = EMPTY_VALUE;
|
||||
BufferS3[i] = EMPTY_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Single live forming bar assignment (Zero loops!)
|
||||
int i = rates_total - 1;
|
||||
BufferPP[i] = levels.PP;
|
||||
BufferR1[i] = levels.R1;
|
||||
BufferS1[i] = levels.S1;
|
||||
BufferR2[i] = levels.R2;
|
||||
BufferS2[i] = levels.S2;
|
||||
BufferR3[i] = levels.R3;
|
||||
BufferS3[i] = levels.S3;
|
||||
|
||||
BufferM1[i] = EMPTY_VALUE;
|
||||
BufferM2[i] = EMPTY_VALUE;
|
||||
BufferM3[i] = EMPTY_VALUE;
|
||||
BufferM4[i] = EMPTY_VALUE;
|
||||
BufferM5[i] = EMPTY_VALUE;
|
||||
BufferM6[i] = EMPTY_VALUE;
|
||||
if(InpShowMedians && levels.PP != EMPTY_VALUE)
|
||||
{
|
||||
BufferM1[i] = (levels.S1 != EMPTY_VALUE && levels.S2 != EMPTY_VALUE) ? (levels.S1 + levels.S2) * 0.5 : EMPTY_VALUE;
|
||||
BufferM2[i] = (levels.S1 != EMPTY_VALUE) ? (levels.S1 + levels.PP) * 0.5 : EMPTY_VALUE;
|
||||
BufferM3[i] = (levels.R1 != EMPTY_VALUE) ? (levels.PP + levels.R1) * 0.5 : EMPTY_VALUE;
|
||||
BufferM4[i] = (levels.R1 != EMPTY_VALUE && levels.R2 != EMPTY_VALUE) ? (levels.R1 + levels.R2) * 0.5 : EMPTY_VALUE;
|
||||
BufferM5[i] = (levels.R2 != EMPTY_VALUE && levels.R3 != EMPTY_VALUE) ? (levels.R2 + levels.R3) * 0.5 : EMPTY_VALUE;
|
||||
BufferM6[i] = (levels.S2 != EMPTY_VALUE && levels.S3 != EMPTY_VALUE) ? (levels.S2 + levels.S3) * 0.5 : EMPTY_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Render Full-Workspace Extended Levels across the Chart Shift zone
|
||||
UpdateExtendedLevels(levels);
|
||||
// 2. State-Guards: Only execute GDI updates when period or candle actually changes!
|
||||
bool period_changed = (levels.period_start != g_last_rendered_period);
|
||||
bool bar_changed = (current_time != g_last_bar_time);
|
||||
|
||||
// 3. Update Text Labels
|
||||
if(InpShowLabels)
|
||||
UpdateLabels(levels);
|
||||
else
|
||||
ObjectsDeleteAll(0, g_prefix_lbl);
|
||||
// A) Ray Lines: ONLY updated when a new HTF period begins (Once every 4 hours or day!)
|
||||
if(period_changed)
|
||||
{
|
||||
UpdateExtendedLevels(levels);
|
||||
g_last_rendered_period = levels.period_start;
|
||||
}
|
||||
|
||||
// B) Labels: ONLY updated when a new bar opens or period changes (Once per candle!)
|
||||
if(period_changed || bar_changed)
|
||||
{
|
||||
if(InpShowLabels)
|
||||
UpdateLabels(levels, current_time);
|
||||
else
|
||||
ObjectsDeleteAll(0, g_prefix_lbl);
|
||||
|
||||
g_last_bar_time = current_time;
|
||||
}
|
||||
|
||||
// On live ticks: ZERO GDI operations executed!
|
||||
return rates_total;
|
||||
}
|
||||
|
||||
@@ -273,10 +296,10 @@ int OnCalculate(const int rates_total,
|
||||
void UpdateExtendedLevels(const PivotLevels &levels)
|
||||
{
|
||||
datetime t_start = levels.period_start;
|
||||
datetime t_end = t_start + PeriodSeconds(InpTimeframe);
|
||||
datetime t_end = t_start + (datetime)PeriodSeconds(InpTimeframe);
|
||||
|
||||
// Main Levels
|
||||
SetLevelRay("PP", levels.PP, t_start, t_end, InpColorPP, InpStylePP, InpWidthPP);
|
||||
SetLevelRay("PP", levels.PP, t_start, t_end, InpColorPP, InpStylePP, InpWidthPP);
|
||||
SetLevelRay("R1", levels.R1, t_start, t_end, InpColorRes, InpStyleRes, InpWidthRes);
|
||||
SetLevelRay("R2", levels.R2, t_start, t_end, InpColorRes, InpStyleRes, InpWidthRes);
|
||||
SetLevelRay("R3", levels.R3, t_start, t_end, InpColorRes, InpStyleRes, InpWidthRes);
|
||||
@@ -288,17 +311,17 @@ void UpdateExtendedLevels(const PivotLevels &levels)
|
||||
if(InpShowMedians && levels.PP != EMPTY_VALUE)
|
||||
{
|
||||
if(levels.S1 != EMPTY_VALUE && levels.S2 != EMPTY_VALUE)
|
||||
SetLevelRay("M_S1_S2", (levels.S1 + levels.S2) / 2.0, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
SetLevelRay("M_S1_S2", (levels.S1 + levels.S2) * 0.5, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
if(levels.S1 != EMPTY_VALUE)
|
||||
SetLevelRay("M_PP_S1", (levels.S1 + levels.PP) / 2.0, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
SetLevelRay("M_PP_S1", (levels.S1 + levels.PP) * 0.5, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
if(levels.R1 != EMPTY_VALUE)
|
||||
SetLevelRay("M_PP_R1", (levels.PP + levels.R1) / 2.0, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
SetLevelRay("M_PP_R1", (levels.PP + levels.R1) * 0.5, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
if(levels.R1 != EMPTY_VALUE && levels.R2 != EMPTY_VALUE)
|
||||
SetLevelRay("M_R1_R2", (levels.R1 + levels.R2) / 2.0, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
SetLevelRay("M_R1_R2", (levels.R1 + levels.R2) * 0.5, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
if(levels.R2 != EMPTY_VALUE && levels.R3 != EMPTY_VALUE)
|
||||
SetLevelRay("M_R2_R3", (levels.R2 + levels.R3) / 2.0, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
SetLevelRay("M_R2_R3", (levels.R2 + levels.R3) * 0.5, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
if(levels.S2 != EMPTY_VALUE && levels.S3 != EMPTY_VALUE)
|
||||
SetLevelRay("M_S2_S3", (levels.S2 + levels.S3) / 2.0, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
SetLevelRay("M_S2_S3", (levels.S2 + levels.S3) * 0.5, t_start, t_end, InpColorMed, InpStyleMed, InpWidthMed);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -332,48 +355,53 @@ void SetLevelRay(const string name,
|
||||
ObjectCreate(0, objName, OBJ_TREND, 0, t1, price, t2, price);
|
||||
ObjectSetInteger(0, objName, OBJPROP_RAY_RIGHT, true);
|
||||
ObjectSetInteger(0, objName, OBJPROP_RAY_LEFT, false);
|
||||
ObjectSetInteger(0, objName, OBJPROP_BACK, true);
|
||||
ObjectSetInteger(0, objName, OBJPROP_BACK, true); // Stays in background
|
||||
ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
|
||||
ObjectSetInteger(0, objName, OBJPROP_SELECTED, false);
|
||||
ObjectSetInteger(0, objName, OBJPROP_HIDDEN, true);
|
||||
ObjectSetInteger(0, objName, OBJPROP_COLOR, col);
|
||||
ObjectSetInteger(0, objName, OBJPROP_STYLE, style);
|
||||
ObjectSetInteger(0, objName, OBJPROP_WIDTH, width);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectSetInteger(0, objName, OBJPROP_TIME, 0, t1);
|
||||
ObjectSetDouble(0, objName, OBJPROP_PRICE, 0, price);
|
||||
ObjectSetInteger(0, objName, OBJPROP_TIME, 1, t2);
|
||||
ObjectSetDouble(0, objName, OBJPROP_PRICE, 1, price);
|
||||
ObjectSetInteger(0, objName, OBJPROP_COLOR, col);
|
||||
}
|
||||
|
||||
ObjectSetInteger(0, objName, OBJPROP_TIME, 0, t1);
|
||||
ObjectSetDouble(0, objName, OBJPROP_PRICE, 0, price);
|
||||
ObjectSetInteger(0, objName, OBJPROP_TIME, 1, t2);
|
||||
ObjectSetDouble(0, objName, OBJPROP_PRICE, 1, price);
|
||||
ObjectSetInteger(0, objName, OBJPROP_COLOR, col);
|
||||
ObjectSetInteger(0, objName, OBJPROP_STYLE, style);
|
||||
ObjectSetInteger(0, objName, OBJPROP_WIDTH, width);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Update Labels in Workspace |
|
||||
//+------------------------------------------------------------------+
|
||||
void UpdateLabels(const PivotLevels &levels)
|
||||
void UpdateLabels(const PivotLevels &levels, const datetime current_time)
|
||||
{
|
||||
CreateLabel("PP", levels.PP, InpColorPP);
|
||||
CreateLabel("R1", levels.R1, InpColorRes);
|
||||
CreateLabel("R2", levels.R2, InpColorRes);
|
||||
CreateLabel("R3", levels.R3, InpColorRes);
|
||||
CreateLabel("S1", levels.S1, InpColorSup);
|
||||
CreateLabel("S2", levels.S2, InpColorSup);
|
||||
CreateLabel("S3", levels.S3, InpColorSup);
|
||||
datetime target_time = current_time + (datetime)(PeriodSeconds(Period()) * InpLabelShift);
|
||||
|
||||
CreateLabel("PP", levels.PP, InpColorPP, target_time);
|
||||
CreateLabel("R1", levels.R1, InpColorRes, target_time);
|
||||
CreateLabel("R2", levels.R2, InpColorRes, target_time);
|
||||
CreateLabel("R3", levels.R3, InpColorRes, target_time);
|
||||
CreateLabel("S1", levels.S1, InpColorSup, target_time);
|
||||
CreateLabel("S2", levels.S2, InpColorSup, target_time);
|
||||
CreateLabel("S3", levels.S3, InpColorSup, target_time);
|
||||
|
||||
if(InpShowMedians && levels.PP != EMPTY_VALUE)
|
||||
{
|
||||
if(levels.S1 != EMPTY_VALUE && levels.S2 != EMPTY_VALUE)
|
||||
CreateLabel("S1-S2", (levels.S1 + levels.S2) / 2.0, InpColorMed, true);
|
||||
CreateLabel("S1-S2", (levels.S1 + levels.S2) * 0.5, InpColorMed, target_time, true);
|
||||
if(levels.S1 != EMPTY_VALUE)
|
||||
CreateLabel("PP-S1", (levels.S1 + levels.PP) / 2.0, InpColorMed, true);
|
||||
CreateLabel("PP-S1", (levels.S1 + levels.PP) * 0.5, InpColorMed, target_time, true);
|
||||
if(levels.R1 != EMPTY_VALUE)
|
||||
CreateLabel("PP-R1", (levels.PP + levels.R1) / 2.0, InpColorMed, true);
|
||||
CreateLabel("PP-R1", (levels.PP + levels.R1) * 0.5, InpColorMed, target_time, true);
|
||||
if(levels.R1 != EMPTY_VALUE && levels.R2 != EMPTY_VALUE)
|
||||
CreateLabel("R1-R2", (levels.R1 + levels.R2) / 2.0, InpColorMed, true);
|
||||
CreateLabel("R1-R2", (levels.R1 + levels.R2) * 0.5, InpColorMed, target_time, true);
|
||||
if(levels.R2 != EMPTY_VALUE && levels.R3 != EMPTY_VALUE)
|
||||
CreateLabel("R2-R3", (levels.R2 + levels.R3) / 2.0, InpColorMed, true);
|
||||
CreateLabel("R2-R3", (levels.R2 + levels.R3) * 0.5, InpColorMed, target_time, true);
|
||||
if(levels.S2 != EMPTY_VALUE && levels.S3 != EMPTY_VALUE)
|
||||
CreateLabel("S2-S3", (levels.S2 + levels.S3) / 2.0, InpColorMed, true);
|
||||
CreateLabel("S2-S3", (levels.S2 + levels.S3) * 0.5, InpColorMed, target_time, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -386,7 +414,7 @@ void UpdateLabels(const PivotLevels &levels)
|
||||
//+------------------------------------------------------------------+
|
||||
//| Helper: Create or Update Text Label |
|
||||
//+------------------------------------------------------------------+
|
||||
void CreateLabel(const string name, const double price, const color col, const bool small = false)
|
||||
void CreateLabel(const string name, const double price, const color col, const datetime target_time, const bool small=false)
|
||||
{
|
||||
string objName = g_prefix_lbl + name;
|
||||
|
||||
@@ -398,21 +426,21 @@ void CreateLabel(const string name, const double price, const color col, const b
|
||||
|
||||
if(ObjectFind(0, objName) < 0)
|
||||
{
|
||||
ObjectCreate(0, objName, OBJ_TEXT, 0, 0, 0);
|
||||
ObjectCreate(0, objName, OBJ_TEXT, 0, target_time, price);
|
||||
ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);
|
||||
ObjectSetInteger(0, objName, OBJPROP_BACK, true); // Stays in background
|
||||
ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
|
||||
ObjectSetInteger(0, objName, OBJPROP_SELECTED, false);
|
||||
ObjectSetInteger(0, objName, OBJPROP_HIDDEN, true);
|
||||
ObjectSetString(0, objName, OBJPROP_TEXT, " " + name);
|
||||
ObjectSetInteger(0, objName, OBJPROP_COLOR, col);
|
||||
ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, small ? MathMax(6, InpFontSize - 2) : InpFontSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
ObjectSetDouble(0, objName, OBJPROP_PRICE, price);
|
||||
ObjectSetInteger(0, objName, OBJPROP_TIME, target_time);
|
||||
}
|
||||
|
||||
// Anchor label into the workspace shift area
|
||||
datetime target_time = iTime(_Symbol, Period(), 0) + PeriodSeconds(Period()) * InpLabelShift;
|
||||
|
||||
ObjectSetString(0, objName, OBJPROP_TEXT, " " + name);
|
||||
ObjectSetDouble(0, objName, OBJPROP_PRICE, price);
|
||||
ObjectSetInteger(0, objName, OBJPROP_TIME, target_time);
|
||||
ObjectSetInteger(0, objName, OBJPROP_COLOR, col);
|
||||
ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, small ? MathMax(6, InpFontSize - 2) : InpFontSize);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
Reference in New Issue
Block a user