Last Works on XSDT Pivot Detector ...
This commit is contained in:
@@ -0,0 +1,899 @@
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
// SaherElm IT Center MQL5 Class
|
||||
// -------------------------------------------------
|
||||
// Name: XCPivotDetector
|
||||
// Description: Forex Pivot Detector with Event System
|
||||
//
|
||||
// Maintainer:
|
||||
// ------------
|
||||
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
||||
//
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// Global Properties ...
|
||||
#property library
|
||||
#property copyright "Copyright 2023, SaherElm IT Center"
|
||||
#property link "https://saherelm.ir"
|
||||
#property version "1.00"
|
||||
#property description "SaherElm Forex Pivot Detector Class"
|
||||
#property strict
|
||||
|
||||
//
|
||||
// Imports ...
|
||||
#include "../Classes/x-saherelm.base.class.mq5"
|
||||
#include "../Classes/x-saherelm.x-alert.class.mq5"
|
||||
#include "../Libraries/x-saherelm.common.extensions.lib.mq5"
|
||||
#include "../Libraries/x-saherelm.x-enums.lib.mq5"
|
||||
#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5"
|
||||
#include "../Libraries/x-saherelm.x-poi.lib.mq5"
|
||||
|
||||
//
|
||||
// Definitions ...
|
||||
|
||||
typedef void (*TOnPivotZoneEvent)(XBoxZone &box);
|
||||
|
||||
//
|
||||
// Implementation ...
|
||||
class XCPivotDetector : public XCBase
|
||||
{
|
||||
//
|
||||
public:
|
||||
//
|
||||
// Props ...
|
||||
//
|
||||
XCAlert *alert; // Alert Handler
|
||||
XBoxZone peaks[]; // Peaks ...
|
||||
XBoxZone vales[]; // Vales ...
|
||||
|
||||
//
|
||||
// Event Handlers ...
|
||||
TOnPivotZoneEvent mOnPeakBreakedHandlers[];
|
||||
TOnPivotZoneEvent mOnValeBreakedHandlers[];
|
||||
TOnPivotZoneEvent mOnPeakDetectedHandlers[];
|
||||
TOnPivotZoneEvent mOnValeDetectedHandlers[];
|
||||
|
||||
//
|
||||
// Constructor ...
|
||||
XCPivotDetector(
|
||||
XCAlert *_alert = NULL, //
|
||||
int _maxAllowedProcessableZones = 10 //
|
||||
)
|
||||
{
|
||||
//
|
||||
alert = _alert;
|
||||
|
||||
//
|
||||
// Normalize ...
|
||||
if (_maxAllowedProcessableZones <= 5)
|
||||
{
|
||||
_maxAllowedProcessableZones = 5;
|
||||
}
|
||||
mMaxAllowedProcessableZones = _maxAllowedProcessableZones;
|
||||
|
||||
//
|
||||
Initialize();
|
||||
}
|
||||
|
||||
//
|
||||
// Deconstructor ...
|
||||
~XCPivotDetector()
|
||||
{
|
||||
//
|
||||
Clean(peaks);
|
||||
Clean(vales);
|
||||
|
||||
//
|
||||
Clean(mOnPeakDetectedHandlers);
|
||||
Clean(mOnValeDetectedHandlers);
|
||||
|
||||
//
|
||||
ZeroMemory(alert);
|
||||
}
|
||||
|
||||
// #region Actions ...
|
||||
void Process(
|
||||
XOHCL &bar,
|
||||
int pivotApproved = 2,
|
||||
int loopback = 20 //
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate ...
|
||||
if (!bar.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Normalize ...
|
||||
|
||||
//
|
||||
// Privot Approve ...
|
||||
if (pivotApproved < 1)
|
||||
{
|
||||
pivotApproved = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Loopback ...
|
||||
if (loopback < pivotApproved * 2)
|
||||
{
|
||||
loopback = pivotApproved * 2;
|
||||
}
|
||||
|
||||
// #region Peak/Vale Validation ...
|
||||
UpdateZones(bar);
|
||||
// #endregion
|
||||
|
||||
// #region Peak/Vale Detection ...
|
||||
//
|
||||
// Loop through Loopback ...
|
||||
XOHCL iBar;
|
||||
bool has = false;
|
||||
XBoxZone peakBox;
|
||||
XBoxZone valeBox;
|
||||
bool hasPeak = false;
|
||||
bool hasVale = false;
|
||||
int start = bar.Index();
|
||||
double jLow = EMPTY_VALUE;
|
||||
double jHigh = EMPTY_VALUE;
|
||||
int end = start + loopback;
|
||||
double tmpPrice = EMPTY_VALUE;
|
||||
double tmpZonePrice = EMPTY_VALUE;
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
//
|
||||
iBar.Clean();
|
||||
|
||||
//
|
||||
// Ignore Loop if not pass Pivot Approve Length ...
|
||||
if (i < start + pivotApproved)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize Bar ...
|
||||
has = iBar.Init(
|
||||
bar.symbol,
|
||||
bar.period,
|
||||
i //
|
||||
);
|
||||
if (!has)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
hasPeak = false;
|
||||
hasVale = false;
|
||||
|
||||
//
|
||||
// Loop through Bars for Approved Side ...
|
||||
int jStart = i + 1;
|
||||
int jEnd = i + pivotApproved;
|
||||
for (int j = jStart; j < jEnd; j++)
|
||||
{
|
||||
//
|
||||
// Reading High and Low Prices ...
|
||||
jLow = iLow(iBar.symbol, iBar.period, j);
|
||||
jHigh = iHigh(iBar.symbol, iBar.period, j);
|
||||
|
||||
//
|
||||
hasVale = iBar.low < jLow;
|
||||
hasPeak = iBar.high > jHigh;
|
||||
has = hasVale || hasPeak;
|
||||
if (!has)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check Peak or Vale Exists ...
|
||||
has = hasPeak || hasVale;
|
||||
if (!has)
|
||||
{
|
||||
//
|
||||
iBar.Clean();
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Loop through Barse for Approved Side ...
|
||||
jStart = i - pivotApproved;
|
||||
jEnd = i - 1;
|
||||
for (int j = jStart; j < jEnd; j++)
|
||||
{
|
||||
//
|
||||
// Reading High and Low Prices ...
|
||||
jLow = iLow(iBar.symbol, iBar.period, j);
|
||||
jHigh = iHigh(iBar.symbol, iBar.period, j);
|
||||
|
||||
//
|
||||
if (hasPeak)
|
||||
{
|
||||
hasPeak = iBar.high > jHigh;
|
||||
}
|
||||
|
||||
//
|
||||
if (hasVale)
|
||||
{
|
||||
hasVale = iBar.low < jLow;
|
||||
}
|
||||
|
||||
//
|
||||
has = hasPeak || hasVale;
|
||||
if (!has)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check Peak or Vale Exists ...
|
||||
has = hasPeak || hasVale;
|
||||
if (!has)
|
||||
{
|
||||
//
|
||||
iBar.Clean();
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Peaks ...
|
||||
if (hasPeak)
|
||||
{
|
||||
//
|
||||
// Detect Lower Price ...
|
||||
tmpPrice = EMPTY_VALUE;
|
||||
tmpZonePrice = EMPTY_VALUE;
|
||||
jStart = i - pivotApproved;
|
||||
jEnd = i + pivotApproved;
|
||||
for (int j = jStart; j < jEnd; j++)
|
||||
{
|
||||
//
|
||||
// Detect Max Price of Open/Close ...
|
||||
tmpPrice = MathMax(
|
||||
iClose(iBar.symbol, iBar.period, j),
|
||||
iOpen(iBar.symbol, iBar.period, j) //
|
||||
);
|
||||
|
||||
//
|
||||
tmpZonePrice =
|
||||
NotEmpty(tmpZonePrice)
|
||||
? tmpPrice > tmpZonePrice
|
||||
? tmpPrice
|
||||
: tmpZonePrice
|
||||
: tmpPrice;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize Peak Box ...
|
||||
peakBox.Clean();
|
||||
has = peakBox.Init(
|
||||
iBar.symbol,
|
||||
iBar.period,
|
||||
iBar.high,
|
||||
tmpZonePrice,
|
||||
iBar.time,
|
||||
bar.time,
|
||||
X_DIRECTION_BEARISH,
|
||||
mPivotPrefix //
|
||||
);
|
||||
|
||||
//
|
||||
HandlePeakDetected(peakBox);
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Vales ...
|
||||
if (hasVale)
|
||||
{
|
||||
//
|
||||
// Detect Higher Price ...
|
||||
tmpPrice = EMPTY_VALUE;
|
||||
tmpZonePrice = EMPTY_VALUE;
|
||||
jStart = i - pivotApproved;
|
||||
jEnd = i + pivotApproved;
|
||||
for (int j = jStart; j < jEnd; j++)
|
||||
{
|
||||
//
|
||||
// Detect Max Price of Open/Close ...
|
||||
tmpPrice = MathMin(
|
||||
iClose(iBar.symbol, iBar.period, j),
|
||||
iOpen(iBar.symbol, iBar.period, j) //
|
||||
);
|
||||
|
||||
//
|
||||
tmpZonePrice =
|
||||
NotEmpty(tmpZonePrice)
|
||||
? tmpPrice < tmpZonePrice
|
||||
? tmpPrice
|
||||
: tmpZonePrice
|
||||
: tmpPrice;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize Vale Box ...
|
||||
valeBox.Clean();
|
||||
has = valeBox.Init(
|
||||
iBar.symbol,
|
||||
iBar.period,
|
||||
tmpZonePrice,
|
||||
iBar.low,
|
||||
iBar.time,
|
||||
bar.time,
|
||||
X_DIRECTION_BULLISH,
|
||||
mPivotPrefix //
|
||||
);
|
||||
|
||||
//
|
||||
HandleValeDetected(valeBox);
|
||||
}
|
||||
|
||||
//
|
||||
iBar.Clean();
|
||||
peakBox.Clean();
|
||||
valeBox.Clean();
|
||||
}
|
||||
// #endregion
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// #region Event Listener Registration ...
|
||||
/**
|
||||
* Add Peak Breaked Event Handler
|
||||
*
|
||||
* @param handler: TOnPivotZoneEvent
|
||||
*/
|
||||
void AddOnPeakBreakedHandler(TOnPivotZoneEvent handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(handler, mOnPeakBreakedHandlers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Vale Breaked Event Handler
|
||||
*
|
||||
* @param handler: TOnPivotZoneEvent
|
||||
*/
|
||||
void AddOnValeBreakedHandler(TOnPivotZoneEvent handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(handler, mOnValeBreakedHandlers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Peak Detected Event Handler
|
||||
*
|
||||
* @param handler: TOnPivotZoneEvent
|
||||
*/
|
||||
void AddOnPeakDetectedHandler(TOnPivotZoneEvent handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(handler, mOnPeakDetectedHandlers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Vale Detected Event Handler
|
||||
*
|
||||
* @param handler: TOnPivotZoneEvent
|
||||
*/
|
||||
void AddOnValeDetectedHandler(TOnPivotZoneEvent handler)
|
||||
{
|
||||
//
|
||||
if (handler == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Add(handler, mOnValeDetectedHandlers);
|
||||
}
|
||||
// #endregion
|
||||
|
||||
//
|
||||
protected:
|
||||
/**
|
||||
* Initialize Class ...
|
||||
*/
|
||||
void Initialize()
|
||||
{
|
||||
//
|
||||
Clean(peaks);
|
||||
Clean(vales);
|
||||
|
||||
//
|
||||
Clean(mOnPeakDetectedHandlers);
|
||||
Clean(mOnValeDetectedHandlers);
|
||||
|
||||
//
|
||||
mPivotPrefix = "XSDT";
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Peak Box Detection ...
|
||||
*
|
||||
* @param peakBox: XBoxZone instance ...
|
||||
*/
|
||||
void HandlePeakDetected(
|
||||
XBoxZone &peakBox //
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate ...
|
||||
if (!peakBox.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Update To ...
|
||||
peakBox.to = TimeCurrent();
|
||||
|
||||
//
|
||||
// Check Peak Exists ...
|
||||
bool riseEvent = false;
|
||||
bool hasPeaks = HasChild(peaks);
|
||||
if (!hasPeaks)
|
||||
{
|
||||
//
|
||||
// Add to Peaks ...
|
||||
AddRef(peakBox, peaks);
|
||||
riseEvent = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Validate ...
|
||||
int idx = -1;
|
||||
hasPeaks = FindIndex(
|
||||
idx,
|
||||
peakBox,
|
||||
peaks //
|
||||
);
|
||||
|
||||
//
|
||||
// Only Valid if there is not any Peak Registered ...
|
||||
if (!hasPeaks)
|
||||
{
|
||||
//
|
||||
// Detect Nearest Peak ...
|
||||
idx = GetYoungest(peaks);
|
||||
hasPeaks = IsValidIndex(idx);
|
||||
if (hasPeaks)
|
||||
{
|
||||
//
|
||||
// Validate New Peak based on Youngest One ...
|
||||
hasPeaks = peakBox.upper > peaks[idx].upper;
|
||||
if (hasPeaks)
|
||||
{
|
||||
//
|
||||
AddRef(peakBox, peaks);
|
||||
riseEvent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Event ...
|
||||
if (riseEvent)
|
||||
{
|
||||
NotifyPeakDetected(peakBox);
|
||||
}
|
||||
|
||||
//
|
||||
CleanupPeaks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Vale Box Detection ...
|
||||
*
|
||||
* @param valeBox: XBoxZone instance ...
|
||||
*/
|
||||
void HandleValeDetected(
|
||||
XBoxZone &valeBox //
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate ...
|
||||
if (!valeBox.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Update To ...
|
||||
valeBox.to = TimeCurrent();
|
||||
|
||||
//
|
||||
bool riseEvent = false;
|
||||
bool hasVales = HasChild(vales);
|
||||
if (!hasVales)
|
||||
{
|
||||
//
|
||||
// Add to Vales ...
|
||||
AddRef(valeBox, vales);
|
||||
riseEvent = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Validate ...
|
||||
int idx = -1;
|
||||
hasVales = FindIndex(
|
||||
idx,
|
||||
valeBox,
|
||||
vales //
|
||||
);
|
||||
|
||||
//
|
||||
// Only Valid if there is not any Vale Registered ...
|
||||
if (!hasVales)
|
||||
{
|
||||
//
|
||||
// Detect Nearest Vale ...
|
||||
idx = GetYoungest(vales);
|
||||
hasVales = IsValidIndex(idx);
|
||||
if (hasVales)
|
||||
{
|
||||
//
|
||||
// Validate New Vale based on Youngest One ...
|
||||
hasVales = valeBox.lower < vales[idx].lower;
|
||||
if (hasVales)
|
||||
{
|
||||
//
|
||||
AddRef(valeBox, vales);
|
||||
riseEvent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Event ...
|
||||
if (riseEvent)
|
||||
{
|
||||
NotifyValeDetected(valeBox);
|
||||
}
|
||||
|
||||
//
|
||||
CleanupVales();
|
||||
}
|
||||
|
||||
// #region Event Notifiers ...
|
||||
/**
|
||||
* Notfiy New Peak Breaked ...
|
||||
*
|
||||
* @param box: XBoxZone instance ...
|
||||
*/
|
||||
void NotifyPeakBreaked(XBoxZone &box)
|
||||
{
|
||||
//
|
||||
// Validate ...
|
||||
if (!box.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Log ...
|
||||
if (alert != NULL)
|
||||
{
|
||||
//
|
||||
// Preparing Log Message ...
|
||||
string message = "Peak Breaked: " + DoubleToString(box.upper, 4) +
|
||||
" at " + TimeToString(TimeCurrent(), TIME_DATE | TIME_SECONDS);
|
||||
|
||||
//
|
||||
// Sending Alert ...
|
||||
alert.SendAlert(message);
|
||||
}
|
||||
|
||||
//
|
||||
// Multiple Handlers ...
|
||||
int count = ArraySize(mOnPeakBreakedHandlers);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
mOnPeakBreakedHandlers[i](box);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notfiy New Vale Breaked ...
|
||||
*
|
||||
* @param box: XBoxZone instance ...
|
||||
*/
|
||||
void NotifyValeBreaked(XBoxZone &box)
|
||||
{
|
||||
//
|
||||
// Validate ...
|
||||
if (!box.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Log ...
|
||||
if (alert != NULL)
|
||||
{
|
||||
//
|
||||
// Preparing Log Message ...
|
||||
string message = "Vale Breaked: " + DoubleToString(box.lower, 4) +
|
||||
" at " + TimeToString(TimeCurrent(), TIME_DATE | TIME_SECONDS);
|
||||
|
||||
//
|
||||
// Sending Alert ...
|
||||
alert.SendAlert(message);
|
||||
}
|
||||
|
||||
//
|
||||
// Multiple Handlers ...
|
||||
int count = ArraySize(mOnValeBreakedHandlers);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
mOnValeBreakedHandlers[i](box);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notfiy New Peak Detected ...
|
||||
*
|
||||
* @param box: XBoxZone instance ...
|
||||
*/
|
||||
void NotifyPeakDetected(XBoxZone &box)
|
||||
{
|
||||
//
|
||||
// Validate ...
|
||||
if (!box.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Log ...
|
||||
if (alert != NULL)
|
||||
{
|
||||
//
|
||||
// Preparing Log Message ...
|
||||
string message = "Peak Detected: " + DoubleToString(box.upper, 4) +
|
||||
" at " + TimeToString(box.from, TIME_DATE | TIME_SECONDS);
|
||||
|
||||
//
|
||||
// Sending Alert ...
|
||||
alert.SendAlert(message);
|
||||
}
|
||||
|
||||
//
|
||||
// Multiple Handlers ...
|
||||
int count = ArraySize(mOnPeakDetectedHandlers);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
mOnPeakDetectedHandlers[i](box);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notfiy New Vale Detected ...
|
||||
*
|
||||
* @param box: XBoxZone instance ...
|
||||
*/
|
||||
void NotifyValeDetected(XBoxZone &box)
|
||||
{
|
||||
//
|
||||
// Validate ...
|
||||
if (!box.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Handle Log ...
|
||||
if (alert != NULL)
|
||||
{
|
||||
//
|
||||
// Preparing Log Message ...
|
||||
string message = "Vale Detected: " + DoubleToString(box.lower, 4) +
|
||||
" at " + TimeToString(box.from, TIME_DATE | TIME_SECONDS);
|
||||
|
||||
//
|
||||
// Sending Alert ...
|
||||
alert.SendAlert(message);
|
||||
}
|
||||
|
||||
//
|
||||
// Multiple Handlers ...
|
||||
int count = ArraySize(mOnValeDetectedHandlers);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
mOnValeDetectedHandlers[i](box);
|
||||
}
|
||||
}
|
||||
// #endregion
|
||||
|
||||
//
|
||||
private:
|
||||
//
|
||||
// Props ...
|
||||
string mPivotPrefix; // Prefix ...
|
||||
int mMaxAllowedProcessableZones; // Max Allowed Processable Zones ...
|
||||
|
||||
/**
|
||||
* Handle Apply Max Allowed Processable Peaks ...
|
||||
*/
|
||||
void CleanupPeaks()
|
||||
{
|
||||
//
|
||||
if (ArraySize(peaks) <= mMaxAllowedProcessableZones)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Sort(
|
||||
peaks, // Collection to Sort ...
|
||||
X_SORT_BY_DATE, // Sorted By ...
|
||||
X_DIRECTION_BEARISH, // Direction of Sorting ...
|
||||
mMaxAllowedProcessableZones // Max Allowed ...
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Apply Max Allowed Processable Vales ...
|
||||
*/
|
||||
void CleanupVales()
|
||||
{
|
||||
//
|
||||
if (ArraySize(vales) <= mMaxAllowedProcessableZones)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
Sort(
|
||||
vales, // Collection to Sort ...
|
||||
X_SORT_BY_DATE, // Sorted By ...
|
||||
X_DIRECTION_BEARISH, // Direction of Sorting ...
|
||||
mMaxAllowedProcessableZones // Max Allowed ...
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* if there is Zones in Peaks or Vales
|
||||
* Update their To Times ...
|
||||
*
|
||||
* @param bar: XOHCL instance ...
|
||||
**/
|
||||
void UpdateZones(XOHCL &bar)
|
||||
{
|
||||
//
|
||||
// Check Bar is Valid ...
|
||||
if (bar.IsValid())
|
||||
{
|
||||
//
|
||||
// Retrieve Last Closed Bar if not Provided ...
|
||||
XOHCL cBar;
|
||||
if (bar.Index() == 1)
|
||||
{
|
||||
cBar = bar;
|
||||
}
|
||||
else
|
||||
{
|
||||
cBar.Init(bar.symbol, bar.period, 1);
|
||||
}
|
||||
|
||||
//
|
||||
// Validate CBar ...
|
||||
// Validate Peaks and Vales ...
|
||||
if (cBar.IsValid())
|
||||
{
|
||||
//
|
||||
int removeIDX[];
|
||||
|
||||
//
|
||||
if (HasChild(peaks))
|
||||
{
|
||||
//
|
||||
Clean(removeIDX);
|
||||
for (int i = 0; i < ArraySize(peaks); i++)
|
||||
{
|
||||
//
|
||||
// Validate Zone by Close Price ...
|
||||
if (cBar.close > peaks[i].upper)
|
||||
{
|
||||
//
|
||||
Add(i, removeIDX);
|
||||
NotifyPeakBreaked(peaks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
if (HasChild(removeIDX))
|
||||
{
|
||||
CleanupArray(removeIDX, peaks);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
if (HasChild(vales))
|
||||
{
|
||||
//
|
||||
Clean(removeIDX);
|
||||
for (int i = 0; i < ArraySize(vales); i++)
|
||||
{
|
||||
//
|
||||
// Validate Zone by Close Price ...
|
||||
if (cBar.close < vales[i].lower)
|
||||
{
|
||||
//
|
||||
Add(i, removeIDX);
|
||||
NotifyValeBreaked(vales[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
if (HasChild(removeIDX))
|
||||
{
|
||||
CleanupArray(removeIDX, vales);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
cBar.Clean();
|
||||
}
|
||||
|
||||
//
|
||||
datetime tc = TimeCurrent();
|
||||
|
||||
//
|
||||
bool has = HasChild(peaks);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < ArraySize(peaks); i++)
|
||||
{
|
||||
peaks[i].to = tc;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
has = HasChild(vales);
|
||||
if (has)
|
||||
{
|
||||
//
|
||||
for (int i = 0; i < ArraySize(vales); i++)
|
||||
{
|
||||
vales[i].to = tc;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
CleanupPeaks();
|
||||
CleanupVales();
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
Reference in New Issue
Block a user