From 5850164aabf4bfb86e188df67ce9c39a751d53a9 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Tue, 30 Dec 2025 04:31:39 +0330 Subject: [PATCH] last ... --- Documents/BKP/XKI_MTF_EA.mq5 | 547 ++++++++ .../BKP}/XPullbackTradeer.mq5 | 0 {Experts => Documents/BKP}/XZoneEa.mq5 | 0 Experts/x-saherelm.x121.xki.ea.mq5 | 33 + Helpers/x-saherelm.x121.xki.helper.mq5 | 1027 ++++++++++++++ Indicators/x-saherelm.x121.xki.mq5 | 1183 +++++++++++++++++ MQL5.code-workspace | 3 +- .../x-saherelm.x121xki.expert.class.mq5 | 0 8 files changed, 2792 insertions(+), 1 deletion(-) create mode 100644 Documents/BKP/XKI_MTF_EA.mq5 rename {Experts => Documents/BKP}/XPullbackTradeer.mq5 (100%) rename {Experts => Documents/BKP}/XZoneEa.mq5 (100%) create mode 100644 Experts/x-saherelm.x121.xki.ea.mq5 create mode 100644 Helpers/x-saherelm.x121.xki.helper.mq5 create mode 100644 Indicators/x-saherelm.x121.xki.mq5 create mode 100644 X121XKIEA/Classes/x-saherelm.x121xki.expert.class.mq5 diff --git a/Documents/BKP/XKI_MTF_EA.mq5 b/Documents/BKP/XKI_MTF_EA.mq5 new file mode 100644 index 00000000..6fa8c1e8 --- /dev/null +++ b/Documents/BKP/XKI_MTF_EA.mq5 @@ -0,0 +1,547 @@ +//+------------------------------------------------------------------+ +//| XKI_MTF_EA.mq5 +//| SaherElm IT Center - Strategy using XKI +//| Author: Hadi Khazaee Asl +//+------------------------------------------------------------------+ +#property strict + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// Inputs +input string InpSymbol = "XAUUSDb"; +input ENUM_TIMEFRAMES InpSignalTF = PERIOD_H1; // Signal timeframe (H1) +input int InpKiLength = 26; // KI length (XKI input) +input bool InpShowKI = true; // (XKI input) +input int InpCalcLastBars = 1500; // (XKI input) + +input bool InpUseRSI = true; // Use RSI confirmation +input int InpRSIPeriod = 14; +input int InpRSIPrice = PRICE_CLOSE; + +input bool InpUseH4Filter = true; // Confirm with H4 +input bool InpUseD1Filter = false; // Confirm with D1 +input bool InpRequireBothFilters = false; // If true, require BOTH H4 and D1 agreement; else either + +input double InpFixedLot = 0.10; // Fixed lot size +input double InpRiskATRMult = 0.0; // Add ATR padding to stop (0=disabled) +input int InpATRPeriod = 14; + +input double InpRR = 2.0; // Reward:Risk target +input bool InpTrailByKI = true; // Trail stop to KI +input int InpSlippagePoints = 20; // Max slippage in points +input int InpMaxSpreadPoints = 200; // Max allowed spread in points + +input bool InpAvoidAsianSession = true; // Avoid 22:00–06:00 server time +input int InpAsianStartHour = 22; +input int InpAsianEndHour = 6; + +input bool InpAvoidNewsWindow = false; // Placeholder flag +input int InpNewsWindowMinutes = 60; // Skip trades within +/- minutes + +input int InpBarsLookbackSignal = 2; // Lookback bars for signal (e.g., last closed bar) + +// Magic number and comments +input int InpMagic = 260126; +input string InpOrderComment = "XKI_MTF_EA"; + +// iCustom indicator path (relative to Indicators folder if compiled there) +string g_xkiIndicatorPath = "x-saherelm.x121.xki"; // the compiled name; adjust if different + +// Buffers indices as per the indicator +#define KI_BUFFER_INDEX 0 +#define KI_COLOR_IDX_BUFFER_INDEX 1 +#define KI_STATE_BUFFER_INDEX 2 + +// States from indicator +#define BULLISH_STATE 1 +#define NEUTURAL_STATE 0 +#define BEARISH_STATE -1 + +// Globals +int g_digits; +double g_point; +MqlTick g_tick; +int g_atrHandleH1 = INVALID_HANDLE; +int g_atrHandleH4 = INVALID_HANDLE; +int g_atrHandleD1 = INVALID_HANDLE; +int g_rsiHandleH1 = INVALID_HANDLE; +int g_rsiHandleH4 = INVALID_HANDLE; +int g_rsiHandleD1 = INVALID_HANDLE; + +//+------------------------------------------------------------------+ +// OnInit +//+------------------------------------------------------------------+ +int OnInit() +{ + // + g_digits = (int)SymbolInfoInteger(InpSymbol, SYMBOL_DIGITS); + g_point = SymbolInfoDouble(InpSymbol, SYMBOL_POINT); + + if (!SymbolInfoTick(InpSymbol, g_tick)) + { + Print("Failed to get tick for symbol: ", InpSymbol); + return INIT_FAILED; + } + + // Quick validation + if (InpKiLength < 5) + { + Print("Invalid KI length: ", InpKiLength); + return INIT_PARAMETERS_INCORRECT; + } + + // + GetOrCreateATRHandle(InpSymbol, InpSignalTF, InpATRPeriod); + if (InpUseH4Filter) + GetOrCreateATRHandle(InpSymbol, PERIOD_H4, InpATRPeriod); + if (InpUseD1Filter) + GetOrCreateATRHandle(InpSymbol, PERIOD_D1, InpATRPeriod); + + // + GetOrCreateRSIHandle(InpSymbol, InpSignalTF, InpRSIPeriod, InpRSIPrice); + if (InpUseH4Filter) + GetOrCreateRSIHandle(InpSymbol, PERIOD_H4, InpRSIPeriod, InpRSIPrice); + if (InpUseD1Filter) + GetOrCreateRSIHandle(InpSymbol, PERIOD_D1, InpRSIPeriod, InpRSIPrice); + + // + return INIT_SUCCEEDED; +} + +//+------------------------------------------------------------------+ +// OnDeinit +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + // + if (g_atrHandleH1 != INVALID_HANDLE) + { + IndicatorRelease(g_atrHandleH1); + g_atrHandleH1 = INVALID_HANDLE; + } + if (g_atrHandleH4 != INVALID_HANDLE) + { + IndicatorRelease(g_atrHandleH4); + g_atrHandleH4 = INVALID_HANDLE; + } + if (g_atrHandleD1 != INVALID_HANDLE) + { + IndicatorRelease(g_atrHandleD1); + g_atrHandleD1 = INVALID_HANDLE; + } + + // + if (g_rsiHandleH1 != INVALID_HANDLE) + { + IndicatorRelease(g_rsiHandleH1); + g_rsiHandleH1 = INVALID_HANDLE; + } + if (g_rsiHandleH4 != INVALID_HANDLE) + { + IndicatorRelease(g_rsiHandleH4); + g_rsiHandleH4 = INVALID_HANDLE; + } + if (g_rsiHandleD1 != INVALID_HANDLE) + { + IndicatorRelease(g_rsiHandleD1); + g_rsiHandleD1 = INVALID_HANDLE; + } +} + +//+------------------------------------------------------------------+ +// OnTick +//+------------------------------------------------------------------+ +void OnTick() +{ + if (_Symbol != InpSymbol) + return; + + // Basic trading safety + if (!SymbolInfoTick(InpSymbol, g_tick)) + return; + double spreadPoints = GetSpread(InpSymbol); + if (spreadPoints > InpMaxSpreadPoints) + return; + + if (InpAvoidAsianSession) + { + // + MqlDateTime now = GetCurrentTime(); + int hr = now.hour; + if (IsHourInRange(hr, InpAsianStartHour, InpAsianEndHour)) + return; + } + + if (InpAvoidNewsWindow) + { + // Placeholder: implement your own calendar integration + // Skip trading in a window near news. Here we simply return. + return; + } + + // Only process on new bar of signal timeframe + static datetime lastSignalBarTime = 0; + datetime currentSignalBarTime = GetLastClosedBarTime(InpSymbol, InpSignalTF); + if (currentSignalBarTime == 0 || currentSignalBarTime == lastSignalBarTime) + return; + lastSignalBarTime = currentSignalBarTime; + + // Get signal state and KI on signal TF (last closed bar) + int signalBarShift = InpBarsLookbackSignal; // 1=last closed, 2=previous + int stateSignal; + double kiSignal, closeSignal; + if (!GetXKIStateAndKI(InpSymbol, InpSignalTF, signalBarShift, stateSignal, kiSignal)) + return; + closeSignal = iClose(InpSymbol, InpSignalTF, signalBarShift); + + // RSI confirmation + if (InpUseRSI) + { + double rsi = GetRSIValue(InpSymbol, InpSignalTF, InpRSIPeriod, InpRSIPrice, signalBarShift); + if (rsi == EMPTY_VALUE) + return; + if (stateSignal == BULLISH_STATE && rsi <= 50.0) + return; + if (stateSignal == BEARISH_STATE && rsi >= 50.0) + return; + } + + // Higher timeframe agreement + bool agreesH4 = true, agreesD1 = true; + if (InpUseH4Filter) + agreesH4 = HigherTFAgrees(InpSymbol, PERIOD_H4, signalBarShift, stateSignal); + if (InpUseD1Filter) + agreesD1 = HigherTFAgrees(InpSymbol, PERIOD_D1, signalBarShift, stateSignal); + + bool filterOK = true; + if (InpUseH4Filter || InpUseD1Filter) + { + if (InpRequireBothFilters) + filterOK = (agreesH4 && agreesD1); + else + filterOK = ((InpUseH4Filter && agreesH4) || (InpUseD1Filter && agreesD1)); + } + if (!filterOK) + return; + + // Neutral or invalid skip + if (stateSignal == NEUTURAL_STATE) + return; + + // Ensure no open positions for this symbol/magic + if (HasOpenPosition(InpSymbol, InpMagic)) + return; + + // Prepare trade params + double atrPad = 0.0; + if (InpRiskATRMult > 0.0) + { + double atr = GetATRValue(InpSymbol, InpSignalTF, InpATRPeriod, signalBarShift); + if (atr != EMPTY_VALUE && atr > 0) + atrPad = atr * InpRiskATRMult; + } + + double sl, tp; + bool isBuy = (stateSignal == BULLISH_STATE); + if (isBuy) + { + sl = kiSignal - atrPad; + tp = closeSignal + (closeSignal - sl) * InpRR; + PlaceOrder(InpSymbol, ORDER_TYPE_BUY, InpFixedLot, sl, tp); + } + else if (stateSignal == BEARISH_STATE) + { + sl = kiSignal + atrPad; + tp = closeSignal - (sl - closeSignal) * InpRR; + PlaceOrder(InpSymbol, ORDER_TYPE_SELL, InpFixedLot, sl, tp); + } + + // After placement, trailing handled in OnTimer or OnTick below + if (InpTrailByKI) + TrailStopsByKI(); +} + +//+------------------------------------------------------------------+ +// Utilities +//+------------------------------------------------------------------+ +// +// Create or reuse an ATR handle for the given TF ... +int GetOrCreateATRHandle( + string symbol, + ENUM_TIMEFRAMES tf, + int period // +) +{ + int h = g_atrHandleH1; + if (tf == PERIOD_H4) + h = g_atrHandleH4; + else if (tf == PERIOD_D1) + h = g_atrHandleD1; + if (h == INVALID_HANDLE) + { + h = iATR(symbol, tf, period); + if (h == INVALID_HANDLE) + Print("Failed to create ATR handle: ", symbol, " ", EnumToString(tf), " period=", period); + } + return h; +} + +// +// Read ATR value for a specific bar shift (1=last closed bar) ... +double GetATRValue( + string symbol, + ENUM_TIMEFRAMES tf, + int period, + int shift // +) +{ + int h = GetOrCreateATRHandle(symbol, tf, period); + if (h == INVALID_HANDLE) + return EMPTY_VALUE; + + // + double buff[]; + + // + // Copy exactly one value at 'shift' ... + int copied = CopyBuffer(h, 0, shift, 1, buff); + if (copied != 1 || !MathIsValidNumber(buff[0])) + return EMPTY_VALUE; + + // + return buff[0]; +} + +// +// Create or reuse an RSI handle for the given TF ... +int GetOrCreateRSIHandle( + string symbol, + ENUM_TIMEFRAMES tf, + int period, + int appliedPrice // +) +{ + // + int h = g_rsiHandleH1; + if (tf == PERIOD_H4) + h = g_rsiHandleH4; + else if (tf == PERIOD_D1) + h = g_rsiHandleD1; + if (h == INVALID_HANDLE) + { + h = iRSI(symbol, tf, period, appliedPrice); + if (h == INVALID_HANDLE) + Print("Failed to create RSI handle: ", symbol, " ", EnumToString(tf), " period=", period, " price=", appliedPrice); + } + return h; +} + +// +// Read RSI value for a specific bar shift (1=last closed bar) .. +double GetRSIValue( + string symbol, + ENUM_TIMEFRAMES tf, + int period, + int appliedPrice, + int shift // +) +{ + int h = GetOrCreateRSIHandle(symbol, tf, period, appliedPrice); + if (h == INVALID_HANDLE) + return EMPTY_VALUE; + double buff[]; + int copied = CopyBuffer(h, 0, shift, 1, buff); + if (copied != 1 || !MathIsValidNumber(buff[0])) + return EMPTY_VALUE; + return buff[0]; +} + +datetime GetLastClosedBarTime(string symbol, ENUM_TIMEFRAMES tf) +{ + datetime times[]; + if (CopyTime(symbol, tf, 0, 3, times) <= 1) + return 0; + // times[0] is current open bar time; last closed is times[1] + return times[1]; +} + +bool IsHourInRange(int hr, int startHr, int endHr) +{ + // Handles wrap-around (e.g., 22 -> 6) + if (startHr <= endHr) + return (hr >= startHr && hr < endHr); + else + return (hr >= startHr || hr < endHr); +} + +bool GetXKIStateAndKI(string symbol, ENUM_TIMEFRAMES tf, int shift, int &stateOut, double &kiOut) +{ + // Prepare indicator handle for this TF + static int handleH1 = INVALID_HANDLE; + static int handleH4 = INVALID_HANDLE; + static int handleD1 = INVALID_HANDLE; + + int handleRef = handleH1; + if (tf == PERIOD_H4) + handleRef = handleH4; + else if (tf == PERIOD_D1) + handleRef = handleD1; + + if (handleRef == INVALID_HANDLE) + { + handleRef = iCustom(symbol, tf, g_xkiIndicatorPath, + InpKiLength, InpShowKI, InpCalcLastBars); + if (handleRef == INVALID_HANDLE) + { + Print("Failed to create XKI handle for TF: ", EnumToString(tf)); + return false; + } + } + + double kiBuff[]; + double stateBuff[]; + + if (CopyBuffer(handleRef, KI_BUFFER_INDEX, shift, 1, kiBuff) != 1) + return false; + if (CopyBuffer(handleRef, KI_STATE_BUFFER_INDEX, shift, 1, stateBuff) != 1) + return false; + + kiOut = kiBuff[0]; + stateOut = (int)stateBuff[0]; + + if (!MathIsValidNumber(kiOut)) + return false; + return true; +} + +bool HigherTFAgrees(string symbol, ENUM_TIMEFRAMES tf, int shift, int signalState) +{ + int stateHTF; + double kiHTF; + if (!GetXKIStateAndKI(symbol, tf, shift, stateHTF, kiHTF)) + return false; + if (signalState == BULLISH_STATE) + return (stateHTF == BULLISH_STATE); + if (signalState == BEARISH_STATE) + return (stateHTF == BEARISH_STATE); + return false; +} + +bool HasOpenPosition(string symbol, int magic) +{ + for (int i = 0; i < PositionsTotal(); i++) + { + ulong ticket = PositionGetTicket(i); + if (ticket == 0) + continue; + if (PositionSelectByTicket(ticket)) + { + string sym = PositionGetString(POSITION_SYMBOL); + long mg = (long)PositionGetInteger(POSITION_MAGIC); + if (sym == symbol && mg == magic) + return true; + } + } + return false; +} + +void PlaceOrder(string symbol, ENUM_ORDER_TYPE type, double lots, double sl, double tp) +{ + MqlTradeRequest req; + MqlTradeResult res; + ZeroMemory(req); + ZeroMemory(res); + + double price = 0.0; + if (!SymbolInfoTick(symbol, g_tick)) + return; + + if (type == ORDER_TYPE_BUY) + price = g_tick.ask; + else if (type == ORDER_TYPE_SELL) + price = g_tick.bid; + + // Normalize SL/TP + sl = NormalizeDouble(sl, g_digits); + tp = NormalizeDouble(tp, g_digits); + price = NormalizeDouble(price, g_digits); + + req.action = TRADE_ACTION_DEAL; + req.symbol = symbol; + req.volume = lots; + req.type = type; + req.price = price; + req.sl = sl; + req.tp = tp; + req.deviation = InpSlippagePoints; + req.magic = InpMagic; + req.comment = InpOrderComment; + + if (!OrderSend(req, res)) + Print("OrderSend failed: ", res.retcode); +} + +void TrailStopsByKI() +{ + // Trail per position using current signal TF KI + for (int i = 0; i < PositionsTotal(); i++) + { + ulong ticket = PositionGetTicket(i); + if (ticket == 0) + continue; + if (!PositionSelectByTicket(ticket)) + continue; + + string sym = PositionGetString(POSITION_SYMBOL); + long mg = (long)PositionGetInteger(POSITION_MAGIC); + if (sym != InpSymbol || mg != InpMagic) + continue; + + ENUM_POSITION_TYPE ptype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + double sl = PositionGetDouble(POSITION_SL); + double priceOpen = PositionGetDouble(POSITION_PRICE_OPEN); + + // Use last closed bar KI for stability + int shift = 1; + int state; + double ki; + if (!GetXKIStateAndKI(sym, InpSignalTF, shift, state, ki)) + continue; + + MqlTradeRequest req; + MqlTradeResult res; + ZeroMemory(req); + ZeroMemory(res); + + double newSL = sl; + + if (ptype == POSITION_TYPE_BUY) + { + double proposedSL = NormalizeDouble(ki, g_digits); + if (proposedSL > sl) + newSL = proposedSL; // only move up + } + else if (ptype == POSITION_TYPE_SELL) + { + double proposedSL = NormalizeDouble(ki, g_digits); + if (proposedSL < sl || sl == 0.0) + newSL = proposedSL; // only move down (or set if none) + } + + if (newSL != sl && newSL != 0.0) + { + req.action = TRADE_ACTION_SLTP; + req.symbol = sym; + req.sl = newSL; + req.tp = PositionGetDouble(POSITION_TP); + req.magic = InpMagic; + + if (!OrderSend(req, res)) + Print("Trail SLTP failed: ", res.retcode); + } + } +} + +//+------------------------------------------------------------------+ diff --git a/Experts/XPullbackTradeer.mq5 b/Documents/BKP/XPullbackTradeer.mq5 similarity index 100% rename from Experts/XPullbackTradeer.mq5 rename to Documents/BKP/XPullbackTradeer.mq5 diff --git a/Experts/XZoneEa.mq5 b/Documents/BKP/XZoneEa.mq5 similarity index 100% rename from Experts/XZoneEa.mq5 rename to Documents/BKP/XZoneEa.mq5 diff --git a/Experts/x-saherelm.x121.xki.ea.mq5 b/Experts/x-saherelm.x121.xki.ea.mq5 new file mode 100644 index 00000000..b2c6c93c --- /dev/null +++ b/Experts/x-saherelm.x121.xki.ea.mq5 @@ -0,0 +1,33 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Expert Advisor +// ------------------------------------------------- +// Name: X121XKIEA +// Description: Base Expert Advisor as Template ... +// +// 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 icon "../Images/SaherElm_Logo_Color.ico" +#property description "SaherElm XFIMA Expert Advisor" +#property strict + +// +#define ShortName "X121XKIEA" + +// +// Importts ... +#include "../X121XKIEA/Classes/x-saherelm.x121xki.expert.class.mq5" + +// +// Inputs ... + +//#region Inputs ... +//#endregion \ No newline at end of file diff --git a/Helpers/x-saherelm.x121.xki.helper.mq5 b/Helpers/x-saherelm.x121.xki.helper.mq5 new file mode 100644 index 00000000..bae8a028 --- /dev/null +++ b/Helpers/x-saherelm.x121.xki.helper.mq5 @@ -0,0 +1,1027 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XCX121XKIHelper +// Description: provides all Indicator +// Helper 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 "../Classes/x-saherelm.x-helper.class.mq5" + +// #region Buffers ... +enum ENUM_X121_XKI_BUFFERS +{ + // + // KI ... + X121_XKI_KI_LINE = 0, + X121_XKI_KI_COLOR_LINE = 1, + X121_XKI_KI_STATE_LINE = 8, + // + // KI Wave ... + X121_XKI_KI_WAVE_LINE = 2, + X121_XKI_KI_WAVE_RAW_LINE = 13, + X121_XKI_KI_WAVE_COLOR_LINE = 3, + X121_XKI_KI_WAVE_STATE_LINE = 14, + // + // Upper/Lower ... + X121_XKI_KI_UPPER_LINE = 4, + X121_XKI_KI_LOWER_LINE = 5, + // + // MA Fast/Slow ... + X121_XKI_MA_FAST_LINE = 6, + X121_XKI_MA_SLOW_LINE = 7, + // + // ATR ... + X121_XKI_ATR_LINE = 9, + X121_XKI_ATR_RAW_UPPER_LINE = 10, + X121_XKI_ATR_RAW_LOWER_LINE = 11, + // + // RSI ... + X121_XKI_RSI_LINE = 12, +}; +// #endregion + +// #region Inputs ... +struct X121XKIInputs +{ + // #region Props ... + // #region Calculations ... + int kiLength; // KI Length + int maFastLength; // MA Fast Length + int maSlowLength; // MA Slow Length + ENUM_MA_METHOD maMethod; // MA Mode + ENUM_APPLIED_PRICE maAppliedTo; // MA Applied To + int rsiLength; // RSI Length + ENUM_APPLIED_PRICE rsiAppliedTo; // RSI Applied To + int kiWaveSmoothingLength; // RSI KI Wave Smoothing Length + ENUM_X_MA_METHOD kiWaveSmoothingMode; // RSI KI Wave Smoothing Method + double rsiMultiplier; // RSI Multiplier + int atrLength; // ATR Length + double atrMultiplier; // ATR Multiplier + int atrSmoothingLength; // ATR Smoothing Length + ENUM_X_MA_METHOD atrSmoothingMode; // ATR Smoothing Method + ENUM_X_PRICE atrUpperPriceType; // ATR Upper Price Type + ENUM_X_PRICE atrLowerPriceType; // ATR Lower Price Type + // #endregion + + // #region Presentations ... + bool showKI; // Show KI + bool showMaFast; // Show Ma Fast + bool showMaSlow; // Show MA Slow + bool showKIWave; // Show KI Wave + bool showKIUpper; // Show KI Upper + bool showKILower; // Show KI Lower + + // + int startCalculationForLastBars; // Calculate Last n Bars + // #endregion + // #endregion + + // + // Constructor(s) ... + X121XKIInputs() + { + Clean(); + } + + // #region Tools ... + // + // Clean ... + void Clean() + { + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + // Calculations ... + kiLength = 26; + maFastLength = 9; + maSlowLength = 26; + maMethod = MODE_EMA; + maAppliedTo = PRICE_CLOSE; + rsiLength = 14; + rsiAppliedTo = PRICE_CLOSE; + kiWaveSmoothingLength = 14; + kiWaveSmoothingMode = X_MA_MODE_EMA; + rsiMultiplier = 0.5; + atrLength = 14; + atrMultiplier = 2; + atrSmoothingLength = 14; + atrSmoothingMode = X_MA_MODE_EMA; + atrUpperPriceType = X_PRICE_HIGH; + atrLowerPriceType = X_PRICE_LOW; + + // + // Presentations ... + showKI = true; + showMaFast = true; + showMaSlow = true; + showKIWave = true; + showKIUpper = true; + showKILower = true; + + // + startCalculationForLastBars = 1500; + } + + // + // Hide ... + void Hide() + { + // + // Presentations ... + showKI = false; + showMaFast = false; + showMaSlow = false; + showKIWave = false; + showKIUpper = false; + showKILower = false; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + // KI ... + kiLength >= 5 && + // + // ATR ... + atrLength >= 5 && + // + // RSI ... + rsiLength >= 5 + // + ; + + // + return result; + } + // #endregion +}; +// #endregion + +// #region Conditions ... +struct X121XKIConditions +{ + // #region Commons ... + string symbol; + ENUM_TIMEFRAMES period; + datetime time; + + // + datetime to; + datetime from; + XOHCL bars[]; + // #endregion + + // #region Buffers ... + double kiBuffer[]; + double kiColorBuffer[]; + double kiWaveBuffer[]; + double kiWaveColorBuffer[]; + double kiUpperBuffer[]; + double kiLowerBuffer[]; + double maFastBuffer[]; + double maSlowBuffer[]; + double kiStateBuffer[]; + double atrBuffer[]; + double atrRawUpperBuffer[]; + double atrRawLowerBuffer[]; + double rsiBuffer[]; + double kiWaveRawBuffer[]; + double kiWaveStateBuffer[]; + // #endregion + + // + // Constructor ... + X121XKIConditions() + { + Clean(); + } + + // #region Tools ... + /** + * Cleaning Up ... + */ + void Clean() + { + // + // Commons ... + to = NULL; + from = NULL; + time = NULL; + symbol = NULL; + period = NULL; + + // + // Buffers ... + + // + XClean(kiBuffer); + XClean(kiColorBuffer); + XClean(kiWaveBuffer); + XClean(kiWaveColorBuffer); + XClean(kiUpperBuffer); + XClean(kiLowerBuffer); + XClean(maFastBuffer); + XClean(maSlowBuffer); + XClean(kiStateBuffer); + XClean(atrBuffer); + XClean(atrRawUpperBuffer); + XClean(atrRawLowerBuffer); + XClean(rsiBuffer); + XClean(kiWaveRawBuffer); + XClean(kiWaveStateBuffer); + + // + ArraySetAsSeries(kiBuffer, true); + ArraySetAsSeries(kiColorBuffer, true); + ArraySetAsSeries(kiWaveBuffer, true); + ArraySetAsSeries(kiWaveColorBuffer, true); + ArraySetAsSeries(kiUpperBuffer, true); + ArraySetAsSeries(kiLowerBuffer, true); + ArraySetAsSeries(maFastBuffer, true); + ArraySetAsSeries(maSlowBuffer, true); + ArraySetAsSeries(kiStateBuffer, true); + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(atrRawUpperBuffer, true); + ArraySetAsSeries(atrRawLowerBuffer, true); + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(kiWaveRawBuffer, true); + ArraySetAsSeries(kiWaveStateBuffer, true); + + // + ZeroMemory(this); + } + + /** + * Retrieve Unique Tag Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + return GetToken(this); + } + // #endregion +}; +// #endregion + +// #region Class ... +class XCX121XKIHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Constructors ... + XCX121XKIHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XKIHelper() + { + } + + // #region Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XKIInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xki", + "", // Calculation ... + mInputs.kiLength, + mInputs.maFastLength, + mInputs.maSlowLength, + mInputs.maMethod, + mInputs.maAppliedTo, + mInputs.rsiLength, + mInputs.rsiAppliedTo, + mInputs.kiWaveSmoothingLength, + mInputs.kiWaveSmoothingMode, + mInputs.rsiMultiplier, + mInputs.atrLength, + mInputs.atrMultiplier, + mInputs.atrSmoothingLength, + mInputs.atrSmoothingMode, + mInputs.atrUpperPriceType, + mInputs.atrLowerPriceType, + "", // Presentation ... + mInputs.showKI, + mInputs.showMaFast, + mInputs.showMaSlow, + mInputs.showKIWave, + mInputs.showKIUpper, + mInputs.showKILower, + mInputs.startCalculationForLastBars // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XKIInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XKIInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs // + ); + } + + // + bool GetConditions( + X121XKIConditions &conditions, // + int barIndex = 0, // + int loopback = 5 // + ) + { + // + bool result = true; + + // + if (loopback < 5) + { + loopback = 5; + } + + // + conditions.Clean(); + + // + conditions.symbol = mSymbol; + conditions.period = mPeriod; + conditions.time = TimeCurrent(); + + // + // Filling Bars ... + int barsCount = GetBars( + conditions.bars, + mSymbol, + mPeriod, + barIndex, + loopback // + ); + result = barsCount == loopback; + if (!result) + { + // + conditions.Clean(); + + // + return result; + } + + // + conditions.to = conditions.bars[0].time; + conditions.from = conditions.bars[ArraySize(conditions.bars) - 1].time; + + // + int zIndex = barIndex; + + // #region Reading Buffers ... + CopyKI( + zIndex, + loopback, + conditions.kiBuffer // + ); + CopyKIColor( + zIndex, + loopback, + conditions.kiColorBuffer // + ); + CopyKIState( + zIndex, + loopback, + conditions.kiStateBuffer // + ); + CopyKIWave( + zIndex, + loopback, + conditions.kiWaveBuffer // + ); + CopyKIWaveRaw( + zIndex, + loopback, + conditions.kiWaveRawBuffer // + ); + CopyKIWaveColor( + zIndex, + loopback, + conditions.kiWaveColorBuffer // + ); + CopyKIWaveState( + zIndex, + loopback, + conditions.kiWaveStateBuffer // + ); + CopyKIUpper( + zIndex, + loopback, + conditions.kiUpperBuffer // + ); + CopyKILower( + zIndex, + loopback, + conditions.kiLowerBuffer // + ); + CopyMAFast( + zIndex, + loopback, + conditions.maFastBuffer // + ); + CopyMASlow( + zIndex, + loopback, + conditions.maSlowBuffer // + ); + CopyRSI( + zIndex, + loopback, + conditions.rsiBuffer // + ); + CopyATR( + zIndex, + loopback, + conditions.atrBuffer // + ); + CopyATRRawUpper( + zIndex, + loopback, + conditions.atrRawUpperBuffer // + ); + CopyATRRawLower( + zIndex, + loopback, + conditions.atrRawLowerBuffer // + ); + // #endregion + + // + return result; + } + // #endregion + + // #region Buffer Readers ... + // #region KI ... + // + double GetKI( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_KI_LINE, + barIndex // + ); + } + + // + int CopyKI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_KI_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region KI Color ... + // + double GetKIColor( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_KI_COLOR_LINE, + barIndex // + ); + } + + // + int CopyKIColor( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_KI_COLOR_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region KI State ... + // + double GetKIState( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_KI_STATE_LINE, + barIndex // + ); + } + + // + int CopyKIState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_KI_STATE_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region KI Wave ... + // + double GetKIWave( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_KI_WAVE_LINE, + barIndex // + ); + } + + // + int CopyKIWave( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_KI_WAVE_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region KI Wave Raw ... + // + double GetKIWaveRaw( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_KI_WAVE_RAW_LINE, + barIndex // + ); + } + + // + int CopyKIWaveRaw( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_KI_WAVE_RAW_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region KI Wave Color ... + // + double GetKIWaveColor( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_KI_WAVE_COLOR_LINE, + barIndex // + ); + } + + // + int CopyKIWaveColor( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_KI_WAVE_COLOR_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region KI Wave State ... + // + double GetKIWaveState( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_KI_WAVE_STATE_LINE, + barIndex // + ); + } + + // + int CopyKIWaveState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_KI_WAVE_STATE_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region KI Upper ... + // + double GetKIUpper( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_KI_UPPER_LINE, + barIndex // + ); + } + + // + int CopyKIUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_KI_UPPER_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region KI Lower ... + // + double GetKILower( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_KI_LOWER_LINE, + barIndex // + ); + } + + // + int CopyKILower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_KI_LOWER_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region MA Fast ... + // + double GetMAFast( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_MA_FAST_LINE, + barIndex // + ); + } + + // + int CopyMAFast( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_MA_FAST_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region MA Slow ... + // + double GetMASlow( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_MA_SLOW_LINE, + barIndex // + ); + } + + // + int CopyMASlow( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_MA_SLOW_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region RSI ... + // + double GetRSI( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_RSI_LINE, + barIndex // + ); + } + + // + int CopyRSI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_RSI_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region ATR ... + // + double GetATR( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_ATR_LINE, + barIndex // + ); + } + + // + int CopyATR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_ATR_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region ATR Raw Upper... + // + double GetATRRawUpper( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_ATR_RAW_UPPER_LINE, + barIndex // + ); + } + + // + int CopyATRRawUpper( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_ATR_RAW_UPPER_LINE, + start, + count, + asSeries // + ); + } + // #endregion + + // #region ATR Raw Lower... + // + double GetATRRawLower( + int barIndex // Bar Index + ) + { + // + return ReadValue( + (int)X121_XKI_ATR_RAW_LOWER_LINE, + barIndex // + ); + } + + // + int CopyATRRawLower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool asSeries = true // As Series Flag + ) + { + // + return ReadValues( + buffer, + (int)X121_XKI_ATR_RAW_LOWER_LINE, + start, + count, + asSeries // + ); + } + // #endregion + // #endregion + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XKIInputs mInputs; // Inputs ... +}; +// #endregion \ No newline at end of file diff --git a/Indicators/x-saherelm.x121.xki.mq5 b/Indicators/x-saherelm.x121.xki.mq5 new file mode 100644 index 00000000..7c6c4ad0 --- /dev/null +++ b/Indicators/x-saherelm.x121.xki.mq5 @@ -0,0 +1,1183 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: XKI +// Description: a Kijunsen Based Indicator ... +// +// +// 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 XKI Indicator" +#property icon "../Images/SaherElm_Logo_Color.ico" +#property strict + +// +// Definitions ... + +// +#define ShortName "XKI" + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// #region Inputs ... +// +input group "Calculation"; +input int kiLength = 26; // KI Length +input int maFastLength = 9; // MA Fast Length +input int maSlowLength = 26; // MA Slow Length +input ENUM_MA_METHOD maMethod = MODE_EMA; // MA Mode +input ENUM_APPLIED_PRICE maAppliedTo = PRICE_CLOSE; // MA Applied To +input int rsiLength = 14; // RSI Length +input ENUM_APPLIED_PRICE rsiAppliedTo = PRICE_CLOSE; // RSI Applied To +input int kiWaveSmoothingLength = 14; // RSI KI Wave Smoothing Length +input ENUM_X_MA_METHOD kiWaveSmoothingMode = X_MA_MODE_EMA; // RSI KI Wave Smoothing Method +input double rsiMultiplier = 0.5; // RSI Multiplier +input int atrLength = 14; // ATR Length +input double atrMultiplier = 2; // ATR Multiplier +input int atrSmoothingLength = 14; // ATR Smoothing Length +input ENUM_X_MA_METHOD atrSmoothingMode = X_MA_MODE_EMA; // ATR Smoothing Method +input ENUM_X_PRICE atrUpperPriceType = X_PRICE_HIGH; // ATR Upper Price Type +input ENUM_X_PRICE atrLowerPriceType = X_PRICE_LOW; // ATR Lower Price Type + +// +// Presentation ... +input group "Presentation"; +input bool showKI = true; // Show KI +input bool showMaFast = true; // Show Ma Fast +input bool showMaSlow = true; // Show MA Slow +input bool showKIWave = true; // Show KI Wave +input bool showKIUpper = true; // Show KI Upper +input bool showKILower = true; // Show KI Lower + +// +input int startCalculationForLastBars = 1500; // Calculate Last n Bars +// #endregion + +// #region Non Inputs ... +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#define bullishState 1 +#define neuturalState 0 +#define bearishState -1 + +// +#define emptyValue 0.0 +// #endregion + +// #region Buffers ... +// +#property indicator_chart_window + +// +#property indicator_buffers 15 +#property indicator_plots 6 + +// #region Plot Buffers ... +// #region KI ... +// +#define kiBufferIndex 0 +#define kiBufferPlotIndex 0 +double kiBuffer[]; + +// +#define kiColorBufferIndex 1 +double kiColorBuffer[]; + +// +#property indicator_label1 "KI" +#property indicator_type1 DRAW_COLOR_LINE +#property indicator_color1 CLR_NONE, clrGreen, clrRed, clrGray +#property indicator_style1 STYLE_SOLID +#property indicator_width1 2 +// #endregion + +// #region KI Wave ... +// +#define kiWaveBufferIndex 2 +#define kiWaveBufferPlotIndex 2 +double kiWaveBuffer[]; + +// +#define kiWaveColorBufferIndex 3 +double kiWaveColorBuffer[]; + +// +#property indicator_label2 "KI Wave" +#property indicator_type2 DRAW_COLOR_LINE +#property indicator_color2 CLR_NONE, clrGreen, clrRed, clrGray +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 +// #endregion + +// #region KI Upper ... +// +#define kiUpperBufferIndex 4 +#define kiUpperBufferPlotIndex 4 +double kiUpperBuffer[]; + +// +#property indicator_label3 "KI Upper" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrAqua +#property indicator_style3 STYLE_DASH +#property indicator_width3 1 +// #endregion + +// #region KI Lower ... +// +#define kiLowerBufferIndex 5 +#define kiLowerBufferPlotIndex 5 +double kiLowerBuffer[]; + +// +#property indicator_label4 "KI Lower" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrMagenta +#property indicator_style4 STYLE_DASH +#property indicator_width4 1 +// #endregion + +// #region MA Fast ... +// +#define maFastBufferIndex 6 +#define maFastBufferPlotIndex 6 +double maFastBuffer[]; + +// +#property indicator_label5 "MA Fast" +#property indicator_type5 DRAW_LINE +#property indicator_color5 clrLime +#property indicator_style5 STYLE_DOT +#property indicator_width5 1 +// #endregion + +// #region MA Slow ... +// +#define maSlowBufferIndex 7 +#define maSlowBufferPlotIndex 7 +double maSlowBuffer[]; + +// +#property indicator_label6 "MA Slow" +#property indicator_type6 DRAW_LINE +#property indicator_color6 clrRed +#property indicator_style6 STYLE_DOT +#property indicator_width6 1 +// #endregion +// #endregion + +// +#define mLastBufferIndex 7 + +// #region Data Buffers ... +// +#define kiStateBufferIndex mLastBufferIndex + 1 +double kiStateBuffer[]; + +// +#define atrBufferIndex mLastBufferIndex + 2 +double atrBuffer[]; + +// +#define atrRawUpperBufferIndex mLastBufferIndex + 3 +double atrRawUpperBuffer[]; + +// +#define atrRawLowerBufferIndex mLastBufferIndex + 4 +double atrRawLowerBuffer[]; + +// +#define rsiBufferIndex mLastBufferIndex + 5 +double rsiBuffer[]; + +// +#define kiWaveRawBufferIndex mLastBufferIndex + 6 +double kiWaveRawBuffer[]; + +// +#define kiWaveStateBufferIndex mLastBufferIndex + 7 +double kiWaveStateBuffer[]; +// #endregion +// #endregion + +// #region Variables, Properties and etc ... +// +int limit; + +// +int maxLength; + +// +int firstBarIndex; + +// +// Handlers ... +int atrHandler = INVALID_HANDLE; +int rsiHandler = INVALID_HANDLE; +int maFastHandler = INVALID_HANDLE; +int maSlowHandler = INVALID_HANDLE; +// #endregion + +// #region Event Handlers ... +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + bool has = false; + + // + // Validate Inputs ... + has = ValidateInputs(); + if (!has) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // 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(); + + // + // Initial Requirements ... + has = InitRequirements(); + if (!has) + { + return INIT_FAILED; + } + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // 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 + + // + // De Initialize all Handlers and etc ... + + // + // ATR ... + if (atrHandler != INVALID_HANDLE) + { + IndicatorRelease(atrHandler); + } + + // + // RSI ... + if (rsiHandler != INVALID_HANDLE) + { + IndicatorRelease(rsiHandler); + } + + // + // MA Fast ... + if (maFastHandler != INVALID_HANDLE) + { + IndicatorRelease(maFastHandler); + } + // + // MA Slow ... + if (maSlowHandler != INVALID_HANDLE) + { + IndicatorRelease(maSlowHandler); + } +} + +/** + * 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); + + // + // Validate Calculated Bars ... + + // + // ATR ... + int atrCalculatedBars = BarsCalculated(atrHandler); + + // + // RSI ... + int rsiCalculatedBars = BarsCalculated(rsiHandler); + + // + // MA ... + int maFastCalculatedBars = BarsCalculated(maFastHandler); + int maSlowCalculatedBars = BarsCalculated(maSlowHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // ATR ... + atrCalculatedBars >= maxLength && + // + // RSI ... + rsiCalculatedBars >= maxLength && + // + // MA ... + maFastCalculatedBars >= maxLength && + maSlowCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // ATR ... + int copiedATRs = CopyBuffer(atrHandler, MAIN_LINE, 0, limit, atrBuffer); + + // + // RSI ... + int copiedRSIs = CopyBuffer(rsiHandler, MAIN_LINE, 0, limit, rsiBuffer); + + // + // MA ... + int copiedMAFasts = CopyBuffer(maFastHandler, MAIN_LINE, 0, limit, maFastBuffer); + int copiedMASlows = CopyBuffer(maSlowHandler, MAIN_LINE, 0, limit, maSlowBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // ATR ... + copiedATRs >= limit && + // + // RSI ... + copiedRSIs >= limit && + // + // MA ... + copiedMAFasts >= limit && + copiedMASlows >= limit + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // 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; +} +// #endregion + +// #region Custom Functions ... +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + // + IndicatorSetInteger(INDICATOR_DIGITS, _Digits); + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + // KI ... + kiLength >= 5 && + // + // ATR ... + atrLength >= 5 && + // + // RSI ... + rsiLength >= 5 + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(kiLength, atrLength); + result = MathMax(result, rsiLength); + + // + if (atrSmoothingLength > 0) + { + result = MathMax(result, atrSmoothingLength); + } + if (kiWaveSmoothingLength > 0) + { + result = MathMax(result, kiWaveSmoothingLength); + } + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // #region KI ... + // + ArraySetAsSeries(kiBuffer, true); + SetIndexBuffer(kiBufferIndex, kiBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(kiBufferPlotIndex, PLOT_SHOW_DATA, showKI); + PlotIndexSetDouble(kiBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + + // + ArraySetAsSeries(kiColorBuffer, true); + SetIndexBuffer(kiColorBufferIndex, kiColorBuffer, INDICATOR_COLOR_INDEX); + + // + ArraySetAsSeries(kiStateBuffer, true); + SetIndexBuffer(kiStateBufferIndex, kiStateBuffer, INDICATOR_CALCULATIONS); + // #endregion + + // #region KI Upper ... + // + ENUM_DRAW_TYPE kiUpperDrawType = showKIUpper ? DRAW_LINE : DRAW_NONE; + + // + // Upper ... + ArraySetAsSeries(kiUpperBuffer, true); + SetIndexBuffer(kiUpperBufferIndex, kiUpperBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(kiUpperBufferPlotIndex, PLOT_SHOW_DATA, showKIUpper); + PlotIndexSetInteger(kiUpperBufferPlotIndex, PLOT_DRAW_TYPE, kiUpperDrawType); + PlotIndexSetDouble(kiUpperBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + // #endregion + + // #region KI Lower ... + // + ENUM_DRAW_TYPE kiLowerDrawType = showKILower ? DRAW_LINE : DRAW_NONE; + + // + // Upper ... + ArraySetAsSeries(kiLowerBuffer, true); + SetIndexBuffer(kiLowerBufferIndex, kiLowerBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(kiLowerBufferPlotIndex, PLOT_SHOW_DATA, showKILower); + PlotIndexSetInteger(kiLowerBufferPlotIndex, PLOT_DRAW_TYPE, kiLowerDrawType); + PlotIndexSetDouble(kiLowerBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + // #endregion + + // #region KI Wave ... + // + ArraySetAsSeries(kiWaveBuffer, true); + SetIndexBuffer(kiWaveBufferIndex, kiWaveBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(kiWaveBufferPlotIndex, PLOT_SHOW_DATA, showKIWave); + PlotIndexSetDouble(kiWaveBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + + // + ArraySetAsSeries(kiWaveColorBuffer, true); + SetIndexBuffer(kiWaveColorBufferIndex, kiWaveColorBuffer, INDICATOR_COLOR_INDEX); + + // + ArraySetAsSeries(rsiBuffer, true); + SetIndexBuffer(rsiBufferIndex, rsiBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(kiWaveRawBuffer, true); + SetIndexBuffer(kiWaveRawBufferIndex, kiWaveRawBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(kiWaveStateBuffer, true); + SetIndexBuffer(kiWaveStateBufferIndex, kiWaveStateBuffer, INDICATOR_CALCULATIONS); + // #endregion + + // #region ATR ... + // + ArraySetAsSeries(atrBuffer, true); + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(atrRawUpperBuffer, true); + SetIndexBuffer(atrRawUpperBufferIndex, atrRawUpperBuffer, INDICATOR_CALCULATIONS); + + // + ArraySetAsSeries(atrRawLowerBuffer, true); + SetIndexBuffer(atrRawLowerBufferIndex, atrRawLowerBuffer, INDICATOR_CALCULATIONS); + // #endregion + + // #region MA ... + // #region Fast ... + // + ENUM_DRAW_TYPE maFastDrawType = showMaFast ? DRAW_LINE : DRAW_NONE; + + // + // Fast ... + ArraySetAsSeries(maFastBuffer, true); + SetIndexBuffer(maFastBufferIndex, maFastBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(maFastBufferPlotIndex, PLOT_SHOW_DATA, showMaFast); + PlotIndexSetInteger(maFastBufferPlotIndex, PLOT_DRAW_TYPE, maFastDrawType); + PlotIndexSetDouble(maFastBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + // #endregion + + // #region Slow ... + // + ENUM_DRAW_TYPE maSlowDrawType = showMaSlow ? DRAW_LINE : DRAW_NONE; + + // + // Slow ... + ArraySetAsSeries(maSlowBuffer, true); + SetIndexBuffer(maSlowBufferIndex, maSlowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(maSlowBufferPlotIndex, PLOT_SHOW_DATA, showMaSlow); + PlotIndexSetInteger(maSlowBufferPlotIndex, PLOT_DRAW_TYPE, maSlowDrawType); + PlotIndexSetDouble(maSlowBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + // #endregion + // #endregion +} + +/** + * Initial all Indicator Requirements ... + * + * @return ( false ) + * + */ +bool InitRequirements() +{ + // + bool result = false; + + // + // Handlers ... + + // + // ATR ... + atrHandler = iATR( + _Symbol, + _Period, + atrLength // + ); + result = atrHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // RSI ... + rsiHandler = iRSI( + _Symbol, + _Period, + rsiLength, + rsiAppliedTo // + ); + result = rsiHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // MA Fast ... + maFastHandler = iMA( + _Symbol, + _Period, + maFastLength, + 0, + maMethod, + maAppliedTo // + ); + result = maFastHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + // + // MA Slow ... + maSlowHandler = iMA( + _Symbol, + _Period, + maSlowLength, + 0, + maMethod, + maAppliedTo // + ); + result = maSlowHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; +} + +/** + * Calculate Custom Buffers ... + * + * @param barIndex: 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 barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // Calculate Bars Limit and First Bar Index ... + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + if (barsLimit == 0) + { + // + barsLimit = ratesTotal; + firstBarIndex = barsLimit - 1; + } + else + { + firstBarIndex = startCalculationForLastBars; + } + + // + // bool canCalculate = true; + bool canCalculate = + barIndex <= barsLimit; + if (canCalculate) + { + // + // Calculate Values ... + CalculateValues( + barIndex, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(barIndex); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + // TODO: Fill Buffers as Empty ... +} + +/** + * Calculate Values ... + * + * @param barIndex: int, Specified Bar Index ... + * @param prevCalculated: int, Provides Previous Calculated Bars ... + * @param ratesTotal: int, Provides All Availabled Bars ... + * @param open: double Collection, Provides Open Prices Time Series ... + * @param high: double Collection, Provides High Prices Time Series ... + * @param close: double Collection, Provides Close Prices Time Series ... + * @param low: double Collection, Provides Low Prices Time Series ... + * @param tickVolume: long Collection, Provides Ticks Volume Prices Time Series ... + */ +void CalculateValues( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int lastBarIndex = barIndex + 1; + int maxBarIndex = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : ratesTotal; + bool isFirstBar = + startCalculationForLastBars > 0 + ? barIndex == startCalculationForLastBars + : barIndex == firstBarIndex; + + // + // Common Requirements ... + + // #region KI ... + CalculateKI( + barIndex, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + // #endregion + + // #region ATR (Ki Upper/Lower) ... + CalculateATR( + barIndex, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + // #endregion + + // #region RSI (Ki Wave) ... + CalculateRSI( + barIndex, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + // #endregion +} + +/** + * Calculate KI Bufer ... + * + * @param barIndex: int, Specified Bar Index ... + * @param prevCalculated: int, Provides Previous Calculated Bars ... + * @param ratesTotal: int, Provides All Availabled Bars ... + * @param open: double Collection, Provides Open Prices Time Series ... + * @param high: double Collection, Provides High Prices Time Series ... + * @param close: double Collection, Provides Close Prices Time Series ... + * @param low: double Collection, Provides Low Prices Time Series ... + * @param tickVolume: long Collection, Provides Ticks Volume Prices Time Series ... + */ +void CalculateKI( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int lastBarIndex = barIndex + 1; + bool isFirstBar = + startCalculationForLastBars > 0 + ? barIndex == startCalculationForLastBars + : barIndex == firstBarIndex; + + // + XOHCL iBar; + bool isInited = iBar.Init( + _Symbol, + _Period, + barIndex // + ); + + // + double iClose = close[barIndex]; + + // + // Calculate KI / Color ... + double lastKI = + isFirstBar + ? emptyValue + : kiBuffer[lastBarIndex]; + double iKI = lastKI; + if (isInited) + { + // + double iLLKI = iBar.FindLowest(kiLength, MODE_LOW); + double iHHKI = iBar.FindHighest(kiLength, MODE_HIGH); + + // + iKI = (iHHKI + iLLKI) / 2; + if (iLLKI == 0 || iHHKI == 0) + { + iKI = lastKI; + } + } + else + { + iKI = lastKI; + } + kiBuffer[barIndex] = iKI; + + // + double iKIState = neuturalState; + double iKIColor = neuturalColorIDX; + if (iClose > iKI) + { + // + iKIState = bullishState; + iKIColor = + !showKI + ? hideColorIDX + : bullishColorIDX; + } + else if (iClose < iKI) + { + // + iKIState = bearishState; + iKIColor = + !showKI + ? hideColorIDX + : bearishColorIDX; + } + kiStateBuffer[barIndex] = iKIState; + kiColorBuffer[barIndex] = iKIColor; + + // + iBar.Clean(); +} + +/** + * Calculate ATR and Ki Upper/Lower Buffers ... + * + * @param barIndex: int, Specified Bar Index ... + * @param prevCalculated: int, Provides Previous Calculated Bars ... + * @param ratesTotal: int, Provides All Availabled Bars ... + * @param open: double Collection, Provides Open Prices Time Series ... + * @param high: double Collection, Provides High Prices Time Series ... + * @param close: double Collection, Provides Close Prices Time Series ... + * @param low: double Collection, Provides Low Prices Time Series ... + * @param tickVolume: long Collection, Provides Ticks Volume Prices Time Series ... + */ +void CalculateATR( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int lastBarIndex = barIndex + 1; + bool isFirstBar = + startCalculationForLastBars > 0 + ? barIndex == startCalculationForLastBars + : barIndex == firstBarIndex; + + // + double iKI = kiBuffer[barIndex]; + double iAtr = atrBuffer[barIndex]; + double iAppliedAtr = atrMultiplier <= 0 + ? iAtr + : atrMultiplier * iAtr; + + // + double iPriceMid = 0; + if (IsXValid(atrUpperPriceType) && + IsXValid(atrLowerPriceType)) + { + // + double iUpperPrice = GetAppliedPrice( + atrUpperPriceType, + open, + high, + low, + close, + barIndex // + ); + double iLowerPrice = GetAppliedPrice( + atrLowerPriceType, + open, + high, + low, + close, + barIndex // + ); + iPriceMid = ((iUpperPrice - iLowerPrice) / 2); + } + + // + double iUpperValue = iKI + iPriceMid + iAppliedAtr; + double iLowerValue = iKI - iPriceMid - iAppliedAtr; + + // + atrRawUpperBuffer[barIndex] = iUpperValue; + atrRawLowerBuffer[barIndex] = iLowerValue; + + // + // Check Can Smooth Atr ... + if (IsXValid(atrSmoothingMode) && + atrSmoothingLength > 0) + { + // + // Upper ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + barIndex, + atrSmoothingLength, + atrRawUpperBuffer, + kiUpperBuffer, + atrSmoothingMode // + ); + + // + // Lower ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + barIndex, + atrSmoothingLength, + atrRawLowerBuffer, + kiLowerBuffer, + atrSmoothingMode // + ); + } + else + { + // + kiUpperBuffer[barIndex] = iUpperValue; + kiLowerBuffer[barIndex] = iLowerValue; + } +} + +/** + * Calculate RSI and Ki Wave Buffers ... + * + * @param barIndex: int, Specified Bar Index ... + * @param prevCalculated: int, Provides Previous Calculated Bars ... + * @param ratesTotal: int, Provides All Availabled Bars ... + * @param open: double Collection, Provides Open Prices Time Series ... + * @param high: double Collection, Provides High Prices Time Series ... + * @param close: double Collection, Provides Close Prices Time Series ... + * @param low: double Collection, Provides Low Prices Time Series ... + * @param tickVolume: long Collection, Provides Ticks Volume Prices Time Series ... + */ +void CalculateRSI( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int lastBarIndex = barIndex + 1; + bool isFirstBar = + startCalculationForLastBars > 0 + ? barIndex == startCalculationForLastBars + : barIndex == firstBarIndex; + + // + double iKI = kiBuffer[barIndex]; + double iRsi = rsiBuffer[barIndex]; + double iAppliedRsi = rsiMultiplier <= 0 + ? iRsi + : rsiMultiplier * iRsi; + + // + double iValue = iKI + iAppliedRsi; + + // + double iState = + iRsi >= 55 + ? bullishState + : iRsi <= 45 + ? bearishState + : neuturalState; + double iColor = + iRsi >= 55 + ? bullishColorIDX + : iRsi <= 45 + ? bearishColorIDX + : neuturalColorIDX; + if (!showKIWave) + { + iColor = hideColorIDX; + } + + // + kiWaveRawBuffer[barIndex] = iValue; + kiWaveColorBuffer[barIndex] = iColor; + kiWaveStateBuffer[barIndex] = iState; + + // + // Check Can Smooth Atr ... + if (IsXValid(kiWaveSmoothingMode) && + kiWaveSmoothingLength > 0) + { + // + // Ki Wave ... + iMAOnBuffer( + ratesTotal, + prevCalculated, + barIndex, + kiWaveSmoothingLength, + kiWaveRawBuffer, + kiWaveBuffer, + kiWaveSmoothingMode // + ); + } + else + { + // + kiWaveBuffer[barIndex] = iValue; + } +} +// #endregion \ No newline at end of file diff --git a/MQL5.code-workspace b/MQL5.code-workspace index 19d29201..cb107554 100644 --- a/MQL5.code-workspace +++ b/MQL5.code-workspace @@ -8,7 +8,8 @@ "C_Cpp.default.includePath": [ "c:\\Users\\SaherElm\\AppData\\Roaming\\MetaQuotes\\Terminal\\D0E8209F77C8CF37AD8BF550E51FF075\\MQL5\\Include\\Include", "c:\\Users\\SaherElm\\AppData\\Roaming\\MetaQuotes\\Terminal\\D0E8209F77C8CF37AD8BF550E51FF075\\MQL5\\Include", - "c:\\Users\\SaherElm\\AppData\\Roaming\\MetaQuotes\\Terminal\\572C4A1F743028C65C8BA0B780030F0D\\MQL5\\Include" + "c:\\Users\\SaherElm\\AppData\\Roaming\\MetaQuotes\\Terminal\\572C4A1F743028C65C8BA0B780030F0D\\MQL5\\Include", + "c:\\Users\\saherelm\\AppData\\Roaming\\MetaQuotes\\Terminal\\D0E8209F77C8CF37AD8BF550E51FF075\\MQL5\\Include" ], "C_Cpp.clang_format_style": "{ BasedOnStyle: Microsoft, UseTab: Never, IndentWidth: 4, TabWidth: 4, ColumnLimit: 0}", "files.associations": { diff --git a/X121XKIEA/Classes/x-saherelm.x121xki.expert.class.mq5 b/X121XKIEA/Classes/x-saherelm.x121xki.expert.class.mq5 new file mode 100644 index 00000000..e69de29b