diff --git a/Documents/BKP/cuvdelta.mq5 b/Documents/BKP/cuvdelta.mq5 new file mode 100644 index 00000000..92d26fbc --- /dev/null +++ b/Documents/BKP/cuvdelta.mq5 @@ -0,0 +1,135 @@ +//+------------------------------------------------------------------+ +//| CumulativeDelta.mq5 | +//| Copyright © 2023, YourName | +//| | +//+------------------------------------------------------------------+ +#property copyright "YourName" +#property link "https://www.yourwebsite.com" +#property version "1.00" + +// +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +#property indicator_separate_window +#property indicator_buffers 3 +#property indicator_plots 3 + +// +//--- Plot settings for Line +#property indicator_label1 "Cumulative Delta" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrYellow + +// +//--- Plot settings for Histogram +#property indicator_label2 "Delta" +#property indicator_type2 DRAW_HISTOGRAM +#property indicator_color2 clrGray + +// +//--- Plot settings for Moving Average line +#property indicator_label3 "Signal" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrOrchid + +// +//--- Input parameters +input int MAPeriod = 14; // Period for the moving average + +// +//--- Indicator buffers +double MABuffer[]; +double DeltaBuffer[]; +double CumulativeDeltaBuffer[]; + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // + // Attach buffer to the indicator + SetIndexBuffer(2, MABuffer, INDICATOR_DATA); + SetIndexBuffer(1, DeltaBuffer, INDICATOR_DATA); + SetIndexBuffer(0, CumulativeDeltaBuffer, INDICATOR_DATA); + IndicatorSetString(INDICATOR_SHORTNAME, "Cumulative Delta"); + + // + return (INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Start from the first uncalculated bar + int start = MathMax(prev_calculated - 1, 0); + + // + // Loop through bars + for (int i = start; i < rates_total; i++) + { + // + // Calculate Delta based on bar-level data + double delta = 0.0; + if (close[i] > open[i]) + { + delta = (double)tick_volume[i]; // Buying pressure (bullish bar) + } + else if (close[i] < open[i]) + { + delta = -(double)tick_volume[i]; // Selling pressure (bearish bar) + } + + // + // Accumulate cumulative delta + if (i == 0) + { + // + DeltaBuffer[i] = delta; + CumulativeDeltaBuffer[i] = delta; // First bar starts with delta + } + else + { + // + DeltaBuffer[i] = DeltaBuffer[i - 1] + delta; + CumulativeDeltaBuffer[i] = CumulativeDeltaBuffer[i - 1] + delta; + } + + // + // Calculate Moving Average of Cumulative Delta + if (i >= MAPeriod - 1) + { + // + double sum = 0.0; + for (int j = 0; j < MAPeriod; j++) + { + sum += CumulativeDeltaBuffer[i - j]; + } + + // + MABuffer[i] = sum / MAPeriod; // Simple Moving Average + } + else + { + MABuffer[i] = EMPTY_VALUE; // Not enough data for MA + } + } + + // + return (rates_total); +} +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/Documents/BKP/volume.mq5 b/Documents/BKP/volume.mq5 new file mode 100644 index 00000000..588abc91 --- /dev/null +++ b/Documents/BKP/volume.mq5 @@ -0,0 +1,210 @@ +//+------------------------------------------------------------------+ +//| BuySellVolumes.mq5 | +//| Copyright © 2023, YourName | +//| | +//+------------------------------------------------------------------+ +#property copyright "YourName" +#property link "https://www.yourwebsite.com" +#property version "1.00" + +// +#property indicator_separate_window +#property indicator_buffers 4 +#property indicator_plots 4 + +//--- Plot settings for Buy Volume +#property indicator_label1 "Buy Volume" +#property indicator_type1 DRAW_HISTOGRAM +#property indicator_color1 clrLime + +//--- Plot settings for Sell Volume +#property indicator_label2 "Sell Volume" +#property indicator_type2 DRAW_HISTOGRAM +#property indicator_color2 clrRed + +//--- Plot settings for Buy Volume MA +#property indicator_label3 "Buy Volume MA" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrGreen + +//--- Plot settings for Sell Volume MA +#property indicator_label4 "Sell Volume MA" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrRed + +//--- Input parameters +input int MAPeriod = 14; // Period for the moving average + +//--- Indicator buffers +double BuyVolumeBuffer[]; // Buffer for Buy Volume +double SellVolumeBuffer[]; // Buffer for Sell Volume +double BuyVolumeMABuffer[]; // Buffer for Buy Volume Moving Average +double SellVolumeMABuffer[]; // Buffer for Sell Volume Moving Average + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + // + // Attach buffers to the indicator + SetIndexBuffer(0, BuyVolumeBuffer, INDICATOR_DATA); + SetIndexBuffer(1, SellVolumeBuffer, INDICATOR_DATA); + SetIndexBuffer(2, BuyVolumeMABuffer, INDICATOR_DATA); + SetIndexBuffer(3, SellVolumeMABuffer, INDICATOR_DATA); + + // + // Set short name for the indicator + IndicatorSetString(INDICATOR_SHORTNAME, "Buy and Sell Volumes"); + + // + return (INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Start from the first uncalculated bar + int start = MathMax(prev_calculated - 1, 0); + + // + // Loop through bars + for (int i = start; i < rates_total; i++) + { + // + // Calculate Buy and Sell Volumes based on bar-level data + double buyVolume = 0.0; + double sellVolume = 0.0; + + // + if (close[i] > open[i]) + { + // + buyVolume = (double)tick_volume[i]; // Buying pressure (bullish bar) + sellVolume = 0.0; + } + else if (close[i] < open[i]) + { + // + sellVolume = (double)tick_volume[i]; // Selling pressure (bearish bar) + buyVolume = 0.0; + } + else + { + // + // Neutral bar: split volume equally between buy and sell + buyVolume = tick_volume[i] / 2.0; + sellVolume = tick_volume[i] / 2.0; + } + + // + // Store Buy and Sell Volumes in their respective buffers + BuyVolumeBuffer[i] = buyVolume; + SellVolumeBuffer[i] = sellVolume; + + // + // Calculate Moving Averages for Buy and Sell Volumes + if (i >= MAPeriod - 1) + { + // + // Calculate Simple Moving Average for Buy Volume + double buySum = 0.0; + for (int j = 0; j < MAPeriod; j++) + buySum += BuyVolumeBuffer[i - j]; + BuyVolumeMABuffer[i] = buySum / MAPeriod; + + // + // Calculate Simple Moving Average for Sell Volume + double sellSum = 0.0; + for (int j = 0; j < MAPeriod; j++) + sellSum += SellVolumeBuffer[i - j]; + SellVolumeMABuffer[i] = sellSum / MAPeriod; + } + else + { + // + // Not enough data for MA + BuyVolumeMABuffer[i] = EMPTY_VALUE; + SellVolumeMABuffer[i] = EMPTY_VALUE; + } + } + + // + // Normalize all values between 0 and 100 + // NormalizeValues(rates_total); + + // + return (rates_total); +} + +//+------------------------------------------------------------------+ +//| Normalize all values between 0 and 100 | +//+------------------------------------------------------------------+ +void NormalizeValues(int rates_total) +{ + // + // Find the maximum and minimum values across all buffers + double maxValue = 0.0; + double minValue = DBL_MAX; + + // + for (int i = 0; i < rates_total; i++) + { + // + if (BuyVolumeBuffer[i] != EMPTY_VALUE && BuyVolumeBuffer[i] > maxValue) + maxValue = BuyVolumeBuffer[i]; + if (SellVolumeBuffer[i] != EMPTY_VALUE && SellVolumeBuffer[i] > maxValue) + maxValue = SellVolumeBuffer[i]; + if (BuyVolumeMABuffer[i] != EMPTY_VALUE && BuyVolumeMABuffer[i] > maxValue) + maxValue = BuyVolumeMABuffer[i]; + if (SellVolumeMABuffer[i] != EMPTY_VALUE && SellVolumeMABuffer[i] > maxValue) + maxValue = SellVolumeMABuffer[i]; + + // + if (BuyVolumeBuffer[i] != EMPTY_VALUE && BuyVolumeBuffer[i] < minValue) + minValue = BuyVolumeBuffer[i]; + if (SellVolumeBuffer[i] != EMPTY_VALUE && SellVolumeBuffer[i] < minValue) + minValue = SellVolumeBuffer[i]; + if (BuyVolumeMABuffer[i] != EMPTY_VALUE && BuyVolumeMABuffer[i] < minValue) + minValue = BuyVolumeMABuffer[i]; + if (SellVolumeMABuffer[i] != EMPTY_VALUE && SellVolumeMABuffer[i] < minValue) + minValue = SellVolumeMABuffer[i]; + } + + // + // Avoid division by zero + if (maxValue == minValue) + return; + + // + // Normalize all values + for (int i = 0; i < rates_total; i++) + { + // + if (BuyVolumeBuffer[i] != EMPTY_VALUE) + BuyVolumeBuffer[i] = ((BuyVolumeBuffer[i] - minValue) / (maxValue - minValue)) * 100.0; + + if (SellVolumeBuffer[i] != EMPTY_VALUE) + SellVolumeBuffer[i] = ((SellVolumeBuffer[i] - minValue) / (maxValue - minValue)) * 100.0; + + if (BuyVolumeMABuffer[i] != EMPTY_VALUE) + BuyVolumeMABuffer[i] = ((BuyVolumeMABuffer[i] - minValue) / (maxValue - minValue)) * 100.0; + + if (SellVolumeMABuffer[i] != EMPTY_VALUE) + SellVolumeMABuffer[i] = ((SellVolumeMABuffer[i] - minValue) / (maxValue - minValue)) * 100.0; + } +} +//+------------------------------------------------------------------+ diff --git a/Documents/BKP/x-121.smc.market.cycle.helper.class.mq5 b/Documents/BKP/x-121.smc.market.cycle.helper.class.mq5 index 810bc744..e3e96a05 100644 --- a/Documents/BKP/x-121.smc.market.cycle.helper.class.mq5 +++ b/Documents/BKP/x-121.smc.market.cycle.helper.class.mq5 @@ -825,7 +825,7 @@ class XC121SMCCycleHelper : public XCBase } // - datetime GetNearestCloseOverX3MAFast( + datetime DetectNearestCloseOverX3MAFast( XOHCL &bar, int maxAllowedBars = 20 // ) @@ -891,7 +891,7 @@ class XC121SMCCycleHelper : public XCBase } // - datetime GetNearestCloseUnderX3MAFast( + datetime DetectNearestCloseUnderX3MAFast( XOHCL &bar, int maxAllowedBars = 20 // ) diff --git a/Indicators/x-saherelm.x121.x-delta.mq5 b/Indicators/x-saherelm.x121.x-delta.mq5 new file mode 100644 index 00000000..ec4031cc --- /dev/null +++ b/Indicators/x-saherelm.x121.x-delta.mq5 @@ -0,0 +1,521 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Ocillator +// ------------------------------------------------- +// Name: X121 XDelta +// Description: Detect Comulative Volumes Delta ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XDelta Ocillator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121_XDELTA" + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Makret ... +input group "Market"; +input int maLength = 14; // Moving Averge Length +input ENUM_X_MA_METHOD maMethod = X_MA_MODE_EMA; // Moving Averge Method + +// +// Presentation ... +input group "Presentation"; +input int startCalculationForLastBars = 1000; // Calculate Last n Bars +input bool showDeltaLine = true; // Show Delta Line +input bool showDeltaHistogram = true; // Show Delta Histogram +input bool showDeltaMa = true; // Show Delta Moving Average + +// +// Buffers Props ... + +// +#property indicator_separate_window + +// +#property indicator_buffers 5 +#property indicator_plots 3 + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 + +// +// Buffers ... + +// +#define deltaLineBufferIndex 0 +double deltaLineBuffer[]; + +#property indicator_label1 "Delta Line" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrYellow +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +// +#define deltaHistogramBufferIndex 1 +double deltaHistogramBuffer[]; + +// +#define deltaHistogramColorBufferIndex 2 +double deltaHistogramColorBuffer[]; + +#property indicator_label2 "Delta Histogram" +#property indicator_type2 DRAW_COLOR_HISTOGRAM +#property indicator_color2 CLR_NONE, clrGreen, clrDarkRed +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +// +#define deltaMaBufferIndex 3 +double deltaMaBuffer[]; + +#property indicator_label3 "Delta MA" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrOrchid +#property indicator_style3 STYLE_SOLID +#property indicator_width3 1 + +// +// Data Buffers ... + +#define mLastBufferIndex 3 + +// +#define rawDeltaBufferIndex mLastBufferIndex + 1 +double rawDeltaBuffer[]; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + IndicatorSetInteger(INDICATOR_DIGITS, 2); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + // + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = maLength > 0 && + IsValid(maMethod); + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(0, maLength); + + // + return result; +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // Delta Line ... + ENUM_DRAW_TYPE deltaLineDrawType = showDeltaLine ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(deltaLineBuffer, true); + SetIndexBuffer(deltaLineBufferIndex, deltaLineBuffer, INDICATOR_DATA); + PlotIndexSetDouble(deltaLineBufferIndex, PLOT_EMPTY_VALUE, 0.0); + PlotIndexSetInteger(deltaLineBufferIndex, PLOT_SHOW_DATA, showDeltaLine); + PlotIndexSetInteger(deltaLineBufferIndex, PLOT_DRAW_TYPE, deltaLineDrawType); + + // + // Delta Histogram ... + ENUM_DRAW_TYPE deltaHistogramDrawType = showDeltaHistogram ? DRAW_COLOR_HISTOGRAM : DRAW_NONE; + + // + ArraySetAsSeries(deltaHistogramBuffer, true); + SetIndexBuffer(deltaHistogramBufferIndex, deltaHistogramBuffer, INDICATOR_DATA); + PlotIndexSetDouble(deltaHistogramBufferIndex, PLOT_EMPTY_VALUE, 0.0); + PlotIndexSetInteger(deltaHistogramBufferIndex, PLOT_SHOW_DATA, showDeltaHistogram); + PlotIndexSetInteger(deltaHistogramBufferIndex, PLOT_DRAW_TYPE, deltaHistogramDrawType); + + // + ArraySetAsSeries(deltaHistogramColorBuffer, true); + SetIndexBuffer(deltaHistogramColorBufferIndex, deltaHistogramColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Delta Ma ... + ENUM_DRAW_TYPE deltaMaDrawType = showDeltaMa ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(deltaMaBuffer, true); + SetIndexBuffer(deltaMaBufferIndex, deltaMaBuffer, INDICATOR_DATA); + PlotIndexSetDouble(deltaMaBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(deltaMaBufferIndex, PLOT_SHOW_DATA, showDeltaMa); + PlotIndexSetInteger(deltaMaBufferIndex, PLOT_DRAW_TYPE, deltaMaDrawType); + + // + // Data Buffers ... + + // + ArraySetAsSeries(rawDeltaBuffer, true); + SetIndexBuffer(rawDeltaBufferIndex, rawDeltaBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculateValues( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + rawDeltaBuffer[barIndex] = 0.0; + deltaLineBuffer[barIndex] = 0.0; + deltaHistogramBuffer[barIndex] = 0.0; + deltaMaBuffer[barIndex] = EMPTY_VALUE; + deltaHistogramColorBuffer[barIndex] = hideColorIDX; +} + +/** + * Calculate Vales ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateValues( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + XOHCL bar; + bool has = bar.Init( + _Symbol, + _Period, + bar_index // + ); + if (!has) + { + return; + } + + // + double iDelta = 0.0; + + // + // Detecting Delta Volume ... + if (bar.IsBullish()) + { + iDelta = (double)bar.volume; + } + else if (bar.IsBearish()) + { + iDelta = -(double)bar.volume; + } + + // + // Checking First Bar Conditions ... + bool isFirstBar = + startCalculationForLastBars > 0 + ? bar_index == startCalculationForLastBars + : bar_index == ratesTotal; + if (isFirstBar) + { + // + deltaLineBuffer[bar_index] = iDelta; + deltaHistogramBuffer[bar_index] = iDelta; + + // + rawDeltaBuffer[bar_index] = iDelta; + } + else + { + // + iDelta += deltaLineBuffer[bar_index + 1]; + + // + rawDeltaBuffer[bar_index] = iDelta; + deltaLineBuffer[bar_index] = iDelta; + deltaHistogramBuffer[bar_index] = iDelta; + + // + // deltaLineBuffer[bar_index] = deltaLineBuffer[bar_index + 1] + iDelta; + // deltaHistogramBuffer[bar_index] = deltaHistogramBuffer[bar_index + 1] + iDelta; + + // // + // rawDeltaBuffer[bar_index] = rawDeltaBuffer[bar_index + 1] + iDelta; + } + + // + double iDeltaColor = iDelta > 0 + ? bullishColorIDX + : iDelta < 0 + ? bearishColorIDX + : hideColorIDX; + deltaHistogramColorBuffer[bar_index] = iDeltaColor; + + // + // Calculate Moving Averages ... + int deltaMAsCount = iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + maLength, + rawDeltaBuffer, + deltaMaBuffer, + maMethod // + ); + + // + bar.Clean(); +} + +// diff --git a/Indicators/x-saherelm.x121.x-volume.mq5 b/Indicators/x-saherelm.x121.x-volume.mq5 new file mode 100644 index 00000000..0c2bb28c --- /dev/null +++ b/Indicators/x-saherelm.x121.x-volume.mq5 @@ -0,0 +1,544 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Ocillator +// ------------------------------------------------- +// Name: X121 XVolume +// Description: Detect Bullish/Bearish Volumes ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XVolume Ocillator" +#property strict + +// +// Definitions ... + +// +#define ShortName "X121_XVOLUME" + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Makret ... +input group "Market"; +input int maLength = 14; // Moving Averge Length +input ENUM_X_MA_METHOD maMethod = X_MA_MODE_EMA; // Moving Averge Method + +// +// Presentation ... +input group "Presentation"; +input int startCalculationForLastBars = 1000; // Calculate Last n Bars +input bool showBullishVolume = true; // Show Bullish Volume +input bool showBullishVolumeMa = true; // Show Bullish Volume Moving Average +input bool showBearishVolume = true; // Show Bearish Volume +input bool showBearishVolumeMa = true; // Show Bearish Volume Moving Average + +// +// Buffers Props ... + +// +#property indicator_separate_window + +// +#property indicator_buffers 6 +#property indicator_plots 4 + +// +// Buffers ... + +// +#define bullishVolumeBufferIndex 0 +double bullishVolumeBuffer[]; + +#property indicator_label1 "Bullish Volume" +#property indicator_type1 DRAW_HISTOGRAM +#property indicator_color1 clrLime +#property indicator_style1 STYLE_DOT +#property indicator_width1 1 + +// +#define bullishVolumeMaBufferIndex 1 +double bullishVolumeMaBuffer[]; + +#property indicator_label2 "Bullish Volume MA" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrLime +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +// +#define bearishVolumeBufferIndex 2 +double bearishVolumeBuffer[]; + +#property indicator_label3 "Bearish Volume" +#property indicator_type3 DRAW_HISTOGRAM +#property indicator_color3 clrRed +#property indicator_style3 STYLE_DOT +#property indicator_width3 1 + +// +#define bearishVolumeMaBufferIndex 3 +double bearishVolumeMaBuffer[]; + +#property indicator_label4 "Bearish Volume MA" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrRed +#property indicator_style4 STYLE_SOLID +#property indicator_width4 1 + +// +// Data Buffers ... + +#define mLastBufferIndex 3 + +// +#define rawBullishVolumeBufferIndex mLastBufferIndex + 1 +double rawBullishVolumeBuffer[]; + +// +#define rawBearishVolumeBufferIndex mLastBufferIndex + 2 +double rawBearishVolumeBuffer[]; + +// +// Variables, Properties and etc ... + +// +// this counts Available Bars ... +int limit; + +// +int maxLength; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Indicator Handlers ... + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + IndicatorSetInteger(INDICATOR_DIGITS, 2); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +int OnCalculate( + const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[] // +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + // + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Functions ... + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = maLength > 0 && + IsValid(maMethod); + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(0, maLength); + + // + return result; +} + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // Bullish ... + + // + // Volume ... + ENUM_DRAW_TYPE bullishVolumeDrawType = showBullishVolume ? DRAW_HISTOGRAM : DRAW_NONE; + + // + ArraySetAsSeries(bullishVolumeBuffer, true); + SetIndexBuffer(bullishVolumeBufferIndex, bullishVolumeBuffer, INDICATOR_DATA); + PlotIndexSetDouble(bullishVolumeBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(bullishVolumeBufferIndex, PLOT_SHOW_DATA, showBullishVolume); + PlotIndexSetInteger(bullishVolumeBufferIndex, PLOT_DRAW_TYPE, bullishVolumeDrawType); + + // + // Average ... + ENUM_DRAW_TYPE bullishVolumeMaDrawType = showBullishVolumeMa ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(bullishVolumeMaBuffer, true); + SetIndexBuffer(bullishVolumeMaBufferIndex, bullishVolumeMaBuffer, INDICATOR_DATA); + PlotIndexSetDouble(bullishVolumeMaBufferIndex, PLOT_EMPTY_VALUE, 0.0); + PlotIndexSetInteger(bullishVolumeMaBufferIndex, PLOT_SHOW_DATA, showBullishVolumeMa); + PlotIndexSetInteger(bullishVolumeMaBufferIndex, PLOT_DRAW_TYPE, bullishVolumeMaDrawType); + + // + // Bearish ... + + // + // Volume ... + ENUM_DRAW_TYPE bearishVolumeDrawType = showBearishVolume ? DRAW_HISTOGRAM : DRAW_NONE; + + // + ArraySetAsSeries(bearishVolumeBuffer, true); + SetIndexBuffer(bearishVolumeBufferIndex, bearishVolumeBuffer, INDICATOR_DATA); + PlotIndexSetDouble(bearishVolumeBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(bearishVolumeBufferIndex, PLOT_SHOW_DATA, showBearishVolume); + PlotIndexSetInteger(bearishVolumeBufferIndex, PLOT_DRAW_TYPE, bearishVolumeDrawType); + + // + // Average ... + ENUM_DRAW_TYPE bearishVolumeMaDrawType = showBearishVolumeMa ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(bearishVolumeMaBuffer, true); + SetIndexBuffer(bearishVolumeMaBufferIndex, bearishVolumeMaBuffer, INDICATOR_DATA); + PlotIndexSetDouble(bearishVolumeMaBufferIndex, PLOT_EMPTY_VALUE, 0.0); + PlotIndexSetInteger(bearishVolumeMaBufferIndex, PLOT_SHOW_DATA, showBearishVolumeMa); + PlotIndexSetInteger(bearishVolumeMaBufferIndex, PLOT_DRAW_TYPE, bearishVolumeMaDrawType); + + // + // Data Buffers ... + + // + ArraySetAsSeries(rawBullishVolumeBuffer, true); + SetIndexBuffer(rawBullishVolumeBufferIndex, rawBullishVolumeBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(rawBearishVolumeBuffer, true); + SetIndexBuffer(rawBearishVolumeBufferIndex, rawBearishVolumeBuffer, INDICATOR_CALCULATIONS); +} + +/** + * Calculate Custom Buffers ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + // + // bool canCalculate = true; + bool canCalculate = + barsLimit == 0 || + bar_index <= barsLimit; + if (canCalculate) + { + // + CalculateValues( + bar_index, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(bar_index); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + bullishVolumeBuffer[barIndex] = EMPTY_VALUE; + bullishVolumeMaBuffer[barIndex] = EMPTY_VALUE; + rawBullishVolumeBuffer[barIndex] = 0; + + // + bearishVolumeBuffer[barIndex] = EMPTY_VALUE; + bearishVolumeMaBuffer[barIndex] = EMPTY_VALUE; + rawBearishVolumeBuffer[barIndex] = 0; +} + +/** + * Calculate Vales ... + * + * @param bar_index: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateValues( + int bar_index, // Selected Bar Index + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + XOHCL bar; + bool has = bar.Init( + _Symbol, + _Period, + bar_index // + ); + if (!has) + { + return; + } + + // + double iBullishVolume = 0; + double iBearishVolume = 0; + + // + if (bar.IsBullish()) + { + // + iBullishVolume = (double)bar.volume; + iBearishVolume = 0; + } + else if (bar.IsBearish()) + { + // + iBearishVolume = (double)bar.volume; + iBullishVolume = 0; + } + else + { + // + double volume = ((double)bar.volume) / 2.0; + iBullishVolume = volume; + iBearishVolume = volume; + } + + // + bullishVolumeBuffer[bar_index] = + iBullishVolume == 0 + ? EMPTY_VALUE + : iBullishVolume; + rawBullishVolumeBuffer[bar_index] = iBullishVolume; + + // + bearishVolumeBuffer[bar_index] = + iBearishVolume == 0 + ? EMPTY_VALUE + : iBearishVolume; + rawBearishVolumeBuffer[bar_index] = iBearishVolume; + + // + // Calculate Moving Averages ... + + // + int bullishMAsCount = iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + maLength, + rawBullishVolumeBuffer, + bullishVolumeMaBuffer, + maMethod // + ); + + // + int bearishMAsCount = iMAOnBuffer( + ratesTotal, + prevCalculated, + bar_index, + maLength, + rawBearishVolumeBuffer, + bearishVolumeMaBuffer, + maMethod // + ); + + // + bar.Clean(); +} + +// diff --git a/Libraries/x-saherelm.x-ohcl.lib.mq5 b/Libraries/x-saherelm.x-ohcl.lib.mq5 index 77d1de64..5570b8fb 100644 --- a/Libraries/x-saherelm.x-ohcl.lib.mq5 +++ b/Libraries/x-saherelm.x-ohcl.lib.mq5 @@ -34,6 +34,7 @@ struct XOHCL double open; double close; double low; + long volume; double spread; // @@ -112,6 +113,13 @@ struct XOHCL ); spread = NormalizePrice(spread, mSymbol); + // + volume = iTickVolume( + mSymbol, + mPeriod, + barIndex // + ); + // bool result = IsValid(); @@ -151,40 +159,6 @@ struct XOHCL return result; } - // - bool Init( - string mSymbol = NULL, // Trading Symbol - ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period - double mOpen = 0, // Open - double mHigh = 0, // High - double mClose = 0, // Close - double mLow = 0, // Low - datetime mTime = NULL // Bar Time - ) - { - // - mSymbol = NormalizeSymbol(mSymbol); - mPeriod = NormalizePeriod(mPeriod); - - // - symbol = mSymbol; - period = mPeriod; - - // - int barIndex = GetBarIndex( - symbol, - period, - mTime // - ); - - // - return Init( - mSymbol, - mPeriod, - barIndex // - ); - } - // // Tools ... @@ -197,6 +171,7 @@ struct XOHCL open = 0; close = 0; spread = 0; + volume = 0; // time = NULL; @@ -221,7 +196,8 @@ struct XOHCL high > 0 && open > 0 && close > 0 && - spread > 0 + spread > 0 && + volume > 0 // ; @@ -1036,7 +1012,7 @@ struct XOHCL IsBearish(forDir) && high > price && GetUp() < price; - + // if (forceType) { diff --git a/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 b/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 index 343cc60e..f5786d97 100644 --- a/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 +++ b/X121SMCEA/Classes/x-121.smc.market.cycle.helper.class.mq5 @@ -475,6 +475,9 @@ class XC121SMCCycleHelper : public XCBase return result; } + // + // Tools ... + // bool GeneratePVBox( XBoxZone &box, @@ -825,7 +828,7 @@ class XC121SMCCycleHelper : public XCBase } // - datetime GetNearestCloseOverX3MAFast( + datetime DetectNearestCloseOverX3MAFast( XOHCL &bar, int maxAllowedBars = 20 // ) @@ -891,7 +894,7 @@ class XC121SMCCycleHelper : public XCBase } // - datetime GetNearestCloseUnderX3MAFast( + datetime DetectNearestCloseUnderX3MAFast( XOHCL &bar, int maxAllowedBars = 20 // ) @@ -956,6 +959,94 @@ class XC121SMCCycleHelper : public XCBase return result; } + // + bool DetectNearestTenKijCross( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int barIndex = 0, + int maxAllowedBars = 20 // + ) + { + // + bool result = false; + + // + bar.Clean(); + dir = X_DIRECTION_NONE; + barIndex = NormalizeInt(barIndex, 0); + maxAllowedBars = NormalizeInt(maxAllowedBars, 20); + + // + // Looping Through LoopBack Period ... + // for Detecting Result ... + for (int i = barIndex; i < barIndex + maxAllowedBars; i++) + { + // + XOHCL iBar; + result = iBar.Init( + GetSymbol(), + GetPeriod(), + i // + ); + if (!result) + { + // + iBar.Clean(); + break; + } + + // + double iTSen = mX121Helper.xichHelper.GetTenkanSen(i); + double iTSenP = mX121Helper.xichHelper.GetTenkanSen(i + 1); + + // + double iKSen = mX121Helper.xichHelper.GetKijunSen(i); + double iKSenP = mX121Helper.xichHelper.GetKijunSen(i + 1); + + // + bool isTSenOverKSen = iTSen > iKSen; + bool isTSenOverKSenP = iTSenP > iKSenP; + + // + bool isTSenUnderKSen = iTSen < iKSen; + bool isTSenUnderKSenP = iTSenP < iKSenP; + + // + + // + bool isTSenCrossedOverKSen = isTSenOverKSen && + !isTSenOverKSenP; + + // + bool isTSenCrossedUnderKSen = isTSenUnderKSen && + !isTSenUnderKSenP; + + // + result = isTSenCrossedOverKSen || + isTSenCrossedUnderKSen; + if (result) + { + // + bar = iBar; + + // + dir = isTSenCrossedOverKSen + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + iBar.Clean(); + break; + } + + // + iBar.Clean(); + } + + // + return result; + } + // // Virtuals ... @@ -3753,6 +3844,9 @@ struct X121SMCStrategyConditionParser cBar.high < vXConditions.senkouMin && vBearishScore > (vBullishScore * 1.5); + // + // ichimokou ... + // // Bullish Conditions ... isBullish = diff --git a/X121SMCEA/Libraries/x-121.smc.lib.mq5 b/X121SMCEA/Libraries/x-121.smc.lib.mq5 index b411b86f..ec449b4e 100644 --- a/X121SMCEA/Libraries/x-121.smc.lib.mq5 +++ b/X121SMCEA/Libraries/x-121.smc.lib.mq5 @@ -37,6 +37,7 @@ const string X121SMCStrategyToken = "X121SMC"; // const string X121SMCXWZToken = "X121XWZ"; +const string X121SMCXICHToken = "X121XICH"; // // X121 SMC Providers ... @@ -45,6 +46,7 @@ enum ENUM_X_121_SMC_PROVIDERS // X_121_SMC_PROVIDER_NONE, X_121_SMC_PROVIDER_XWZ, + X_121_SMC_PROVIDER_XICH, }; // @@ -700,6 +702,11 @@ string ToString(ENUM_X_121_SMC_PROVIDERS value) case X_121_SMC_PROVIDER_XWZ: result = X121SMCXWZToken; break; + + // + case X_121_SMC_PROVIDER_XICH: + result = X121SMCXICHToken; + break; } // @@ -729,6 +736,10 @@ ENUM_X_121_SMC_PROVIDERS ParseProvider(string value) { result = X_121_SMC_PROVIDER_XWZ; } + else if (Contains(X121SMCXICHToken, value)) + { + result = X_121_SMC_PROVIDER_XICH; + } // return result; diff --git a/X121SMCEA/Signals/x-121.smc.xich.signal.class.mq5 b/X121SMCEA/Signals/x-121.smc.xich.signal.class.mq5 new file mode 100644 index 00000000..da38ac73 --- /dev/null +++ b/X121SMCEA/Signals/x-121.smc.xich.signal.class.mq5 @@ -0,0 +1,1391 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XICH +// Description: provide all Signalling functions ... +// +// +// 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 "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.guard.lib.mq5" +#include "../Libraries/x-121.smc.lib.mq5" +#include "./x-121.smc.xich.signal.lib.mq5" + +// +// Definition ... +class XCX121SMCXICHSignalDetector : public XCBase +{ + // + public: + // + // Props ... + bool useGuards; + double rfRewar; + X121SMCStrategyXICHSignalConditions mConditions; + X121SMCStrategyXICHSignalConditions mConditionsCollection[]; + + // + // Constructor(s) ... + XCX121SMCXICHSignalDetector( + string _symbol, + ENUM_TIMEFRAMES _period // + ) + { + // + symbol = _symbol; + period = _period; + Init(); + } + + // + // Deconstructor ... + ~XCX121SMCXICHSignalDetector() + { + DeInit(); + } + + // + // + // + + // + // Detect Setup Conditions ... + bool DetectSignalSetup( + // + X121SMCStrategySignalProviderData &provider, + // + double maxAllowedSLDistanceInPoint = 300 + // + ) + { + // + bool result = false; + + // + // Validate Cycle Helpers ... + result = provider.IsValid(); + if (!result) + { + // + mConditions.Clean(); + + // + return result; + } + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + mConditions.symbol = symbol; + mConditions.period = period; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + result = provider.Prepare( + zIndex, + loopback, + true, // Trigger ... + true, // Decision ... + true, // Analyse ... + true, // Verification ... + true, // Consolidation ... + true // Vision ... + ); + if (!result) + { + // + mConditions.Clean(); + return result; + } + + // + // Select Drawer Class ... + XCPOIDrawer *drawer = provider.visionCycleHelper.mPOIDrawer; + + // + // Detecting Bars based on Decision Cycle ... + XOHCL zBar; + XOHCL cBar; + XOHCL pBar; + XOHCL pPBar; + XOHCL consolidationZBar; + result = zBar.Init( + provider.decisionXConditions.symbol, + provider.decisionXConditions.period, + zIndex // + ); + result = + result && + zBar.GetPreviousBar(cBar); + result = + result && + cBar.GetPreviousBar(pBar); + result = + result && + pBar.GetPreviousBar(pPBar); + result = + result && + provider.consolidationCycleHelper.GetBar( + consolidationZBar, + zIndex // + ); + if (!result) + { + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + pPBar.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + bool drawBar = false; + if (drawBar) + { + // + DrawBar( + consolidationZBar, + drawer // + ); + } + + // + // + // + + // + // Setup Conditions ... + double sls[]; + double sl = 0; + double pivot = 0; + double point = 0; + double targets[]; + XBoxZone signalBox; + bool hasSignalBox = false; + ENUM_X_DIRECTION signalBoxDir = X_DIRECTION_NONE; + ENUM_X121SMC_XICH_PROVIDERS signalProvider = X121SMC_XICH_PROVIDER_NONE; + + // + // + // + + // + // Update Models To Time ... + UpdateTo(cTime); + + // + // Here we Detect Signal Box ... + if (!hasSignalBox) + { + // + // HTF Proves ... + + // + double scoreMultiplier = 1.5; + + // + bool isConsolidationScoreBullish = + provider.consolidationBullishScore > (provider.consolidationBearishScore * scoreMultiplier); + + // + bool isConsolidationScoreBearish = + provider.consolidationBearishScore > (provider.consolidationBullishScore * scoreMultiplier); + + // + // Detect Kumo Trend ... + bool isKumoBullish = provider.decisionXConditions.isSenkouSpanAOverB; + bool isKumoBearish = provider.decisionXConditions.isSenkouSpanAUnderB; + + // + // Detect Nearest Cross ... + XOHCL tkCrossedBar; + ENUM_X_DIRECTION tkCrossDir; + bool hasNearestTenkanSenKijunSenCross = + provider + .decisionCycleHelper + .DetectNearestTenKijCross( + tkCrossedBar, + tkCrossDir, + zIndex // + ); + + // + bool isNearestTenkensSenCrossedOverKijunSen = + hasNearestTenkanSenKijunSenCross && + IsBullish(tkCrossDir); + + // + bool isNearestTenkensSenCrossedUnderKijunSen = + hasNearestTenkanSenKijunSenCross && + IsBearish(tkCrossDir); + + // + // Detect Price in TK Zone ... + bool isBarInsideTKZone = + isNearestTenkensSenCrossedOverKijunSen + ? cBar.low < provider.decisionXConditions.tenkanSenBuffer[cIndex] + : isNearestTenkensSenCrossedUnderKijunSen + ? cBar.high > provider.decisionXConditions.tenkanSenBuffer[cIndex] + : false; + + // + // Checking Bar Based on Positions State ... + ENUM_X_DIRECTION iBarPosDir; + bool isBarValidForDir = provider.decisionCycleHelper + .mBarAnalyser + .IsValidForPosition( + cBar, + iBarPosDir // + ); + bool isBarValidForBullish = + isBarValidForDir && + IsBullish(iBarPosDir); + bool isBarValidForBearish = + isBarValidForDir && + IsBearish(iBarPosDir); + + // + // Summarize Conditions ... + + // + isBullish = + // + isKumoBullish && + isBarInsideTKZone && + isBarValidForBullish && + isConsolidationScoreBullish && + isNearestTenkensSenCrossedOverKijunSen + // + ; + + // + isBearish = + // + isKumoBearish && + isBarInsideTKZone && + isBarValidForBearish && + isConsolidationScoreBearish && + isNearestTenkensSenCrossedUnderKijunSen + // + ; + + // + result = + isBullish || + isBearish; + if (result) + { + // + signalProvider = X121SMC_XICH_PROVIDER_XTKKUMO; + + // + signalBoxDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + signalBox.from = pPBar.time; + signalBox.to = TimeCurrent(); + signalBox.dir = signalBoxDir; + signalBox.symbol = cBar.symbol; + signalBox.period = cBar.period; + + // + pivot = isBullish + ? cBar.low - (points * 5) + : cBar.high + (points * 5); + + // + point = GetEntry( + cBar.symbol, + signalBoxDir // + ); + + // + signalBox.upper = + isBullish + ? point + : pivot; + + // + signalBox.lower = + isBullish + ? pivot + : point; + } + + // + hasSignalBox = signalBox.IsValid(); + + // + tkCrossedBar.Clean(); + } + + // + // Cleanup Signal if UnApproved ... + if (!hasSignalBox) + { + // + signalBox.Clean(); + isBullish = false; + isBearish = false; + signalBoxDir = X_DIRECTION_NONE; + } + + // + // Check Signal Conditions ... + if (hasSignalBox) + { + // + int idx = -1; + bool has = false; + + // + // Draw Signal Box ... + XCBoxObject *object; + has = drawer.DrawBox( + signalBox, + object // + ); + if (has) + { + mObjects.Add(object); + } + + // + // Detect Signal Direction ... + isBullish = IsBullish(signalBoxDir); + isBearish = IsBearish(signalBoxDir); + + // + pivot = isBullish + ? signalBox.lower + : signalBox.upper; + + // + point = isBullish + ? signalBox.upper + : signalBox.lower; + + // + double entry = GetEntry( + signalBox.symbol, + signalBoxDir // + ); + + // + // Selecting SL(s) ... + + // + double iSL = 0; + + // + // Default SL ... + iSL = pivot; + + // + Add( + iSL, + sls // + ); + + // + // Select and Provide SL Based on ... + double iAtr = 0; + if (signalProvider == X121SMC_XICH_PROVIDER_XTKKUMO) + { + // + iAtr = provider.decisionXConditions.atrBuffer[1]; + iAtr *= 0; + + // + // Fix rf Reward ... + rfRewar = 2; + } + + // + Print("XICH ", ToString(signalBoxDir), " Signal Provided: ", EnumToString(signalProvider)); + + // + // Select Condition SL ... + + // + double slsMin = GetMin(sls); + double slsMax = GetMax(sls); + + // + double longSL = slsMax - iAtr; + double shortSL = slsMin + iAtr; + + // + sl = isBullish + ? longSL + : shortSL; + + // + // Targets ... + + // + double risk = MathAbs(entry - sl); + + // + // Checking risk ... + if (risk >= maxAllowedSLDistanceInPoint) + { + // Print("Max Aloowed Risk Point Reached ..."); + } + + // + // Reward to RF ... + if (rfRewar > 0) + { + // + double iRFReward = rfRewar * risk; + double iRFTP = isBullish + ? entry + iRFReward + : entry - iRFReward; + + // + Add( + iRFTP, + targets // + ); + } + } + + // + // Summarize Results ... + // result = hasPriority && + // hasSignalBox && + // hasRewardAmount; + result = hasSignalBox; + + // + if (result) + { + // + Copy( + sls, + mConditions.sls // + ); + Copy( + targets, + mConditions.targets // + ); + + // + mConditions.sl = sl; + mConditions.pivot = pivot; + mConditions.point = point; + mConditions.setupTime = cTime; + mConditions.dir = signalBoxDir; + mConditions.signalBox = signalBox; + mConditions.provider = signalProvider; + } + + // + // + // + + // + // Cleanup Resources ... + + // + Clean(sls); + Clean(targets); + + // + provider.Clean(); + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + pPBar.Clean(); + signalBox.Clean(); + consolidationZBar.Clean(); + + // + return result; + } + + // + // Detect Trigger Conditions ... + bool DetectSignalTrigger( + // + X121SMCStrategyXICHSignalConditions &conditions, + // + X121SMCStrategySignalProviderData &provider, + // + int maxAllowedSetupAge = 60 + // + ) + { + // + bool result = false; + + // + result = + // + provider.IsValid() + // + ; + if (!result) + { + return result; + } + + // + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + datetime setupTime = conditions.setupTime; + ENUM_X_DIRECTION setupDir = conditions.dir; + + // + bool isBullish = IsBullish(setupDir); + bool isBearish = IsBearish(setupDir); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + int loopback = 10; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + result = provider.Prepare( + zIndex, + loopback // + ); + if (!result) + { + return result; + } + + // + double iAtr = provider.decisionXConditions.atrBuffer[1]; + iAtr *= 1.5; + + // + // Check Signal Validation ... + // IMPORTANT: since all Validations done in SetUp Process ... + // here we only Execute Signal ... + + // + result = isBullish || + isBearish; + + // + if (result) + { + // + conditions.triggerTime = cTime; + conditions.type = isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + } + + // + // Cleanup ... + + // + provider.Clean(); + + // + return result; + } + + // + // Detect Guards ... + bool DetectGuards( + // + X121SMCGuard &guards[], + const XPosition &positions[], + // + X121SMCStrategySignalProviderData &provider + // + ) + { + // + bool result = false; + + // + if (!useGuards) + { + return result; + } + + // + Clean(guards); + + // + // Set Provider for Common Guards ... + string signalProvider = ToString(X121SMC_XICH_PROVIDER_XTKKUMO); + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + XOHCL cBar; + + // + int loopback = 10; + + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + datetime cTime = TimeCurrent(); + double points = GetPoints(symbol); + + // + // Cycles Conditions ... + result = provider.IsValid(); + result = + result && + provider.Prepare( + zIndex, + loopback // + ); + if (!result) + { + // + provider.Clean(); + return result; + } + + // + // Select Own Positions ... + int count = ArraySize(positions); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + XPosition ownPositions[]; + XPosition ownLongPositions[]; + XPosition ownShortPositions[]; + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + bool isOwn = iPosition + .IsFiltersPassed( + symbol, + signalProvider, + NULL, + X_POSITION_TYPE_ALL, + iPosition.magic // + ); + if (isOwn) + { + // + AddRef( + iPosition, + ownPositions // + ); + + // + bool isLong = IsLong(positions[i].type); + if (isLong) + { + // + AddRef( + iPosition, + ownLongPositions // + ); + } + else + { + // + AddRef( + iPosition, + ownShortPositions // + ); + } + } + } + + // + // Check Extracted Positions ... + + // + count = ArraySize(ownPositions); + + // + int longsCount = ArraySize(ownLongPositions); + bool hasLongs = IsValidSize(longsCount); + + // + int shortsCount = ArraySize(ownShortPositions); + bool hasShorts = IsValidSize(shortsCount); + + // + // Validate Own Positions ... + result = IsValidSize(count); + if (!result) + { + // + Clean(ownPositions); + Clean(ownLongPositions); + Clean(ownShortPositions); + + // + return result; + } + + // + // + // + + // + // Get Global and Common Guards ... + + // + // ENUM_X_121_SMC_GUARD_ACTIONS ignoreGuards[1] = { + // X_121_SMC_GUARD_ACTION_TRAIL_STOP // + // }; + // result = DetectX121SMCGuards( + // signalProvider, + // guards, + // positions, + // provider, + // // + // ignoreGuards + // // + // ); + + // + // + // + + // + // Implement Custom Implemented Guards ... + + // + // Here we Are Sure there is Positions to Guard ... + // based on Current Provider ... + + // + // Selected Consolidation Zones ... + + // + int idx = -1; + bool has = false; + + // + bool hasBullishConsolidationZone = false; + XConsolidationZone bullishConsolidationZone; + has = provider.decisionState.HasBullishConsolidationZones(); + if (has) + { + // + idx = GetYoungest(provider.decisionState.bullishConsolidationZones); + hasBullishConsolidationZone = IsValidIndex(idx); + if (hasBullishConsolidationZone) + { + bullishConsolidationZone = provider.decisionState.bullishConsolidationZones[idx]; + } + } + + // + bool hasBearishConsolidationZone = false; + XConsolidationZone bearishConsolidationZone; + has = provider.decisionState.HasBearishConsolidationZones(); + if (has) + { + // + idx = GetYoungest(provider.decisionState.bearishConsolidationZones); + hasBearishConsolidationZone = IsValidIndex(idx); + if (hasBearishConsolidationZone) + { + bearishConsolidationZone = provider.decisionState.bearishConsolidationZones[idx]; + } + } + + // + XBoxZone bullishBox; + bool hasBullishBox = false; + bool isBullishBoxBreaked = false; + if (!hasBullishBox) + { + // + XCOrderBlock *ob = NULL; + idx = GetYoungest(provider.analyseState.bullishOrderBlocks); + has = IsValidIndex(idx); + if (has) + { + // + ob = provider.analyseState.bullishOrderBlocks[idx]; + + // + hasBullishBox = ToBox( + bullishBox, + ob // + ); + } + + // + if (!hasBullishBox) + { + bullishBox.Clean(); + } + + // + ZeroMemory(ob); + } + + // + XBoxZone bearishBox; + bool hasBearishBox = false; + bool isBearishBoxBreaked = false; + if (!hasBearishBox) + { + // + XCOrderBlock *ob = NULL; + idx = GetYoungest(provider.analyseState.bearishOrderBlocks); + has = IsValidIndex(idx); + if (has) + { + // + ob = provider.analyseState.bearishOrderBlocks[idx]; + + // + hasBearishBox = ToBox( + bearishBox, + ob // + ); + } + + // + if (!hasBearishBox) + { + bearishBox.Clean(); + } + + // + ZeroMemory(ob); + } + + // + // Here We Have all Requirements for Guarding Positions ... + + // + // Available Guards: + // X_121_SMC_GUARD_ACTION_NONE + // X_121_SMC_GUARD_ACTION_CLOSE + // X_121_SMC_GUARD_ACTION_CLOSE_ALL + // X_121_SMC_GUARD_ACTION_CLOSE_LONGS + // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS + // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE + // X_121_SMC_GUARD_ACTION_TRAIL_STOP + // X_121_SMC_GUARD_ACTION_TRAIL_TARGET + // X_121_SMC_GUARD_ACTION_HEDGE + + // + // X_121_SMC_GUARD_ACTION_CLOSE: + // Close Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_ALL: + // Close All Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_LONGS: + // Close All Long Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_CLOSE_SHORTS: + // Close All Short Positions on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_PARTIAL_CLOSE: + // Partial Close Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_TRAIL_STOP: + // Trail Stop Specified Position on Specified Conditions ... + bool handleStoptrailingBasedOnBoxes = true; + bool handleStoptrailingBasedOnConsolidationZones = true; + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = ownPositions[i]; + + // + bool isInited = cBar.Init( + iPosition.symbol, + iPosition.period, + cIndex // + ); + + // + isBullishBoxBreaked = + isInited && + hasBullishBox && + cBar.high < bullishBox.lower; + + // + isBearishBoxBreaked = + isInited && + hasBearishBox && + cBar.low > bearishBox.upper; + + // + bool isLong = IsLong(iPosition.type); + bool isInProfit = iPosition.profit > 0; + + // + double sl = iPosition.sl; + double tp = iPosition.tp; + + // + // Trail Stops Using Consolidation Zones ... + + // + bool canTraiLonglUsingCZone = + // + handleStoptrailingBasedOnConsolidationZones && + // + (isLong && + isInProfit && + hasBullishConsolidationZone && + bullishConsolidationZone.lower > iPosition.sl && + bullishConsolidationZone.lower > iPosition.entry) + // + ; + if (canTraiLonglUsingCZone) + { + sl = bullishConsolidationZone.lower; + } + + // + bool canTraiShortlUsingCZone = + // + handleStoptrailingBasedOnConsolidationZones && + // + (!isLong && + isInProfit && + hasBearishConsolidationZone && + bearishConsolidationZone.upper < iPosition.sl && + bearishConsolidationZone.upper < iPosition.entry) + // + ; + if (canTraiShortlUsingCZone) + { + sl = bearishConsolidationZone.upper; + } + + // + bool canTrailUsingCZone = + canTraiLonglUsingCZone || + canTraiShortlUsingCZone; + + // + // Trail Stop Using Boxes ... + + // + bool canTraiLonglUsingBox = + // + handleStoptrailingBasedOnBoxes && + // + (isLong && + isInProfit && + hasBullishBox && + bullishBox.lower > iPosition.sl && + bullishBox.lower > iPosition.entry) + // + ; + if (canTraiLonglUsingBox) + { + sl = bullishBox.lower; + } + + // + bool canTraiShortlUsingBox = + // + handleStoptrailingBasedOnBoxes && + // + (!isLong && + isInProfit && + hasBearishBox && + bearishBox.upper < iPosition.sl && + bearishBox.upper < iPosition.entry) + // + ; + if (canTraiShortlUsingBox) + { + sl = bearishBox.upper; + } + + // + bool canTrailUsingBox = + canTraiLonglUsingBox || + canTraiShortlUsingBox; + + // + bool canTraiLonglUsingBreakedBox = + // + handleStoptrailingBasedOnBoxes && + // + (isLong && + isInProfit && + isBearishBoxBreaked && + bearishBox.upper > iPosition.sl && + bearishBox.upper > iPosition.entry) + // + ; + if (canTraiLonglUsingBreakedBox) + { + sl = bearishBox.upper; + } + + // + bool canTraiShortlUsingBreakedBox = + // + handleStoptrailingBasedOnBoxes && + // + (!isLong && + isInProfit && + isBullishBoxBreaked && + bullishBox.lower < iPosition.sl && + bullishBox.lower < iPosition.entry) + // + ; + if (canTraiShortlUsingBreakedBox) + { + sl = bullishBox.lower; + } + + // + bool canTrailUsingBreakedBox = + canTraiLonglUsingBreakedBox || + canTraiShortlUsingBreakedBox; + + // + // Summarize SL ... + + // + bool isSLPassed = + sl > 0 && + (isLong + ? iPosition.price - sl >= points * 15 + : sl - iPosition.price >= points * 15); + + // + bool canTrail = + isSLPassed && + (canTrailUsingBox || + canTrailUsingCZone || + canTrailUsingBreakedBox); + if (canTrail) + { + // + X121SMCGuard iGuard; + + // + iGuard.time = cTime; + iGuard.symbol = symbol; + iGuard.provider = signalProvider; + iGuard.action = X_121_SMC_GUARD_ACTION_TRAIL_STOP; + + // + iGuard.ticket = iPosition.ticket; + + // + iGuard.sl = sl; + + // + AddGuard( + iGuard, + guards // + ); + } + } + + // + // X_121_SMC_GUARD_ACTION_TRAIL_TARGET: + // Trail Target Specified Position on Specified Conditions ... + + // + // X_121_SMC_GUARD_ACTION_HEDGE: + // Hedge all Positions on Specified Conditions ... + + // + // Cleanup Collections ... + + // + cBar.Clean(); + + // + provider.Clean(); + + // + bullishBox.Clean(); + bearishBox.Clean(); + + // + bullishConsolidationZone.Clean(); + bearishConsolidationZone.Clean(); + + // + count = ArraySize(guards); + result = IsValidSize(count); + + // + return result; + } + + // + // Add Conditions to Conditions Collection ... + int AddConditionsIfNotExists( + int maxAllowed = 10 // + ) + { + // + int result = 0; + + // + bool isSetuped = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!isSetuped) + { + return result; + } + + // + int count = ArraySize(mConditionsCollection); + if (IsValidSize(count)) + { + // + // Copy Original Items ... + X121SMCStrategyXICHSignalConditions tmpItems[]; + Copy( + mConditionsCollection, + tmpItems // + ); + + // + // Prese Item Data ... + bool isBullish = IsBullish(mConditions.dir); + + // + for (int i = 0; i < count; i++) + { + // + X121SMCStrategyXICHSignalConditions iItem = tmpItems[i]; + + // + bool canRemove = mConditions.dir == iItem.dir && + mConditions.pivot == iItem.pivot; + if (canRemove) + { + // + ArrayRemove( + mConditionsCollection, + i, + 1 // + ); + } + } + + // + Clean(tmpItems); + } + + // + AddRef( + mConditions, + mConditionsCollection // + ); + + // + // Remove Olds ... + CleanupArray( + mConditionsCollection, + maxAllowed // + ); + + // + result = ArraySize(mConditionsCollection); + + // + return result; + } + + // + // Draw Functions ... + // + + // + void DrawBar( + XOHCL &bar, + XCPOIDrawer *drawer, + bool forceClean = true // + ) + { + // + if (forceClean) + { + mBarObjects.Clear(); + } + + // + if (drawer == NULL || + !bar.IsValid()) + { + return; + } + + // + bool isBullish = bar.IsBullish(); + + // + int widthBar = 2; + bool fillShadowsBar = true; + ENUM_LINE_STYLE styleBar = STYLE_SOLID; + color clrBar = + isBullish + ? clrAqua + : clrMagenta; + + // + datetime to = bar.NextAt(); + + // + XCOHCLObject *iObj; + bool isCreated = drawer + .CreateBar( + bar, + iObj, + to // + ); + if (isCreated) + { + // + iObj.BarSpes( + widthBar, + clrBar, + styleBar // + ); + + // + iObj.LowShadowFill(fillShadowsBar); + iObj.HighShadowFill(fillShadowsBar); + + // + mBarObjects.Add(iObj); + } + } + + // + protected: + // + + // + private: + // + // Props ... + string symbol; + ENUM_TIMEFRAMES period; + CArrayObj mObjects; + CArrayObj mBarObjects; + + /** + * Initialize ... + */ + void Init() + { + // + rfRewar = 2; + useGuards = false; + } + + /** + * DeInitialize ... + */ + void DeInit() + { + // + mConditions.Clean(); + Clean(mConditionsCollection); + + // + mObjects.Clear(); + mBarObjects.Clear(); + } + + /** + * Update To Time of Exists Components ... + * + * @param value: updated time ... + */ + void UpdateTo( + datetime value = NULL // + ) + { + // + value = NormalizeTime(value); + } + + // +}; + +// \ No newline at end of file diff --git a/X121SMCEA/Signals/x-121.smc.xich.signal.lib.mq5 b/X121SMCEA/Signals/x-121.smc.xich.signal.lib.mq5 new file mode 100644 index 00000000..a4e8931a --- /dev/null +++ b/X121SMCEA/Signals/x-121.smc.xich.signal.lib.mq5 @@ -0,0 +1,225 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121 SMC Signal Class +// ------------------------------------------------- +// Name: XICH +// Description: provide all Signalling functions ... +// +// +// 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 "../../Libraries/x-trade.lib" +#include "../Classes/x-121.smc.market.cycle.helper.class.mq5" +#include "../Libraries/x-121.smc.guard.lib.mq5" +#include "../Libraries/x-121.smc.lib.mq5" + +// +// Provided Signals Enumeration ... +enum ENUM_X121SMC_XICH_PROVIDERS +{ + X121SMC_XICH_PROVIDER_NONE, + X121SMC_XICH_PROVIDER_XTKKUMO, +}; + +// +// Definitions ... + +// +// XICH Signal Conditions ... +struct X121SMCStrategyXICHSignalConditions +{ + // + // Props ... + + // + string symbol; + ENUM_TIMEFRAMES period; + + // + double sl; + ENUM_X_DIRECTION dir; + ENUM_X_POSITION_TYPES type; + + // + // Setup Props ... + + // + datetime setupTime; + datetime triggerTime; + + // + double pivot; + double point; + double sls[]; + double targets[]; + + // + XBoxZone signalBox; + + // + ENUM_X121SMC_XICH_PROVIDERS provider; + + // + // Constructor ... + X121SMCStrategyXICHSignalConditions() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleaning Up ... + */ + void Clean() + { + // + sl = 0; + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; + + // + symbol = NULL; + period = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + ExtensionClean(); + + // + ZeroMemory(this); + } + + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() + { + // + bool result = false; + + // + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + + // + // Extensions ... + + /** + * Clean Additional Properties ... + */ + void ExtensionClean() + { + // + pivot = 0; + point = 0; + + // + Clean(sls); + Clean(targets); + signalBox.Clean(); + + // + provider = X121SMC_XICH_PROVIDER_NONE; + } + + // + // + // + + // + void UpdateTo(datetime value = NULL) + { + // + value = NormalizeTime(value); + + // + int count = 0; + bool has = false; + } + + // +}; + +// +// Extension Functions ... + +// \ No newline at end of file diff --git a/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 b/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 index fb263093..9328cf9c 100644 --- a/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 +++ b/X121SMCEA/Strategy/x-121.smc.strategy.class.mq5 @@ -27,6 +27,7 @@ #include "../Classes/x-121.smc.market.cycle.helper.class.mq5" // +#include "../Signals/x-121.smc.xich.signal.class.mq5" #include "../Signals/x-121.smc.xwz.signal.class.mq5" // @@ -42,8 +43,11 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy // // Props ... bool useXWZSignal; + bool useXICHSignal; bool useXWZSignalGuard; + bool useXICHSignalGuard; XCX121SMCXWZSignalDetector *mXWZSignalDetector; + XCX121SMCXICHSignalDetector *mXICHSignalDetector; X121SMCStrategySignalProviderData cycleProvider; // @@ -64,6 +68,12 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy _symbol, _period // ); + + // + mXICHSignalDetector = new XCX121SMCXICHSignalDetector( + _symbol, + _period // + ); } // @@ -121,6 +131,7 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy // ZeroMemory(mXWZSignalDetector); + ZeroMemory(mXICHSignalDetector); // cycleProvider.Destroy(); @@ -203,9 +214,9 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy // bool hasXWZSignal = false; + bool hasXICHSignal = false; // - // XSupDemOBS Signal ... X121SMCStrategyXWZSignalConditions mXWZConditions; if (useXWZSignal && !hasSignal) { @@ -217,6 +228,18 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy hasSignal = hasXWZSignal; } + // + X121SMCStrategyXICHSignalConditions mXICHConditions; + if (useXICHSignal && !hasSignal) + { + // + hasXICHSignal = DetectXICHSignal( + conditions, + mXICHConditions // + ); + hasSignal = hasXICHSignal; + } + // result = hasSignal; if (!result) @@ -400,6 +423,7 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy // mXWZConditions.Clean(); + mXICHConditions.Clean(); // return result; @@ -455,6 +479,34 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy Clean(xwzGuards); } + // + // XICH Guard Detection ... + if (useXICHSignal && + useXICHSignalGuard) + { + // + X121SMCGuard xichGuards[]; + bool hasGuard = mXICHSignalDetector.DetectGuards( + xichGuards, + positions, + cycleProvider // + ); + + // + if (hasGuard) + { + // + Copy( + xichGuards, + guards, + false // + ); + } + + // + Clean(xichGuards); + } + // count = ArraySize(guards); result = IsValidSize(count); @@ -676,6 +728,180 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy return result; } + // + // XICH Signal ... + bool DetectXICHSignal( + X121SMCStrategyConditions &conditions, + X121SMCStrategyXICHSignalConditions &xICHConditions // + ) + { + // + bool result = false; + + // + bool isBullish = false; + bool isBearish = false; + + // + int zIndex = 0; + int cIndex = zIndex + 1; + int pIndex = cIndex + 1; + int ppIndex = pIndex + 1; + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + datetime cTime = TimeCurrent(); + + // + ENUM_X_121_SMC_PROVIDERS provider = X_121_SMC_PROVIDER_XICH; + string providerStr = ToString(provider); + + // + // Detect Setup Conditions ... + datetime setupTime = mXICHSignalDetector.mConditions.setupTime; + bool isSetuped = mXICHSignalDetector.mConditions.IsSetuped(); + ENUM_X_DIRECTION setupDir = mXICHSignalDetector.mConditions.dir; + if (!isSetuped) + { + // + // Detect Signal Setup ... + isSetuped = mXICHSignalDetector.DetectSignalSetup( + cycleProvider // + ); + + // + setupDir = mXICHSignalDetector.mConditions.dir; + setupTime = mXICHSignalDetector.mConditions.setupTime; + + // + if (isSetuped) + { + // + int items = mXICHSignalDetector + .AddConditionsIfNotExists(); + + // + mXICHSignalDetector.mConditions.Clean(); + } + } + + // + int conditionsCount = ArraySize(mXICHSignalDetector.mConditionsCollection); + result = IsValidSize(conditionsCount); + if (!result) + { + return result; + } + + // + // Looking For Conditions ... + int selectedIndex = 0; + X121SMCStrategyXICHSignalConditions mTmpConditions[]; + Copy( + mXICHSignalDetector.mConditionsCollection, + mTmpConditions // + ); + X121SMCStrategyXICHSignalConditions mConditions; + for (int i = 0; i < conditionsCount; i++) + { + // + // Check Triggers ... + bool canTrigger = mTmpConditions[i].CanTrigger(); + datetime triggerTime = mTmpConditions[i].triggerTime; + if (!canTrigger) + { + // + // Detect Signal Trigger ... + canTrigger = mXICHSignalDetector + .DetectSignalTrigger( + mTmpConditions[i], + cycleProvider // + ); + + // + result = canTrigger; + if (!result) + { + // + bool isISetuped = mTmpConditions[i].IsSetuped(); + if (!isISetuped) + { + // + ArrayRemove( + mXICHSignalDetector.mConditionsCollection, + i, + 1 // + ); + } + continue; + } + + // + triggerTime = mTmpConditions[i].triggerTime; + } + + // + if (canTrigger) + { + // + selectedIndex = i; + mConditions = mTmpConditions[i]; + break; + } + } + + // + result = IsValid(mConditions.setupTime) && + HasDirection(mConditions.dir); + if (!result) + { + return result; + } + + // + // Remove Selected Index from Main Collection ... + ArrayRemove( + mXICHSignalDetector.mConditionsCollection, + selectedIndex, + 1 // + ); + + // + // Check Signal Direction ... + isBullish = IsBullish(mConditions.dir); + isBearish = IsBearish(mConditions.dir); + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + // Issues Signal on Conditions ... + conditions.sl = mConditions.sl; + conditions.provider = providerStr; + conditions.signalDir = mConditions.dir; + + // + Copy( + mConditions.targets, + conditions.targets // + ); + + // + xICHConditions = mConditions; + + // + mConditions.Clean(); + + // + return result; + } + // // Private ... private: @@ -691,9 +917,13 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy void InitialHelpers() { // - useXWZSignal = true; + useXWZSignal = false; useXWZSignalGuard = false; + // + useXICHSignal = true; + useXICHSignalGuard = false; + // string symbol = GetSymbol(); ENUM_TIMEFRAMES period = GetPeriod(); @@ -865,7 +1095,7 @@ class XCX121SMCStrategy : public XCX121SMCBaseStrategy x121Inputs.xichInputs.showChikouSpan = showAll || true; x121Inputs.xichInputs.showSenkouSpanA = showAll || true; x121Inputs.xichInputs.showSenkouSpanB = showAll || true; - x121Inputs.xichInputs.showKumo = showAll || false; + x121Inputs.xichInputs.showKumo = showAll || true; // // Initialize Cycle Helpers ...