/////////////////////////////////////////////////////// // // 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 #include #include "../Classes/x-saherelm.base.class.mq5" #include "../Libraries/x-saherelm.draw.lib.mq5" #include // // 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); ArrayReverse(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; double percent; // // 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 ... int highIDX = ArrayMaximum(mHighs); mRangeHigh = mHighs[highIDX]; // // Retrieve Lows ... Clean(mLows); CopyLow( mSymbol, mPeriod, mStartTime, mEndTime, mLows // ); // // Find Lowest Value in Range ... int lowIDX = ArrayMinimum(mLows); mRangeLow = mLows[lowIDX]; // datetime mTimes[]; CopyTime( mSymbol, mPeriod, mStartTime, mEndTime, mTimes // ); mRangeHighTime = mTimes[highIDX]; mRangeLowTime = mTimes[lowIDX]; // 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; } } } // // Calculating Zone Percents ... for (int i = 0; i < mZones.Total(); i++) { // XSCZone *iZone = mZones.At(i); // double percent = CalculateZoneTickPercent(iZone); iZone.percent = percent; } // mZones.Sort(); } // int CountZones() { return mZones.Total(); } // 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; } // mZones.Sort(); // int ticksCount = CountTicks(); result = IsValidSize(ticksCount); 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); // iLabel.Description(ToString(iZone.percent) + "%"); // // Set Levels and Colors if Provided ... if (canSetLevels) { // color iRectColor = defZoneBGColor; for (int z = 0; z < levelsCount; z++) { // double zLevel = levels[z]; color zColor = colors[z]; // if (iZone.ticks >= ticksCount * zLevel) { // iRectColor = zColor; break; } } // iRect.Color(iRectColor); } // mChartObjects.Add(iRect); mChartObjects.Add(iLabel); } // return result; } // // Protected ... protected: // // Props ... // datetime mStartTime; datetime mEndTime; // MqlTick mTicks[]; double mHighs[]; double mLows[]; double mRangeHigh; datetime mRangeHighTime; double mRangeLow; datetime mRangeLowTime; // 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 ... };