642 lines
12 KiB
Plaintext
642 lines
12 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class Library
|
|
// ----------------------------------------------
|
|
// Name: XSCZone
|
|
// Description: provides all Alerts requirements ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
#include <Arrays/ArrayObj.mqh>
|
|
#include <ChartObjects/ChartObjectsShapes.mqh>
|
|
#include "../Classes/x-saherelm.base.class.mq5"
|
|
#include <ChartObjects/ChartObjectsTxtControls.mqh>
|
|
|
|
//
|
|
// Definitions ...
|
|
#define defZoneBGColor clrLightGray
|
|
#define defZoneLBLColor clrWhite
|
|
|
|
//
|
|
// All Required Inputs ...
|
|
struct XSCZonesInput
|
|
{
|
|
//
|
|
int length; // Calculation Length
|
|
int numberOfZones; // Number of Zones
|
|
|
|
//
|
|
double levels[]; // Levels Percentage
|
|
color colors[]; // level Colors
|
|
|
|
//
|
|
// Constructor ...
|
|
void XSCZonesInput()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
length = 0;
|
|
numberOfZones = 0;
|
|
|
|
//
|
|
Clean(levels);
|
|
Clean(colors);
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
length >= 5 &&
|
|
numberOfZones >= 2
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Add Specified Level/Color ...
|
|
void AddLevelColor(
|
|
double level,
|
|
color clr //
|
|
)
|
|
{
|
|
//
|
|
Add(
|
|
level,
|
|
levels);
|
|
|
|
//
|
|
Add(
|
|
clr,
|
|
colors //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Retrieve Sort Indexed Levels Color ...
|
|
void RetrieveSortedLevels(
|
|
double &_levels[],
|
|
color &_colors[] //
|
|
)
|
|
{
|
|
//
|
|
Clean(_levels);
|
|
Clean(_colors);
|
|
|
|
//
|
|
int levelsCount = ArraySize(levels);
|
|
int colorsCount = ArraySize(colors);
|
|
|
|
//
|
|
bool hasChild = IsValidSize(levelsCount) &&
|
|
IsValidSize(colorsCount);
|
|
if (!hasChild)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Create Temp Levels ...
|
|
double tmpLevels[];
|
|
Copy(
|
|
levels,
|
|
tmpLevels //
|
|
);
|
|
ArraySort(tmpLevels);
|
|
|
|
//
|
|
// Size of Looping ...
|
|
int minSize = MathMin(levelsCount, colorsCount);
|
|
|
|
//
|
|
for (int i = 0; i < minSize; i++)
|
|
{
|
|
//
|
|
double iLevel = tmpLevels[i];
|
|
|
|
//
|
|
int iLevelIDX = FindIndex(
|
|
iLevel,
|
|
levels //
|
|
);
|
|
if (!IsValidIndex(iLevelIDX))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
Add(
|
|
levels[iLevelIDX],
|
|
_levels //
|
|
);
|
|
|
|
//
|
|
Add(
|
|
colors[iLevelIDX],
|
|
_colors //
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
//
|
|
// Class ...
|
|
|
|
//
|
|
// Specific Zone ...
|
|
class XSCZone : public CObject
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
double high;
|
|
double low;
|
|
int ticks;
|
|
|
|
//
|
|
// Compare Two Zone With Each Other ...
|
|
virtual int Compare(
|
|
const CObject *node,
|
|
const int mode = 0 //
|
|
) const
|
|
{
|
|
//
|
|
const XSCZone *other = (XSCZone *)node;
|
|
|
|
//
|
|
return other.ticks - ticks;
|
|
}
|
|
|
|
//
|
|
// Create Object ...
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Private ...
|
|
private:
|
|
};
|
|
|
|
//
|
|
// Zones ...
|
|
|
|
//
|
|
class XSCZones : public XSCBase
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Constructor(s) ...
|
|
void XSCZones(
|
|
string symbol,
|
|
ENUM_TIMEFRAMES period //
|
|
) : XSCBase()
|
|
{
|
|
//
|
|
this.mSymbol = symbol;
|
|
this.mPeriod = period;
|
|
}
|
|
|
|
//
|
|
void ~XSCZones()
|
|
{
|
|
//
|
|
mZones.Clear();
|
|
mChartObjects.Clear();
|
|
}
|
|
|
|
//
|
|
// Initialize Zones by Providing required
|
|
// Input Variables ...
|
|
bool Init(
|
|
XSCZonesInput &inputs // Inputs ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Inputs ...
|
|
result = inputs.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Set Inputs ...
|
|
mInputs = inputs;
|
|
|
|
//
|
|
// Do Calculatins ...
|
|
Calculate();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XSCZonesInput GetInputs()
|
|
{
|
|
return mInputs;
|
|
}
|
|
|
|
//
|
|
bool SetInputs(XSCZonesInput &inputs)
|
|
{
|
|
return Init(inputs);
|
|
}
|
|
|
|
//
|
|
void Calculate()
|
|
{
|
|
//
|
|
// Prevent Double Calculating ...
|
|
int bars = iBars(
|
|
mSymbol,
|
|
mPeriod //
|
|
);
|
|
if (mCalculatedBars == bars)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
mCalculatedBars = bars;
|
|
|
|
//
|
|
// Calculate Start and End Time ...
|
|
|
|
//
|
|
mStartTime = iTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
mInputs.length + 1 //
|
|
);
|
|
|
|
//
|
|
mEndTime = iTime(
|
|
mSymbol,
|
|
mPeriod,
|
|
0 //
|
|
);
|
|
|
|
//
|
|
// Retrieve Ticks between Times ...
|
|
Clean(mTicks);
|
|
CopyTicksRange(
|
|
mSymbol,
|
|
mTicks,
|
|
COPY_TICKS_ALL,
|
|
mStartTime * 1000,
|
|
mEndTime * 1000 //
|
|
);
|
|
|
|
//
|
|
// Retrieve Highs ...
|
|
Clean(mHighs);
|
|
CopyHigh(
|
|
mSymbol,
|
|
mPeriod,
|
|
mStartTime,
|
|
mEndTime,
|
|
mHighs //
|
|
);
|
|
|
|
//
|
|
// Find Highest Value in Range ...
|
|
mRangeHigh = mHighs[ArrayMaximum(mHighs)];
|
|
|
|
//
|
|
// Retrieve Lows ...
|
|
Clean(mLows);
|
|
CopyLow(
|
|
mSymbol,
|
|
mPeriod,
|
|
mStartTime,
|
|
mEndTime,
|
|
mLows //
|
|
);
|
|
|
|
//
|
|
// Find Lowest Value in Range ...
|
|
mRangeLow = mLows[ArrayMaximum(mLows)];
|
|
|
|
//
|
|
double mRangeSize = GetRange();
|
|
|
|
//
|
|
// Prepare Zones Array ...
|
|
mZones.Clear();
|
|
|
|
//
|
|
// Create Zones ...
|
|
for (int i = 0; i < mInputs.numberOfZones; i++)
|
|
{
|
|
//
|
|
// Instance a New Zone ...
|
|
XSCZone *iZone = new XSCZone();
|
|
|
|
//
|
|
// Calculate Each Zones High / Low based on Range ...
|
|
double iH = mRangeHigh - mRangeSize * i / mInputs.numberOfZones;
|
|
double iL = mRangeHigh - mRangeSize * (i + 1) / mInputs.numberOfZones;
|
|
|
|
//
|
|
// Set Zone High Low Properties ...
|
|
iZone.low = iL;
|
|
iZone.high = iH;
|
|
|
|
//
|
|
// Add Zone to Zone Array Objects ...
|
|
mZones.Add(iZone);
|
|
}
|
|
|
|
//
|
|
// Calculate Each Zone Ticks ...
|
|
int mTicksCount = CountTicks();
|
|
for (int i = 0; i < mTicksCount; i++)
|
|
{
|
|
//
|
|
// Retrieve i Index Tick Object ...
|
|
MqlTick iTick = mTicks[i];
|
|
|
|
//
|
|
// Loop Through Zones ...
|
|
for (int j = 0; j < mZones.Total(); j++)
|
|
{
|
|
//
|
|
// Retrieve j Index Zone Object ...
|
|
XSCZone *jZone = mZones.At(j);
|
|
|
|
//
|
|
bool isInRange = IsTickInZoneRange(
|
|
iTick,
|
|
jZone //
|
|
);
|
|
if (isInRange)
|
|
{
|
|
//
|
|
jZone.ticks++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
mZones.Sort();
|
|
}
|
|
|
|
//
|
|
XSCZone *GetZone(int index)
|
|
{
|
|
return mZones.At(index);
|
|
}
|
|
|
|
//
|
|
double CalculateZoneTickPercent(
|
|
XSCZone *zone,
|
|
int normalizationDigits = 2 //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (normalizationDigits < 2 || normalizationDigits > 5)
|
|
{
|
|
normalizationDigits = 2;
|
|
}
|
|
|
|
//
|
|
result = (double)zone.ticks / CountTicks() * 100;
|
|
result = NormalizeDouble(result, normalizationDigits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool DrawZones(
|
|
long chartId = 0,
|
|
string prefix = "XSCZone",
|
|
int subWindow = 0,
|
|
bool redraw = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (redraw)
|
|
{
|
|
mChartObjects.Clear();
|
|
}
|
|
|
|
//
|
|
if (StringLen(prefix) <= 0)
|
|
{
|
|
prefix = "XSCZone";
|
|
}
|
|
|
|
//
|
|
int zonesCount = mZones.Total();
|
|
result = IsValidSize(zonesCount);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double levels[];
|
|
color colors[];
|
|
mInputs.RetrieveSortedLevels(
|
|
levels,
|
|
colors);
|
|
int levelsCount = ArraySize(levels);
|
|
int colorsCount = ArraySize(colors);
|
|
bool canSetLevels = IsValidSize(levelsCount) &&
|
|
IsValidSize(colorsCount) &&
|
|
levelsCount == colorsCount;
|
|
|
|
//
|
|
// Loop Through Zones ...
|
|
for (int i = 0; i < zonesCount; i++)
|
|
{
|
|
//
|
|
XSCZone *iZone = mZones.At(i);
|
|
|
|
//
|
|
// Generate Chart Object Names ...
|
|
string iRectName = prefix + ToString(i);
|
|
string iLabelName = iRectName + "_lbl";
|
|
|
|
//
|
|
// Creating Rectangles ...
|
|
CChartObjectRectangle *iRect = new CChartObjectRectangle();
|
|
result = iRect.Create(
|
|
chartId,
|
|
iRectName,
|
|
subWindow,
|
|
mStartTime,
|
|
iZone.high,
|
|
mEndTime,
|
|
iZone.low //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set Default Rectangle Color ...
|
|
iRect.Color(defZoneBGColor);
|
|
iRect.Fill(true);
|
|
|
|
//
|
|
// Create Label ...
|
|
CChartObjectLabel *iLabel = new CChartObjectLabel();
|
|
result = iLabel.Create(
|
|
chartId,
|
|
iLabelName,
|
|
subWindow,
|
|
mStartTime,
|
|
iZone.high //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
iLabel.Color(defZoneLBLColor);
|
|
|
|
//
|
|
double iPercentage = CalculateZoneTickPercent(iZone);
|
|
iLabel.Description(ToString(iPercentage) + "%");
|
|
|
|
//
|
|
// Set Levels and Colors if Provided ...
|
|
if (canSetLevels) {
|
|
|
|
}
|
|
|
|
//
|
|
mChartObjects.Add(iRect);
|
|
mChartObjects.Add(iLabel);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
datetime mStartTime;
|
|
datetime mEndTime;
|
|
|
|
//
|
|
MqlTick mTicks[];
|
|
double mHighs[];
|
|
double mLows[];
|
|
double mRangeHigh;
|
|
double mRangeLow;
|
|
|
|
//
|
|
CArrayObj mZones;
|
|
CArrayObj mChartObjects;
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
int CountTicks()
|
|
{
|
|
return ArraySize(mTicks);
|
|
}
|
|
|
|
//
|
|
double GetRange()
|
|
{
|
|
return mRangeHigh - mRangeLow;
|
|
}
|
|
|
|
//
|
|
// Check a Tick is in a Zone rage or not ...
|
|
bool IsTickInZoneRange(
|
|
MqlTick &tick, // Tick For Checking
|
|
XSCZone *zone // Zone For Checking
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
tick.bid >= zone.low &&
|
|
tick.bid <= zone.high
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
string mSymbol; // Analyzing Symbol
|
|
ENUM_TIMEFRAMES mPeriod; // Analyzing Period
|
|
|
|
//
|
|
XSCZonesInput mInputs; // Configurations
|
|
|
|
//
|
|
int mCalculatedBars; // Calculated Bars ...
|
|
}; |