diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.http.class.ex5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.http.class.ex5 new file mode 100644 index 0000000..4314b81 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.http.class.ex5 differ diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.http.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.http.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.http.class.mq5 rename to MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.http.class.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.provider.class.ex5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.provider.class.ex5 new file mode 100644 index 0000000..9306aaf Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.provider.class.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.provider.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.provider.class.mq5 new file mode 100644 index 0000000..70d67e2 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.provider.class.mq5 @@ -0,0 +1,62 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSC121Provider +// Description: a Market Analyser and Signal Provider +// +// +// 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 + +// +// TODO: +// - [] add XCT for Candle Timing ... +// - [] add XCS for Candle Styling ... +// - [] add Support for XZG Indicator ... +// - [] implement XPV based on Market Cycles ... +// - [] create XPV Helper class ... +// - [] create XZG Helper class ... +// - [] add Pivots Functionality based on XZG and XPV ... +// - [] add File as Struct functionality and implement it ... +// - [] add Support for OnSignal Event ... +// - [] add support for Alerting ... +// - [] Refactor XSignal: +// -- [] Add support for Multiple TPS and Trailing Stops ... +// -- [] Add support for Clean, Constructor and Init Functions on struct ... +// -- [] Add support for Prepare Signal inside struct ... +// -- [] Add Support for Position Management inside XTrade Class for Handling +// Trail SL, or Partial Close Positions ... +// -- [] Convert providers from Array to string ... +// -- [] Add Support For Serializing and also Deseriallizing functionality ... + +// +// Imports ... + +// +#include "../Classes/x-saherelm.x121.xmcycle.class.mq5" + +// +// Definitions ... + +// +// Configuration of X121 Provider ... +struct X121ProviderInputs +{ +}; + +// +// Class ... + +// +// Tools ... \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.xmcycle.class.ex5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.xmcycle.class.ex5 new file mode 100644 index 0000000..907eb05 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.xmcycle.class.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.xmcycle.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.xmcycle.class.mq5 new file mode 100644 index 0000000..fdb370b --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.x121.xmcycle.class.mq5 @@ -0,0 +1,3086 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSC121MCycle +// Description: provides all requirements for +// Handling Specified Market Cycle Analysis... +// +// +// 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-saherelm.draw.lib.mq5" + +// +#include "../Helpers/x-saherelm.x121.xmc.helper.mq5" +#include "../Helpers/x-saherelm.x121.xche.helper.mq5" +#include "../Helpers/x-saherelm.x121.xosc.helper.mq5" +#include "../Helpers/x-saherelm.x121.xstr.helper.mq5" +#include "../Helpers/x-saherelm.x121.xich.helper.mq5" + +// +// Definitions ... + +// +struct X121MCycleInputs +{ + // + // Props ... + + // + XMarketCycle cycle; // Cycle Descriptor ... + + // + // Draw Props ... + + // + XDrawSpecifications cBarMidDrawSpecs; // Current Bar MidLine Draw Specifications + XOHCLDrawSpecification cBarDrawSpecs; // Current Bar Draw Specifications + + // + XDrawSpecifications pBarMidDrawSpecs; // Previous Bar MidLine Draw Specifications + XOHCLDrawSpecification pBarDrawSpecs; // Previous Bar Draw Specifications + + // + bool drawLabels; // Draw Labels + bool drawCBar; // Draw Current Bar + bool drawPBar; // Draw Previous Bar + bool drawCBarMid; // Draw Current Bar Mid Line + bool drawPBarMid; // Draw Previous Bar Mid Line + + // + X121MCInputs mcInputs; // MC Inputs ... + X121STRInputs strInputs; // STR Inputs ... + X121OSCInputs oscInputs; // OSC Inputs ... + X121CHEInputs cheInputs; // CHE Inputs ... + X121ICHInputs ichInputs; // ICH Inputs ... + + // + // Constructor ... + X121MCycleInputs() + { + Clean(); + } + + // + // Tools ... + + // + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + ENUM_TIMEFRAMES mPeriod, // Cycle Period + ENUM_X_PERIOD_METHOD mPeriodMethod, // Cycle Period Method + string mPrefix = "", // Prefix + bool useDefaults = true // Use Inputs Default Settings ... + ) + { + // + bool result = false; + + // + cycle.period = mPeriod; + cycle.method = mPeriodMethod; + + // + // Initial Cycle Model ... + result = cycle.Init( + mSymbol, + mHostPeriod, + mCycle, + mPrefix + // + ); + if (!result) + { + return result; + } + + // + if (useDefaults) + { + // + mcInputs.Default(); + strInputs.Default(); + oscInputs.Default(); + cheInputs.Default(); + ichInputs.Default(); + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + return result; + } + + // + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + X121MCInputs &mMcInputs, // MC Inputs + X121STRInputs &mStrInputs, // STR Inputs + X121OSCInputs &mOscInputs, // OSC Inputs + X121CHEInputs &mCheInputs, // CHE Inputs + int mHostBarIndex = 0, // Specified Host Period Bar Index + string mPrefix = "" // Prefix + ) + { + // + bool result = false; + + // + // Initial Cycle Model ... + result = cycle.Init( + mSymbol, + mHostPeriod, + mCycle, + mPrefix + // + ); + if (!result) + { + return result; + } + + // + mcInputs = mMcInputs; + strInputs = mStrInputs; + oscInputs = mOscInputs; + cheInputs = mCheInputs; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + return result; + } + + // + void Clean() + { + // + cycle.Clean(); + mcInputs.Clean(); + strInputs.Clean(); + oscInputs.Clean(); + cheInputs.Clean(); + ichInputs.Clean(); + + // + cBarDrawSpecs.Clean(); + pBarDrawSpecs.Clean(); + cBarMidDrawSpecs.Clean(); + pBarMidDrawSpecs.Clean(); + + // + drawLabels = false; + drawCBar = false; + drawPBar = false; + drawCBarMid = false; + drawPBarMid = false; + } + + // + void Default() + { + // + mcInputs.Default(); + strInputs.Default(); + oscInputs.Default(); + cheInputs.Default(); + ichInputs.Default(); + + // + drawLabels = false; + drawCBar = false; + drawPBar = false; + drawCBarMid = false; + drawPBarMid = false; + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = cycle.IsValid(); + if (!result) + { + return result; + } + + // + result = mcInputs.IsValid(); + if (!result) + { + return result; + } + + // + result = strInputs.IsValid(); + if (!result) + { + return result; + } + + // + result = oscInputs.IsValid(); + if (!result) + { + return result; + } + + // + result = cheInputs.IsValid(); + if (!result) + { + return result; + } + + // + result = ichInputs.IsValid(); + if (!result) + { + return result; + } + + // + return result; + } +}; + +// +// Specific Market Sense Based on Specified Bar Index on Host Period ... +struct X121MCycleConditions +{ + // + // Props ... + + // + // Common ... + string prefix; // Cycle Prefix ... + string symbol; // Analysing Symbol ... + ENUM_TIMEFRAMES period; // Analysing Time Frame ... + ENUM_TIMEFRAMES hostPeriod; // Hosting Time Frame ... + ENUM_X_MARKET_CYCLES cycle; // Init Cycle ... + + // + // Bars ... + XOHCL bars[]; // Some Bars ... + datetime time; // Extracting Time ... + + // + // Candlestic Conditions ... + bool isLastBullish; + bool isLastBearish; + bool isCurrentBullish; + bool isCurrentBearish; + bool isCurrentMidLineOverLastHigh; + bool isCurrentMidLineUnderLastLow; + bool isCurrentMidLineOverLastUp; + bool isCurrentMidLineUnderLastDown; + bool isCurrentMidLineOverLastMidLine; + bool isCurrentMidLineUnderLastMidLine; + + // + // XICH ... + // Ichimoku strategy + // Strategy one: Ichimoku trend identifier: + // According to this strategy, we need a trigger that can be used + // to inform us about the trend type, + // if it is an uptrend or downtrend. + // We will check three values to do that and these values are the: + // closing price, Senkou Span A, and Senkou Span B. + // If the closing price is greater than the Senkou Span B and at the same time + // the closing price is greater than Senkou Span A, + // this will be the trigger to know that the trend is up. + // Vice versa, if the closing price is lower than the Senkou Span B and at the same time + // the closing price is lower than the Senkou Span A, + // this will be the trigger to the downtrend. + // + // Closing price > Senkou Span B and closing price > Senkou Span A --> Uptrend + // Closing price < Senkou Span B and closing price < Senkou Span A --> Downtrend + // + // Strategy two: Ichimoku trend strength: + // Based on this strategy, we need a trigger that can inform us the current trend is strong. + // We will check three values to do that and these values are the: + // - current Senkou Span A, + // - the previous Senkou Span A, and + // - the Senkou Span B. + // If the current Senkou Span A is greater than the previous Senkous Span A and at the same time + // the current Senkou Span A is greater than the Senkou Span B, + // this is a trigger that the trend is up and strong. + // Vice versa, if the current Senkou Span A is lower than the previous Senkou Span A and at the + // same time, the current Senkou Span A is lower than the Senkou Span B, + // this will be a signal that the trend is down and strong. + // + // Current Senkou Span A > previous Senkou Span A and current Senkou Span A > Senkou Span B --> the uptrend is strong + // Current Senkou Span A < previous Senkou Span A and current Senkou Span A < Senkou Span B --> the downtrend is strong + bool isSenkouSpanAOverB; + bool isSenkouSpanAUnderB; + bool isSenkouSpanAOverLast; + bool isSenkouSpanAUnderLast; + bool isFutureSenkouSpanAOverB; + bool isFutureSenkouSpanAUnderB; + bool isFutureSenkouSpanAOverLast; + bool isFutureSenkouSpanAUnderLast; + // + // Strategy three: Ichimoku price-Ki signal: + // According to this strategy, during the uptrend, we need a trigger that can + // alert us about the bullish signal, and during the downtrend, we need a trigger than can alert us about the bearish signal. + // We will check based on this strategy two values, closing price, and Kijun-Sen. + // If the closing price is greater than the Kijun-sen value, + // this will be a trigger to a bullish signal. + // Vice versa, if the closing price is lower than the Kijun-sen value, + // this will be a bearish signal. + // + // During uptrend, closing price > Kijun -sen --> bullish signal + // Duuring downtrend, closing price < Kijun -sen --> bearish signal + bool isCloseOverKijunSen; + bool isCloseUnderKijunSen; + // + // Strategy four: Ichimoku ten-ki signal: + // According to this strategy, during the uptrend, we need another trigger or + // method to alert us when there is a bullish signal or + // during the downtrend, we need a signal of bearishness. + // We will check based on this strategy two values, Tenkan-sen and Kijum-sen. + // If the Tenkan-sen value is greater than the Kijun-sen, + // this will be a signal of bullishness. + // Vice versa, if the Tenkan-sen is lower than the Kijun-sen, + // this will be a signal of bearishness. + // + // Tenkan-sen > Kijun-sen --> bullish signal + // Tenkan-sen < Kijun-sen --> bearish signal + bool isTenkanSenOverKijunSen; + bool isTenkanSenUnderKijunSen; + + // + // XMC ... + // Three Moving Averages Crossover + // In this strategy, we will use three simple moving averages: + // the shorter simple moving average period is 10, the longer one period is 48, and in between a period of 24. + // + // According to the strategy, we need the three simple moving averages to be checked at every tick: + // + // If 10 SMA > 24 SMA, 10 SMA > 48 SMA, and 24 SMA > 48 SMA: the signal will be to buy and we need to be appeared as a comment on the chart. + // If 10 SMA < 24 SMA, 10 SMA < 48 SMA, and 24 SMA < 48 SMA: the signal will be to sell and we need to be appeared as a comment on the chart. + // If anything, else do nothing. + bool isFastOverSlow; + bool isFastUnderSlow; + bool isFastOverVerifier; + bool isFastUnderVerifier; + bool isSlowOverVerifier; + bool isSlowUnderVerifier; + bool isCloseOverFast; + bool isCloseUnderFast; + bool isCloseOverSlow; + bool isCloseUnderSlow; + bool isCloseOverVerifier; + bool isCloseUnderVerifier; + + // + // XSTR ... + bool isTrendBullish; + bool isTrendBearish; + + // + // XCHE ... + bool isCHEInLong; + bool isCHEInStrongLong; + bool isCHEInShort; + bool isCHEInStrongShort; + + // + // XOSC ... + + // + // RVI Signals ... + // Strategy one: RVI Crossover - Uptrend: + // Based on this strategy, we need to get buy and close signals during the uptrend by a specific condition. + // When the RVI current value and RVI signal current value are greater than the zero level at the same time + // that RVI current value is greater than the current value of the RVI signal, this will be a buy signal. + // Vice Versa, when the RVI current value and RVI signal current value is below zero level at + // the same time that the RVI current value is below the current value of the RVI signal, this will be a close signal. + // + // RVI value > 0 and RVI signal value > 0 and RVI value > RVI signal value --> buy + // RVI value < 0 and RVI signal value < 0 and RVI value < RVI signal value --> close + bool isRVILongStart; + bool isRVILongStop; + // + // Strategy two: RVI Crossover - Downtrend: + // Based on this strategy, we need to get the opposite signals of the previous RVI Crossover - + // Uptrend strategy as we need to get short and cover signals. + // When the RVI current value and RVI signal current value are lower than the zero level at + // the same time that RVI current value is lower than the current value of the RVI signal, this will be a short signal. + // Vice Versa, when the RVI current value and RVI signal current value is above the zero level + // at the same time that the RVI current value is above the current value of the RVI signal, this will be a cover signal. + // + // RVI value < 0 and RVI signal value < 0 and RVI value < RVI signal value --> short + // RVI value > 0 and RVI signal value > 0 and RVI value > RVI signal value --> cover + bool isRVIShortStart; + bool isRVIShortStop; + // + // Strategy three: RVI and MA Crossover + // Based on this strategy, we need to get buy and sell signals based on specific conditions + // as we need to get a + // buy signal + // when the closing price is greater than the 100 -period moving average + // at the same time that the current RVI value is greater than the current RVI signal value. + // In the other scenario, we need to get a + // sell signal + // when the closing price is lower than the 100 -period moving average + // at the same time that the current RVI value is lower than the current RVI signal value. + + // + // RSI strategy ... + // During Uptrend + // In this case, most of the time RSI values move between or moving between + // the mid range and level 70 (Overbought level). + // The trading strategy for the uptrend is: + // + // RSI Value < 50 = Buy + // RSI Value > 70 = Take Profit + bool isRSIUnder50; + bool isRSIOver70; + // + // During Downtrend + // During the downtrend, the RSI moves most of the time between + // the mid range and level 30 (Oversold level). + // The trading strategy will be as follows: + // + // RSI Value > 50 = Short + // RSI Value < 30 = Take Profit + bool isRSIOver50; + bool isRSIUnder30; + // + // During Sideways: + // RSI spends most of the time between levels 30 (Oversold level) and 70 (Oversbought level). + // The trading strategy will be as follows: + // RSI Value < 30 = Buy + // RSI Value > 50 = Take Profit + // RSI Value > 70 = Short + // RSI Value < 50 = Take Profit + + // + // Bull's Power strategy: + // In this part, we will learn how we can use Bull's Power through simple strategies + // that can be used based on the basic concept of this indicator. + // The following are for these strategies and their conditions. + // I need to confirm here, that these strategies for education only as the main objective + // is to understand the main concept behind the indicator and how we can use them in our favor, + // so you must test any of them before using them on your real account to make sure that + // it will be good for your trading as there is no strategy is suitable for everyone. + // + // Strategy one: Bull's Power Movement: + // Based on this strategy, we need to get signals based on the position of current and previous bull's power values. + // If the current bull's power value is greater than the previous one, + // we will consider it as a signal of the rising of the Bull's Power indicator. + // Vice versa, if the current value is lower than the previous one, we will consider that as a signal of + // declining Bull's Power. + // + // To simplify that, it will be the same as the following: + // + // Current Bull's Power > Previous Bull's Power --> Bull's Power is Rising + // Current Bull's Power < Previous Bull's Power --> Bull's Power is declining + bool isBullPowerOverLast; + bool isBullPoswerUnderLast; + // + // Strategy two: Bull's Power - Strong or Divergence + // Based on this strategy, we want to get a signal that informs us if there is a strong movement + // or there is a divergence by evaluating four values and these values are current high, + // the previous high, bull power, and previous bull power. + // If the current high is higher than the previous high and + // the current bull power value is higher than the previous one, + // we will consider that as a signal of a strong move. + // In the other case, if the current high is higher than the previous high and the current + // bull value is lower than the previous one, we will consider that as a signal of bearish divergence. + // + // To simplify that, it will be the same as the following: + // + // Current high > previous high and current bull's power > previous bull's power --> strong move + // Current high < previous high and current bull's power > previous bull's power --> bearish divergence + // + // Strategy three: Bull's Power signals + // Based on this strategy, we need a signal that can be used to get buy and sell signals and we will + // evaluate four values to do that based on this strategy. + // These four values are: + // - current bull's power, + // - zero level, + // - current close value, and + // - current exponential moving average. + // If the current bull's power is lower than the zero level and + // the current close is lower than the exponential moving average, + // we will consider it as a signal of selling. + // If the current bull's power is greater than the zero level and the current close is greater than + // the exponential moving average, this will be a signal of buying. + // + // To simplify that, it will be the same as the following: + // + // Current bull's power < zero level and current close < EMA --> sell + // Current bear's power > zero level and current close > EMA --> buy + bool isBullPowerOverZero; + bool isBullPoswerUnderZero; + + // + // Bear's Power strategy + // In this part, we will learn how we can use Bear's Power through simple strategies + // that can be used based on the basic concept of this indicator. + // The following are for these strategies and their conditions. + // I need to confirm here, that these strategies for education as the main objective + // is to understand the main concept behind the indicator and how we can use it, + // so you must test any of them before using them on your real account to + // make sure that it will be good for your trading. + // + // Strategy one: Bear's Power Movement + // According to this strategy, we need to get signals based on the position of current and previous + // bear's power values. + // If the current value is greater than the previous, this will be a signal of the rising of + // Bear's Power indicator. + // Vice versa, if the current value is lower than the previous value, + // this will be a signal of declining Bear's Power. + // + // Simply, + // + // Current Bear's Power > Previous Bear's Power --> Bear's Power is Rising + // Current Bear's Power < Previous Bear's Power --> Bear's Power is declining + bool isBearPowerOverLast; + bool isBearPoswerUnderLast; + // + // Strategy two: Bear's Power - Strong or Divergence + // According to this strategy, we need to get a signal that informs us if there are strong movements or + // there are divergences by evaluating four values and they are: + // -current low, + // - previous low, + // - bear power, and + // - previous bear power. + // If the current low is lower than the previous low and the current bear power value + // is lower than the previous one, this will be a signal of a strong move. + // In the other case, if the current low is lower than the previous low and the current + // bear value is greater than the previous one, this will be a signal of bullish divergence. + // + // Simply, + // + // Current low < previous low and current bear's power < previous bear's power --> strong move + // Current low < previous low and current bear's power > previous bear's power --> bullish divergence + // + // Strategy three + // According to this strategy, we need a trigger that can be used to get buy and sell signals and + // we will evaluate four values to do that based on this strategy. + // These four values are current: + // - bear's power, + // - zero level, + // - current close value, and + // - current exponential moving average. + // If the current bear's power is greater than the zero level and the current close is greater than + // the exponential moving average, this will be a signal of buy. + // If the current bear's power is lower than the zero level and the current close is lower than + // the exponential moving average, this will be a signal of selling. + // + // Simply, + // + // Current bear's power > zero level and current close > EMA --> buy + // Current bear's power < zero level and current close < EMA --> sell + bool isBearPowerOverZero; + bool isBearPoswerUnderZero; + + // + // CCI ... + bool isCCIPositive; + bool isCCINegative; + bool isCCIOverPositiveHundred; + bool isCCIUnderNegativeHundred; + + // + // STDDEV ... + // Based on this strategy, we need to measure the volatility based on the comparison between the + // current Std Dev and the average of the five previous Std values. + // If the current Std Dev is greater than the Std Dev 5-periods average, this will be a high volatility signal. + // If the current Std is lower than the Std Dev 5- period average, this will be low volatility. + // + // Based on this strategy, we need to get buy and sell signals based on specific conditions. + // If the current Std Dev is greater than the previous Std Dev and the Ask value is greater than the moving average, + // this will be a buy signal. + // If the current Std Dev is greater than the previous Std Dev and the Bid value is lower than the moving average, + // this will be a sell signal. + // + // Current Std > Prev. Std and Ask > MA --> Buy signal + // Current Std > Prev. Std and Bid < MA --> Sell signal + // + // Based on this strategy, we need to get buy and sell signals based on other conditions. + // If the current Std Dev is greater than Std Dev Avg and Ask is greater than the moving average, + // this will be a buy signal. + // If the current Std Dev is greater than Std Dev Avg and Bid is lower than the moving average, + // this will be a sell signal. + // + // Current Std > Std Avg and Ask > MA --> Buy signal + // Current Std > Std Avg and Bid < Ma --> Sell signal + bool isSTDDEVOverAVG; + bool isSTDDEVOverLast; + bool isSTDDEVUnderAVG; + bool isSTDDEVUnderLast; + + // + // MACD ... + // According to this strategy, we need to identify the market setup: + // is it buying setup or shorting setup. + // In other words we need to identify the market direction, if it is bullish or bearish market, + // and this will be identified by MACD. + // If the MACD main line breaks above zero level, this will be a buying setup or bullish setup and + // vice versa if MACD main line breaks below zero level, this will be a shorting setup or bearish. + // + // MACD main line > 0 = Bullish Setup + // MACD main line < 0 = Bearish Setup + // + // According to this strategy, we need to identify generated signals + // if there is a buy signal or a sell signal based on MACD main line and Signal line crossover. + // If MACD main line breaks above Signal line, this will be a buy signal and if MACD main line breaks + // below Signal line, this will be a short signal. + // + // MACD main line > MACD signal line = Buying Signal + // MACD main line < MACD signal line = Shorting signal + bool isMACDPositiove; + bool isMACDNegative; + bool isMACDOverSignal; + bool isMACDUnderSignal; + + // + // STOCHASTIC ... + // Stochastic strategy + // In this part, we will talk about how we can use this indicator through simple strategies. + // We can get signals from the stochastic indicator according to market trend and these strategies are + // uptrend strategy, downtrend strategy, and sideways strategy. + // + // Strategy one: Uptrend strategy + // According to this strategy, we need to check if the %K line and %D line are below the 50 level, + // then, the buy signal will be generated + // when the %K line crosses above the %D line. + // We can take profit according to another effective tool like price action by searching + // for a lower low for example. + // + // %K, %D < 50 --> %K > %D = buy signal + bool isStochKOverD; + bool isStochKDUnder50; + // + // Strategy two: downtrend strategy + // According to this strategy, we need to check if the %K line and %D line are above the 50 level, + // then, the sell signal will be generated + // when the %K line crosses below the %D line. + // We can take profit according to another effective tool like price action by searching + // for a higher high for example. + // + // %K, %D > 50 --> %K < %D = sell signal + bool isStochKUnderD; + bool isStochKDOver50; + // + // Strategy three: sideways strategy + // + // The buy signal: + // According to this strategy, we need to check if the %K line and %D line are below the 20 level, + // then, the buy signal will be generated + // when the %K line crosses above the %D line. + // When the %K line and %D line are above 80, then the take profit signal will be generated + // when the %K line crosses below the %D line. + // %K, %D < 20 --> %K > %D = buy signal + // %K, %D > 80 --> %K < %D = take profit + bool isStochKDUnder20; + // + // The sell signal + // According to this strategy, we need to check if the %K line and %D line are above the 80 level, + // then, the sell signal will be generated + // when the %K line crosses below the %D line. + // When the %K line and %D are below the 20 level, then, the take profit signal will be generated + // when the %K line crosses above the %D line. + // + // %K, %D > 80 --> %K < %D = sell signal + // %K, %D < 20 --> %K > %D = take profit + bool isStochKDOver80; + + // + // Constructor(s) ... + X121MCycleConditions() + { + Clean(); + } + + // + void Clean() + { + // + // Commons ... + time = 0; + cycle = NULL; + prefix = NULL; + symbol = NULL; + period = NULL; + hostPeriod = NULL; + + // + Clean(bars); + + // + // Candlestic ... + isLastBullish = false; + isLastBearish = false; + isCurrentBullish = false; + isCurrentBearish = false; + isCurrentMidLineOverLastHigh = false; + isCurrentMidLineUnderLastLow = false; + isCurrentMidLineOverLastUp = false; + isCurrentMidLineUnderLastDown = false; + isCurrentMidLineOverLastMidLine = false; + isCurrentMidLineUnderLastMidLine = false; + + // + // XTSR ... + isTrendBullish = false; + isTrendBearish = false; + + // + // XCHE ... + isCHEInLong = false; + isCHEInStrongLong = false; + isCHEInShort = false; + isCHEInStrongShort = false; + + // + // XICH ... + isSenkouSpanAOverB = false; + isSenkouSpanAUnderB = false; + isSenkouSpanAOverLast = false; + isSenkouSpanAUnderLast = false; + isFutureSenkouSpanAOverB = false; + isFutureSenkouSpanAUnderB = false; + isFutureSenkouSpanAOverLast = false; + isFutureSenkouSpanAUnderLast = false; + isCloseOverKijunSen = false; + isCloseUnderKijunSen = false; + isTenkanSenOverKijunSen = false; + isTenkanSenUnderKijunSen = false; + + // + // XMC ... + isFastOverSlow = false; + isFastUnderSlow = false; + isFastOverVerifier = false; + isFastUnderVerifier = false; + isSlowOverVerifier = false; + isSlowUnderVerifier = false; + isCloseOverFast = false; + isCloseUnderFast = false; + isCloseOverSlow = false; + isCloseUnderSlow = false; + isCloseOverVerifier = false; + isCloseUnderVerifier = false; + + // + // XOSC ... + + // + // STDDEV ... + isSTDDEVOverAVG = false; + isSTDDEVUnderAVG = false; + isSTDDEVOverLast = false; + isSTDDEVUnderLast = false; + + // + // RVI ... + isRVILongStart = false; + isRVILongStop = false; + isRVIShortStart = false; + isRVIShortStop = false; + + // + // RSI ... + isRSIUnder50 = false; + isRSIOver70 = false; + isRSIOver50 = false; + isRSIUnder30 = false; + + // + // BULLPOWER ... + isBullPowerOverLast = false; + isBullPoswerUnderLast = false; + isBullPowerOverZero = false; + isBullPoswerUnderZero = false; + + // + // BEARPOWER ... + isBearPowerOverLast = false; + isBearPoswerUnderLast = false; + isBearPowerOverZero = false; + isBearPoswerUnderZero = false; + + // + // CCI ... + isCCIPositive = false; + isCCINegative = false; + isCCIOverPositiveHundred = false; + isCCIUnderNegativeHundred = false; + + // + // MACD ... + isMACDPositiove = false; + isMACDNegative = false; + isMACDOverSignal = false; + isMACDUnderSignal = false; + + // + // STOCH ... + isStochKOverD = false; + isStochKDUnder50 = false; + isStochKUnderD = false; + isStochKDOver50 = false; + isStochKDUnder20 = false; + isStochKDOver80 = false; + } + + // + // Tools ... + + // + // Generate Score ... + void GenerateScore( + double &bullishScore, // Holds Bullish Score ... + double &bearishScore, // Holds Bearish Score ... + double multiplier = 1 // Score Multiplier ... + ) + { + // + double bullScore = 0; + double bearScore = 0; + + // + if (multiplier <= 0) + { + multiplier = 1; + } + + // + // Candlestic ... + + // + // BULLISH ... + if (isLastBullish) + { + bullScore++; + } + if (isCurrentBullish) + { + bullScore++; + } + if (isCurrentMidLineOverLastUp) + { + bullScore++; + } + if (isCurrentMidLineOverLastHigh) + { + bullScore++; + } + if (isCurrentMidLineOverLastMidLine) + { + bullScore++; + } + + // + // BEARISH ... + if (isLastBearish) + { + bearScore++; + } + if (isCurrentBearish) + { + bearScore++; + } + if (isCurrentMidLineUnderLastLow) + { + bearScore++; + } + if (isCurrentMidLineUnderLastDown) + { + bearScore++; + } + if (isCurrentMidLineUnderLastMidLine) + { + bearScore++; + } + + // + // XSTR ... + if (isTrendBullish) + { + bullScore++; + } + if (isTrendBearish) + { + bearScore++; + } + + // + // XICH ... + + // + // BULLISH ... + if (isSenkouSpanAOverB) + { + bullScore++; + } + if (isSenkouSpanAOverLast) + { + bullScore++; + } + if (isCloseOverKijunSen) + { + bullScore++; + } + if (isTenkanSenOverKijunSen) + { + bullScore++; + } + if (isFutureSenkouSpanAOverB) + { + bullScore++; + } + if (isFutureSenkouSpanAOverLast) + { + bullScore++; + } + + // + // BEARISH ... + if (isSenkouSpanAUnderB) + { + bearScore++; + } + if (isSenkouSpanAUnderLast) + { + bearScore++; + } + if (isCloseUnderKijunSen) + { + bearScore++; + } + if (isTenkanSenUnderKijunSen) + { + bearScore++; + } + if (isFutureSenkouSpanAUnderB) + { + bearScore++; + } + if (isFutureSenkouSpanAUnderLast) + { + bearScore++; + } + + // + // XMC ... + + // + // BULLISH ... + if (isFastOverSlow) + { + bullScore++; + } + if (isFastOverVerifier) + { + bullScore++; + } + if (isSlowOverVerifier) + { + bullScore++; + } + if (isCloseOverFast) + { + bullScore++; + } + if (isCloseOverSlow) + { + bullScore++; + } + if (isCloseOverVerifier) + { + bullScore++; + } + + // + // BEARISH ... + if (isFastUnderSlow) + { + bearScore++; + } + if (isFastUnderVerifier) + { + bearScore++; + } + if (isSlowUnderVerifier) + { + bearScore++; + } + if (isCloseUnderFast) + { + bearScore++; + } + if (isCloseUnderSlow) + { + bearScore++; + } + if (isCloseUnderVerifier) + { + bearScore++; + } + + // + // XOSC ... + + // + // STDDEV ... + + // + // BULLISH ... + if (isSTDDEVOverAVG) + { + bullScore++; + } + if (isSTDDEVOverLast) + { + bullScore++; + } + + // + // BEARISH ... + if (isSTDDEVUnderAVG) + { + bearScore++; + } + if (isSTDDEVUnderLast) + { + bearScore++; + } + + // + // RVI ... + if (isRVILongStart && !isRVILongStop) + { + bullScore++; + } + if (isRVIShortStart && isRVIShortStop) + { + bearScore++; + } + + // + // RSI ... + + // + // BULLISH ... + if (isRSIUnder30 || (!isRSIUnder30 && isRSIOver50 && isRSIOver70)) + { + bullScore++; + } + + // + // BEARISH ... + if (isRSIOver70 || (!isRSIOver70 && !isRSIOver50 && isRSIUnder30)) + { + bearScore++; + } + + // + // BULLPOWER ... + + // + // BULLISH ... + if (isBullPowerOverLast) + { + bullScore++; + } + if (isBullPowerOverZero) + { + bullScore++; + } + + // + // BEARISH ... + if (isBullPoswerUnderLast) + { + bearScore++; + } + if (isBullPoswerUnderZero) + { + bearScore++; + } + + // + // BEARPOWER ... + + // + // BULLISH ... + if (isBearPoswerUnderLast) + { + bullScore++; + } + if (isBearPoswerUnderZero) + { + bullScore++; + } + + // + // BEARISH ... + if (isBearPowerOverLast) + { + bearScore++; + } + if (isBearPowerOverZero) + { + bearScore++; + } + + // + // CCI ... + + // + // BULLISH ... + if (isCCIPositive) + { + bullScore++; + } + if (isCCIOverPositiveHundred) + { + bullScore++; + } + + // + // BEARISH ... + if (isCCINegative) + { + bearScore++; + } + if (isCCIUnderNegativeHundred) + { + bearScore++; + } + + // + // MACD ... + + // + // BULLISH ... + if (isMACDPositiove) + { + bullScore++; + } + if (isMACDOverSignal) + { + bullScore++; + } + + // + // BEARISH ... + if (isMACDNegative) + { + bearScore++; + } + if (isMACDUnderSignal) + { + bearScore++; + } + + // + // STOCH ... + + // + // BULLISH ... + if (isStochKOverD) + { + bullScore++; + } + if (isStochKDUnder20) + { + bullScore++; + } + if (isStochKDUnder50) + { + bullScore++; + } + + // + // BEARISH ... + if (isStochKUnderD) + { + bearScore++; + } + if (isStochKDOver50) + { + bearScore++; + } + if (isStochKDOver80) + { + bearScore++; + } + + // + bullishScore = bullScore * multiplier; + bearishScore = bearScore * multiplier; + } + + // + // Generate Summary ... + string GenerateSummary( + double multiplier = 1, // Score Multiplier + bool ignoreFalseConditions = true // Ignore False Conditions + ) + { + // + string result = ""; + + // + double bullScore = 0; + double bearScore = 0; + GenerateScore( + bullScore, + bearScore, + multiplier + // + ); + + // + // Commons ... + string commons = + // + ToString(cycle) + "[" + prefix + "]" + "\n" + + "-------------" + "\n" + + "Time: " + ToString(time) + "\n" + + "\n" + + "Scores:" + "\n" + + "-------------" + "\n" + + "Bullish: " + ToString(bullScore) + "\n" + + "Bearish: " + ToString(bearScore) + "\n" + + "\n" + // + ; + + // + string candlestic = + // + ((isLastBullish || !ignoreFalseConditions) ? "isLastBullish: " + ToString(isLastBullish) + "\n" : "") + + ((isLastBearish || !ignoreFalseConditions) ? "isLastBearish: " + ToString(isLastBearish) + "\n" : "") + + ((isCurrentBullish || !ignoreFalseConditions) ? "isCurrentBullish: " + ToString(isCurrentBullish) + "\n" : "") + + ((isCurrentBearish || !ignoreFalseConditions) ? "isCurrentBearish: " + ToString(isCurrentBearish) + "\n" : "") + + ((isCurrentMidLineOverLastHigh || !ignoreFalseConditions) ? "isCurrentMidLineOverLastHigh: " + ToString(isCurrentMidLineOverLastHigh) + "\n" : "") + + ((isCurrentMidLineUnderLastLow || !ignoreFalseConditions) ? "isCurrentMidLineUnderLastLow: " + ToString(isCurrentMidLineUnderLastLow) + "\n" : "") + + ((isCurrentMidLineOverLastUp || !ignoreFalseConditions) ? "isCurrentMidLineOverLastUp: " + ToString(isCurrentMidLineOverLastUp) + "\n" : "") + + ((isCurrentMidLineUnderLastDown || !ignoreFalseConditions) ? "isCurrentMidLineUnderLastDown: " + ToString(isCurrentMidLineUnderLastDown) + "\n" : "") + + ((isCurrentMidLineOverLastMidLine || !ignoreFalseConditions) ? "isCurrentMidLineOverLastMidLine: " + ToString(isCurrentMidLineOverLastMidLine) + "\n" : "") + + ((isCurrentMidLineUnderLastMidLine || !ignoreFalseConditions) ? "isCurrentMidLineUnderLastMidLine: " + ToString(isCurrentMidLineUnderLastMidLine) + "\n" : "") + + "" + // + ; + if (StringLen(candlestic) > 0) + { + // + candlestic = + // + "XOHCL(s):" + "\n" + + "-------------" + "\n" + + candlestic + + "\n" + // + ; + } + + // + // XSTR ... + string str = + // + ((isTrendBullish || !ignoreFalseConditions) ? "isTrendBullish: " + ToString(isTrendBullish) + "\n" : "") + + ((isTrendBearish || !ignoreFalseConditions) ? "isTrendBearish: " + ToString(isTrendBearish) + "\n" : "") + + "" + // + ; + if (StringLen(str) > 0) + { + // + str = + // + "XSTR:" + "\n" + + "-------------" + "\n" + + str + + "\n" + // + ; + } + + // + // XCHE ... + string che = + // + ((isCHEInLong || !ignoreFalseConditions) ? "isCHEInLong: " + ToString(isCHEInLong) + "\n" : "") + + ((isCHEInStrongLong || !ignoreFalseConditions) ? "isCHEInStrongLong: " + ToString(isCHEInStrongLong) + "\n" : "") + + ((isCHEInShort || !ignoreFalseConditions) ? "isCHEInShort: " + ToString(isCHEInShort) + "\n" : "") + + ((isCHEInStrongShort || !ignoreFalseConditions) ? "isCHEInStrongShort: " + ToString(isCHEInStrongShort) + "\n" : "") + + "" + // + ; + if (StringLen(che) > 0) + { + // + che = + // + "XCHE:" + "\n" + + "-------------" + "\n" + + che + + "\n" + // + ; + } + + // + // XICH ... + string ich = + // + ((isSenkouSpanAOverB || !ignoreFalseConditions) ? "isSenkouSpanAOverB: " + ToString(isSenkouSpanAOverB) + "\n" : "") + + ((isSenkouSpanAUnderB || !ignoreFalseConditions) ? "isSenkouSpanAUnderB: " + ToString(isSenkouSpanAUnderB) + "\n" : "") + + ((isSenkouSpanAOverLast || !ignoreFalseConditions) ? "isSenkouSpanAOverLast: " + ToString(isSenkouSpanAOverLast) + "\n" : "") + + ((isSenkouSpanAUnderLast || !ignoreFalseConditions) ? "isSenkouSpanAUnderLast: " + ToString(isSenkouSpanAUnderLast) + "\n" : "") + + ((isCloseOverKijunSen || !ignoreFalseConditions) ? "isCloseOverKijunSen: " + ToString(isCloseOverKijunSen) + "\n" : "") + + ((isCloseUnderKijunSen || !ignoreFalseConditions) ? "isCloseUnderKijunSen: " + ToString(isCloseUnderKijunSen) + "\n" : "") + + ((isTenkanSenOverKijunSen || !ignoreFalseConditions) ? "isTenkanSenOverKijunSen: " + ToString(isTenkanSenOverKijunSen) + "\n" : "") + + ((isTenkanSenUnderKijunSen || !ignoreFalseConditions) ? "isTenkanSenUnderKijunSen: " + ToString(isTenkanSenUnderKijunSen) + "\n" : "") + + ((isFutureSenkouSpanAOverB || !ignoreFalseConditions) ? "isFutureSenkouSpanAOverB: " + ToString(isFutureSenkouSpanAOverB) + "\n" : "") + + ((isFutureSenkouSpanAUnderB || !ignoreFalseConditions) ? "isFutureSenkouSpanAUnderB: " + ToString(isFutureSenkouSpanAUnderB) + "\n" : "") + + ((isFutureSenkouSpanAOverLast || !ignoreFalseConditions) ? "isFutureSenkouSpanAOverLast: " + ToString(isFutureSenkouSpanAOverLast) + "\n" : "") + + ((isFutureSenkouSpanAUnderLast || !ignoreFalseConditions) ? "isFutureSenkouSpanAUnderLast: " + ToString(isFutureSenkouSpanAUnderLast) + "\n" : "") + + "" + // + ; + if (StringLen(ich) > 0) + { + // + ich = + // + "XICH:" + "\n" + + "-------------" + "\n" + + ich + + "\n" + // + ; + } + + // + // XMC ... + string mc = + // + ((isFastOverSlow || !ignoreFalseConditions) ? "isFastOverSlow: " + ToString(isFastOverSlow) + "\n" : "") + + ((isFastUnderSlow || !ignoreFalseConditions) ? "isFastUnderSlow: " + ToString(isFastUnderSlow) + "\n" : "") + + ((isFastOverVerifier || !ignoreFalseConditions) ? "isFastOverVerifier: " + ToString(isFastOverVerifier) + "\n" : "") + + ((isFastUnderVerifier || !ignoreFalseConditions) ? "isFastUnderVerifier: " + ToString(isFastUnderVerifier) + "\n" : "") + + ((isSlowOverVerifier || !ignoreFalseConditions) ? "isSlowOverVerifier: " + ToString(isSlowOverVerifier) + "\n" : "") + + ((isSlowUnderVerifier || !ignoreFalseConditions) ? "isSlowUnderVerifier: " + ToString(isSlowUnderVerifier) + "\n" : "") + + ((isCloseOverFast || !ignoreFalseConditions) ? "isCloseOverFast: " + ToString(isCloseOverFast) + "\n" : "") + + ((isCloseUnderFast || !ignoreFalseConditions) ? "isCloseUnderFast: " + ToString(isCloseUnderFast) + "\n" : "") + + ((isCloseOverSlow || !ignoreFalseConditions) ? "isCloseOverSlow: " + ToString(isCloseOverSlow) + "\n" : "") + + ((isCloseUnderSlow || !ignoreFalseConditions) ? "isCloseUnderSlow: " + ToString(isCloseUnderSlow) + "\n" : "") + + ((isCloseOverVerifier || !ignoreFalseConditions) ? "isCloseOverVerifier: " + ToString(isCloseOverVerifier) + "\n" : "") + + ((isCloseUnderVerifier || !ignoreFalseConditions) ? "isCloseUnderVerifier: " + ToString(isCloseUnderVerifier) + "\n" : "") + + "" + // + ; + if (StringLen(mc) > 0) + { + // + mc = + // + "XMC:" + "\n" + + "-------------" + "\n" + + mc + + "\n" + // + ; + } + + // + // XOSC ... + + // + // STDDEV ... + string stddev = + // + ((isSTDDEVOverAVG || !ignoreFalseConditions) ? "isSTDDEVOverAVG: " + ToString(isSTDDEVOverAVG) + "\n" : "") + + ((isSTDDEVUnderAVG || !ignoreFalseConditions) ? "isSTDDEVUnderAVG: " + ToString(isSTDDEVUnderAVG) + "\n" : "") + + ((isSTDDEVOverLast || !ignoreFalseConditions) ? "isSTDDEVOverLast: " + ToString(isSTDDEVOverLast) + "\n" : "") + + ((isSTDDEVUnderLast || !ignoreFalseConditions) ? "isSTDDEVUnderLast: " + ToString(isSTDDEVUnderLast) + "\n" : "") + + "" + // + ; + if (StringLen(stddev) > 0) + { + // + stddev = + // + "STDDev:" + "\n" + + "-------------" + "\n" + + stddev + + "\n" + // + ; + } + + // + // RVI ... + string rvi = + // + ((isRVILongStart || !ignoreFalseConditions) ? "isRVILongStart: " + ToString(isRVILongStart) + "\n" : "") + + ((isRVILongStop || !ignoreFalseConditions) ? "isRVILongStop: " + ToString(isRVILongStop) + "\n" : "") + + ((isRVIShortStart || !ignoreFalseConditions) ? "isRVIShortStart: " + ToString(isRVIShortStart) + "\n" : "") + + ((isRVIShortStop || !ignoreFalseConditions) ? "isRVIShortStop: " + ToString(isRVIShortStop) + "\n" : "") + + "" + // + ; + if (StringLen(rvi) > 0) + { + // + rvi = + // + "RVI:" + "\n" + + "-------------" + "\n" + + rvi + + "\n" + // + ; + } + + // + // RSI ... + string rsi = + // + ((isRSIOver50 || !ignoreFalseConditions) ? "isRSIOver50: " + ToString(isRSIOver50) + "\n" : "") + + ((isRSIUnder50 || !ignoreFalseConditions) ? "isRSIUnder50: " + ToString(isRSIUnder50) + "\n" : "") + + ((isRSIOver70 || !ignoreFalseConditions) ? "isRSIOver70: " + ToString(isRSIOver70) + "\n" : "") + + ((isRSIUnder30 || !ignoreFalseConditions) ? "isRSIUnder30: " + ToString(isRSIUnder30) + "\n" : "") + + "" + // + ; + if (StringLen(rsi) > 0) + { + // + rsi = + // + "RSI:" + "\n" + + "-------------" + "\n" + + rsi + + "\n" + // + ; + } + + // + // XCCI ... + string cci = + // + ((isCCIPositive || !ignoreFalseConditions) ? "isCCIPositive: " + ToString(isCCIPositive) + "\n" : "") + + ((isCCINegative || !ignoreFalseConditions) ? "isCCINegative: " + ToString(isCCINegative) + "\n" : "") + + ((isCCIOverPositiveHundred || !ignoreFalseConditions) ? "isCCIOverPositiveHundred: " + ToString(isCCIOverPositiveHundred) + "\n" : "") + + ((isCCIUnderNegativeHundred || !ignoreFalseConditions) ? "isCCIUnderNegativeHundred: " + ToString(isCCIUnderNegativeHundred) + "\n" : "") + + "" + // + ; + if (StringLen(cci) > 0) + { + // + cci = + // + "CCI:" + "\n" + + "-------------" + "\n" + + cci + + "\n" + // + ; + } + + // + // MACD ... + string macd = + // + ((isMACDPositiove || !ignoreFalseConditions) ? "isMACDPositiove: " + ToString(isMACDPositiove) + "\n" : "") + + ((isMACDNegative || !ignoreFalseConditions) ? "isMACDNegative: " + ToString(isMACDNegative) + "\n" : "") + + ((isMACDOverSignal || !ignoreFalseConditions) ? "isMACDOverSignal: " + ToString(isMACDOverSignal) + "\n" : "") + + ((isMACDUnderSignal || !ignoreFalseConditions) ? "isMACDUnderSignal: " + ToString(isMACDUnderSignal) + "\n" : "") + + "" + // + ; + if (StringLen(macd) > 0) + { + // + macd = + // + "MACD:" + "\n" + + "-------------" + "\n" + + macd + + "\n" + // + ; + } + + // + // BULLP ... + string bullp = + // + ((isBullPowerOverLast || !ignoreFalseConditions) ? "isBullPowerOverLast: " + ToString(isBullPowerOverLast) + "\n" : "") + + ((isBullPoswerUnderLast || !ignoreFalseConditions) ? "isBullPoswerUnderLast: " + ToString(isBullPoswerUnderLast) + "\n" : "") + + ((isBullPowerOverZero || !ignoreFalseConditions) ? "isBullPowerOverZero: " + ToString(isBullPowerOverZero) + "\n" : "") + + ((isBullPoswerUnderZero || !ignoreFalseConditions) ? "isBullPoswerUnderZero: " + ToString(isBullPoswerUnderZero) + "\n" : "") + + "" + // + ; + if (StringLen(bullp) > 0) + { + // + bullp = + // + "BullPower:" + "\n" + + "-------------" + "\n" + + bullp + + "\n" + // + ; + } + + // + // BEARP ... + string bearp = + // + ((isBearPowerOverLast || !ignoreFalseConditions) ? "isBearPowerOverLast: " + ToString(isBearPowerOverLast) + "\n" : "") + + ((isBearPoswerUnderLast || !ignoreFalseConditions) ? "isBearPoswerUnderLast: " + ToString(isBearPoswerUnderLast) + "\n" : "") + + ((isBearPowerOverZero || !ignoreFalseConditions) ? "isBearPowerOverZero: " + ToString(isBearPowerOverZero) + "\n" : "") + + ((isBearPoswerUnderZero || !ignoreFalseConditions) ? "isBearPoswerUnderZero: " + ToString(isBearPoswerUnderZero) + "\n" : "") + + "" + // + ; + if (StringLen(bearp) > 0) + { + // + bearp = + // + "BearPower:" + "\n" + + "-------------" + "\n" + + bearp + + "\n" + // + ; + } + + // + // STOCH ... + string stoch = + // + ((isStochKOverD || !ignoreFalseConditions) ? "isStochKOverD: " + ToString(isStochKOverD) + "\n" : "") + + ((isStochKUnderD || !ignoreFalseConditions) ? "isStochKUnderD: " + ToString(isStochKUnderD) + "\n" : "") + + ((isStochKDOver50 || !ignoreFalseConditions) ? "isStochKDOver50: " + ToString(isStochKDOver50) + "\n" : "") + + ((isStochKDOver80 || !ignoreFalseConditions) ? "isStochKDOver80: " + ToString(isStochKDOver80) + "\n" : "") + + ((isStochKDUnder20 || !ignoreFalseConditions) ? "isStochKDUnder20: " + ToString(isStochKDUnder20) + "\n" : "") + + ((isStochKDUnder50 || !ignoreFalseConditions) ? "isStochKDUnder50: " + ToString(isStochKDUnder50) + "\n" : "") + + "" + // + ; + if (StringLen(stoch) > 0) + { + // + stoch = + // + "Stoch:" + "\n" + + "-------------" + "\n" + + stoch + + "\n" + // + ; + } + + string osc = + // + stddev + + rvi + + rsi + + cci + + macd + + bullp + + bearp + + stoch + + "" + // + ; + if (StringLen(osc) > 0) + { + // + osc = + // + "XOSC:" + "\n" + + "-------------" + "\n" + + osc + + "\n" + // + ; + } + + // + result = + // + commons + + candlestic + + str + + che + + ich + + mc + + osc + + "" + // + ; + + // + return result; + } +}; + +// +// Class ... + +// +class XSC121Market +{ + // + // Public ... +public: + // + // Props ... + XSCX121MCHelper mc; + XSCX121STRHelper str; + XSCX121CHEHelper che; + XSCX121OSCHelper osc; + XSCX121ICHHelper ich; + + // + // Constructors ... + XSC121Market() {} + + // + // Deconstructors ... + ~XSC121Market() {} + + // + // Props ... + + // + // Retrieve Trading Symbol ... + string GetSymbol() + { + return mInputs.cycle.symbol; + } + + // + // Retrieve Cycle Time Frame ... + ENUM_TIMEFRAMES GetPeriod() + { + return mInputs.cycle.period; + } + + // + // Retrieve Market Host Time Frame ... + ENUM_TIMEFRAMES GetHostPeriod() + { + return mInputs.cycle.hostPeriod; + } + + // + // Retrieve Current Market Config ... + X121MCycleInputs GetInputs() + { + return mInputs; + } + + // + // Count Total Available Bars in Market ... + int CountBars() + { + // + Update(0); + return mInputs.cycle.CountBars(); + } + + // + // Check Market is in new Bar ... + int IsNewBar() + { + // + Update(0); + return mInputs.cycle.IsNewBar(); + } + + // + // Retrieve Current Cycles Specific Bar ... + XOHCL GetBar(int barIndex) + { + // + Update(0); + return mInputs.cycle.GetBar(barIndex); + } + + // + // Retrieve Current Bar Index based on Host Period bar Index ... + int GetBarIndex(int barIndex) + { + // + Update(barIndex); + return mInputs.cycle.GetBarIndex(barIndex); + } + + // + // Retrieve Bar Time ... + datetime GetBarTime(int barIndex) + { + // + Update(0); + return mInputs.cycle.GetBarTime(barIndex); + } + + // + // Set Market Inputs and Re Initial ... + bool SetInputs( + X121MCycleInputs &inputs // Config + ) + { + // + return Init(inputs); + } + + // + // Tools ... + + // + // Initial Market Cycle ... + bool Init( + X121MCycleInputs &inputs // Inputs for Initialization + ) + { + // + bool result = false; + + // + // Validate Input ... + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + string symbol = mInputs.cycle.symbol; + ENUM_TIMEFRAMES period = mInputs.cycle.period; + + // + // Init Helpers ... + + // + // XMC ... + result = mc.Init( + symbol, + period, + mInputs.mcInputs + // + ); + if (!result) + { + return result; + } + + // + // XSTR ... + result = str.Init( + symbol, + period, + mInputs.strInputs + // + ); + if (!result) + { + return result; + } + + // + // XCHE ... + result = che.Init( + symbol, + period, + mInputs.cheInputs + // + ); + if (!result) + { + return result; + } + + // + // XOSC ... + result = osc.Init( + symbol, + period, + mInputs.oscInputs + // + ); + if (!result) + { + return result; + } + + // + // XICH ... + result = ich.Init( + symbol, + period, + mInputs.ichInputs + // + ); + if (!result) + { + return result; + } + + // + return result; + } + + // + // Retrieve Current Market Conditions ... + X121MCycleConditions GetMarketConditions( + int barIndex // Specified Bar Index + ) + { + // + X121MCycleConditions result; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex >= CountBars()) + { + barIndex = CountBars() + 2; + } + + // + // Here i Have to Calculate Market Conditions based on + // Several Indicator/Oscillator(s) ... + + // + // Set Commons ... + result.time = GetBarTime(barIndex); + result.cycle = mInputs.cycle.cycle; + result.prefix = mInputs.cycle.prefix; + result.symbol = mInputs.cycle.symbol; + result.period = mInputs.cycle.period; + result.hostPeriod = mInputs.cycle.hostPeriod; + + // + Clean(result.bars); + GetBars( + result.bars, + result.symbol, + result.period, + barIndex, + barIndex + 5); + + // + XOHCL cBar = GetBar(barIndex); + XOHCL pBar = GetBar(barIndex + 1); + + // + // CANDELSTICK ... + + // + bool isLastBullish = + // + pBar.IsBullish() + // + ; + + // + bool isLastBearish = + // + pBar.IsBearish() + // + ; + + // + bool isCurrentBullish = + // + cBar.IsBullish() + // + ; + + // + bool isCurrentBearish = + // + cBar.IsBearish() + // + ; + + // + bool isCurrentMidLineOverLastHigh = + // + cBar.GetMid() > pBar.high; + // + ; + + // + bool isCurrentMidLineUnderLastLow = + // + cBar.GetMid() < pBar.low + // + ; + + // + bool isCurrentMidLineOverLastUp = + // + cBar.GetMid() > pBar.GetUp() + // + ; + + // + bool isCurrentMidLineUnderLastDown = + // + cBar.GetMid() < pBar.GetDown() + // + ; + + // + bool isCurrentMidLineOverLastMidLine = + // + cBar.GetMid() > pBar.GetMid() + // + ; + + // + bool isCurrentMidLineUnderLastMidLine = + // + cBar.GetMid() < pBar.GetMid() + // + ; + + // + result.isLastBullish = isLastBullish; + result.isLastBearish = isLastBearish; + result.isCurrentBullish = isCurrentBullish; + result.isCurrentBearish = isCurrentBearish; + result.isCurrentMidLineOverLastHigh = isCurrentMidLineOverLastHigh; + result.isCurrentMidLineUnderLastLow = isCurrentMidLineUnderLastLow; + result.isCurrentMidLineOverLastUp = isCurrentMidLineOverLastUp; + result.isCurrentMidLineUnderLastDown = isCurrentMidLineUnderLastDown; + result.isCurrentMidLineOverLastMidLine = isCurrentMidLineOverLastMidLine; + result.isCurrentMidLineUnderLastMidLine = isCurrentMidLineUnderLastMidLine; + + // + // XSTR ... + bool isTrendBullish = + // + str.IsBullish(str.GetState(barIndex)) + // + ; + bool isTrendBearish = + // + str.IsBearish(str.GetState(barIndex)) + // + ; + + // + result.isTrendBullish = isTrendBullish; + result.isTrendBearish = isTrendBearish; + + // + // XCHE ... + bool isCHEInLong = + // + NotEmpty(che.GetLongExit1(barIndex)) + // + ; + bool isCHEInStrongLong = + // + isCHEInLong && + NotEmpty(che.GetLongExit2(barIndex)) + // + ; + bool isCHEInShort = + // + NotEmpty(che.GetShortExit1(barIndex)) + // + ; + bool isCHEInStrongShort = + // + isCHEInShort && + NotEmpty(che.GetShortExit2(barIndex)) + // + ; + + // + result.isCHEInLong = isCHEInLong; + result.isCHEInShort = isCHEInShort; + result.isCHEInStrongLong = isCHEInStrongLong; + result.isCHEInStrongShort = isCHEInStrongShort; + + // + // XMC ... + + // + double fasts[]; + mc.CopyFast( + barIndex, + 2, + fasts + // + ); + + // + double slows[]; + mc.CopySlow( + barIndex, + 2, + slows + // + ); + + // + double verifiers[]; + mc.CopyVerifier( + barIndex, + 2, + verifiers + // + ); + + // + bool isFastOverSlow = + // + fasts[0] > slows[0] && + fasts[1] > slows[1] + // + ; + bool isFastUnderSlow = + // + fasts[0] < slows[0] && + fasts[1] < slows[1] + // + ; + bool isFastOverVerifier = + // + fasts[0] > verifiers[0] && + fasts[1] > verifiers[1] + // + ; + bool isFastUnderVerifier = + // + fasts[0] < verifiers[0] && + fasts[1] < verifiers[1] + // + ; + bool isSlowOverVerifier = + // + slows[0] > verifiers[0] && + slows[1] > verifiers[1] + // + ; + bool isSlowUnderVerifier = + // + slows[0] < verifiers[0] && + slows[1] < verifiers[1] + // + ; + bool isCloseOverFast = + // + pBar.close > fasts[1] + // + ; + bool isCloseUnderFast = + // + pBar.close < fasts[1] + // + ; + bool isCloseOverSlow = + // + pBar.close > slows[1] + // + ; + bool isCloseUnderSlow = + // + pBar.close < slows[1] + // + ; + bool isCloseOverVerifier = + // + pBar.close > verifiers[1] + // + ; + bool isCloseUnderVerifier = + // + pBar.close < verifiers[1] + // + ; + + // + result.isFastOverSlow = isFastOverSlow; + result.isFastUnderSlow = isFastUnderSlow; + result.isFastOverVerifier = isFastOverVerifier; + result.isFastUnderVerifier = isFastUnderVerifier; + result.isSlowOverVerifier = isSlowOverVerifier; + result.isSlowUnderVerifier = isSlowUnderVerifier; + result.isCloseOverFast = isCloseOverFast; + result.isCloseUnderFast = isCloseUnderFast; + result.isCloseOverSlow = isCloseOverSlow; + result.isCloseUnderSlow = isCloseUnderSlow; + result.isCloseOverVerifier = isCloseOverVerifier; + result.isCloseUnderVerifier = isCloseUnderVerifier; + + // + // XICH ... + + // + // XOSC ... + + // + // STDDEV ... + + // + double stdDev = osc.GetSTDDEV(barIndex); + double stdDevLast = osc.GetSTDDEV(barIndex + 1); + double stdDevs[]; + osc.CopySTDDEV( + barIndex + 1, + 5, + stdDevs // + ); + double stdDevAVG = GetAverage(stdDevs); + + // + bool isSTDDEVOverAVG = + // + stdDev > stdDevAVG + // + ; + bool isSTDDEVUnderAVG = + // + stdDev < stdDevAVG + // + ; + bool isSTDDEVOverLast = + // + stdDev > stdDevLast + // + ; + bool isSTDDEVUnderLast = + // + stdDev < stdDevLast + // + ; + + // + result.isSTDDEVOverAVG = isSTDDEVOverAVG; + result.isSTDDEVUnderAVG = isSTDDEVUnderAVG; + result.isSTDDEVOverLast = isSTDDEVOverLast; + result.isSTDDEVUnderLast = isSTDDEVUnderLast; + + // + // RVI ... + + // + double rvi = osc.GetRVI(barIndex); + double rviSignal = osc.GetRVISignal(barIndex); + + // + bool isRVILongStart = + // + rvi > 0 && + rviSignal > 0 && + rvi > rviSignal + // + ; + bool isRVILongStop = + // + rvi < 0 && + rviSignal < 0 && + rvi < rviSignal + // + ; + bool isRVIShortStart = + // + rvi < 0 && + rviSignal < 0 && + rvi < rviSignal + // + ; + bool isRVIShortStop = + // + rvi > 0 && + rviSignal > 0 && + rvi > rviSignal + // + ; + + // + result.isRVILongStart = isRVILongStart; + result.isRVILongStop = isRVILongStop; + result.isRVIShortStart = isRVIShortStart; + result.isRVIShortStop = isRVIShortStop; + + // + // RSI ... + double rsi = osc.GetRSI(barIndex); + + // + bool isRSIUnder50 = + // + rsi < 50 + // + ; + bool isRSIOver70 = + // + rsi > 70 + // + ; + bool isRSIOver50 = + // + rsi > 50 + // + ; + bool isRSIUnder30 = + // + rsi < 30 + // + ; + + // + result.isRSIUnder50 = isRSIUnder50; + result.isRSIOver70 = isRSIOver70; + result.isRSIOver50 = isRSIOver50; + result.isRSIUnder30 = isRSIUnder30; + + // + // BULLPOWER ... + + // + double bullp = osc.GetBullPower(barIndex); + double bullpLast = osc.GetBullPower(barIndex + 1); + + // + bool isBullPowerOverLast = + // + bullp > bullpLast + // + ; + bool isBullPoswerUnderLast = + // + bullp < bullpLast + // + ; + bool isBullPowerOverZero = + // + bullp > 0 + // + ; + bool isBullPoswerUnderZero = + // + bullp < 0 + // + ; + + // + result.isBullPowerOverLast = isBullPowerOverLast; + result.isBullPoswerUnderLast = isBullPoswerUnderLast; + result.isBullPowerOverZero = isBullPowerOverZero; + result.isBullPoswerUnderZero = isBullPoswerUnderZero; + + // + // BEARPOWER ... + + // + double bearp = osc.GetBearPower(barIndex); + double bearpLast = osc.GetBearPower(barIndex + 1); + + // + bool isBearPowerOverLast = + // + bearp > bearpLast + // + ; + bool isBearPoswerUnderLast = + // + bearp < bearpLast + // + ; + bool isBearPowerOverZero = + // + bearp > 0 + // + ; + bool isBearPoswerUnderZero = + // + bearp < 0 + // + ; + + // + result.isBearPowerOverLast = isBearPowerOverLast; + result.isBearPoswerUnderLast = isBearPoswerUnderLast; + result.isBearPowerOverZero = isBearPowerOverZero; + result.isBearPoswerUnderZero = isBearPoswerUnderZero; + + // + // CCI ... + + // + double cci = osc.GetCCI(barIndex); + + // + bool isCCIPositive = + // + cci > 0 + // + ; + bool isCCINegative = + // + cci < 0 + // + ; + bool isCCIOverPositiveHundred = + // + cci > 100 + // + ; + bool isCCIUnderNegativeHundred = + // + cci < -100 + // + ; + + // + result.isCCIPositive = isCCIPositive; + result.isCCINegative = isCCINegative; + result.isCCIOverPositiveHundred = isCCIOverPositiveHundred; + result.isCCIUnderNegativeHundred = isCCIUnderNegativeHundred; + + // + // MACD ... + + // + double macd = osc.GetMACD(barIndex); + double macdSignal = osc.GetMACDSignal(barIndex); + + // + bool isMACDPositiove = + // + macd > 0 + // + ; + bool isMACDNegative = + // + macd < 0 + // + ; + bool isMACDOverSignal = + // + macd > macdSignal + // + ; + bool isMACDUnderSignal = + // + macd < macdSignal + // + ; + + // + result.isMACDPositiove = isMACDPositiove; + result.isMACDNegative = isMACDNegative; + result.isMACDOverSignal = isMACDOverSignal; + result.isMACDUnderSignal = isMACDUnderSignal; + + // + // STOCH ... + + // + double stoch = osc.GetSTOCH(barIndex); + double stochSignal = osc.GetSTOCHSignal(barIndex); + + // + bool isStochKOverD = + // + stoch > stochSignal + // + ; + bool isStochKDUnder50 = + // + stoch < 50 && + stochSignal < 50 + // + ; + bool isStochKUnderD = + // + stoch < stochSignal + // + ; + bool isStochKDOver50 = + // + stoch > 50 && + stochSignal > 50 + // + ; + bool isStochKDUnder20 = + // + stoch < 20 && + stochSignal < 20 + // + ; + bool isStochKDOver80 = + // + stoch > 80 && + stochSignal > 80 + // + ; + + // + result.isStochKOverD = isStochKOverD; + result.isStochKDUnder50 = isStochKDUnder50; + result.isStochKUnderD = isStochKUnderD; + result.isStochKDOver50 = isStochKDOver50; + result.isStochKDUnder20 = isStochKDUnder20; + result.isStochKDOver80 = isStochKDOver80; + + // + return result; + } + + // + // Completely Draw Bars ... + void Draw( + long chartID, // Chart ID ... + int subWindow, // Chart Sub Window ... + int &offset // Distance used for Labels ... + ) + { + // + if (mInputs.drawCBar || mInputs.drawPBar) + { + // + DrawOHCL( + chartID, + subWindow, + mInputs.drawLabels, + !mInputs.drawCBar && mInputs.drawPBar, + !mInputs.drawPBar && mInputs.drawCBar, + offset + // + ); + + // + if (mInputs.drawLabels) + { + offset += 3; + } + } + + // + if (mInputs.drawCBarMid || mInputs.drawPBarMid) + { + // + DrawMidLine( + chartID, + subWindow, + mInputs.drawLabels, + !mInputs.drawCBarMid && mInputs.drawPBarMid, + !mInputs.drawPBarMid && mInputs.drawCBarMid, + offset + // + ); + + // + if (mInputs.drawLabels) + { + // + if (mInputs.drawCBarMid) + { + offset++; + } + + // + if (mInputs.drawPBarMid) + { + offset++; + } + } + } + } + + // + // Draw Functions ... + // + // Draw Middle Line of Cycle ... + void DrawOHCL( + long chartID, + int subWindow, + bool drawLabel = false, // Specify Draw Label of Mid Line or not ... + bool drawOnlyPrev = false, // Specify Draw Only Prev Bar of Cycle ... + bool drawOnlyCurrent = false, // Specify Draw Only Current Bar of Cycle ... + int offset = 0 // Distance used for Labels ... + ) + { + // + if (offset < 0) + { + offset = 0; + } + + // + string baseTag = ToString(mInputs.cycle.cycle); + + // + XOHCL cBar = GetBar(0); + XOHCL pBar = GetBar(1); + + // + datetime fromCDate = GetBarTime(0); + datetime fromPDate = GetBarTime(1); + + // + datetime cTime = TimeCurrent(); + + // + // Try to Draw ... + + // + bool canDrawPrev = !drawOnlyCurrent; + bool canDrawCurrent = !drawOnlyPrev; + + // + // Set Cycles Color based on Current Candle ... + + // + bool isCBarBullish = + cBar.IsBullish(); + + // + bool isPBarBullish = + pBar.IsBearish(); + + // + color clrTemoBullishColor = mInputs.cBarDrawSpecs.openStyle.clr; + color clrTemoBearishColor = mInputs.cBarDrawSpecs.closeStyle.clr; + + // + color cBarSelectedColor = isCBarBullish ? clrTemoBullishColor : clrTemoBearishColor; + color pBarSelectedColor = isPBarBullish ? clrTemoBullishColor : clrTemoBearishColor; + + // + mInputs.cBarDrawSpecs.openStyle.clr = cBarSelectedColor; + mInputs.cBarDrawSpecs.openStyle.labelColor = cBarSelectedColor; + + // + mInputs.cBarDrawSpecs.closeStyle.clr = cBarSelectedColor; + mInputs.cBarDrawSpecs.closeStyle.labelColor = cBarSelectedColor; + + // + mInputs.pBarDrawSpecs.openStyle.clr = pBarSelectedColor; + mInputs.pBarDrawSpecs.openStyle.labelColor = pBarSelectedColor; + + // + mInputs.pBarDrawSpecs.closeStyle.clr = pBarSelectedColor; + mInputs.pBarDrawSpecs.closeStyle.labelColor = pBarSelectedColor; + + // + if (canDrawPrev) + { + offset++; + } + + // + // Label ... + if (drawLabel) + { + // + if (canDrawPrev) + { + // + // Draw Prev Bar Lables ... + + // + DrawXOHCLLabel( + chartID, + subWindow, + pBar, + mInputs.pBarDrawSpecs, + "P", + cTime, + offset - 1 + // + ); + + // + offset += 3; + } + + // + if (canDrawCurrent) + { + // + // Draw Current Bar Lables ... + + // + DrawXOHCLLabel( + chartID, + subWindow, + cBar, + mInputs.cBarDrawSpecs, + "C", + cTime, + offset + // + ); + } + } + + // + // Line ... + + // + if (canDrawPrev) + { + // + // Draw Cycle Prev Bar ... + DrawXOHCLContent( + chartID, + subWindow, + pBar, + mInputs.pBarDrawSpecs, + "P", + fromPDate + // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Cycle Current Bar ... + DrawXOHCLContent( + chartID, + subWindow, + cBar, + mInputs.cBarDrawSpecs, + "C", + fromCDate + // + ); + } + } + + // + // Draw Middle Line of Cycle ... + void DrawMidLine( + long chartID, + int subWindow, + bool drawLabel = false, // Specify Draw Label of Mid Line or not ... + bool drawOnlyPrev = false, // Specify Draw Only Prev Bar of Cycle ... + bool drawOnlyCurrent = false, // Specify Draw Only Current Bar of Cycle ... + int offset = 0 // Distance used for Labels ... + ) + { + // + if (offset < 0) + { + offset = 0; + } + + // + // Calculate Mid Line ... + XOHCL cBar = GetBar(0); + double cMidLine = cBar.GetMid(); + + // + XOHCL pBar = GetBar(1); + double pMidLine = pBar.GetMid(); + + // + string baseTag = ToString(mInputs.cycle.cycle); + + // + string midCTag = baseTag + "|MID|C|"; + string midPTag = baseTag + "|MID|P|"; + + // + string midCLblTag = midCTag + "lbl"; + string midPLblTag = midPTag + "lbl"; + + // + datetime fromCDate = GetBarTime(0); + datetime fromPDate = GetBarTime(1); + + // + datetime cTime = TimeCurrent(); + + // + // Try to Draw ... + + // + bool canDrawPrev = !drawOnlyCurrent; + bool canDrawCurrent = !drawOnlyPrev; + + // + if (canDrawPrev) + { + offset++; + } + + // + // Label ... + if (drawLabel) + { + // + if (canDrawPrev) + { + // + // Draw Prev Candle MidLine Lable ... + DrawLabel( + chartID, + subWindow, + mInputs.pBarMidDrawSpecs, + midPLblTag, + cTime, + pMidLine, + offset // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Current Candle MidLine Label ... + DrawLabel( + chartID, + subWindow, + mInputs.cBarMidDrawSpecs, + midCLblTag, + cTime, + cMidLine, + offset - 1 // + ); + } + } + + // + // Line ... + + // + if (canDrawPrev) + { + // + // Draw Prev Candle MidLine ... + DrawLine( + chartID, + subWindow, + mInputs.pBarMidDrawSpecs, + midPTag, + fromPDate, + pMidLine // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Current Candle MidLine ... + DrawLine( + chartID, + subWindow, + mInputs.cBarMidDrawSpecs, + midCTag, + fromCDate, + cMidLine // + ); + } + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + + // + X121MCycleInputs mInputs; + + // + // Tools ... + + // + bool Update(int hostBarIndex = 0) + { + return mInputs.cycle.Update(hostBarIndex); + } + + // + // Draw Functions ... + // + // Draw OHCL Labels ... + void DrawXOHCLLabel( + long chartID, + int subWindow, + XOHCL &bar, // Specify Cycle XOHCL Model to Draw ... + XOHCLDrawSpecification &specs, // Specify Cycle XOHCL Draw Specifications ... + string baseTag, // Specify a Unique Tag ... + datetime time, // Draw Time ... + int offset = 0 // + ) + { + // + // Open ... + string openTag = mInputs.cycle.prefix + "_" + baseTag + "_O_lbl"; + DrawLabel( + chartID, + subWindow, + specs.openStyle, + openTag, + time, + bar.open, + offset + // + ); + + // + // High ... + string highTag = mInputs.cycle.prefix + "_" + baseTag + "_H_lbl"; + DrawLabel( + chartID, + subWindow, + specs.highStyle, + highTag, + time, + bar.high, + offset + 1 + // + ); + + // + // Close ... + string closeTag = mInputs.cycle.prefix + "_" + baseTag + "_C_lbl"; + DrawLabel( + chartID, + subWindow, + specs.closeStyle, + closeTag, + time, + bar.close, + offset + 2 + // + ); + + // + // Low ... + string lowTag = mInputs.cycle.prefix + "_" + baseTag + "_L_lbl"; + DrawLabel( + chartID, + subWindow, + specs.lowStyle, + lowTag, + time, + bar.low, + offset + 3 + // + ); + } + + // + // Draw XOHCL Content ... + void DrawXOHCLContent( + long chartID, + int subWindow, + XOHCL &bar, // Specify Cycle XOHCL Model to Draw ... + XOHCLDrawSpecification &specs, // Specify Cycle XOHCL Draw Specifications ... + string baseTag, // Specify a Unique Tag ... + datetime time // Draw Time ... + ) + { + // + // Open ... + string openTag = mInputs.cycle.prefix + "_" + baseTag + "_O"; + DrawLine( + chartID, + subWindow, + specs.openStyle, + openTag, + time, + bar.open + // + ); + + // + // High ... + string highTag = mInputs.cycle.prefix + "_" + baseTag + "_H"; + DrawLine( + chartID, + subWindow, + specs.highStyle, + highTag, + time, + bar.high + // + ); + + // + // Close ... + string closeTag = mInputs.cycle.prefix + "_" + baseTag + "_C"; + DrawLine( + chartID, + subWindow, + specs.closeStyle, + closeTag, + time, + bar.close + // + ); + + // + // Low ... + string lowTag = mInputs.cycle.prefix + "_" + baseTag + "_L"; + DrawLine( + chartID, + subWindow, + specs.lowStyle, + lowTag, + time, + bar.low + // + ); + } + + // + // Draw Label Using Specifications ... + void DrawLabel( + long chartID, + int subWindow, + XDrawSpecifications &specs, + string tag, + datetime time, + double price, + int offset = 0 // + ) + { + // + if (offset < 0) + { + offset = 0; + } + + // + int offsetSeconds = PeriodSeconds(mInputs.cycle.hostPeriod) * offset; + + // + string value = specs.label; + + // + DrawText( + chartID, + tag, + subWindow, + time - offsetSeconds, + price, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw TrendLine Using Specifications ... + void DrawLine( + long chartID, + int subWindow, + XDrawSpecifications &specs, + string tag, + datetime fromDate, + double fromPrice, + datetime toDate = NULL, + double toPrice = 0 // + ) + { + // + if (toPrice <= 0) + { + toPrice = fromPrice; + } + + // + if (toDate == 0 || toDate == NULL) + { + toDate = TimeCurrent(); + } + + // + DrawTrendLine( + chartID, + tag, + subWindow, + fromDate, + fromPrice, + toDate, + toPrice, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); + } +}; diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xaccount.class.ex5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xaccount.class.ex5 new file mode 100644 index 0000000..afafc70 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xaccount.class.ex5 differ diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xaccount.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xaccount.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xaccount.class.mq5 rename to MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xaccount.class.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xdata-collector.ex5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xdata-collector.ex5 new file mode 100644 index 0000000..fc681af Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xdata-collector.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xdata-collector.mq5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xdata-collector.mq5 new file mode 100644 index 0000000..5a2c9ed --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xdata-collector.mq5 @@ -0,0 +1,444 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCDataCollector +// Description: provides Data Collection 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 "../Libraries/x-saherelm.common.lib.mq5" + +// +template +class XSCDataCollector +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + void XSCDataCollector( + string path = NULL, // Base Folder for Data Store + string fileName = NULL // File Name for Data Store + ) + { + // + if (!IsValid(path)) + { + path = GetType(); + } + + // + if (!IsValid(fileName)) + { + fileName = GetType() + ".txt"; + } + + // + Path(path); + FileName(fileName); + } + + // + // Deconstructor ... + void ~XSCDataCollector() {} + + // + // Properties ... + + // + bool Path(string value) + { + // + bool result = false; + + // + result = IsValid(value); + if (!result) + { + return result; + } + + // + result = value != mPath; + if (!result) + { + return result; + } + + // + mPath = value; + + // + return result; + } + + // + string Path() + { + return mPath; + } + + // + bool FileName(string value) + { + // + bool result = false; + + // + result = IsValid(value); + if (!result) + { + return result; + } + + // + result = value != mFileName; + if (!result) + { + return result; + } + + // + mFileName = value; + + // + return result; + } + + // + string FileName() + { + return mFileName; + } + + // + // Tools ... + + // + // Clear Exists Collected Data ... + void Clear() + { + // + ResetLastError(); + + // + string dataStorePath = GetStorePath(); + + // + // Check Data Store Exists or not ... + bool isExists = FileIsExist(dataStorePath); + if (!isExists) + { + return; + } + + // + FileDelete(dataStorePath); + } + + // + // Collect All Stored Items ... + int Collect( + T &items[] // Hold Result + ) + { + // + int result = 0; + + // + Clean(items); + + // + // Reading Store Whole Content ... + + // + string storePath = GetStorePath(); + int mFileHandler = FileOpen( + storePath, + FILE_READ | FILE_TXT); + result = mFileHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // Parse Store Content and Read Data ... + while (!FileIsEnding(mFileHandler)) + { + // + // Each Line Represent One Model ... + string content = FileReadString(mFileHandler); + + // + T iItem; + bool isValid = iItem.Parse(content); + if (isValid) + { + // + AddRef( + iItem, + items + // + ); + } + } + + // + // Close File ... + FileClose(mFileHandler); + + // + result = ArraySize(items); + + // + return result; + } + + // + // Add Item ... + bool Add( + T &item // Item to Store + ) + { + // + bool result = false; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + string content = item.ToString(); + result = IsValid(content); + if (!result) + { + return result; + } + + // + string storePath = GetStorePath(); + int mFileHandler = FileOpen( + storePath, + FILE_READ | FILE_WRITE | FILE_TXT); + result = mFileHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileSeek(mFileHandler, 0, SEEK_END); + FileWrite(mFileHandler, content); + FileFlush(mFileHandler); + FileClose(mFileHandler); + + // + return result; + } + + // + // Add Items ... + int Add( + T &items[] // Items to Add ... + ) + { + // + int result = 0; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < itemsCount; i++) + { + // + T iItem = items[i]; + + // + if (!iItem.IsValid()) + { + continue; + } + + // + bool isAdded = Add(iItem); + if (isAdded) + { + result++; + } + } + + // + return result; + } + + // + // Remove Item ... + bool Remove( + T &item // Item to Remove + ) + { + // + bool result = false; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + T items[]; + int itemsCount = Collect(items); + if (itemsCount <= 0) + { + return result; + } + + // + int itemIndex = item.FindIndex(items); + result = ArrayRemove( + items, + itemIndex, + 1); + if (!result) + { + return result; + } + + // + Clear(); + + // + int itemsAdded = Add(items); + + // + result = itemsAdded == ArraySize(items); + + // + return result; + } + + // + // Protected ... +protected: + // + // Tools ... + + // + // Retrieve Type of Class as String ... + string GetType() + { + // + string mType = (string) typename(T); + + // + string result = mType; + + // + string parts[]; + int partsCount = SplitContent( + parts, + result, + " " + // + ); + if (partsCount <= 0) + { + // + result = mType; + return result; + } + + // + bool hasLastPart = GetLastItem( + result, + parts + // + ); + if (!hasLastPart) + { + // + result = mType; + return result; + } + + // + return result; + } + + // + // Pricate ... +private: + // + // Props ... + + // + string mPath; // Path + string mFileName; // Data Store File Name + + // + // Tools ... + + // + // Generate Full File Path ... + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + Path() + "\\" + fileName + // + ; + + // + return result; + } + + // + // Retrieve Data Store File Address ... + string GetStorePath() + { + // + string result = NULL; + + // + result = GetFilePath(mFileName); + + // + return result; + } +}; + +// \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xea.class.ex5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xea.class.ex5 new file mode 100644 index 0000000..8d6e45c Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xea.class.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xea.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xea.class.mq5 new file mode 100644 index 0000000..626a8cd --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xea.class.mq5 @@ -0,0 +1,2142 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCBaseEA +// Description: provides all Base EA 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 + +// +// START Definitions ... +// + +// +// if Signal Execution Failed this is the reason ... +enum ENUM_X_SIGNAL_EXECUTION_FAILED +{ + X_NOTHING, // Succeeded ... + X_UNKNOWN, // Failed, but Unknown ... + X_FAILED_REASON_EQUITY, // Failed, Since Equity ... + X_FAILED_REASON_SPREAD, // Failed, Since Spread ... + X_FAILED_REASON_MAX_REACHED // Failed Signce Max Allowed Reached ... +}; + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Libraries/x-saherelm.alert.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" +#include "../Classes/x-saherelm.xaccount.class.mq5" +#include "../Classes/x-saherelm.xprovider.class.mq5" +#include "../Libraries/x-saherelm.seriallizer.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Class for Handle base requirements ... +// for indicators ... +class XSCBaseEA +{ + // + // Public ... +public: + // + // Props ... + XSCTrade *mTrader; + XSCAccount *mAccount; + + // + bool isNewHour; + bool isNewDay; + bool isNewWeek; + bool isNewMonth; + bool isNewCandle; + + // + bool isInTestMode; + + // + bool mWaitsUntilNewCandle; + + // + // Constructor ... + void XSCBaseEA( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Time Frame + ulong magic, // Magic Number + int slippage, // Slippgae + double maxAllowedSpread, // Max Allowed Spread to Execute Signal + int maxAllowedPositions, // Maximum Allowed Same Time Position + double minProfitPerTrade, // Min Profit Per Trade based On Volume Factor (Hedge) + double minProfitPerVolumeFactor, // Min Volume Factor for Calculating Profit (Hedge) + double maxAllowedDrawDownFactor, // Max Allowed Drawdown factor for Open New Positions + TOnStopLoss onStopLossTriggered = NULL, // On StopLoass Triggered Event Handler + TOnTakeProfit onTakeProfitTriggered = NULL, // On TakeProfit Triggered Event Handler + TOnDealsChanged onDealsChangedHandler = NULL, // On Deals Changed Event Handler + TOnOrdersChanged onOrdersChangedHandler = NULL, // On Orders Changed Event Handler + TOnPositionsChanged onPositionsChangedHandler = NULL, // On Positions Changed Event Handler + TOnTradeStateChanged onTradeStateChangedHandler = NULL // On Trade State Changed Event Handler + ) + { + // + mSymbol = symbol; + mPeriod = period; + + // + mMagic = magic; + mSlippage = slippage; + + // + mMaxAllowedSpread = maxAllowedSpread; + + // + mMaxAllowedPositions = maxAllowedPositions; + mMaxAllowedDrawDownFactor = maxAllowedDrawDownFactor; + + // + mMinProfitPerTrade = minProfitPerTrade; + mMinProfitPerVolumeFactor = minProfitPerVolumeFactor; + + // + mOnStopLossTriggered = onStopLossTriggered; + mOnTakeProfitTriggered = onTakeProfitTriggered; + mOnDealsChangedHandler = onDealsChangedHandler; + mOnOrdersChangedHandler = onOrdersChangedHandler; + mOnPositionsChangedHandler = onPositionsChangedHandler; + mOnTradeStateChangedHandler = onTradeStateChangedHandler; + + // + // Reset Timings ... + ResetTiming(); + + // + InitRequirements(); + } + + // + // Deconstructor ... + void ~XSCBaseEA() + { + // + delete mTrader; + delete mAccount; + } + + // + // START Properties ... + // + + // + // Symbol ... + string GetSymbol() + { + return mSymbol; + } + + // + // Period ... + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + // + // Tag ... + string GetTag() + { + return mTag; + } + + // + ulong GetMagic() + { + return mMagic; + } + + // + int GetSlippage() + { + return mSlippage; + } + + // + // Check Long Signalling State ... + bool EnableLongs() + { + return mEnableLongs; + } + + // + // Set Long Signalling State ... + void EnableLongs(bool enable) + { + // + if (enable == mEnableLongs) + { + return; + } + + // + mEnableLongs = enable; + } + + // + // Check Short Signalling State ... + bool EnableShorts() + { + return mEnableShorts; + } + + // + // Set Short Signalling State ... + void EnableShorts(bool enable) + { + // + if (enable == mEnableShorts) + { + return; + } + + // + mEnableShorts = enable; + } + + // + double MaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + // + void MaxAllowedSpread(double value) + { + // + if (value <= 0) + { + value = 0; + } + + // + if (value == mMaxAllowedSpread) + { + return; + } + + // + mMaxAllowedSpread = value; + } + + // + // Get Max Allowed Positions at Same Time ... + int MaxAllowedPositions() + { + return mMaxAllowedPositions; + } + + // + // Set Max Allowed Positions at Same Time ... + void MaxAllowedPositions(int value) + { + // + if (value < 0 || + value == mMaxAllowedPositions) + { + return; + } + + // + mMaxAllowedPositions = value; + } + + // + // Get Max Allowed DrawDown Factor ... + double MaxAllowedDrawDownFactor() + { + return mMaxAllowedDrawDownFactor; + } + + // + // Set Max Allowed Positions at Same Time ... + void MaxAllowedDrawDownFactor(double value) + { + // + if (value < 0 || + value == mMaxAllowedDrawDownFactor) + { + return; + } + + // + mMaxAllowedDrawDownFactor = value; + } + + // + double MinProfitPerTrade() + { + return mMinProfitPerTrade; + } + + // + void MinProfitPerTrade(double value) + { + // + if (value <= 0) + { + value = 0; + } + + // + if (value == mMinProfitPerTrade) + { + return; + } + + // + mMinProfitPerTrade = value; + } + + // + double MinProfitPerVolumeFactor() + { + return mMinProfitPerVolumeFactor; + } + + // + void MinProfitPerVolumeFactor(double value) + { + // + if (value <= 0) + { + value = 0; + } + + // + if (value == mMinProfitPerVolumeFactor) + { + return; + } + + // + mMinProfitPerVolumeFactor = value; + } + + // + // END Properties ... + // + + // + // START Provided Functions ... + // + + // + // Prepare Tag ... + virtual void PrepareTag() + { + mTag = "XEA" + mSymbol + "," + ToString(mPeriod) + (string)mMagic; + } + + // + // Handle Chart Events ... + virtual void OnChartEvent( + const int id, // event ID + const long &lparam, // long type event parameter + const double &dparam, // double type event parameter + const string &sparam // string type event parameter + ) + { + } + + // + // Check any Registered Providers Signalling ... + virtual bool SignalCheck(XSignal &signals[]) + { + return false; + } + + // + // Check for any Custom Guard Actions Guard Actions ... + virtual bool CheckGuard(XGuard &guards[]) + { + return false; + } + + // + virtual void BeforeSignalExecution(XSignal &signals[]) {} + + // + // NOTE: you have to call these Functions on Static Classes to Handle Works ... + + // + // Handle StopLoss Event ... + virtual void OnStopLossTriggered(const XDeal &deal) {} + + // + // Handle TakeProfit Event ... + virtual void OnTakeProfitTriggered(const XDeal &deal) {} + + // + // Handle Deals Changed Event ... + virtual void OnDealsChangedHandler(int count) {} + + // + // Handle Order Changed Event ... + virtual void OnOrdersChangedHandler(int count) {} + + // + // Handle Position Changed Event ... + virtual void OnPositionsChangedHandler(int count) {} + + // + // Handle Trade State Changed ... + virtual void OnTradeStateChangedHandler(const XOnTradeHandlerState &state) {} + + // + // Implemented Actions ... + + // + // OnTick Handler ... + void OnTick() + { + // + // First Check Guards .... + // Only when Open Positions Exists or Has Pending Order ... + XGuard guards[]; + bool hasGuard = CheckGuard(guards); + if (hasGuard) + { + DoGuards(guards); + } + + // + XSignal signals[]; + bool hasSignal = SignalCheck(signals); + if (hasSignal) + { + // + // Here we have to Check Signals and also it's State ... + XSignal enabledSignals[]; + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return; + } + + // + // Filter Signals by their type and + // also Check EA Enable their type ... + for (int i = 0; i < signalsCount; i++) + { + // + XSignal iSignal = signals[i]; + bool isLong = IsLong(iSignal.type); + if ((isLong && mEnableLongs) || + (!isLong && mEnableShorts)) + { + // + Add( + iSignal, + enabledSignals); + } + } + + // + int enabledSignalsCount = ArraySize(enabledSignals); + if (enabledSignalsCount <= 0) + { + return; + } + + // + // Here we have do All things before Signals Execution ... + // in this way we can implement custom searios on Inherited Classes ... + BeforeSignalExecution(enabledSignals); + + // + // Now double chack signals Array .... + // if there isn't any signal we prevent moving forward ... + // this helps us to Manage Signal Executions on Above Part ... + // for inherited classes ... + enabledSignalsCount = ArraySize(enabledSignals); + if (enabledSignalsCount <= 0) + { + return; + } + + // + ENUM_X_SIGNAL_EXECUTION_FAILED reasons[]; + ExecuteSignals( + enabledSignals, + reasons, + true // Check Policiese ... + ); + } + } + + // + // Handle On Trade ... + void OnTrade() + { + // + XOnTradeHandlerState state = mTrader.HandleOnTrade(); + + // + if ( + !state.hasNewDeal && + !state.hasNewOrder && + !state.hasNewPosition && + !state.hasNewHistoryOrder) + { + return; + } + + // + // STATE ... + + // + // Notfy Trade State Changed Event ... + OnTradeStateChangedHandler(state); + + // + // DEALS ... + if (state.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + OnDealsChangedHandler(state.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + mTrader.GetDeals(deals); + int dealsCount = ArraySize(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + OnTakeProfitTriggered(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + OnStopLossTriggered(lastDeal); + } + } + } + + // + // ORDERS ... + if (state.hasNewOrder || state.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + OnOrdersChangedHandler(state.newOrders + state.newHistoryOrders); + } + + // + // POSITIONS ... + if (state.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + OnPositionsChangedHandler(state.newPositions); + } + } + + // + // Retrieve Dept Of Market ... + void OnBookEvent(const string &symbol) + { + // + // TODO: Implement this ... + } + + // + // TOOLS ... + + // + // Execute Specific Signal by Checking Spreads ... + // if provided ... + bool ExecuteSignal( + const XSignal &signal, // Source Signal ... + ENUM_X_SIGNAL_EXECUTION_FAILED &reason, // Provides Error Reason ... + bool checkPoliciese = true // Check Account Policies Before Execute Signal ... + ) + { + // + bool result = false; + reason = X_NOTHING; + + // + // Check Account Policies ... + if (checkPoliciese) + { + // + // First Check Equity ... + result = CheckEquityForTrade(); + if (!result) + { + // + reason = X_FAILED_REASON_EQUITY; + return result; + } + + // + // Check Positions Count ... + result = ChecPositionsForTrade(); + if (!result) + { + // + reason = X_FAILED_REASON_MAX_REACHED; + return result; + } + + // + // Check Spread ... + result = IsSpreadOkForSignalExecution(signal); + if (!result) + { + // + reason = X_FAILED_REASON_SPREAD; + return result; + } + } + + // + XSignal tmpSignal = signal; + PrepareSignal(tmpSignal); + + // + // Generate Provider Comment ... + string comment = GenerateProvidersString(tmpSignal); + + // + result = mTrader + .ExecuteSignal( + tmpSignal, + comment // + ); + if (!result) + { + reason = X_UNKNOWN; + } + + // + return result; + } + + // + // Execute Specific Signals by Checking Spreads ... + // if provided ... + int ExecuteSignals( + const XSignal &signals[], // Signals Collection ... + ENUM_X_SIGNAL_EXECUTION_FAILED &reasons[], // Provides Error Reason ... + bool checkPoliciese = true // Check Account Policies Before Execute Signal ... + ) + { + // + int result = 0; + + // + Clean(reasons); + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + // Here we Have to Check Account Policies + // and Execute Signals base on them ... + + // + for (int i = 0; i < signalsCount; i++) + { + // + XSignal iSignal = signals[i]; + + // + ENUM_X_SIGNAL_EXECUTION_FAILED iReason = X_NOTHING; + + // + bool isExecuted = ExecuteSignal( + iSignal, + iReason, + checkPoliciese // + ); + if (isExecuted) + { + result++; + } + + // + Add( + iReason, + reasons); + } + + // + return result; + } + + // + // Get All Open Trades ... + int GetPositions( + XPosition &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_POSITION_TYPE type = NULL, // Trading Type ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL // Signal Provider ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + bool hasSymbol = !(symbol == NULL || StringLen(symbol) == 0); + bool hasProvider = !(provider == NULL || StringLen(provider) == 0); + + // + int positionsCount = mTrader.CountPositions(); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition positions[]; + mTrader.GetPositions( + positions, + symbol, + period); + positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return mResult; + } + + // + if (!hasProvider && type == NULL) + { + // + Copy( + positions, + result); + + // + return ArraySize(result); + } + + // + if (type == NULL) + { + // + ArrayResize( + result, + ArraySize(positions)); + + // + for (int i = 0; i < positionsCount; i++) + { + // + Add( + positions[i], + result); + } + + // + return ArraySize(result); + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + string iProvider = ExtractProvider(iPosition.comment); + if (hasProvider && iProvider != provider) + { + continue; + } + + // + if (type == NULL || iPosition.type == type) + { + // + Add( + iPosition, + result); + } + } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + // Extract Positions by it's Profits ... + void ExtractPositionsBasedOnProfits( + const XPosition &positions[], // Check as Data Source + XPosition &inDPositions[], // Hold In Drawdown Positions + XPosition &inPPositions[] // Hold In Profit Positions + ) + { + // + Clean(inDPositions); + Clean(inPPositions); + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit > 0) + { + // + Add( + iPosition, + inPPositions); + } + else if (iPosition.profit < 0) + { + // + Add( + iPosition, + inDPositions); + } + } + } + + // + // Get All In Profit Trades ... + int GetInProfitPositions( + XPosition &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_POSITION_TYPE type = NULL, // Trading Type ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL, // Signal Provider ... + ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + if (method == NULL) + { + method = X_POSITION_SELECT_ALL; + } + + // + // Prevent Going Forwars Since selection type is NONE ... + if (method == X_POSITION_SELECT_NONE) + { + return mResult; + } + + // + bool isMinSelectable = method == X_POSITION_SELECT_MIN; + bool isMaxSelectable = method == X_POSITION_SELECT_MAX; + + // + XPosition positions[]; + GetPositions( + positions, + symbol, + type, + period, + provider); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return mResult; + } + + // + // Define Temp Position for Selecting Max Position ... + XPosition maxPos; + maxPos.profit = INVALID_HANDLE; + + // + // Define Temp Position for Selecting Min Position ... + XPosition minPos; + minPos.profit = INVALID_HANDLE; + + // + // Loop through available Positions for Selecting Positions ... + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + // Check Profit State ... + if (iPosition.profit <= 0) + { + continue; + } + + // + // Check Selection State ... + if (isMinSelectable) + { + // + if (minPos.profit == INVALID_HANDLE || + minPos.profit > iPosition.profit) + { + minPos = iPosition; + } + + // + continue; + } + else if (isMaxSelectable) + { + // + if (maxPos.profit == INVALID_HANDLE || + maxPos.profit < iPosition.profit) + { + maxPos = iPosition; + } + + // + continue; + } + else + { + // + Add( + iPosition, + result); + } + } + + // + // Add Selected Position if Provided to Results ... + if (isMinSelectable) + { + // + Add( + minPos, + result); + } + else if (isMaxSelectable) + { + // + Add( + maxPos, + result); + } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + // Get All In Drawdown Trades ... + int GetInDrawdownPositions( + XPosition &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_POSITION_TYPE type = NULL, // Trading Type ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL, // Signal Provider ... + ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + if (method == NULL) + { + method = X_POSITION_SELECT_ALL; + } + + // + // Prevent Going Forwars Since selection type is NONE ... + if (method == X_POSITION_SELECT_NONE) + { + return mResult; + } + + // + bool isMinSelectable = method == X_POSITION_SELECT_MIN; + bool isMaxSelectable = method == X_POSITION_SELECT_MAX; + + // + XPosition positions[]; + GetPositions( + positions, + symbol, + type, + period, + provider); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return mResult; + } + + // + // Define Temp Position for Selecting Max Position ... + XPosition maxPos; + maxPos.profit = INVALID_HANDLE; + + // + // Define Temp Position for Selecting Min Position ... + XPosition minPos; + minPos.profit = INVALID_HANDLE; + + // + // Loop through available Positions for Selecting Positions ... + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + // Check Profit State ... + if (iPosition.profit >= 0) + { + continue; + } + + // + // Check Selection State ... + if (isMinSelectable) + { + // + if (minPos.profit == INVALID_HANDLE || + minPos.profit < iPosition.profit) + { + minPos = iPosition; + } + + // + continue; + } + else if (isMaxSelectable) + { + // + if (maxPos.profit == INVALID_HANDLE || + maxPos.profit > iPosition.profit) + { + maxPos = iPosition; + } + + // + continue; + } + else + { + // + Add( + iPosition, + result); + } + } + + // + // Add Selected Position if Provided to Results ... + if (isMinSelectable) + { + // + Add( + minPos, + result); + } + else if (isMaxSelectable) + { + // + Add( + maxPos, + result); + } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + // Retrieve Orders ... + int GetOrders( + XOrder &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_ORDER_TYPE type = NULL, // Trading Type ... + ENUM_ORDER_STATE state = NULL, // Trading State ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL // Signal Provider ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + XOrder orders[]; + mTrader.GetOrders( + orders, + symbol, + period, + state); + int ordersCount = ArraySize(orders); + if (ordersCount <= 0) + { + return mResult; + } + + // + if (type == NULL && + (provider == NULL || + StringLen(provider) == 0)) + { + // + Copy( + orders, + result); + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + if (type != NULL && iOrder.type != type) + { + continue; + } + + // + if (provider != NULL && + StringLen(provider) > 0) + { + // + // Generate Order Provider ... + string iProvider = ExtractProvider(iOrder.comment); + if (iProvider != provider) + { + continue; + } + } + + // + Add( + iOrder, + result); + } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + int GetHistoryOrders( + XOrder &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_ORDER_TYPE type = NULL, // Trading Type ... + ENUM_ORDER_STATE state = NULL, // Trading State ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL, // Signal Provider ... + datetime startDate = 0, // Start Date ... + datetime endDate = 0 // End Date ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + XOrder history[]; + int historyCount = mTrader + .GetHistoryOrders( + history, + symbol, + period, + type, + state, + startDate, + endDate); + if (historyCount <= 0) + { + return mResult; + } + + // + if (StringLen(provider) == 0 || provider == NULL) + { + // + Copy( + history, + result); + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + for (int i = 0; i < historyCount; i++) + { + // + XOrder iHistory = history[i]; + + // + if (provider != NULL && + StringLen(provider) > 0) + { + // + // Generate Order Provider ... + string iProvider = ExtractProvider(iHistory.comment); + if (iProvider != provider) + { + continue; + } + } + + // + Add( + iHistory, + result); + } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + int GetHistoryDeals( + XDeal &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_DEAL_TYPE type = NULL, // Specify Deal Type ... + ENUM_DEAL_REASON reason = NULL, // Specify Deal Reason ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL, // Signal Provider ... + datetime startDate = 0, // Start Date ... + datetime endDate = 0 // End Date ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + XDeal history[]; + int historyCount = mTrader + .GetHistoryDeals( + history, + symbol, + type, + reason, + startDate, + endDate); + if (historyCount <= 0) + { + return mResult; + } + + // + bool canCheckPeriod = period != NULL; + bool canCheckProvider = provider != NULL && + StringLen(provider) > 0; + + // + if (!canCheckPeriod && !canCheckProvider) + { + // + Copy( + history, + result); + + // + mResult = ArraySize(history); + + // + return mResult; + } + + // + for (int i = 0; i < historyCount; i++) + { + // + XDeal iDeal = history[i]; + + // + if (canCheckPeriod) + { + // + ENUM_TIMEFRAMES dealPeriod = mTrader.GetDealPeriod(iDeal); + if (dealPeriod != period) + { + continue; + } + } + + // + if (canCheckProvider) + { + // + string comment = mTrader.GetDealPositionComment(iDeal); + if (StringLen(comment) <= 0) + { + continue; + } + + // + string oProvider = ExtractPeriodString(comment); + if (oProvider != provider) + { + continue; + } + } + + // + Add( + iDeal, + result); + } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + // GUARD Handlers ... + + // + // Parse Recievd Guards and Do them ... + void DoGuards(XGuard &guards[]) + { + // + int guardsCount = ArraySize(guards); + if (guardsCount <= 0) + { + return; + } + + // + for (int i = 0; i < guardsCount; i++) + { + // + XGuard iGuard = guards[i]; + + // + switch (iGuard.action) + { + // + // Hedge In Profit Specified Positions ... + case X_GUARD_ACTION_HEDGE: + HandleGuardHedgeAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + + // + // Trail Stop Loss in Specified Positions ... + case X_GUARD_ACTION_TRAIL_STOP: + HandleGuardTrailingStopAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period, + iGuard.dblPayLoad); + break; + + // + // Force Close Specified Positions ... + case X_GUARD_ACTION_FORCE_CLOSE: + HandleGuardForceCloseAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + + // + // Generate and Place Support Signals ... + case X_GUARD_ACTION_ADD_SUPPORT_SIGNAL: + HandleGuardAddSupportPositionAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + + // + // Delete All Placed Pending Orders ... + case X_GUARD_ACTION_CANCEL_PENDING_ORDERS: + HandleGuardCancelPendingOrdersAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + } + } + } + + // + // Close All Specified Provider's Positions in Profit Summary ... + void HandleGuardHedgeAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + double minProfitForHedging = 1 // Specified Profit for Hedge + ) + { + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + type, + period, + provider); + if (positionsCount <= 1) + { + return; + } + + // + double profit = CalculatePositionsProfit(positions); + double requiredProfit = CalculateRequiredProfitForHedge(positions); + + // + bool isReadyForHedge = profit >= requiredProfit; + if (!isReadyForHedge) + { + return; + } + + // + string comment = "Guard Hedge " + provider; + int closed = mTrader.ClosePositions( + positions, + comment); + if (closed > 0) + { + // + string message = "Guard Hedge " + provider + "'s Positions on Profit: " + ToString(profit); + + // + LogMessage(message); + } + } + + // + // Close Max In Profit Trade Guard Action ... + void HandleGuardCloseInProfitAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method + ) + { + // + XPosition positions[]; + GetInProfitPositions( + positions, + symbol, + type, + period, + provider, + method); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + string comment = "Close InProfit ..."; + mTrader.ClosePositions( + positions, + comment); + + // + string message = "Guard Close (" + ToString(positionsCount) + ") Postion(s) In Profit ..."; + LogMessage(message); + } + + // + // Close Max In Drawdown Trade Guard Action ... + void HandleGuardCloseInDrawdownAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method + ) + { + // + XPosition positions[]; + GetInDrawdownPositions( + positions, + symbol, + type, + period, + provider, + method); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + string comment = "Close InDrawdown ..."; + mTrader.ClosePositions( + positions, + comment); + + // + string message = "Guard Close (" + ToString(positionsCount) + ") Position(s) In Drawdown ..."; + LogMessage(message); + } + + // + // Force Close Specified Set Of Position ... + void HandleGuardForceCloseAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + ulong ticket = 0 // Specific Ticket + ) + { + // + string comment = ""; + + // + // Close All Positions ... + if (ticket == 0) + { + // + XPosition positions[]; + GetPositions( + positions, + symbol, + type, + period, + provider); + if (ArraySize(positions) <= 0) + { + return; + } + + // + comment = provider + " Force Close Guard ..."; + + // + mTrader.ClosePositions( + positions, + comment); + } + // + // Close Specific Position ... + else + { + // + XPosition position; + bool hasPosition = mTrader.GetPosition( + position, + ticket); + + // + if (hasPosition) + { + // + comment = provider + "(" + ToString(ticket) + ")" + " Force Close Guard ..."; + + // + mTrader.Close( + ticket, + comment); + } + } + + // + if (StringLen(comment) > 0) + { + LogMessage(comment); + } + } + + // + // Trailing Specified Set Of Positions Stop Losses ... + void HandleGuardTrailingStopAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + double sl // Desired SL Value ... + ) + { + // + if (sl <= 0) + { + return; + } + + // + NormalizePrice( + sl, + symbol); + + // + XPosition positions[]; + GetPositions( + positions, + symbol, + type, + period, + provider); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + int modified = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + string comment = PrepareSLTrailComment(iPosition.comment); + + // + if (iPosition.sl == sl) + { + continue; + } + + // + bool isModified = mTrader.Modify( + iPosition.ticket, + sl, + iPosition.tp, + comment); + if (isModified) + { + modified++; + } + } + + // + if (modified > 0) + { + // + string msg = "(" + ToString(modified) + ") Position's Stop Trailed Successfully ..."; + + // + LogMessage(msg); + } + } + + // + // Add Support Signal for Specified Positions ... + void HandleGuardAddSupportPositionAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period // Specified Time Frame + ) + { + // + // TODO: Implement this ... + } + + // + // Cancel all Placed Orders ... + void HandleGuardCancelPendingOrdersAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period // Specified Time Frame + ) + { + // + // TODO: Implement this ... + } + + // + // END Provided Functions ... + // + + // + // Protected ... +protected: + // + string GetTagPrefix() + { + // + string result = "(" + mSymbol + ")(" + ToString(mPeriod) + ")"; + + // + return result; + } + + // + // Symbol ... + string mSymbol; + + // + // Period ... + ENUM_TIMEFRAMES mPeriod; + + // + // ExpertAdviser MAgic Number ... + ulong mMagic; + + // + // Slipppage ... + int mSlippage; + + // + // Tag Identifier ... + string mTag; + + // + bool mEnableLongs; + bool mEnableShorts; + + // + double mMaxAllowedSpread; + + // + int mMaxAllowedPositions; + double mMaxAllowedDrawDownFactor; + + // + double mMinProfitPerTrade; + double mMinProfitPerVolumeFactor; + + // + // Prepare a Signal and Do Calculations ... + void PrepareSignal( + XSignal &signal // a Signal for Preparation ... + ) + { + // + // Normalize Signal ... + NormalizeSignal(signal); + } + + // + // Check Acocunt Balance is Allow new Trades or not ... + bool CheckEquityForTrade() + { + // + bool result = false; + + // + if (mMaxAllowedDrawDownFactor <= 0) + { + // + result = true; + return result; + } + + // + double equity = mAccount.GetEquity(); + double balance = mAccount.GetBalance(); + + // + double selectedBalance = MathMax(equity, balance) - MathMin(equity, balance); + + // + double balanceForFactor = MathAbs(equity - balance); + if (balanceForFactor <= 0) + { + balanceForFactor = balance; + } + else + { + balanceForFactor = equity; + } + + // + double maxAllowedBalanceDrawDown = balanceForFactor * mMaxAllowedDrawDownFactor; + + // + result = equity > balance || + (equity <= balance && + selectedBalance <= maxAllowedBalanceDrawDown); + + // + return result; + } + + // + // Check Max Allowed Positions Policy for Trade ... + bool ChecPositionsForTrade() + { + // + bool result = false; + + // + if (mMaxAllowedPositions <= 0) + { + // + result = true; + return result; + } + + // + int positionsCount = mTrader.CountPositions(); + if (positionsCount <= 0) + { + // + result = true; + return result; + } + + // + result = positionsCount <= mMaxAllowedPositions; + + // + return result; + } + + // + // Check Spread is Ok for Executing Specific Signal ... + bool IsSpreadOkForSignalExecution(const XSignal &signal) + { + // + bool result = false; + + // + bool isSpreadCheckEnable = mMaxAllowedSpread > 0; + if (!isSpreadCheckEnable) + { + result = true; + } + else + { + // + // Retrieve Signal Spread ... + double spread = PriceToPoint( + signal.symbol, + GetSpread(signal.symbol)); + result = spread <= mMaxAllowedSpread; + } + + // + return result; + } + + // + // Calculate Required Profit for Hedging ... + double CalculateRequiredProfitForHedge( + XPosition &positions[] // Source + ) + { + // + double result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + bool isHedgingEnable = mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0; + if (!isHedgingEnable) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0) + { + // + result += + ((iPosition.volume / mMinProfitPerVolumeFactor) * + mMinProfitPerTrade) + + (-1 * iPosition.swap); + } + } + + // + return result; + } + + // + // Calculate Positions Profit Summary ... + double CalculatePositionsProfit( + XPosition &positions[] // Source + ) + { + // + double result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + result += iPosition.profit; + } + + // + return result; + } + + // + // Close a Position Pack and Cancel All of it's Supports ... + bool HandleClosePack(XPositionPack &pack) + { + // + bool result = false; + + // + if (pack.ticket <= 0) + { + return result; + } + + // + XOrder orders[]; + XPosition positions[]; + + // + bool hasPos = pack.position.ticket > 0; + if (hasPos) + { + Add( + pack.position, + positions); + } + + // + bool hasSupportPos = pack.supportPositionsCount > 0; + if (hasSupportPos) + { + // + Copy( + pack.supportPositions, + positions, + false); + } + + // + bool hasSupportOrd = pack.supportOrdersCount > 0; + if (hasSupportOrd) + { + // + Copy( + pack.supportOrders, + orders); + } + + // + string comment = "Close Pack"; + + // + int closed = mTrader.ClosePositions(positions, comment); + int canceled = mTrader.CancelOrders(orders); + + // + result = closed + canceled == ArraySize(orders) + ArraySize(positions); + if (result) + { + // + string message = "Close Position(" + ToString(pack.ticket) + ")'s Pack ..."; + + // + LogMessage(message); + } + + // + return result; + } + + // + // Private ... +private: + // + // Define Requirements ... + + // + // XSCTrade Event Handlers ... + TOnStopLoss mOnStopLossTriggered; + TOnTakeProfit mOnTakeProfitTriggered; + TOnDealsChanged mOnDealsChangedHandler; + TOnOrdersChanged mOnOrdersChangedHandler; + TOnPositionsChanged mOnPositionsChangedHandler; + TOnTradeStateChanged mOnTradeStateChangedHandler; + + // + // Initi Requirements ... + void InitRequirements() + { + // + // Account Manager ... + mAccount = new XSCAccount(); + + // + // Trader ... + mTrader = new XSCTrade( + mSlippage, + mMagic); + + // + // Attach Event Handlers ... + + // + if (mOnStopLossTriggered != NULL) + { + mTrader.AddOnStopLossEventHandler(mOnStopLossTriggered); + } + + // + if (mOnTakeProfitTriggered != NULL) + { + mTrader.AddOnTakeProfitEventHandler(mOnTakeProfitTriggered); + } + + // + if (mOnDealsChangedHandler != NULL) + { + mTrader.AddOnDealsChangedEventHandler(mOnDealsChangedHandler); + } + + // + if (mOnOrdersChangedHandler != NULL) + { + mTrader.AddOnOrdersChangedEventHandler(mOnOrdersChangedHandler); + } + + // + if (mOnPositionsChangedHandler != NULL) + { + mTrader.AddOnPositionsChangedEventHandler(mOnPositionsChangedHandler); + } + + // + if (mOnTradeStateChangedHandler != NULL) + { + mTrader.AddOnTradeStateChangedEventHandler(mOnTradeStateChangedHandler); + } + } +}; + +// +// START Usefull Functions ... +// + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xhelper.class.ex5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xhelper.class.ex5 new file mode 100644 index 0000000..99adfcc Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xhelper.class.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xhelper.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xhelper.class.mq5 new file mode 100644 index 0000000..ea582f5 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xhelper.class.mq5 @@ -0,0 +1,123 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCBaseHelper +// Description: provides all Base 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 + +// +// Includes ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Definitions ... + +// +// a Class for Handle base requirements ... +// for indicators ... +class XSCBaseHelper +{ + // + // Public ... +public: + // + // Constructor ... + void XSCBaseHelper( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period // Trading Time Frame + ) + { + // + mSymbol = symbol; + mPeriod = period; + } + + // + // Deconstructor ... + void ~XSCBaseHelper() + { + // + IndicatorRelease(mHandler); + } + + // + // Setter(s) / Getter(s) ... + + // + // Symbol ... + string GetSymbol() + { + return mSymbol; + } + + // + // Period ... + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + // + // Retrieve Bars ... + int CountBars() + { + // + int result = + Bars( + mSymbol, + mPeriod); + + // + return result; + } + + // + int CountCalculatedBars() + { + return BarsCalculated(mHandler); + } + + // + // Functions ... + + // + // Protected ... +protected: + // + // Props ... + + // + // Symbol ... + string mSymbol; + + // + // Period ... + ENUM_TIMEFRAMES mPeriod; + + // + // Indicator Handler ... + int mHandler; + + // + // Private ... +private: + // +}; + +// +// Tools .... \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xmd5.class.ex5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xmd5.class.ex5 new file mode 100644 index 0000000..7903eb1 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xmd5.class.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xmd5.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xmd5.class.mq5 new file mode 100644 index 0000000..3311aa5 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xmd5.class.mq5 @@ -0,0 +1,441 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCMD5 +// Description: Provides MD5 Hashing 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 + +// +// START Definitions ... +// + +// +static uchar _md5_PADDING[64] = + { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +// +#define _md5_F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define _md5_G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define _md5_H(x, y, z) ((x) ^ (y) ^ (z)) +#define _md5_I(x, y, z) ((y) ^ ((x) | (~z))) +#define _md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +// +#define _md5_FF(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_F((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_GG(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_G((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_HH(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_H((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_II(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_I((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_INIT_STATE_0 0x67452301 +#define _md5_INIT_STATE_1 0xefcdab89 +#define _md5_INIT_STATE_2 0x98badcfe +#define _md5_INIT_STATE_3 0x10325476 + +// +#define _md5_S11 7 +#define _md5_S12 12 +#define _md5_S13 17 +#define _md5_S14 22 + +// +#define _md5_S21 5 +#define _md5_S22 9 +#define _md5_S23 14 +#define _md5_S24 20 + +// +#define _md5_S31 4 +#define _md5_S32 11 +#define _md5_S33 16 +#define _md5_S34 23 + +// +#define _md5_S41 6 +#define _md5_S42 10 +#define _md5_S43 15 +#define _md5_S44 21 + +// +// END Definitions ... +// + +// +// XCMD5 a library for Hashing ... +class XSCMD5 +{ + // + // Public Provides ... +public: + // + // Protected Provides ... + + // + // Constructor ... + XSCMD5(void) {} + + // + // Deconstructor ... + ~XSCMD5(void) {} + + // + // Hash Specified Char Array ... + string Hash( + uchar &mSource[], // Specify Char Array to Hash + int mLength = 0 // Specify Length of Char Array which required to hash + ) + { + // + string result = ""; + + // + int sourceCount = ArraySize(mSource); + + // + // Validate Args ... + if ( + sourceCount <= 0 || + (sourceCount > 0 && mLength > sourceCount)) + { + return result; + } + + // + // Normalize Args ... + if (mLength == 0) + { + mLength = sourceCount; + } + + // + // Init MD5 ... + MD5Init(); + + // + // Update Buffer ... + MD5Update(mSource, mLength); + + // + // Calculate Result ... + result = MD5Final(); + + // + return result; + } + + // + // Hash Specified String ... + string Hash( + string mSource // Specified String + ) + { + // + string result = ""; + + // + // Converts String to Char Array ... + uchar bytes[]; + StringToCharArray( + mSource, + bytes, + 0, + StringLen(mSource)); + + // + result = Hash( + bytes, + ArraySize(bytes)); + + // + return result; + } + +protected: + // + // Private Provides ... +private: + // + uint m_lMD5[4]; + uint m_nCount[2]; + uchar m_lpszBuffer[64]; + + // + // Convert Byte to DWord ... + void ByteToDWord(int &out[], uint &in[], uint len) + { + // + uint i = 0; + uint j = 0; + + // + for (; j < len; i++, j += 4) + { + out[i] = (int)in[j] | (int)in[j + 1] << 8 | (int)in[j + 2] << 16 | (int)in[j + 3] << 24; + } + } + + // + // Convert DWord to Byte ... + void DWordToByte(uchar &out[], int &in[], uint len) + { + // + uint i = 0; + uint j = 0; + + // + for (; j < len; i++, j += 4) + { + // + out[j] = (uchar)(in[i] & 0xff); + out[j + 1] = (uchar)((in[i] >> 8) & 0xff); + out[j + 2] = (uchar)((in[i] >> 16) & 0xff); + out[j + 3] = (uchar)((in[i] >> 24) & 0xff); + } + } + + // + // Init MD5 Array ... + void MD5Init() + { + // + ArrayInitialize(m_lpszBuffer, 64); + + // + m_nCount[0] = m_nCount[1] = 0; + m_lMD5[0] = _md5_INIT_STATE_0; + m_lMD5[1] = _md5_INIT_STATE_1; + m_lMD5[2] = _md5_INIT_STATE_2; + m_lMD5[3] = _md5_INIT_STATE_3; + } + + // + // Update MD5 ... + void MD5Update(uchar &inBuf[], uint inLen) + { + // + int i, ii; + int mdi; + + // + uint in[16]; + int i0 = 0; + + // + mdi = (int)((m_nCount[0] >> 3) & 0x3F); + + // + if ((m_nCount[0] + ((uint)inLen << 3)) < m_nCount[0]) + { + m_nCount[1]++; + } + + // + m_nCount[0] += ((uint)inLen << 3); + m_nCount[1] += ((uint)inLen >> 29); + + // + while ((inLen--) > 0) + { + // + m_lpszBuffer[mdi++] = inBuf[i0++]; + if (mdi == 0x40) + { + // + for (i = 0, ii = 0; i < 16; i++, ii += 4) + { + in[i] = (((uint)m_lpszBuffer[ii + 3]) << 24) | (((uint)m_lpszBuffer[ii + 2]) << 16) | (((uint)m_lpszBuffer[ii + 1]) << 8) | ((uint)m_lpszBuffer[ii]); + } + + // + Transform(m_lMD5, in); + + // + mdi = 0; + } + } + } + + // + // Finalize an MD5 Expression ... + string MD5Final() + { + // + uchar bits[8]; + int nIndex; + uint nPadLen; + const int nMD5Size = 16; + uchar lpszMD5[16]; + string temp; + string out = ""; + int i; + + // + DWordToByte(bits, m_nCount, 8); + nIndex = (int)((m_nCount[0] >> 3) & 0x3f); + nPadLen = (nIndex < 56) ? (56 - nIndex) : (120 - nIndex); + MD5Update(_md5_PADDING, nPadLen); + MD5Update(bits, 8); + DWordToByte(lpszMD5, m_lMD5, nMD5Size); + + // + for (i = 0; i < nMD5Size; i++) + { + // + if (lpszMD5[i] == 0) + { + temp = "00"; + } + else if (lpszMD5[i] <= 15) + { + temp = StringFormat("0%x", lpszMD5[i]); + } + else + { + temp = StringFormat("%x", lpszMD5[i]); + } + + // + out += temp; + } + + // + lpszMD5[0] = '\0'; + + // + return (out); + } + + // + // Transform Buffers ... + void Transform(uint &buf[], uint &in[]) + { + // + uint a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + // + _md5_FF(a, b, c, d, in[0], _md5_S11, 0xD76AA478); + _md5_FF(d, a, b, c, in[1], _md5_S12, 0xE8C7B756); + _md5_FF(c, d, a, b, in[2], _md5_S13, 0x242070DB); + _md5_FF(b, c, d, a, in[3], _md5_S14, 0xC1BDCEEE); + _md5_FF(a, b, c, d, in[4], _md5_S11, 0xF57C0FAF); + _md5_FF(d, a, b, c, in[5], _md5_S12, 0x4787C62A); + _md5_FF(c, d, a, b, in[6], _md5_S13, 0xA8304613); + _md5_FF(b, c, d, a, in[7], _md5_S14, 0xFD469501); + _md5_FF(a, b, c, d, in[8], _md5_S11, 0x698098D8); + _md5_FF(d, a, b, c, in[9], _md5_S12, 0x8B44F7AF); + _md5_FF(c, d, a, b, in[10], _md5_S13, 0xFFFF5BB1); + _md5_FF(b, c, d, a, in[11], _md5_S14, 0x895CD7BE); + _md5_FF(a, b, c, d, in[12], _md5_S11, 0x6B901122); + _md5_FF(d, a, b, c, in[13], _md5_S12, 0xFD987193); + _md5_FF(c, d, a, b, in[14], _md5_S13, 0xA679438E); + _md5_FF(b, c, d, a, in[15], _md5_S14, 0x49B40821); + + // + _md5_GG(a, b, c, d, in[1], _md5_S21, 0xF61E2562); + _md5_GG(d, a, b, c, in[6], _md5_S22, 0xC040B340); + _md5_GG(c, d, a, b, in[11], _md5_S23, 0x265E5A51); + _md5_GG(b, c, d, a, in[0], _md5_S24, 0xE9B6C7AA); + _md5_GG(a, b, c, d, in[5], _md5_S21, 0xD62F105D); + _md5_GG(d, a, b, c, in[10], _md5_S22, 0x02441453); + _md5_GG(c, d, a, b, in[15], _md5_S23, 0xD8A1E681); + _md5_GG(b, c, d, a, in[4], _md5_S24, 0xE7D3FBC8); + _md5_GG(a, b, c, d, in[9], _md5_S21, 0x21E1CDE6); + _md5_GG(d, a, b, c, in[14], _md5_S22, 0xC33707D6); + _md5_GG(c, d, a, b, in[3], _md5_S23, 0xF4D50D87); + _md5_GG(b, c, d, a, in[8], _md5_S24, 0x455A14ED); + _md5_GG(a, b, c, d, in[13], _md5_S21, 0xA9E3E905); + _md5_GG(d, a, b, c, in[2], _md5_S22, 0xFCEFA3F8); + _md5_GG(c, d, a, b, in[7], _md5_S23, 0x676F02D9); + _md5_GG(b, c, d, a, in[12], _md5_S24, 0x8D2A4C8A); + + // + _md5_HH(a, b, c, d, in[5], _md5_S31, 0xFFFA3942); + _md5_HH(d, a, b, c, in[8], _md5_S32, 0x8771F681); + _md5_HH(c, d, a, b, in[11], _md5_S33, 0x6D9D6122); + _md5_HH(b, c, d, a, in[14], _md5_S34, 0xFDE5380C); + _md5_HH(a, b, c, d, in[1], _md5_S31, 0xA4BEEA44); + _md5_HH(d, a, b, c, in[4], _md5_S32, 0x4BDECFA9); + _md5_HH(c, d, a, b, in[7], _md5_S33, 0xF6BB4B60); + _md5_HH(b, c, d, a, in[10], _md5_S34, 0xBEBFBC70); + _md5_HH(a, b, c, d, in[13], _md5_S31, 0x289B7EC6); + _md5_HH(d, a, b, c, in[0], _md5_S32, 0xEAA127FA); + _md5_HH(c, d, a, b, in[3], _md5_S33, 0xD4EF3085); + _md5_HH(b, c, d, a, in[6], _md5_S34, 0x04881D05); + _md5_HH(a, b, c, d, in[9], _md5_S31, 0xD9D4D039); + _md5_HH(d, a, b, c, in[12], _md5_S32, 0xE6DB99E5); + _md5_HH(c, d, a, b, in[15], _md5_S33, 0x1FA27CF8); + _md5_HH(b, c, d, a, in[2], _md5_S34, 0xC4AC5665); + + // + _md5_II(a, b, c, d, in[0], _md5_S41, 0xF4292244); + _md5_II(d, a, b, c, in[7], _md5_S42, 0x432AFF97); + _md5_II(c, d, a, b, in[14], _md5_S43, 0xAB9423A7); + _md5_II(b, c, d, a, in[5], _md5_S44, 0xFC93A039); + _md5_II(a, b, c, d, in[12], _md5_S41, 0x655B59C3); + _md5_II(d, a, b, c, in[3], _md5_S42, 0x8F0CCC92); + _md5_II(c, d, a, b, in[10], _md5_S43, 0xFFEFF47D); + _md5_II(b, c, d, a, in[1], _md5_S44, 0x85845DD1); + _md5_II(a, b, c, d, in[8], _md5_S41, 0x6FA87E4F); + _md5_II(d, a, b, c, in[15], _md5_S42, 0xFE2CE6E0); + _md5_II(c, d, a, b, in[6], _md5_S43, 0xA3014314); + _md5_II(b, c, d, a, in[13], _md5_S44, 0x4E0811A1); + _md5_II(a, b, c, d, in[4], _md5_S41, 0xF7537E82); + _md5_II(d, a, b, c, in[11], _md5_S42, 0xBD3AF235); + _md5_II(c, d, a, b, in[2], _md5_S43, 0x2AD7D2BB); + _md5_II(b, c, d, a, in[9], _md5_S44, 0xEB86D391); + + // + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; + } +}; diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xprovider.class.ex5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xprovider.class.ex5 new file mode 100644 index 0000000..dedfe7e Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xprovider.class.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xprovider.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xprovider.class.mq5 new file mode 100644 index 0000000..75c1a76 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xprovider.class.mq5 @@ -0,0 +1,319 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCEABaseProvider +// Description: provides base requirements for +// Specific Sgnal Provider ... +// +// +// 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 + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.draw.lib.mq5" +#include "../Libraries/x-saherelm.models.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Definitions ... +// + +// +// Notified a Signal was Appears ... +typedef void (*OnSignal)( + XSignal &signal); + +// +// Notified a Guard Appears ... +typedef void (*OnGuard)(XGuard &guard); + +// +// END Definitions ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Base Class for All of our EA's ... +class XSCEABaseProvider +{ + // + // Public ... +public: + // + // Constructor ... + void XSCEABaseProvider() + { + mSymbol = _Symbol; + mPeriod = _Period; + } + void XSCEABaseProvider( + string symbol, + ENUM_TIMEFRAMES period, + bool ignoreTicksAfterSignalTillNewCandle = true) + { + // + mSymbol = symbol; + mPeriod = period; + + // + mTag = mSymbol + "," + ToString(mPeriod); + + // + mIsInTestMode = IsRunningOnTestMode(); + + // + mIgnoreTicksAfterSignalTillNewCandle = ignoreTicksAfterSignalTillNewCandle; + } + + // + // Deconstructor ... + void ~XSCEABaseProvider() + { + } + + // + bool CanIgnoreTick() + { + // + mIsNewCandle = IsNewCandle( + mSymbol, + mPeriod); + bool result = mIsInTestMode + ? !mIsNewCandle + : !mIsNewCandle && mWaitUntilNewCandle; + + // + if (result) + { + // + result = mIgnoreTicksAfterSignalTillNewCandle; + } + + // + return result; + } + + // + // Prepare State ... + void OnTick() + { + // + mIsNewCandle = IsNewCandle( + mSymbol, + mPeriod); + mCanIgnoreTick = mIsInTestMode + ? !mIsNewCandle + : !mIsNewCandle && mWaitUntilNewCandle; + + // + ProcessBuffers(); + + // + if (mCanIgnoreTick) + { + return; + } + + // + mWaitUntilNewCandle = false; + + // + ProcessTick(); + } + + // + virtual void PrepareTag(); + + // + // Initialize Indicators and Requirements ... + virtual bool Init(); + + // + virtual int GetMaxLength(); + + // + virtual int GetCalculatedBars(); + + // + // Handle Update Buffers ... + virtual void ProcessBuffers() + { + return; + } + + // + // Handle On Tick Event ... + virtual void ProcessTick() + { + return; + } + + // + // Check for Guards ... + virtual bool GuardCheck(XGuard &guards[]); + + // + // Add Specific On Signal Event Handler ... + int AddOnSignalEventHandler(OnSignal handler) + { + // + ArrayResize( + mSignalEventHandlers, + ArraySize(mSignalEventHandlers) + 1); + + // + int result = ArraySize(mSignalEventHandlers) - 1; + mSignalEventHandlers[result] = handler; + + // + return result; + } + + // + // Remove All On Signal Event Handler ... + void ReoveOnSignalEventHandlers() + { + // + ArrayFree(mSignalEventHandlers); + } + + // + // Notify a Signal Found on all Event Listeners ... + void NotifyOnSignalEvent(XSignal &info) + { + // + int listenerCount = ArraySize(mSignalEventHandlers); + if (listenerCount <= 0) + { + return; + } + + // + // Loop Through Listeners ... + for (int i = 0; i < listenerCount; i++) + { + // + OnSignal listener = mSignalEventHandlers[i]; + + // + listener(info); + } + } + + // + // Protected ... +protected: + // + string mSymbol; + + // + ENUM_TIMEFRAMES mPeriod; + + // + string mTag; + + // + bool mIsNewCandle; + bool mIsInTestMode; + bool mCanIgnoreTick; + bool mWaitUntilNewCandle; + + // + // Private ... +private: + // + // Signal Event Handlers ... + OnSignal mSignalEventHandlers[]; + + // + bool mIgnoreTicksAfterSignalTillNewCandle; +}; + +// +// START Definitions ... +// + +// +// Model Signal Providers Definitions ... +struct XBaseSignalProvider +{ + // + // Provider use Which Symbol ... + string symbol; + + // + // Provider use Which Time Frame ... + ENUM_TIMEFRAMES period; + + // + // Risk Amount Per Trades Related to Time Frames ... + // Percent of Available Balance ... + double riskAmount; + + // + // Desired Magic Number ... + ulong magicNumber; +}; + +// +struct XLastSignal +{ + datetime at; + string provider; +}; + +// +// END Definitions ... +// + +// +// START Usefull Functions ... +// + +// +// Add Specific Provider to List ... +void Add( + XBaseSignalProvider &item, // item want to add + XBaseSignalProvider &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xtrade.class.ex5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xtrade.class.ex5 new file mode 100644 index 0000000..5955e67 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xtrade.class.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xtrade.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xtrade.class.mq5 new file mode 100644 index 0000000..d6e38f2 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Classes/x-saherelm.xtrade.class.mq5 @@ -0,0 +1,3175 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCTrade +// Description: provides all Trade 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 "../Libraries/x-saherelm.xtrade.lib.mq5" + +// +// Definitions ... + +// +// Overrides ... + +// +// XCTrade Base Class ... +class XSCTradeBase : public CTrade +{ +public: + // + // Modify Specific Position, by Specific Comment ... + bool PositionModify( + const string symbol, // Symbol + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!SelectPosition(symbol)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.symbol = symbol; + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + bool PositionModify( + const ulong ticket, // Position Ticket + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.position = ticket; + m_request.symbol = PositionGetString(POSITION_SYMBOL); + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + + // + // Close Specific Position, by Specific Comment ... + bool PositionClose( + const string symbol, // Symbol + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + bool partial_close = false; + int retry_count = 10; + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + do + { + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specify Comment ... + m_request.comment = comment; + + // + // check volume + double max_volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); + if (m_request.volume > max_volume) + { + // + m_request.volume = max_volume; + partial_close = true; + } + else + { + partial_close = false; + } + + // + // hedging? just send order + if (IsHedging()) + { + return (OrderSend(m_request, m_result)); + } + + // + // order send + if (!OrderSend(m_request, m_result)) + { + // + if (--retry_count != 0) + { + continue; + } + + // + if (retcode == TRADE_RETCODE_DONE_PARTIAL) + { + m_result.retcode = retcode; + } + + // + return (false); + } + + // + //--- WARNING. If position volume exceeds the maximum volume allowed for deal, + //--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely, + //--- but partially. It is decreased by the maximum volume allowed for deal. + if (m_async_mode) + { + break; + } + + // + retcode = TRADE_RETCODE_DONE_PARTIAL; + if (partial_close) + { + Sleep(1000); + } + } while (partial_close); + + // + // succeed + return (true); + } + bool PositionClose( + const ulong ticket, // Position Ticket + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specify Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } + + // + // Partial Close Specific Position, by Specific Comment ... + bool PositionClosePartial( + const string symbol, // Symbol + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // hedging? just send order + return (OrderSend(m_request, m_result)); + } + bool PositionClosePartial( + const ulong ticket, // Position Ticket + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } +}; + +// +// Implementation ... + +// a Class For Manage Trades and Handle Trading Actions ... +class XSCTrade +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + void XSCTrade( + int slippage, // Specify Slippage + ulong magicNumber // Specify Magic Number + ) + { + // + // Setting Props ... + mSlippage = slippage; + mMagicNumber = magicNumber; + + // + // Instance Base Trader Class ... + mTrader = new XSCTradeBase(); + + // + // Configuring Base Trader Class ... + mTrader.SetAsyncMode(false); + mTrader.SetDeviationInPoints(mSlippage); + mTrader.SetExpertMagicNumber(mMagicNumber); + + // + // Setting Log Level ... + mTrader.LogLevel(LOG_LEVEL_ERRORS); + + // + // OnTrade Context ... + + // + mDaysForRead = 1; + mScanStarted = false; + + // + // Reset On Trade Counter ... + ResetOnTradeContext(); + + // + // Init On Trade Context ... + InitOnTradeContext(); + } + + // + // Deconstructor ... + ~XSCTrade() + { + // + // Remove Pointer ... + delete mTrader; + } + + // + // Props ... + + // + // Retrieve Slippage ... + int GetSlippage() + { + return mSlippage; + } + + // + // Retrieve Magic Number ... + ulong GetMagicNumber() + { + return mMagicNumber; + } + + // + // Add Event Listeners ... + + // + // Add New Deals Changed Event Handler ... + void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) + { + // + Add( + handler, + mTradeStateChangedEventHandlers + // + ); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnDealsChangedEventHandler(TOnDealsChanged handler) + { + // + Add( + handler, + mDealsChangedEventHandlers + // + ); + } + + // + // Add New Orders Changed Event Handler ... + void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) + { + // + Add( + handler, + mOrdersChangedEventHandlers + // + ); + } + + // + // Add New Positions Changed Event Handler ... + void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) + { + // + Add( + handler, + mPositionsChangedEventHandlers + // + ); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + Add( + handler, + mStopLossEventHandlers + // + ); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + Add( + handler, + mTakeProfitEventHandlers + // + ); + } + + // + // Functions ... + + // + // Handlers ... + + // + // Process On Trade Requirement ... + // this Only Used when we Have to Proccess OnTrade Event in EA(s) ... + void HandleOnTradeEvent( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + result.Clean(); + + // + if (mScanStarted) + { + // + ProcessOnTradeContext(result); + } + else + { + // + // Init Trade Context ... + InitOnTradeContext(); + + // + return; + } + + // + // Here we Can Check the Start ... + bool isValid = + // + result.IsValid() && + // + !result.hasNewDeal && + !result.hasNewOrder && + !result.hasNewPosition && + !result.hasNewHistoryOrder + // + ; + if (!isValid) + { + return; + } + + // + // State ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(result); + + // + // Deals ... + if (result.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(result.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + int dealsCount = GetDeals(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // Orders ... + if (result.hasNewOrder || result.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(result.newOrders + result.newHistoryOrders); + } + + // + // Positions ... + if (result.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(result.newPositions); + } + } + + // + // This Must be Called Every time OnTrade Event Happening ... + // this Used for Implementing Custom Senarios ... + XOnTradeHandlerState HandleOnTrade() + { + // + // Handle OnTrade Event ... + XOnTradeHandlerState state; + HandleOnTradeEvent(state); + if ( + !state.hasNewDeal && + !state.hasNewOrder && + !state.hasNewPosition && + !state.hasNewHistoryOrder) + { + return state; + } + + // + // State ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(state); + + // + // DEALS ... + if (state.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(state.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + GetDeals(deals); + int dealsCount = ArraySize(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // ORDERS ... + if (state.hasNewOrder || state.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(state.newOrders + state.newHistoryOrders); + } + + // + // POSITIONS ... + if (state.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(state.newPositions); + } + + // + return state; + } + + // + // Trade Actions ... + + // + // Main ... + + // + // Manage ... + // this must be Call on OnTick for Manage + // Positions ... + void Manage() + { + // + // All required Position Managements Actions implemented here ... + + // + // - [] Partial Close; + // - [] Risk Free; + // - [] Trail Stop; + // - [] SLS; + // - [] TPS; + + // + // - [] Data Collector; + // - [] Profit Management; + } + + // + // Execute a Signal ... + bool ExecuteSignal( + XSignal &signal, // Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL // order expiration time + ) + { + // + bool result = false; + state = X_SIGNAL_EXECUTION_UNKNOWN; + + // + double currentEntry = GetEntry( + signal.symbol, + signal.type + // + ); + bool isLong = IsLong(signal.type); + + // + // Select SL and TP ... + double selectedSL = 0; + double selectedTP = 0; + + // + if (!signal.IsValid()) + { + // + state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; + return result; + } + + // + // Handle Market Execution ... + if (signal.mode == X_ORDER_MODE_MARKET) + { + // + if (isLong) + { + // + result = Buy( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + signal.comment + // + ); + } + else + { + // + result = Sell( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + signal.comment + // + ); + } + } + // + // Handle Stop Execution ... + else if (signal.mode == X_ORDER_MODE_STOP) + { + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? signal.entry > currentEntry + : signal.entry < currentEntry; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; + return result; + } + + // + // Execute Order ... + if (isLong) + { + // + result = BuyStop( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + lifetime, + expiration, + signal.comment + // + ); + } + else + { + // + result = SellStop( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + lifetime, + expiration, + signal.comment + // + ); + } + } + // + // Handle Limit Execution ... + else if (signal.mode == X_ORDER_MODE_LIMIT) + { + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? signal.entry < currentEntry + : signal.entry > currentEntry; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; + return result; + } + + // + // Execute Order ... + if (isLong) + { + // + result = BuyLimit( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + lifetime, + expiration, + signal.comment + // + ); + } + else + { + // + result = SellLimit( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + lifetime, + expiration, + signal.comment + // + ); + } + } + + // + // Handle Ticket ... + if (result) + { + // + state = X_SIGNAL_EXECUTION_SUCCEED; + + // + ulong ticket; + if (signal.mode == X_ORDER_MODE_MARKET) + { + ticket = GetLastOpenPositionTicket(); + } + else + { + ticket = GetLastPlacedOrderTicket(); + } + + // + signal.positionId = ticket; + + // + // Handle Executing Support Signals ... + int supportsCount = ArraySize(signal.supports); + if (supportsCount > 0) + { + // + int executed = 0; + for (int i = 0; i < supportsCount; i++) + { + // + XSignal iSupport = signal.supports[i]; + + // + int supIndex = i + 1; + string iComment = GenerateSupportTag(ticket); + + // + bool isExecuted = ExecuteSignal( + iSupport, + state, + lifetime, + expiration + // + ); + if (isExecuted) + { + executed++; + } + } + + // + result = executed == supportsCount; + } + } + + // + return result; + } + + // + // Execute a Collection Of Signals ... + int ExecuteSignals( + XSignal &signals[], // Collection of Signal for Execution + ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL // order expiration time + ) + { + // + int result = 0; + + // + Clean(states); + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + ArrayResize(states, signalsCount); + ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN); + for (int i = 0; i < signalsCount; i++) + { + // + bool isExecuted = ExecuteSignal( + signals[i], + states[i], + lifetime, + expiration + // + ); + + // + if (isExecuted) + { + result++; + } + } + + // + return result; + } + + // + // Regular Trade Actions ... + + // + // Buy ... + + // + // Force Open a Buy/Long Position ... + bool Buy( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.Buy( + volume, + symbol, + price, + sl, + tp, + comment + // + ); + + // + return result; + } + + // + // Send BUY LIMIT order ... + bool BuyLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.BuyLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Send BUY STOP order ... + bool BuyStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.BuyStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Sell ... + + // + // Force Open a Sell/Short Position ... + bool Sell( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.Sell( + volume, + symbol, + price, + sl, + tp, + comment + // + ); + + // + return result; + } + + // + // Send SELL LIMIT order ... + bool SellLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.SellLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Send SELL STOP order ... + bool SellStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.SellStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Check a Position is Exists Open or not ... + bool IsOpen( + ulong ticket // Specified Position Ticket + ) + { + // + bool result = false; + + // + result = mPositionInfo + .SelectByTicket(ticket); + + // + return result; + } + + // + // Modify Position ... + bool Modify( + const ulong ticket, // position ticket + double sl = 0, // stop loss price + double tp = 0, // take profit + string comment = NULL // comment + ) + { + // + bool result = false; + + // + // Validate Args ... + result = + IsOpen(ticket) && + (tp >= 0 || sl >= 0); + if (!result) + { + return result; + } + + // + // Use Position Comment when there isn't new One ... + if (!IsValid(comment) == 0) + { + // + // if there isn't provided Comment + // Use Position Comment for default ... + comment = "Modify " + GetPositionComment(ticket); + } + + // + result = mTrader.PositionModify( + ticket, + sl, + tp, + comment + // + ); + + // + return result; + } + + // + // Close Position By Ticket ... + bool Close( + ulong ticket, // Position Ticket + string comment = NULL // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + // Check Position Open ... + result = !IsOpen(ticket); + if (!result) + { + return result; + } + + // + // Use Default Position Comment if it's Not Provided ... + if (!IsValid(comment)) + { + comment = "Close " + GetPositionComment(ticket); + } + + // + // Close Position By Specific Comment ... + result = mTrader.PositionClose( + ticket, + mSlippage, + comment + // + ); + + // + return result; + } + + // + // Close Specified Positions ... + int Close( + string comment = NULL, // Close Position By Specific Comment + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true // Get Only Self Open Positions + ) + { + // + int result = 0; + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isClosed = Close( + iPosition.ticket, + comment + // + ); + if (isClosed) + { + result++; + } + } + + // + return result; + } + + // + // Close a Collection of Positions ... + int Close( + XPosition &positions[], // Collection of Positions + string comment // Close Comment + ) + { + // + int result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isClosed = Close( + iPosition.ticket, + comment + // + ); + if (isClosed) + { + result++; + } + } + + // + return result; + } + + // + // Close Partial By Ticket ... + bool ClosePartial( + ulong ticket, // Position Ticket + double volume, // Volume Size for Partial Closing + string comment = NULL // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + result = IsOpen(ticket); + if (!result) + { + return result; + } + + // + // Use Default Partial Close Comment ... + if (!IsValid(comment)) + { + // + comment += "PClose " + GetPositionComment(ticket); + } + + // + result = mTrader.PositionClosePartial( + ticket, + volume, + mSlippage, + comment + // + ); + + // + return result; + } + + // + // Cancel Specific Order ... + bool CancelOrder(ulong ticket) + { + return mTrader + .OrderDelete(ticket); + } + + // + // Cancel Specific Orders ... + int CancelOrders( + XOrder &orders[] // Specified Orders ... + ) + { + // + int result = 0; + + // + int ordersCount = ArraySize(orders); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + bool isDeleted = mTrader + .OrderDelete(iOrder.ticket); + if (isDeleted && !result) + { + result++; + } + } + + // + return result; + } + + // + // Extractors ... + + // + // Positions ... + + // + // Calculate Positions Profit ... + double Profit( + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true // Get Only Self Open Positions + ) + { + // + double result = 0; + + // + // Retrieve Positions ... + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic + // + ); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + result += positions[i].profit; + } + + // + return result; + } + + // + // Retrieve Specific Position by Index ... + bool GetPosition( + int index, // Specified Index + XPosition &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + // Retrieve Specific Position by Ticket ... + bool GetPosition( + ulong ticket, // Specified Ticket + XPosition &result // Hold's Result + ) + { + // + return result + .ByTicket(ticket); + } + + // + // Retrieve Positions ... + int GetPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = PositionsTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XPosition iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Select In Profit Positions ... + int GetInProfitPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) + ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic, + forceClean); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition min; + XPosition max; + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit <= 0) + { + continue; + } + + // + // Calculate Min and Max ... + + // + // Min ... + if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) + { + min = iPosition; + } + + // + // Max ... + if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) + { + max = iPosition; + } + + // + bool isSelectionMethodFilterPassed = + // + (method == NULL || + method == X_POSITION_SELECT_ALL || + method == X_POSITION_SELECT_ALL) + ? true + : false; + // + ; + if (!isSelectionMethodFilterPassed) + { + continue; + } + + // + AddRef( + iPosition, + result + // + ); + } + + // + if (min.IsValid() && + (method == X_POSITION_SELECT_MIN || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + min, + result + // + ); + } + + // + if (max.IsValid() && + (method == X_POSITION_SELECT_MAX || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + max, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Select In Drawdown Positions ... + int GetInDrawdownPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) + ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic, + forceClean); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition min; + XPosition max; + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit >= 0) + { + continue; + } + + // + // Calculate Min and Max ... + + // + // Min ... + if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) + { + min = iPosition; + } + + // + // Max ... + if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) + { + max = iPosition; + } + + // + bool isSelectionMethodFilterPassed = + // + (method == NULL || + method == X_POSITION_SELECT_ALL || + method == X_POSITION_SELECT_ALL) + ? true + : false; + // + ; + if (!isSelectionMethodFilterPassed) + { + continue; + } + + // + AddRef( + iPosition, + result + // + ); + } + + // + if (min.IsValid() && + (method == X_POSITION_SELECT_MIN || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + min, + result + // + ); + } + + // + if (max.IsValid() && + (method == X_POSITION_SELECT_MAX || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + max, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Orders ... + + // + // Retrieve Specific Order by Index ... + bool GetOrder( + int index, // Specified Index + XOrder &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + // Retrieve Specific Positions Orders ... + int GetOrders( + ulong ticket, // Positions Ticket + XOrder &result[], // Hold's Result + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + // Select History by Specified Ticket ... + bool isHistorySelected = HistorySelectByPosition(ticket); + if (!isHistorySelected) + { + return mResult; + } + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder; + bool isLoaded = iOrder.HistoryByIndex(i); + if (!isLoaded) + { + continue; + } + + // + bool isTicketFilterPassed = + // + iOrder.ticket = ticket + // + ; + if (!isTicketFilterPassed) + { + continue; + } + + // + AddRef( + iOrder, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Retrieve All Orders ... + int GetOrders( + XOrder &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_ORDER_TYPE type = NULL, // Long (Buy) or Short (Sell) + ENUM_ORDER_STATE state = NULL, // Order State + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = OrdersTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XOrder iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + state, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Retrieve Historical Orders ... + int GetOrders( + XOrder &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_ORDER_TYPE type = NULL, // Long (Buy) or Short (Sell) + ENUM_ORDER_STATE state = NULL, // Order State + datetime startDate = NULL, // Specify Start Date + datetime endDate = NULL, // Specify End Date + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + endDate = NormalizeTime(endDate); + + // + if (!IsValid(startDate)) + { + startDate = endDate - PeriodSeconds(PERIOD_D1); + } + + // + bool isHistorySelected = HistorySelect( + startDate, + endDate); + if (!isHistorySelected) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = OrdersTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XOrder iItem; + bool isLoaded = iItem.HistoryByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + state, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Deals ... + + // + // Retrieve Specific Deal by Index ... + bool GetDeal( + int index, // Specified Index + XDeal &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + // Retrieve Specified Deal's History ... + int GetDealsHistory( + XDeal &deal, // Specified Deal + XOrder &history[], // Deals History + bool forceClean = true // Clean Result Array + ) + { + // + int result = 0; + + // + if (!deal.IsValid()) + { + return result; + } + + // + result = GetOrders( + deal.positionId, + history, + forceClean); + + // + return result; + } + + // + // Retrieve All Deals ... + int GetDeals( + XDeal &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_DEAL_TYPE type = NULL, // Deal Type + ENUM_DEAL_ENTRY entry = NULL, // Deal Entry + ENUM_DEAL_REASON reason = NULL, // Deal Reason + datetime startDate = NULL, // Specify Start Date + datetime endDate = NULL, // Specify End Date + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + endDate = NormalizeTime(endDate); + + // + if (!IsValid(startDate)) + { + startDate = endDate - PeriodSeconds(PERIOD_D1); + } + + // + bool isHistorySelected = HistorySelect( + startDate, + endDate); + if (!isHistorySelected) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = HistoryDealsTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XDeal iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + entry, + reason, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Protected ... +protected: + // + // Props ... + + // + // Event Listener Notifiers ... + + // + // State ... + void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) + { + // + int count = ArraySize(mTradeStateChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i]; + iHandler(state); + } + } + + // + // Deals ... + void NotifyDealsChangeEvent(int changes) + { + // + int count = ArraySize(mDealsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnDealsChanged iHandler = mDealsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // Orders ... + void NotifyOrdersChangeEvent(int changes) + { + // + int count = ArraySize(mOrdersChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnOrdersChanged iHandler = mOrdersChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // Positions ... + void NotifyPositionsChangeEvent(int changes) + { + // + int count = ArraySize(mPositionsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // StopLoss ... + void NotifyStopLossEvent(const XDeal &deal) + { + // + int count = ArraySize(mStopLossEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnStopLoss iHandler = mStopLossEventHandlers[i]; + iHandler(deal); + } + } + + // + // Take Profit ... + void NotifyTakeProfitEvent(const XDeal &deal) + { + // + int count = ArraySize(mTakeProfitEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTakeProfit iHandler = mTakeProfitEventHandlers[i]; + iHandler(deal); + } + } + + // + // Tools ... + + // + // Retrieve Specified Position Comment ... + string GetPositionComment(ulong ticket) + { + // + string result = NULL; + + // + if (!IsOpen(ticket)) + { + return result; + } + + // + XPosition position; + bool isLoaded = position.ByTicket(ticket); + if (!isLoaded) + { + return result; + } + + // + result = position.comment; + + // + return result; + } + + // + // Retrieve Last Open Position Ticket ... + ulong GetLastOpenPositionTicket() + { + // + ulong result = 0; + + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + result = PositionGetTicket(PositionsTotal() - 1); + + // + return result; + } + + // + // Retrieve Last Placed Order Ticket ... + ulong GetLastPlacedOrderTicket() + { + // + ulong result = 0; + + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + if (mOrderInfo.SelectByIndex(ordersCount - 1)) + { + result = mOrderInfo.Ticket(); + } + + // + return result; + } + + // + // XPosition Pack ... + + // + // Extract specific Positions Pack ... + // in this senario there is no need to Position exists itself ... + bool GetPositionPack( + ulong ticket, // Specified Positions Ticket + string symbol, // Specified Position Symbol + ENUM_TIMEFRAMES period, // Specified Position Period + XPositionPack &pack // Hold Result + ) + { + // + bool result = false; + + // + pack.Clean(); + + // + XPosition position; + bool hasPosition = GetPosition( + ticket, + position + // + ); + if (hasPosition) + { + pack.position = position; + } + + // + XOrder supportOrders[]; + XPosition supportPositions[]; + + // + XOrder orders[]; + GetOrders( + orders, + symbol, // Specified Symbol + NULL, // All Providers + period, // Specified Period + NULL, // All Types + ORDER_STATE_PLACED, // Just UnTriggered Orders + true // Filter by Magic + ); + int ordersCount = ArraySize(orders); + + // + // Select Orders ... + if (ordersCount > 0) + { + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + // Retrieve Order Supported Ticket ... + ulong parentTicket = ExtractSupportedTicket(iOrder.comment); + if (NotEmpty(parentTicket) && parentTicket == ticket) + { + // + AddRef( + iOrder, + supportOrders + // + ); + } + } + } + + // + int supportOrdersCount = ArraySize(supportOrders); + if (supportOrdersCount > 0) + { + // + pack.supportOrdersCount = supportOrdersCount; + + // + Copy( + supportOrders, + pack.supportOrders); + } + + // + XPosition positions[]; + GetPositions( + positions, + symbol, // Specified Symbol ... + NULL, // All Providers ... + period // Specified Period ... + ); + int positionsCount = ArraySize(positions); + + // + // Select Positions ... + if (positionsCount > 0) + { + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + ulong parentTicket = ExtractSupportedTicket(iPosition.comment); + if (NotEmpty(parentTicket) && parentTicket == ticket) + { + // + AddRef( + iPosition, + supportPositions + // + ); + } + } + } + + // + int supportPositionsCount = ArraySize(supportPositions); + if (supportPositionsCount > 0) + { + // + pack.supportPositionsCount = supportPositionsCount; + + // + Copy( + supportPositions, + pack.supportPositions); + } + + // + result = supportOrdersCount > 0 || supportPositionsCount > 0; + + // + return result; + } + + // + // Extract Specific Deals Position's Pack ... + // this used when a Position SL or TP triggered and we want to close + // all it's Supported Packs ... + bool GetDealPack( + XDeal &deal, + XPositionPack &pack // + ) + { + // + bool result = false; + + // + ulong ticket = deal.positionId; + ENUM_TIMEFRAMES dealPeriod = GetDealPeriod(deal); + string dealSymbol = deal.symbol; + + // + // So We Have to Get Positions Pack ... + result = GetPositionPack( + ticket, + dealSymbol, + dealPeriod, + pack + // + ); + + // + return result; + } + + // + ENUM_TIMEFRAMES GetDealPeriod(XDeal &deal) + { + // + ENUM_TIMEFRAMES result = NULL; + + // + XOrder orders[]; + int ordersCount = GetDealsHistory( + deal, + orders); + if (!ordersCount) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + if (IsValid(iOrder.comment)) + { + // + ENUM_TIMEFRAMES iPeriod = ExtractPeriod(iOrder.comment); + if (IsValid(iPeriod)) + { + result = iPeriod; + break; + } + } + } + + // + return result; + } + + // + // Private ... +private: + // + // Props ... + + // + int mSlippage; // Slippage ... + ulong mMagicNumber; // Magic Number (Unique Identifier) ... + + // + XSCTradeBase *mTrader; // Base CTrade Manipulated Instance ... + + // + CDealInfo mDealInfo; // Deals Info ... + COrderInfo mOrderInfo; // Order Info ... + CPositionInfo mPositionInfo; // Positions Info + CHistoryOrderInfo mHistoryOrderInfo; // History Orders Info ... + + // + // Tools ... + + // + // OnTrade Event Handlers Section ... + + // + // Props ... + + // + int mDaysForRead; // Reading Dates for Trade History Checker ... + datetime mEndDate; // End Date for Trade history Checking ... + datetime mStartDate; // Start Date for Trade history Checking ... ... + int mOrdersCount; // Number of Active orders ... + int mPositionsCount; // Number of Open positions ... + int mDealsCount; // Number of Deals in the Trade History Checking ... + int mHistoryOrdersCount; // Number of Orders in the Trade History Checking ... + bool mScanStarted; // a Flag of counter relevance ... + + // + // Event Listeners ... + + // + // Deals Changed Event Handlers ... + TOnDealsChanged mDealsChangedEventHandlers[]; + + // + // Orders Changed Event Handlers ... + TOnOrdersChanged mOrdersChangedEventHandlers[]; + + // + // Positions Changed Event Handlers ... + TOnPositionsChanged mPositionsChangedEventHandlers[]; + + // + // Trade State Changed Event Handlers ... + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + // TPSL ... + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + + // + // Reset On Trade Scanner Context ... + void ResetOnTradeContext() + { + // + mEndDate = TimeCurrent(); + mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + } + + // + // Initial Context Of Trade Scanner ... + void InitOnTradeContext() + { + // + ResetLastError(); + + // + mOrdersCount = OrdersTotal(); + mPositionsCount = PositionsTotal(); + + // + // load history ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current value ... + mDealsCount = HistoryDealsTotal(); + mHistoryOrdersCount = HistoryOrdersTotal(); + + // + mScanStarted = true; + } + + // + // Check Statrt Date In Trade History ... + void CheckStartDateInTradeHistory() + { + // + // initial interval, if we were to start working right now .. + datetime currStart = TimeCurrent() - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + + // + // make sure that the start limit of the trade history has not gone + // more than 1 day over the intended date ... + if (currStart - mStartDate > PeriodSeconds(PERIOD_D1)) + { + // + // correct the start date of history to be loaded in the cache ... + mStartDate = currStart; + + // + // now reload the trade history for the updated interval ... + HistorySelect(mStartDate, mEndDate); + + // + // correct the deal and order counters in history for further comparison + mHistoryOrdersCount = HistoryOrdersTotal(); + mDealsCount = HistoryDealsTotal(); + } + } + + // + // Process On Trade Context ... + void ProcessOnTradeContext( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + mEndDate = TimeCurrent(); + + // + ResetLastError(); + + // + // download trading history from the specified interval to the program cache ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current values ... + int currOrders = OrdersTotal(); + int currPositions = PositionsTotal(); + int currDeals = HistoryDealsTotal(); + int currHistoryOrders = HistoryOrdersTotal(); + + // + // Orders ... + // check if the number of active orders has been changed ... + if (currOrders != mOrdersCount) + { + // + // number of active orders has been changed ... + result.hasNewOrder = true; + result.newOrders = currOrders - mOrdersCount; + + // + // update the value ... + mOrdersCount = currOrders; + } + + // + // Positions ... + // changes in the number of open positions ... + if (currPositions != mPositionsCount) + { + // + // number of open positions has been changed ... + result.hasNewPosition = true; + result.newPositions = currPositions - mPositionsCount; + + // + // update the value ... + mPositionsCount = currPositions; + } + + // + // Deals ... + // changes in the number of deals in the trade history cache ... + if (currDeals != mDealsCount) + { + // + // number of deals in the trade history cache has been changed ... + result.hasNewDeal = true; + result.newDeals = currDeals - mDealsCount; + + // + // update the value ... + mDealsCount = currDeals; + } + + // + // History Orders ... + // changes in the number of history orders in the trade history cache ... + if (currHistoryOrders != mHistoryOrdersCount) + { + // + // number of history orders in the trade history cache has been changed ... + result.hasNewHistoryOrder = true; + result.newHistoryOrders = currHistoryOrders - mHistoryOrdersCount; + + // + // update the value ... + mHistoryOrdersCount = currHistoryOrders; + } + + // + // checking if it is necessary to change the limits of the trade history to be requested in cache ... + CheckStartDateInTradeHistory(); + } +}; + +// \ No newline at end of file diff --git a/MQLTestWorkspace/X121/14030217/Documents/.gitkeep b/MQLTestWorkspace/BKPS/14030228/Documents/.gitkeep similarity index 100% rename from MQLTestWorkspace/X121/14030217/Documents/.gitkeep rename to MQLTestWorkspace/BKPS/14030228/Documents/.gitkeep diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Class/x-saherelm.xtrade.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Class/x-saherelm.xtrade.class.mq5 new file mode 100644 index 0000000..3b302a3 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Class/x-saherelm.xtrade.class.mq5 @@ -0,0 +1,5012 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCTrade +// Description: provides all Trade 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 + +// +// START Definitions ... +// + +// +// Model an Open Position ... +struct XPosition +{ + // + // Magic Number ... + ulong magic; + + // + // Ticket ID ... + ulong ticket; + + // + // Tradinng Symbol ... + string symbol; + + // + // Trading Period ... + ENUM_TIMEFRAMES period; + + // + // Position Type ... + ENUM_POSITION_TYPE type; + + // + // Take Profit ... + double tp; + + // + // Stop Loss ... + double sl; + + // + // Position Current Profit ... + double profit; + + // + // Position Open Price ... + double entry; + + // + // Current Symbol Price ... + double price; + + // + // Position Swap ... + double swap; + + // + // Position Commission ... + double commission; + + // + // Volume ... + double volume; + + // + // Position Open Time ... + datetime openAt; + + // + // Position Comment ... + string comment; +}; + +// +// Model an Order ... +struct XOrder +{ + // + // Time of order placement ... + datetime setupAt; + + // + // Time of order expiration ... + datetime expiredAt; + + // + // Time of order execution or cancellation ... + datetime executedAt; + + // + // Order type ... + ENUM_ORDER_TYPE type; + + // + // Order state ... + ENUM_ORDER_STATE state; + + // + // Type of execution by remainder ... + ENUM_ORDER_TYPE_FILLING filling; + + // + // Order lifetime ... + ENUM_ORDER_TYPE_TIME lifetime; + + // + // Order ticket ... + ulong ticket; + + // + // Magic Number ... + long magic; + + // + // Position id, that is placed on order, + // when it is executed. Each executed order invokes a + // deal, that opens new or changes existing + // position. Id of that position is placed on + // executed order in this moment. + long pocitionID; + + // + // Initial volume on order placement ... + double initialVolume; + + // + // Unfilled volume ... + double currentVolume; + + // + // Price, specified in the order ... + double openPrice; + + // + // Current price by order symbol ... + double currentPrice; + + // + // Price of placing Limit order when StopLimit order is triggered ... + double stopLimitPrice; + + // + // Take Profit level ... + double tp; + + // + // Stop Loss level ... + double sl; + + // + // Trading Symbol ... + string smybol; + + // + // Order Comment ... + string comment; + + // + ENUM_TIMEFRAMES period; +}; + +// +// Model a Deal ... +struct XDeal +{ + // + // the ID of the Expert Advisor, that executed the deal ... + ulong magic; + + // + // the ID of position, in which the deal was involved ... + ulong positionId; + + // + // Ticket ... + ulong ticket; + + // + // the name of the deal symbol ... + string symbol; + + // + // order by which the deal is executed ... + ulong order; + + // + // the time of deal execution ... + datetime time; + + // + // Deal price ... + double price; + + // + // the financial result of the deal (in deposit currency) ... + double profit; + + // + // the amount of swap when position is closed ... + double swap; + + // + // the amount of commission of the deal ... + double commission; + + // + // the volume of deal ... + double volume; + + // + // the deal comment ... + string comment; + + // + // the deal type ... + // ------------------------------------------------------------------ + // DEAL_TYPE_BUY => Buy ... + // DEAL_TYPE_SELL => Sell ... + // DEAL_TYPE_BUY_CANCELED => Canceled buy deal ... + // There can be a situation when a previously executed buy deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ... + // + // DEAL_TYPE_SELL_CANCELED => Canceled sell deal ... + // There can be a situation when a previously executed sell deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation + // + // DEAL_TYPE_BALANCE => Balance ... + // DEAL_TYPE_CREDIT => Credit ... + // DEAL_TYPE_CHARGE => Additional charge ... + // DEAL_TYPE_CORRECTION => Correction ... + // DEAL_TAX => Tax charges ... + // DEAL_TYPE_BONUS => Bonus ... + // DEAL_TYPE_INTEREST => Interest rate ... + // DEAL_DIVIDEND => Dividend operations... + // DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ... + // DEAL_TYPE_COMMISSION => Additional commission ... + // DEAL_TYPE_COMMISSION_DAILY => Daily commission ... + // DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ... + // DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ... + // DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission + ENUM_DEAL_TYPE type; + + // + // the deal direction ... + // ---------------------------------- + // DEAL_ENTRY_IN => Entry in ... + // DEAL_ENTRY_OUT => Entry out ... + // DEAL_ENTRY_INOUT => Reverse ... + // DEAL_ENTRY_OUT_BY => Close a position by an opposite one ... + ENUM_DEAL_ENTRY entry; + + // + // deal reson ... + // --------------------- + // DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ... + // DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ... + // DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ... + // DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ... + // DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ... + // DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ... + // DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ... + // DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ... + // DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ... + // DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ... + ENUM_DEAL_REASON reason; +}; + +// +// Model a Position with all of it's Supports ... +struct XPositionPack +{ + // + ulong ticket; + + // + XPosition position; + + // + int supportOrdersCount; + int supportPositionsCount; + + // + XOrder supportOrders[]; + XPosition supportPositions[]; +}; + +// +// Model OnTrade Event Handler Result on XCTrade Class ... +struct XOnTradeHandlerState +{ + // + bool hasNewDeal; + int newDeals; + + // + bool hasNewOrder; + int newOrders; + + // + bool hasNewPosition; + int newPositions; + + // + bool hasNewHistoryOrder; + int newHistoryOrders; +}; + +// +typedef void (*TOnDealsChanged)(int count); + +// +typedef void (*TOnOrdersChanged)(int count); + +// +typedef void (*TOnPositionsChanged)(int count); + +// +typedef void (*TOnStopLoss)(const XDeal &deal); +typedef void (*TOnTakeProfit)(const XDeal &deal); + +// +typedef void (*TOnTradeStateChanged)(const XOnTradeHandlerState &state); + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Libraries/x-saherelm.seriallizer.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// XCTrade Base Class ... +class XSCTradeBase : public CTrade +{ +public: + // + // Modify Specific Position, by Specific Comment ... + bool PositionModify( + const string symbol, // Symbol + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!SelectPosition(symbol)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.symbol = symbol; + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + bool PositionModify( + const ulong ticket, // Position Ticket + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.position = ticket; + m_request.symbol = PositionGetString(POSITION_SYMBOL); + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + + // + // Close Specific Position, by Specific Comment ... + bool PositionClose( + const string symbol, // Symbol + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + bool partial_close = false; + int retry_count = 10; + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + do + { + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specify Comment ... + m_request.comment = comment; + + // + // check volume + double max_volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); + if (m_request.volume > max_volume) + { + // + m_request.volume = max_volume; + partial_close = true; + } + else + { + partial_close = false; + } + + // + // hedging? just send order + if (IsHedging()) + { + return (OrderSend(m_request, m_result)); + } + + // + // order send + if (!OrderSend(m_request, m_result)) + { + // + if (--retry_count != 0) + { + continue; + } + + // + if (retcode == TRADE_RETCODE_DONE_PARTIAL) + { + m_result.retcode = retcode; + } + + // + return (false); + } + + // + //--- WARNING. If position volume exceeds the maximum volume allowed for deal, + //--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely, + //--- but partially. It is decreased by the maximum volume allowed for deal. + if (m_async_mode) + { + break; + } + + // + retcode = TRADE_RETCODE_DONE_PARTIAL; + if (partial_close) + { + Sleep(1000); + } + } while (partial_close); + + // + // succeed + return (true); + } + bool PositionClose( + const ulong ticket, // Position Ticket + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specify Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } + + // + // Partial Close Specific Position, by Specific Comment ... + bool PositionClosePartial( + const string symbol, // Symbol + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // hedging? just send order + return (OrderSend(m_request, m_result)); + } + bool PositionClosePartial( + const ulong ticket, // Position Ticket + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } +}; + +// +// END Overrides ... +// + +// +// a Class for Manage Trades ... +class XSCTrade +{ + // + // Public ... +public: + // + // Constructor ... + void XSCTrade( + int slippage, // Specify Slippage + ulong magicNumber // Specify Magic Number + ) + { + // + mSlippage = slippage; + mMagicNumber = magicNumber; + + // + mPeriodPrefix = "PR"; + + // + mTrader = new XSCTradeBase(); + + // + mTrader.SetAsyncMode(false); + mTrader.SetDeviationInPoints(mSlippage); + mTrader.SetExpertMagicNumber(mMagicNumber); + + // + // Setting Log Level ... + mTrader.LogLevel(LOG_LEVEL_ERRORS); + + // + // Prepare Trade Event Materials ... + // + mDaysForRead = 1; + mScanStarted = false; + + // + // Reset On Trade Counter ... + ResetOnTradeContext(); + + // + // Init On Trade Context ... + InitOnTradeContext(); + } + + // + // Deconstructor ... + void ~XSCTrade() + { + } + + // + // START Event Processing ... + // + + // + // This Must be Called Every time OnTrade Event Happening ... + XOnTradeHandlerState HandleOnTrade() + { + // + // Handle OnTrade Event ... + XOnTradeHandlerState state = {}; + HandleOnTradeEvent(state); + if ( + !state.hasNewDeal && + !state.hasNewOrder && + !state.hasNewPosition && + !state.hasNewHistoryOrder) + { + return state; + } + + // + // STATE ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(state); + + // + // DEALS ... + if (state.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(state.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + GetDeals(deals); + int dealsCount = ArraySize(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // ORDERS ... + if (state.hasNewOrder || state.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(state.newOrders + state.newHistoryOrders); + } + + // + // POSITIONS ... + if (state.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(state.newPositions); + } + + // + return state; + } + + // + // Process On Trade Requirement + void HandleOnTradeEvent( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + if (mScanStarted) + { + ProcessOnTradeContext(result); + } + else + { + InitOnTradeContext(); + } + } + + // + // Event Emitters ... + + // + // STATE Changed ... + + // + // Clear Trade State Changed Event Handlers ... + void ClearOnTradeStateChangedEventHandlers() + { + // + ArrayFree(mTradeStateChangedEventHandlers); + + // + ArrayResize(mTradeStateChangedEventHandlers, 0); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) + { + // + ArrayResize( + mTradeStateChangedEventHandlers, + ArraySize(mTradeStateChangedEventHandlers) + 1); + + // + mTradeStateChangedEventHandlers[ArraySize(mTradeStateChangedEventHandlers) - 1] = handler; + } + + // + // DEALS ... + + // + // Clear Deals Changed Event Handlers ... + void ClearOnDealsChangedEventHandlers() + { + // + ArrayFree(mDealsChangedEventHandlers); + + // + ArrayResize(mDealsChangedEventHandlers, 0); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnDealsChangedEventHandler(TOnDealsChanged handler) + { + // + ArrayResize( + mDealsChangedEventHandlers, + ArraySize(mDealsChangedEventHandlers) + 1); + + // + mDealsChangedEventHandlers[ArraySize(mDealsChangedEventHandlers) - 1] = handler; + } + + // + // ORDERS ... + + // + // Clear Orders Changed Event Handlers ... + void ClearOnOrdersChangedEventHandlers() + { + // + ArrayFree(mOrdersChangedEventHandlers); + + // + ArrayResize(mOrdersChangedEventHandlers, 0); + } + + // + // Add New Orders Changed Event Handler ... + void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) + { + // + ArrayResize( + mOrdersChangedEventHandlers, + ArraySize(mOrdersChangedEventHandlers) + 1); + + // + mOrdersChangedEventHandlers[ArraySize(mOrdersChangedEventHandlers) - 1] = handler; + } + + // + // POSITIONS ... + + // + // Clear Positions Changed Event Handlers ... + void ClearOnPositionsChangedEventHandlers() + { + // + ArrayFree(mPositionsChangedEventHandlers); + + // + ArrayResize(mPositionsChangedEventHandlers, 0); + } + + // + // Add New Positions Changed Event Handler ... + void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) + { + // + ArrayResize( + mPositionsChangedEventHandlers, + ArraySize(mPositionsChangedEventHandlers) + 1); + + // + mPositionsChangedEventHandlers[ArraySize(mPositionsChangedEventHandlers) - 1] = handler; + } + + // + // TPSL ... + + // + // Clear Stop Loss Event Handlers ... + void ClearOnStopLossEventHandlers() + { + // + ArrayFree(mStopLossEventHandlers); + + // + ArrayResize(mStopLossEventHandlers, 0); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + ArrayResize( + mStopLossEventHandlers, + ArraySize(mStopLossEventHandlers) + 1); + + // + mStopLossEventHandlers[ArraySize(mStopLossEventHandlers) - 1] = handler; + } + + // + // Clear Take Profit Event Handlers ... + void ClearOnTakeProfitEventHandlers() + { + // + ArrayFree(mTakeProfitEventHandlers); + + // + ArrayResize(mTakeProfitEventHandlers, 0); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + ArrayResize( + mTakeProfitEventHandlers, + ArraySize(mTakeProfitEventHandlers) + 1); + + // + mTakeProfitEventHandlers[ArraySize(mTakeProfitEventHandlers) - 1] = handler; + } + + // + // END Event Processing ... + // + + // + // START Provided Functions ... + // + + // + // Count Currently Open Positions ... + int CountPositions( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + int result = 0; + + // + int allPositions = 0; + int longPositions = 0; + int shortPositions = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + allPositions++; + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + longPositions++; + } + else + { + shortPositions++; + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + allPositions++; + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + longPositions++; + } + else + { + shortPositions++; + } + + // + continue; + } + } + } + + // + // Specify Result ... + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + result = allPositions; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == POSITION_TYPE_BUY) + { + result = longPositions; + } + else + { + result = shortPositions++; + } + } + else if (StringLen(symbol) > 0) + { + // + result = allPositions; + } + else if (type != NULL) + { + // + if (type == POSITION_TYPE_BUY) + { + result = longPositions; + } + else + { + result = shortPositions; + } + } + + // + return result; + } + + // + // Retrieve Max In Profit Position Ticket ... + ulong GetMaxInProfitPosition( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + ulong result = -1; + + // + double profit = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + double positionAbsProfit = MathAbs(positionProfit); + if (positionProfit <= 0) + { + continue; + } + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Retrieve Max In DrawDown Position Ticket ... + ulong GetMaxInDrawDownPosition( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + ulong result = -1; + + // + double profit = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + double positionAbsProfit = MathAbs(positionProfit); + if (positionProfit >= 0) + { + continue; + } + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Retrieve Specific Position's Profit ... + double GetPositionProfit( + const ulong ticket // Specified Position Ticket + ) + { + // + double result = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + result = mPositionInfo.Profit(); + break; + } + + // + return result; + } + + // + // Retrieve Specific Position's OpenDate ... + datetime GetPositionOpenDate( + const ulong ticket // Specified Position Ticket + ) + { + // + datetime result = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + result = mPositionInfo.Time(); + break; + } + + // + return result; + } + + // + // Retrieve Specific Position's Comment ... + string GetPositionComment( + const ulong ticket // Specified Position Ticket + ) + { + // + string result = ""; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + result = mPositionInfo.Comment(); + break; + } + + // + return result; + } + + // + // Retrieve All Open Positions Profit ... + double GetPositionsProfit( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + double result = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + result += positionProfit; + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + result += positionProfit; + } + else + { + result += positionProfit; + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + result += positionProfit; + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + result += positionProfit; + } + else + { + result += positionProfit; + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Find Oldes Position ... + ulong GetOldestPosition( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + ulong result = 0; + + // + int age = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + double positionAbsProfit = MathAbs(positionProfit); + if (positionProfit >= 0) + { + continue; + } + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + string positionComment = mPositionInfo.Comment(); + ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(positionComment); + + // + // Calculate Position's Age ... + datetime positionOpenTime = mPositionInfo.Time(); + + // + // Retrieve Trade Open Bar Index based on Current Period ... + int positionOpenBarIndex = iBarShift( + positionSymbol, + positionPeriod, + positionOpenTime); + + // + // Calculate Trade Life ... + int positionAge = MathAbs(0 - positionOpenBarIndex); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + else + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + else + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Force Open a Buy/Long Position ... + bool Buy( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.Buy( + volume, + symbol, + price, + sl, + tp, + comment); + + // + return result; + } + + // + // Send BUY LIMIT order ... + bool BuyLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.BuyLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Send BUY STOP order ... + bool BuyStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.BuyStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Force Open a Sell/Short Position ... + bool Sell( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.Sell( + volume, + symbol, + price, + sl, + tp, + comment); + + // + return result; + } + + // + // Send SELL LIMIT order ... + bool SellLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.SellLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Send SELL STOP order ... + bool SellStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.SellStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Modify Position ... + bool Modify( + const ulong ticket, // position ticket + double sl = 0, // stop loss price + double tp = 0, // take profit + string comment = "" // comment + ) + { + // + bool result = false; + + // + // Validate Args ... + if (tp <= 0 && sl <= 0) + { + result = false; + return result; + } + + // + // Use Position Comment when there isn't new One ... + if (StringLen(comment) == 0) + { + comment = GetPositionComment(ticket); + } + + // + result = mTrader.PositionModify( + ticket, + sl, + tp, + comment); + + // + return result; + } + + // + // Close Position By Ticket ... + bool Close( + ulong ticket, // Position Ticket + string comment = "" // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + // Try to Select Position ... + if (!mPositionInfo.SelectByTicket(ticket)) + { + return result; + } + + // + // Close Position By Specific Comment ... + result = mTrader.PositionClose( + ticket, + mSlippage, + comment); + + // + return result; + } + + // + // Close All Positions ... + void CloseAllPositions( + string comment = "" // Close Position By Specific Comment + ) + { + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + Close( + positionTicket, + comment); + } + } + + // + // Close Partial By Ticket ... + bool ClosePartial( + ulong ticket, // Position Ticket + double volume, // Volume Size for Partial Closing + string comment = "" // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + if (!mPositionInfo.SelectByTicket(ticket)) + { + return result; + } + + // + result = mTrader.PositionClosePartial( + ticket, + volume, + mSlippage, + comment); + + // + return result; + } + + // + // Find Position Open Bar Index ... + int GetPositionOpenBarIndex( + const ulong ticket // position ticket + ) + { + // + int result = -1; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + string symbol = mPositionInfo.Symbol(); + datetime openAt = mPositionInfo.Time(); + string comment = mPositionInfo.Comment(); + ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment); + + // + result = iBarShift( + symbol, + period, + openAt); + } + + // + return result; + } + + // + bool GetPosition( + XPosition &position, // Holds result ... + ulong ticket // Required Position Ticket ... + ) + { + // + bool result = false; + + // + XPosition positions[]; + GetPositions(positions); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + result = iPosition.ticket == ticket; + if (!result) + { + continue; + } + + // + position = iPosition; + break; + } + + // + return result; + } + + // + // Retrieve Positions as an Array ... + void GetPositions( + XPosition &result[] // Hold Result ... + ) + { + // + Clean(result); + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong magic = mPositionInfo.Magic(); + ulong ticket = mPositionInfo.Ticket(); + string symbol = mPositionInfo.Symbol(); + datetime openAt = mPositionInfo.Time(); + double swap = mPositionInfo.Swap(); + double sl = mPositionInfo.StopLoss(); + double tp = mPositionInfo.TakeProfit(); + double profit = mPositionInfo.Profit(); + double volume = mPositionInfo.Volume(); + string comment = mPositionInfo.Comment(); + double entry = mPositionInfo.PriceOpen(); + double price = mPositionInfo.PriceCurrent(); + double commission = mPositionInfo.Commission(); + ENUM_POSITION_TYPE type = mPositionInfo.PositionType(); + ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment); + + // + XPosition iPosition = {}; + + // + iPosition.tp = tp; + iPosition.sl = sl; + iPosition.swap = swap; + iPosition.type = type; + iPosition.magic = magic; + iPosition.entry = entry; + iPosition.price = price; + iPosition.ticket = ticket; + iPosition.symbol = symbol; + iPosition.period = period; + iPosition.volume = volume; + iPosition.openAt = openAt; + iPosition.profit = profit; + iPosition.comment = comment; + iPosition.commission = commission; + + // + Add( + iPosition, + result); + } + } + + // + void GetPositions( + XPosition &result[], // Hold Result ... + string symbol, // Trading Symbol ... + ENUM_TIMEFRAMES period // Trading Period ... + ) + { + // + Clean(result); + + // + bool hasPeriod = period != NULL; + bool hasSymbol = symbol != NULL && StringLen(symbol) > 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return; + } + + // + XPosition allPositions[]; + GetPositions(allPositions); + + // + if (!hasPeriod && !hasSymbol) + { + // + Copy( + allPositions, + result); + + // + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = allPositions[i]; + + // + if (hasSymbol && + symbol != iPosition.symbol) + { + continue; + } + + // + ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(iPosition.comment); + if (hasPeriod && + period != positionPeriod) + { + continue; + } + + // + Add( + iPosition, + result); + } + } + + // + // Execute a Signal ... + bool ExecuteSignal( + XSignal &signal, // Signal ... + string comment = "", // Position Comment ... + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ... + datetime expiration = 0 // order expiration time + ) + { + // + bool result = false; + + // + double currentEntry = GetEntry( + signal.symbol, + signal.type); + bool isLong = IsLong(signal.type); + + // + ResetLastError(); + + // + if (signal.mode == X_ORDER_MODE_MARKET) + { + // + // Execute MArket Orders ... + if (isLong) + { + // + result = Buy( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + comment); + } + else + { + // + result = Sell( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + comment); + } + } + else if (signal.mode == X_ORDER_MODE_LIMIT) + { + // + // Execute Limit Orders ... + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? signal.entry < currentEntry + : signal.entry > currentEntry; + if (!result) + { + return result; + } + + // + // Check Expiration Date ... + result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY) + ? expiration > 0 + : true; + if (!result) + { + return result; + } + + // + if (isLong) + { + // + result = BuyLimit( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + else + { + // + result = SellLimit( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + } + else if (signal.mode == X_ORDER_MODE_STOP) + { + // + // Execute Stop Orders ... + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? signal.entry > currentEntry + : signal.entry < currentEntry; + if (!result) + { + return result; + } + + // + // Check Expiration Date ... + result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY) + ? expiration > 0 + : true; + if (!result) + { + return result; + } + + // + if (isLong) + { + // + result = BuyStop( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + else + { + // + result = SellStop( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + } + + // + if (!result) + { + LogMessage("Error: " + (string)GetLastError() + ", " + GetErrorDescription(GetLastError())); + } + else + { + // + // Retrieve Last Position Ticket ... + ulong ticket = GetLastOpenPositionTicket(); + + // + // Check Position have Support Signals or not ... + int supportsCount = ArraySize(signal.supports); + if (supportsCount > 0) + { + // + int executed = 0; + for (int i = 0; i < supportsCount; i++) + { + // + XSignal iSupport = signal.supports[i]; + + // + int supIndex = i + 1; + string iComment = GenerateSupportSignalComment( + ticket, + supIndex); + + // + bool isExecuted = ExecuteSignal( + iSupport, + iComment); + if (isExecuted) + { + executed++; + } + } + + // + result = executed == supportsCount; + } + } + + // + return result; + } + + // + // Execute a Collection of Signals ... + int ExecuteSignals( + const XSignal &signals[], // an Array of Signals ... + string comment = "", // Position Comment ... + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ... + datetime expiration = 0 // order expiration time + ) + { + // + int result = 0; + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < signalsCount; i++) + { + // + XSignal iSignal = signals[i]; + + // + if (StringLen(comment) == 0) + { + comment = GenerateProvidersString(iSignal); + } + + // + bool isExecuted = ExecuteSignal( + iSignal, + comment, + lifetime, + expiration); + + // + if (isExecuted) + { + result++; + } + } + + // + return result; + } + + // + // Retrieve in Profit Positions ... + void GetInProfitPositions( + XPosition &result[] // Hold Result ... + ) + { + // + Clean(result); + + // + XPosition allPositions[]; + GetPositions(allPositions); + int positionsCount = ArraySize(allPositions); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = allPositions[i]; + + // + if (iPosition.profit > 0) + { + Add( + iPosition, + result); + } + } + } + + // + // Retrieve in Drawdown Positions ... + void GetInDrawdownPositions( + XPosition &result[] // Hold Result ... + ) + { + // + Clean(result); + + // + XPosition allPositions[]; + GetPositions(allPositions); + int positionsCount = ArraySize(allPositions); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = allPositions[i]; + + // + if (iPosition.profit < 0) + { + Add( + iPosition, + result); + } + } + } + + // + // Close a Collection Of Positions ... + int ClosePositions( + XPosition &positions[], // Positions to Close ... + string comment = "" // Specified Comment ... + ) + { + // + int result = 0; + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isClosed = Close( + iPosition.ticket, + comment); + if (isClosed) + { + result++; + } + } + + // + return result; + } + + // + // Retrieve All Orders ... + void GetOrders( + XOrder &result[], // Holdes Result .... + string symbol, // Trading Symbol ... + ENUM_TIMEFRAMES period, // Trading TimeFrame ... + ENUM_ORDER_STATE state = NULL // Order State ... + ) + { + // + Clean(result); + + // + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return; + } + + // + // Since Orders may be so more than positions ... + // start Orders Collectiong Loops reverse ... + for (int i = ordersCount - 1; i >= 0; i--) + { + // + if (!mOrderInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mOrderInfo.Magic() != mMagicNumber) + { + continue; + } + + // + // Reading Order Info ... + long magic = mOrderInfo.Magic(); + double sl = mOrderInfo.StopLoss(); + ulong ticket = mOrderInfo.Ticket(); + double tp = mOrderInfo.TakeProfit(); + string oSymbol = mOrderInfo.Symbol(); + string comment = mOrderInfo.Comment(); + long positionID = mOrderInfo.PositionId(); + double openPrice = mOrderInfo.PriceOpen(); + datetime setupAt = mOrderInfo.TimeSetup(); + datetime executedAt = mOrderInfo.TimeDone(); + ENUM_ORDER_STATE oState = mOrderInfo.State(); + ENUM_ORDER_TYPE type = mOrderInfo.OrderType(); + double currentPrice = mOrderInfo.PriceCurrent(); + datetime expiredAt = mOrderInfo.TimeExpiration(); + double initialVolume = mOrderInfo.VolumeInitial(); + double currentVolume = mOrderInfo.VolumeCurrent(); + double stopLimitPrice = mOrderInfo.PriceStopLimit(); + ENUM_ORDER_TYPE_TIME lifetime = mOrderInfo.TypeTime(); + ENUM_ORDER_TYPE_FILLING filling = mOrderInfo.TypeFilling(); + + // + if (StringLen(symbol) > 0 && symbol != oSymbol) + { + continue; + } + + // + ENUM_TIMEFRAMES oPeriod = ExtractPositionPeriod(comment); + if (period != NULL && period != oPeriod) + { + continue; + } + + // + if (state != NULL && oState != state) + { + continue; + } + + // + // Now Create an instance of XOrder struct and fill it by + // retrieved data, and add it to results ... + XOrder iOrder = {}; + + // + iOrder.sl = sl; + iOrder.tp = tp; + iOrder.type = type; + iOrder.magic = magic; + iOrder.state = oState; + iOrder.ticket = ticket; + iOrder.smybol = oSymbol; + iOrder.period = oPeriod; + iOrder.setupAt = setupAt; + iOrder.comment = comment; + iOrder.filling = filling; + iOrder.lifetime = lifetime; + iOrder.expiredAt = expiredAt; + iOrder.openPrice = openPrice; + iOrder.pocitionID = positionID; + iOrder.executedAt = executedAt; + iOrder.currentPrice = currentPrice; + iOrder.initialVolume = initialVolume; + iOrder.currentVolume = currentVolume; + iOrder.stopLimitPrice = stopLimitPrice; + + // + Add( + iOrder, + result); + } + } + + // + int CountOrders() + { + return OrdersTotal(); + } + + // + // Cancel Specific Order ... + bool CancelOrder(ulong ticket) + { + return mTrader.OrderDelete(ticket); + } + + // + // Cancel Specific Orders ... + bool CancelOrders( + XOrder &orders[]) + { + // + bool result = false; + + // + int ordersCount = ArraySize(orders); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + bool isDeleted = mTrader.OrderDelete(iOrder.ticket); + if (isDeleted && !result) + { + result = isDeleted; + } + } + + // + return result; + } + + // + // Retrieve All Deals ... + void GetDeals(XDeal &result[]) + { + // + Clean(result); + + // + int dealsCount = HistoryDealsTotal(); + if (dealsCount <= 0) + { + return; + } + + // + for (int i = dealsCount - 1; i >= 0; i--) + { + // + if (!mDealInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mDealInfo.Magic() != mMagicNumber) + { + continue; + } + + // + // Reading Order Info ... + double swap = mDealInfo.Swap(); + ulong magic = mDealInfo.Magic(); + ulong order = mDealInfo.Order(); + ulong ticket = mDealInfo.Ticket(); + datetime time = mDealInfo.Time(); + double price = mDealInfo.Price(); + string symbol = mDealInfo.Symbol(); + double profit = mDealInfo.Profit(); + double volume = mDealInfo.Volume(); + string comment = mDealInfo.Comment(); + ulong positionId = mDealInfo.PositionId(); + ENUM_DEAL_ENTRY entry = mDealInfo.Entry(); + double commission = mDealInfo.Commission(); + ENUM_DEAL_TYPE type = mDealInfo.DealType(); + ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( + ticket, + DEAL_REASON); + + // + XDeal iDeal = {}; + + // + iDeal.swap = swap; + iDeal.time = time; + iDeal.type = type; + iDeal.magic = magic; + iDeal.entry = entry; + iDeal.order = order; + iDeal.price = price; + iDeal.ticket = ticket; + iDeal.symbol = symbol; + iDeal.profit = profit; + iDeal.volume = volume; + iDeal.reason = reason; + iDeal.comment = comment; + iDeal.positionId = positionId; + iDeal.commission = commission; + + // + Add( + iDeal, + result); + } + } + + // + // Retrieve all History Orders of Specific Deal ... + int GetDealHistory( + const XDeal &deal, // Specified Deal + XOrder &history[] // Hold Result + ) + { + // + int result = 0; + + // + Clean(history); + + // + bool isHistorySelected = HistorySelectByPosition(deal.positionId); + if (!isHistorySelected) + { + return result; + } + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + if (!mHistoryOrderInfo.SelectByIndex(i)) + { + continue; + } + + // + ulong ticket = mHistoryOrderInfo.Ticket(); + + // + long positionId = mHistoryOrderInfo.PositionId(); + if (positionId != deal.positionId) + { + continue; + } + + // + // Reading Order Info ... + long magic = mHistoryOrderInfo.Magic(); + double sl = mHistoryOrderInfo.StopLoss(); + double tp = mHistoryOrderInfo.TakeProfit(); + string oSymbol = mHistoryOrderInfo.Symbol(); + string comment = mHistoryOrderInfo.Comment(); + double openPrice = mHistoryOrderInfo.PriceOpen(); + datetime setupAt = mHistoryOrderInfo.TimeSetup(); + datetime executedAt = mHistoryOrderInfo.TimeDone(); + ENUM_ORDER_STATE oState = mHistoryOrderInfo.State(); + ENUM_ORDER_TYPE type = mHistoryOrderInfo.OrderType(); + double currentPrice = mHistoryOrderInfo.PriceCurrent(); + datetime expiredAt = mHistoryOrderInfo.TimeExpiration(); + double initialVolume = mHistoryOrderInfo.VolumeInitial(); + double currentVolume = mHistoryOrderInfo.VolumeCurrent(); + double stopLimitPrice = mHistoryOrderInfo.PriceStopLimit(); + ENUM_ORDER_TYPE_TIME lifetime = mHistoryOrderInfo.TypeTime(); + ENUM_ORDER_TYPE_FILLING filling = mHistoryOrderInfo.TypeFilling(); + + // + ENUM_TIMEFRAMES oPeriod = ExtractPositionPeriod(comment); + + // + // Now Create an instance of XOrder struct and fill it by + // retrieved data, and add it to results ... + XOrder iOrder = {}; + + // + iOrder.sl = sl; + iOrder.tp = tp; + iOrder.type = type; + iOrder.magic = magic; + iOrder.state = oState; + iOrder.ticket = ticket; + iOrder.smybol = oSymbol; + iOrder.period = oPeriod; + iOrder.setupAt = setupAt; + iOrder.comment = comment; + iOrder.filling = filling; + iOrder.lifetime = lifetime; + iOrder.expiredAt = expiredAt; + iOrder.openPrice = openPrice; + iOrder.pocitionID = positionId; + iOrder.executedAt = executedAt; + iOrder.currentPrice = currentPrice; + iOrder.initialVolume = initialVolume; + iOrder.currentVolume = currentVolume; + iOrder.stopLimitPrice = stopLimitPrice; + + // + Add( + iOrder, + history); + } + + // + result = ArraySize(history); + + // + return result; + } + + // + // Retrieve Specific Dates History Orders ... + int GetHistoryOrders( + XOrder &orders[], // Hold Result + string symbol = NULL, // Specify Symbol + ENUM_TIMEFRAMES period = NULL, // Speify Period + ENUM_ORDER_TYPE type = NULL, // Trading Type + ENUM_ORDER_STATE state = NULL, // Trading State + datetime startDate = 0, // Start Date + datetime endDate = 0 // End Date + ) + { + // + int result = 0; + + // + Clean(orders); + + // + if (startDate <= 0) + { + startDate = TimeCurrent() - (3 * PeriodSeconds(PERIOD_D1)); + } + + // + if (endDate <= 0) + { + endDate = TimeCurrent(); + } + + // + if (endDate <= startDate) + { + return result; + } + + // + bool isSelected = HistorySelect(startDate, endDate); + if (!isSelected) + { + return result; + } + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + if (!mHistoryOrderInfo.SelectByIndex(i)) + { + continue; + } + + // + // + // Reading Order Info ... + + // + long magic = mHistoryOrderInfo.Magic(); + if (magic != mMagicNumber) + { + continue; + } + + // + string oSymbol = mHistoryOrderInfo.Symbol(); + if (StringLen(symbol) > 0 && symbol != NULL && oSymbol != symbol) + { + continue; + } + + // + string comment = mHistoryOrderInfo.Comment(); + ENUM_TIMEFRAMES oPeriod = ExtractPositionPeriod(comment); + if (period != NULL && oPeriod != period) + { + continue; + } + + // + ENUM_ORDER_TYPE oType = mHistoryOrderInfo.OrderType(); + if (type != NULL && oType != type) + { + continue; + } + + // + ENUM_ORDER_STATE oState = mHistoryOrderInfo.State(); + if (state != NULL && oState != state) + { + continue; + } + + // + double sl = mHistoryOrderInfo.StopLoss(); + ulong ticket = mHistoryOrderInfo.Ticket(); + double tp = mHistoryOrderInfo.TakeProfit(); + long positionId = mHistoryOrderInfo.PositionId(); + double openPrice = mHistoryOrderInfo.PriceOpen(); + datetime setupAt = mHistoryOrderInfo.TimeSetup(); + datetime executedAt = mHistoryOrderInfo.TimeDone(); + double currentPrice = mHistoryOrderInfo.PriceCurrent(); + datetime expiredAt = mHistoryOrderInfo.TimeExpiration(); + double initialVolume = mHistoryOrderInfo.VolumeInitial(); + double currentVolume = mHistoryOrderInfo.VolumeCurrent(); + double stopLimitPrice = mHistoryOrderInfo.PriceStopLimit(); + ENUM_ORDER_TYPE_TIME lifetime = mHistoryOrderInfo.TypeTime(); + ENUM_ORDER_TYPE_FILLING filling = mHistoryOrderInfo.TypeFilling(); + + // + + // + // Now Create an instance of XOrder struct and fill it by + // retrieved data, and add it to results ... + XOrder iOrder = {}; + + // + iOrder.sl = sl; + iOrder.tp = tp; + iOrder.type = type; + iOrder.magic = magic; + iOrder.state = oState; + iOrder.ticket = ticket; + iOrder.smybol = oSymbol; + iOrder.period = oPeriod; + iOrder.setupAt = setupAt; + iOrder.comment = comment; + iOrder.filling = filling; + iOrder.lifetime = lifetime; + iOrder.expiredAt = expiredAt; + iOrder.openPrice = openPrice; + iOrder.pocitionID = positionId; + iOrder.executedAt = executedAt; + iOrder.currentPrice = currentPrice; + iOrder.initialVolume = initialVolume; + iOrder.currentVolume = currentVolume; + iOrder.stopLimitPrice = stopLimitPrice; + + // + Add( + iOrder, + orders); + } + + // + result = ArraySize(orders); + + // + return result; + } + + // + // Retrieve Specific Dates History Deals ... + int GetHistoryDeals( + XDeal &deals[], // Hold Result + string symbol = NULL, // Specify Symbol + ENUM_DEAL_TYPE type = NULL, // Specify Deal Type + ENUM_DEAL_REASON reason = NULL, // Specify Deal Reason + datetime startDate = 0, // Start Date + datetime endDate = 0 // End Date + ) + { + // + int result = 0; + + // + Clean(deals); + + // + if (startDate <= 0) + { + startDate = TimeCurrent() - (3 * PeriodSeconds(PERIOD_D1)); + } + + // + if (endDate <= 0) + { + endDate = TimeCurrent(); + } + + // + if (endDate <= startDate) + { + return result; + } + + // + bool isSelected = HistorySelect(startDate, endDate); + if (!isSelected) + { + return result; + } + + // + int dealsCount = HistoryDealsTotal(); + if (dealsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < dealsCount; i++) + { + // + if (!mDealInfo.SelectByIndex(i)) + { + continue; + } + + // + // Reading Deal Info ... + + // + long magic = mDealInfo.Magic(); + if (magic != mMagicNumber) + { + continue; + } + + // + string oSymbol = mDealInfo.Symbol(); + if (StringLen(symbol) > 0 && symbol != NULL && oSymbol != symbol) + { + continue; + } + + // + ENUM_DEAL_TYPE oType = mDealInfo.DealType(); + if (type != NULL && oType != type) + { + continue; + } + + // + ulong ticket = mDealInfo.Ticket(); + ENUM_DEAL_REASON oReason = (ENUM_DEAL_REASON)HistoryDealGetInteger( + ticket, + DEAL_REASON); + if (reason != NULL && oReason != reason) + { + continue; + } + + // + double swap = mDealInfo.Swap(); + ulong order = mDealInfo.Order(); + datetime time = mDealInfo.Time(); + double price = mDealInfo.Price(); + double profit = mDealInfo.Profit(); + double volume = mDealInfo.Volume(); + string comment = mDealInfo.Comment(); + ulong positionId = mDealInfo.PositionId(); + ENUM_DEAL_ENTRY entry = mDealInfo.Entry(); + double commission = mDealInfo.Commission(); + + // + XDeal iDeal; + + // + iDeal.swap = swap; + iDeal.time = time; + iDeal.type = type; + iDeal.magic = magic; + iDeal.entry = entry; + iDeal.order = order; + iDeal.price = price; + iDeal.ticket = ticket; + iDeal.symbol = symbol; + iDeal.profit = profit; + iDeal.volume = volume; + iDeal.reason = reason; + iDeal.comment = comment; + iDeal.positionId = positionId; + iDeal.commission = commission; + + // + Add( + iDeal, + deals); + } + + // + result = ArraySize(deals); + + // + return result; + } + + // + // Find Deal Period ... + ENUM_TIMEFRAMES GetDealPeriod(const XDeal &deal) + { + // + ENUM_TIMEFRAMES result = NULL; + + // + XOrder history[]; + int historyCount = GetDealHistory( + deal, + history); + if (historyCount <= 0) + { + return result; + } + + // + for (int i = 0; i < historyCount; i++) + { + // + XOrder iOrder = history[i]; + + // + if (StringLen(iOrder.comment) == 0) + { + continue; + } + + // + string periodStr = ExtractPositionPeriodString(iOrder.comment); + if (StringLen(periodStr) > 0) + { + // + result = ToPeriod(periodStr); + break; + } + } + + // + return result; + } + + // + // Find Deal Position Comment ... + string GetDealPositionComment(const XDeal &deal) + { + // + string result = ""; + + // + XOrder history[]; + int historyCount = GetDealHistory( + deal, + history); + if (historyCount <= 0) + { + return result; + } + + // + for (int i = 0; i < historyCount; i++) + { + // + XOrder iOrder = history[i]; + + // + if (StringLen(iOrder.comment) > 0) + { + // + result = iOrder.comment; + break; + } + } + + // + return result; + } + + // + // Generate String Representation Of Position's Time Frame ... + string GeneratePositionPeriodComment(ENUM_TIMEFRAMES period) + { + // + string result = mPeriodPrefix + "(" + ToString(period) + ")"; + + // + return result; + } + + // + string ExtractPositionPeriodString(string comment) + { + // + string result = ""; + + // + if (StringLen(comment) <= 0) + { + return result; + } + + // + result = ExtractString( + comment, + mPeriodPrefix + "(", + ")"); + + // + return result; + } + + // + // Extract Position Time Frame From it's Comment ... + ENUM_TIMEFRAMES ExtractPositionPeriod(string comment) + { + // + ENUM_TIMEFRAMES result = NULL; + + // + string periodStr = ExtractPositionPeriodString(comment); + if (StringLen(periodStr) <= 0) + { + return result; + } + + // + result = ToPeriod(periodStr); + + // + return result; + } + + // + // Retrieve Last Open Position Ticket ... + ulong GetLastOpenPositionTicket() + { + // + ulong result = 0; + + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + result = PositionGetTicket(PositionsTotal() - 1); + + // + return result; + } + + // + // Retrieve Last Placed Order Ticket ... + ulong GetLastPlacedOrderTicket() + { + // + ulong result = 0; + + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + if (mOrderInfo.SelectByIndex(ordersCount - 1)) + { + result = mOrderInfo.Ticket(); + } + + // + return result; + } + + // + // SUPPORT Signals ... + + // + // Retrieve a Position if Exists + // by all of it's Supported Positon/Order (s) ... + bool GetPositionPack( + ulong ticket, // Sepcified Position's Ticket + XPositionPack &pack // Hold Result ... + ) + { + // + bool result = false; + + // + int positionsCount = CountPositions(); + int ordersCount = CountOrders(); + if (ordersCount <= 0 && positionsCount <= 0) + { + return result; + } + + // + XPosition position; + result = GetPosition( + position, + ticket); + if (!result) + { + return result; + } + + // + XOrder supportOrders[]; + XPosition supportPositions[]; + + // + XOrder orders[]; + GetOrders( + orders, + position.symbol, + position.period, + ORDER_STATE_PLACED); + ordersCount = ArraySize(orders); + + // + // Select Orders ... + if (ordersCount > 0) + { + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + string params[]; + bool hasSupport = ExtractSupportParams( + iOrder.comment, + params); + if (hasSupport) + { + // + ulong parentTicket = ExtractParentTicket(iOrder.comment); + if (parentTicket == ticket) + { + // + Add( + iOrder, + supportOrders); + } + } + } + } + + // + XPosition positions[]; + GetPositions( + positions, + position.symbol, + position.period); + positionsCount = ArraySize(positions); + + // + // Select Positions ... + if (positionsCount > 0) + { + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + string params[]; + bool hasSupport = ExtractSupportParams( + iPosition.comment, + params); + if (hasSupport) + { + // + ulong parentTicket = ExtractParentTicket(iPosition.comment); + if (parentTicket == ticket) + { + // + Add( + iPosition, + supportPositions); + } + } + } + } + + // + int supportOrdersCount = ArraySize(supportOrders); + int supportPositionsCount = ArraySize(supportPositions); + + // + pack.ticket = ticket; + pack.position = position; + + // + Copy(supportOrders, + pack.supportOrders); + Copy(supportPositions, + pack.supportPositions); + + // + pack.supportOrdersCount = supportOrdersCount; + pack.supportPositionsCount = supportPositionsCount; + + // + result = true; + + // + return result; + } + + // + // Extract specific Positions Pack ... + // in this senario there is no need to Position exists itself ... + bool GetPositionPack( + ulong ticket, // Specified Positions Ticket ... + string symbol, // Specified Position Symbol ... + ENUM_TIMEFRAMES period, // Specified Position Period ... + XPositionPack &pack // Hold Result ... + ) + { + // + bool result = false; + + // + // NOTE: We Have to Force Retrieve Position's pack event + // it's parent Position not Eists ... + pack.ticket = ticket; + pack.supportOrdersCount = 0; + Clean(pack.supportOrders); + pack.supportPositionsCount = 0; + Clean(pack.supportPositions); + + // + XPosition position; + bool hasPosition = GetPosition( + position, + ticket); + if (hasPosition) + { + pack.position = position; + } + + // + XOrder supportOrders[]; + XPosition supportPositions[]; + + // + XOrder orders[]; + GetOrders( + orders, + symbol, // Specified Symbol ... + period, // Specified Period + ORDER_STATE_PLACED // Just UnTriggered Orders ... + ); + int ordersCount = ArraySize(orders); + + // + // Select Orders ... + if (ordersCount > 0) + { + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + string params[]; + bool hasSupport = ExtractSupportParams( + iOrder.comment, + params); + if (hasSupport) + { + // + ulong parentTicket = ExtractParentTicket(iOrder.comment); + if (parentTicket == ticket) + { + // + Add( + iOrder, + supportOrders); + } + } + } + } + + // + int supportOrdersCount = ArraySize(supportOrders); + if (supportOrdersCount > 0) + { + // + pack.supportOrdersCount = supportOrdersCount; + + // + Copy( + supportOrders, + pack.supportOrders); + } + + // + XPosition positions[]; + GetPositions( + positions, + symbol, // Specified Symbol ... + period // Specified Period ... + ); + int positionsCount = ArraySize(positions); + + // + // Select Positions ... + if (positionsCount > 0) + { + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + string params[]; + bool hasSupport = ExtractSupportParams( + iPosition.comment, + params); + if (hasSupport) + { + // + ulong parentTicket = ExtractParentTicket(iPosition.comment); + if (parentTicket == ticket) + { + // + Add( + iPosition, + supportPositions); + } + } + } + } + + // + int supportPositionsCount = ArraySize(supportPositions); + if (supportPositionsCount > 0) + { + // + pack.supportPositionsCount = supportPositionsCount; + + // + Copy( + supportPositions, + pack.supportPositions); + } + + // + result = supportOrdersCount > 0 || supportPositionsCount > 0; + + // + return result; + } + + // + // Extract Specific Deals Position's Pack ... + // this used when a Position SL or TP triggered and we want to close + // all it's Supported Packs ... + bool GetDealPack( + const XDeal &deal, + XPositionPack &pack) + { + // + bool result = false; + + // + ulong ticket = deal.positionId; + ENUM_TIMEFRAMES dealPeriod = GetDealPeriod(deal); + string dealSymbol = deal.symbol; + + // + // So We Have to Get Positions Pack ... + result = GetPositionPack( + ticket, + dealSymbol, + dealPeriod, + pack); + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... +protected: + // + // Private ... + + // + // EVENTS Handlers Notifiers ... + + // + // STATE ... + void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) + { + // + int count = ArraySize(mTradeStateChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i]; + iHandler(state); + } + } + + // + // DEALS ... + void NotifyDealsChangeEvent(int changes) + { + // + int count = ArraySize(mDealsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnDealsChanged iHandler = mDealsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // ORDERS ... + void NotifyOrdersChangeEvent(int changes) + { + // + int count = ArraySize(mOrdersChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnOrdersChanged iHandler = mOrdersChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // POSITIONS ... + void NotifyPositionsChangeEvent(int changes) + { + // + int count = ArraySize(mPositionsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // TPSL ... + + // + void NotifyStopLossEvent(const XDeal &deal) + { + // + int count = ArraySize(mStopLossEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnStopLoss iHandler = mStopLossEventHandlers[i]; + iHandler(deal); + } + } + + // + void NotifyTakeProfitEvent(const XDeal &deal) + { + // + int count = ArraySize(mTakeProfitEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTakeProfit iHandler = mTakeProfitEventHandlers[i]; + iHandler(deal); + } + } + +private: + // + // using deviation, it must be in Point ... + int mSlippage; + + // + // using magic number ... + ulong mMagicNumber; + + // + // using CTrade instance ... + XSCTradeBase mTrader; + + // + // Deals Info ... + CDealInfo mDealInfo; + + // + // Order Info ... + COrderInfo mOrderInfo; + + // + // using PositionInfo instance ... + CPositionInfo mPositionInfo; + + // + // History Orders ... + CHistoryOrderInfo mHistoryOrderInfo; + + // + // ADDITIONAL Data ... + + // + string mPeriodPrefix; + + // + // START Trade Processing ... + // + + // + int mDaysForRead; + + // + // set the limits of the trade history on the global scope ... + + // + // // start date for trade history in cache ... + datetime mStartDate; + + // + // end date for trade history in cache ... + datetime mEndDate; + + // + // global OnTrade counters ... + + // + // number of active orders ... + int mOrdersCount; + + // + // number of open positions ... + int mPositionsCount; + + // + // number of deals in the trade history cache ... + int mDealsCount; + + // + // number of orders in the trade history cache ... + int mHistoryOrdersCount; + + // + // flag of counter relevance ... + bool mScanStarted; + + // + // Check Statrt Date In Trade History ... + void CheckStartDateInTradeHistory() + { + // + // initial interval, if we were to start working right now .. + datetime currStart = TimeCurrent() - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + + // + // make sure that the start limit of the trade history has not gone + // more than 1 day over the intended date ... + if (currStart - mStartDate > PeriodSeconds(PERIOD_D1)) + { + // + // correct the start date of history to be loaded in the cache ... + mStartDate = currStart; + + // + // now reload the trade history for the updated interval ... + HistorySelect(mStartDate, mEndDate); + + // + // correct the deal and order counters in history for further comparison + mHistoryOrdersCount = HistoryOrdersTotal(); + mDealsCount = HistoryDealsTotal(); + } + } + + // + // Process On Trade Context ... + void ProcessOnTradeContext( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + mEndDate = TimeCurrent(); + + // + ResetLastError(); + + // + // download trading history from the specified interval to the program cache ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current values ... + int currOrders = OrdersTotal(); + int currPositions = PositionsTotal(); + int currDeals = HistoryDealsTotal(); + int currHistoryOrders = HistoryOrdersTotal(); + + // + // Orders ... + // check if the number of active orders has been changed ... + if (currOrders != mOrdersCount) + { + // + // number of active orders has been changed ... + result.hasNewOrder = true; + result.newOrders = currOrders - mOrdersCount; + + // + // update the value ... + mOrdersCount = currOrders; + } + + // + // Positions ... + // changes in the number of open positions ... + if (currPositions != mPositionsCount) + { + // + // number of open positions has been changed ... + result.hasNewPosition = true; + result.newPositions = currPositions - mPositionsCount; + + // + // update the value ... + mPositionsCount = currPositions; + } + + // + // Deals ... + // changes in the number of deals in the trade history cache ... + if (currDeals != mDealsCount) + { + // + // number of deals in the trade history cache has been changed ... + result.hasNewDeal = true; + result.newDeals = currDeals - mDealsCount; + + // + // update the value ... + mDealsCount = currDeals; + } + + // + // History Orders ... + // changes in the number of history orders in the trade history cache ... + if (currHistoryOrders != mHistoryOrdersCount) + { + // + // number of history orders in the trade history cache has been changed ... + result.hasNewHistoryOrder = true; + result.newHistoryOrders = currHistoryOrders - mHistoryOrdersCount; + + // + // update the value ... + mHistoryOrdersCount = currHistoryOrders; + } + + // + // checking if it is necessary to change the limits of the trade history to be requested in cache ... + CheckStartDateInTradeHistory(); + } + + // + // Reset On Trade Scanner Context ... + void ResetOnTradeContext() + { + // + mEndDate = TimeCurrent(); + mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + } + + // + // Initial Context Of Trade Scanner ... + void InitOnTradeContext() + { + // + ResetLastError(); + + // + mOrdersCount = OrdersTotal(); + mPositionsCount = PositionsTotal(); + + // + // load history ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current value ... + mDealsCount = HistoryDealsTotal(); + mHistoryOrdersCount = HistoryOrdersTotal(); + + // + mScanStarted = true; + } + + // + // Deals Changed Event Handlers ... + TOnDealsChanged mDealsChangedEventHandlers[]; + + // + // Orders Changed Event Handlers ... + TOnOrdersChanged mOrdersChangedEventHandlers[]; + + // + // Positions Changed Event Handlers ... + TOnPositionsChanged mPositionsChangedEventHandlers[]; + + // + // Trade State Changed Event Handlers ... + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + // TPSL ... + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + + // + // END Trade Processing ... + // +}; + +// +// START Usefull Functions ... +// + +// +// Add Specific XPosition to Specified Array ... +void Add( + XDeal &item, + XDeal &buffer[]) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + XOrder &item, + XOrder &buffer[]) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + XPosition &item, + XPosition &buffer[]) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} + +// +// Clear All Items Inside Array ... +void Clean(XDeal &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(XOrder &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(XPosition &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} + +// +// Generate Identifier Tag ... +string GenerateTag(XSignal &info) +{ + // + string result = ""; + + // + result = info.symbol + "," + ToString(info.period); + + // + return result; +} + +// +// Convert Position to Signal ... +XSignal ToSignalInfo( + XPosition &position) +{ + // + XSignal result; + + // + result.tp = position.tp; + result.sl = position.sl; + result.type = position.type; + result.entry = position.entry; + result.symbol = position.symbol; + result.period = position.period; + result.volume = position.volume; + + // + return result; +} + +// +// AGE Calculations ... +// + +// +// Retrieve a Position Age ... +int GetAge( + XPosition &position, // Selected Position ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + position.symbol, + period, + position.openAt); + + // + return result; +} + +// +// Retrieve an Order Age ... +int GetAge( + XOrder &order, // Selected Order ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + order.smybol, + period, + order.setupAt); + + // + return result; +} + +// +// Retrieve a Deal Age ... +int GetAge( + XDeal &deal, // Selected Deal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + deal.symbol, + period, + deal.time); + + // + return result; +} + +// +// OLDEST Detection ... + +// +// Get Oldest Deal ... +int GetOldest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Deal ... +int GetYoungest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldest Order ... +int GetOldest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Order ... +int GetYoungest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldes Position ... +int GetOldest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Position ... +int GetYoungest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xdema.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Indicators/x-saherelm.x121.xdema.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xdema.mq5 rename to MQLTestWorkspace/BKPS/14030228/Documents/BKP/Indicators/x-saherelm.x121.xdema.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.xdon.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Indicators/x-saherelm.x121.xdon.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.xdon.mq5 rename to MQLTestWorkspace/BKPS/14030228/Documents/BKP/Indicators/x-saherelm.x121.xdon.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xdsr.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Indicators/x-saherelm.x121.xdsr.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xdsr.mq5 rename to MQLTestWorkspace/BKPS/14030228/Documents/BKP/Indicators/x-saherelm.x121.xdsr.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xich.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Indicators/x-saherelm.x121.xich.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xich.mq5 rename to MQLTestWorkspace/BKPS/14030228/Documents/BKP/Indicators/x-saherelm.x121.xich.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Libraries/x-saherelm.common.lib.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Libraries/x-saherelm.common.lib.mq5 new file mode 100644 index 0000000..494aae5 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Libraries/x-saherelm.common.lib.mq5 @@ -0,0 +1,5923 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: XCommon +// Description: provide all commonly used 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 + +// +// START Inputs ... +// + +// +// END Inputs ... +// + +// +// Include Models Library ... +#include "x-saherelm.models.lib.mq5" +#include "../Classes/x-saherelm.xmd5.class.mq5" + +// +// START Global Definitions: Variables, Properties and etc ... +// +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// + +// +// Detect is new Candle or not ... +bool IsNewCandle() +{ + // + bool result = false; + + // + static int barsOnChart = 0; + int currentBarsOnChart = Bars(_Symbol, _Period); + result = currentBarsOnChart > barsOnChart; + if (!result) + { + return result; + } + + // + barsOnChart = currentBarsOnChart; + result = true; + + // + return result; +} +bool IsNewCandle( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod // Trading Time Frame ... +) +{ + // + bool result = false; + + // + static string mChartTags[]; + static int mChartBars[]; + + // + string chTag = mSymbol + "," + ToString(mPeriod); + + // + int currChTagIdx = -1; + int chCountedBars = 0; + int currentBars = Bars(mSymbol, mPeriod); + + // + if (ArraySize(mChartTags) > 0) + { + // + for (int i = 0; i < ArraySize(mChartTags); i++) + { + // + string iTag = mChartTags[i]; + if (iTag != chTag) + { + continue; + } + + // + currChTagIdx = i; + break; + } + + // + if (currChTagIdx > -1) + { + chCountedBars = mChartBars[currChTagIdx]; + } + } + + // + result = currentBars > chCountedBars; + if (result) + { + // + if (currChTagIdx > -1) + { + // + mChartTags[currChTagIdx] = chTag; + mChartBars[currChTagIdx] = currentBars; + } + else + { + // + Add(chTag, mChartTags); + Add(currentBars, mChartBars); + } + } + + // + return result; +} + +// +double XNZ(double check, double val = 0) +{ + if (check == EMPTY_VALUE || check == 0) + { + return val; + } + else + { + return check; + } +} + +// +template +bool NotEmpty(T value) +{ + return value != EMPTY_VALUE; +} + +// +// Retrive Ask Price ... +double GetAsk() +{ + return SymbolInfoDouble(_Symbol, SYMBOL_ASK); +} +double GetAsk( + string symbol // selected symbol for calculations +) +{ + // + double result = SymbolInfoDouble(symbol, SYMBOL_ASK); + + // + return result; +} + +// +// Retrieve Bid Price ... +double GetBid() +{ + return SymbolInfoDouble(_Symbol, SYMBOL_BID); +} +double GetBid( + string symbol // selected symbol for calculations +) +{ + // + double result = SymbolInfoDouble(symbol, SYMBOL_BID); + + // + return result; +} + +// +// Calculate and Retrieve Spread Price ... +double GetSpread() +{ + // + double ask = GetAsk(); + double bid = GetBid(); + double result = MathAbs(ask - bid); + + // + return result; +} +double GetSpread( + string symbol // selected symbol for calculations +) +{ + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + double result = MathAbs(ask - bid); + + // + return result; +} + +// +// Get Points ... +double GetPoints() +{ + return _Point; +} +double GetPoints( + string symbol // selected symbol for calculations +) +{ + // + double result = SymbolInfoDouble(symbol, SYMBOL_POINT); + + // + return result; +} + +// +// Get Digits ... +int GetDigits() +{ + return _Digits; +} +int GetDigits( + string symbol // selected symbol for calculations +) +{ + // + int result = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); + + // + return result; +} + +// +// Get Signal Entry ... +double GetEntry( + ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + bool isLong = type == POSITION_TYPE_BUY; + result = isLong ? GetAsk() : GetBid(); + result = NormalizePrice(result); + + // + return result; +} +double GetEntry( + string symbol, // Specified Symbol + ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + bool isLong = type == POSITION_TYPE_BUY; + result = isLong ? GetAsk(symbol) : GetBid(symbol); + result = NormalizePrice(result, symbol); + + // + return result; +} + +// +// Get Signal Exit ... +double GetExit( + ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + bool isLong = type == POSITION_TYPE_BUY; + result = isLong ? GetBid() : GetAsk(); + result = NormalizePrice(result); + + // + return result; +} +double GetExit( + string symbol, // Specified Symbol + ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + bool isLong = type == POSITION_TYPE_BUY; + result = isLong ? GetBid(symbol) : GetAsk(symbol); + result = NormalizePrice(result, symbol); + + // + return result; +} + +// +// Determine a Position type is Long or not ... +bool IsLong(ENUM_POSITION_TYPE type) +{ + // + bool result = type == POSITION_TYPE_BUY; + + // + return result; +} +bool IsLong(ENUM_ORDER_TYPE type) +{ + // + bool result = type == ORDER_TYPE_BUY; + + // + return result; +} + +// +// Determine a Position type is Short or not ... +bool IsShort(ENUM_POSITION_TYPE type) +{ + // + bool result = type == POSITION_TYPE_SELL; + + // + return result; +} +bool IsShort(ENUM_ORDER_TYPE type) +{ + // + bool result = type == ORDER_TYPE_SELL; + + // + return result; +} + +// +// Get 1 Pip in Price Value ... +double GetPipPrice() +{ + // + double result = _Point; + if (_Digits == 3 || _Digits == 5) + { + result *= 10; + } + + // + return result; +} +double GetPipPrice( + string symbol // selected symbol for calculations +) +{ + // + double symbolPoint = GetPoints(symbol); + int symbolDigits = GetDigits(symbol); + + // + double result = symbolPoint; + if (symbolDigits == 3 || symbolDigits == 5) + { + result *= 10; + } + + // + return result; +} + +// +// Converts Pips To Price ... +double PipsToPrice( + int pips // pips amount +) +{ + // + int digits = GetDigits(); + double pipValue = GetPipPrice(); + double result = pips * pipValue; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} +double PipsToPrice( + double pips // pips amount +) +{ + // + int digits = GetDigits(); + double pipValue = GetPipPrice(); + double result = pips * pipValue; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} +double PipsToPrice( + string symbol, // selected symbol for calculation + int pips // pips amount +) +{ + // + int digits = GetDigits(symbol); + double pipValue = GetPipPrice(symbol); + double result = pips * pipValue; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} +double PipsToPrice( + string symbol, // selected symbol for calculation + double pips // pips amount +) +{ + // + int digits = GetDigits(symbol); + double pipValue = GetPipPrice(symbol); + double result = pips * pipValue; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +// Converts Price to Pips ... +double PriceToPips( + double price // the price amount which required to calculate +) +{ + // + int digits = GetDigits(); + double pipPrice = GetPipPrice(); + + // + double result = price / pipPrice; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} +double PriceToPips( + string symbol, // Selected Symbol + double price // the price amount which required to calculate +) +{ + // + int digits = GetDigits(symbol); + double pipPrice = GetPipPrice(symbol); + + // + double result = price / pipPrice; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +// Convert Price to Point ... +double PriceToPoint( + double price // the price amount which required to calculate +) +{ + return PriceToPoint(_Symbol, price); +} +double PriceToPoint( + string symbol, // Selected Symbol + double price // the price amount which required to calculate +) +{ + // + double result = 0; + + // + double point = GetPoints(symbol); + result = price / point; + + // + return result; +} + +// +// Converts Point to Price ... +double PointToPrice( + double points // Points Size +) +{ + return PointToPrice(_Symbol, points); +} +double PointToPrice( + string symbol, // Selected Symbol + double points // Points Size +) +{ + // + double result = 0; + + // + double point = GetPoints(symbol); + result = points * point; + + // + return result; +} + +// +// CANDLES ... + +// +// Validate Candle ... +bool IsValid( + XOHCL &candle // specified candle +) +{ + // + bool result = false; + + // + result = + // + candle.open > 0 && + candle.close > 0 && + candle.high > 0 && + candle.low > 0 + // + ; + + // + return result; +} + +// +// Get a Candle Body ... +double GetCandleBody( + XOHCL &candle // specified candle +) +{ + // + double result = 0; + + // + bool isValid = IsValid(candle); + if (!isValid) + { + return result; + } + + // + result = MathAbs(candle.open - candle.close); + + // + return result; +} + +// +// Get a Candle Range ... +double GetCandleRange( + XOHCL &candle // specified candle +) +{ + // + double result = 0; + + // + bool isValid = IsValid(candle); + if (!isValid) + { + return result; + } + + // + result = MathAbs(candle.high - candle.low); + + // + return result; +} + +// +// Get a Candle Shadow ... +double GetCandleShadow( + XOHCL &candle // specified candle +) +{ + // + double result = 0; + + // + bool isValid = IsValid(candle); + if (!isValid) + { + return 0; + } + + // + double range = GetCandleRange(candle); + double body = GetCandleBody(candle); + + // + result = MathAbs(range - body); + + // + return result; +} + +// +// Retrieve High Shadow of Candle ... +double GetCandleHighShadow( + XOHCL &candle // specified candle +) +{ + // + double result = 0; + + // + bool isValid = IsValid(candle); + if (!isValid) + { + return result; + } + + // + double upPrice = MathMax(candle.open, candle.close); + + // + result = candle.high - upPrice; + + // + return result; +} + +// +// Retrieve Low Shadow of Candle ... +double GetCandleLowShadow( + XOHCL &candle // specified candle +) +{ + // + double result = 0; + + // + bool isValid = IsValid(candle); + if (!isValid) + { + return result; + } + + // + double downPrice = MathMin(candle.open, candle.close); + + // + result = downPrice - candle.low; + + // + return result; +} + +// +// Check a Candle is Base Candle for RTM or not ... +bool IsBaseCandle( + XOHCL &candle // specified candle +) +{ + // + double range = GetCandleRange(candle); + double body = GetCandleBody(candle); + + // + bool result = body > range; + + // + return result; +} + +// +// Check Candle Body Bigger Than it's Shadow ... +bool CandleHasStrongBody(XOHCL &candle) +{ + // + double bodySize = MathAbs(candle.open - candle.close); + double shadowSize = MathAbs(candle.high - candle.low) - bodySize; + + // + bool result = bodySize > (shadowSize * 1.5); + + // + return result; +} + +// +// Detect Doji Candle ... +bool IsDojiCandle( + XOHCL &candle, // Specified Candle + double detectFactor = 0.05 // Detect Factor +) +{ + // + bool result = false; + + // + bool isValid = IsValid(candle); + if ( + !isValid || + detectFactor <= 0 || + detectFactor > 1) + { + return result; + } + + // + // Retrieve Candle Parts ... + double body = GetCandleBody(candle); + double range = GetCandleRange(candle); + double shadows = GetCandleShadow(candle); + + // + // Calculate Candle Rate ... + double factor = range * detectFactor; + double shadowFactor = (1 - detectFactor) * range; + + // + result = + // + body > 0 && + range > 0 && + factor > 0 && + shadows > 0 && + body <= factor && + shadowFactor > 0 && + shadows >= shadowFactor + // + ; + + // + return result; +} + +// +// Detect Shadows of Specific Candles must be same .. +bool IsCrossShadowCandle( + XOHCL &candle, // Specified Candle + double smoothingFactor = 0.05 // Smoothing Factor +) +{ + // + bool result = false; + + // + bool isValid = IsValid(candle); + if (!isValid || + smoothingFactor <= 0 || + smoothingFactor >= 1) + { + return result; + } + + // + // Retrieve Candle Parts ... + double body = GetCandleBody(candle); + double range = GetCandleRange(candle); + double shadows = GetCandleShadow(candle); + + // + double upBody = MathMax(candle.open, candle.close); + double downBody = MathMin(candle.open, candle.close); + + // + double upShadow = candle.high - upBody; + double downShadow = downBody - candle.low; + + // + // Calculate Candle Rate ... + double factor = range * smoothingFactor; + + // + result = + upShadow > 0 && + downShadow > 0 && + body > 0 && + range > 0 && + shadows > 0 && + ((upShadow == downShadow) || + MathAbs(upShadow - downShadow) <= factor); + + // + return result; +} + +// +// Detect a Candle Shadow Hunt Specific price or not ... +bool IsShadowHuntCandle( + XOHCL &candle, // Specified Candle + double price // Specified Price +) +{ + // + bool result = false; + + // + // Validate Args ... + bool isValid = IsValid(candle); + if (!isValid || price <= 0) + { + return result; + } + + // + double upBody = MathMax(candle.open, candle.close); + double downBody = MathMin(candle.open, candle.close); + + // + double hShadow = GetCandleHighShadow(candle); + double lShadow = GetCandleLowShadow(candle); + + // + double range = GetCandleRange(candle); + double factor = range * 0.3; + + // + bool isStrongHShadow = hShadow >= factor; + bool isStrongLShadow = lShadow >= factor; + + // + bool isPriceUp = + price >= candle.high || + price >= upBody; + + // + result = + // + isPriceUp + // + ? + // + isStrongHShadow && + (price == candle.high || + (price > upBody && price < candle.high)) + // + : + // + isStrongLShadow && + (price == candle.low || + (price < downBody && price > candle.low)) + // + ; + + // + return result; +} + +// +// Check a Candle is Bullish or not ... +bool IsBullishCandle( + XOHCL &candle // specified candle +) +{ + // + bool result = false; + + // + bool isValid = IsValid(candle); + if (!isValid) + { + return result; + } + + // + result = candle.open < candle.close; + + // + return result; +} +bool IsBullishCandle( + int bar_index // candle index +) +{ + // + bool result = false; + + // + XOHCL candle = GetCandle(bar_index); + + // + result = IsBullishCandle(candle); + + // + return result; +} +bool IsBullishCandle( + string symbol, // specify symbol + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // candle index +) +{ + // + bool result = false; + + // + XOHCL candle = GetCandle( + symbol, + mPeriod, + bar_index); + + // + result = IsBullishCandle(candle); + + // + return result; +} + +// +// Check a Candle is Bullish or not ... +bool IsBearishCandle( + XOHCL &candle // specified candle +) +{ + // + bool result = false; + + // + bool isValid = IsValid(candle); + if (!isValid) + { + return result; + } + + // + result = candle.open > candle.close; + + // + return result; +} +bool IsBearishCandle( + int bar_index // candle index +) +{ + // + bool result = false; + + // + XOHCL candle = GetCandle(bar_index); + + // + result = IsBearishCandle(candle); + + // + return result; +} +bool IsBearishCandle( + string symbol, // specify symbol + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // candle index +) +{ + // + bool result = false; + + // + XOHCL candle = GetCandle( + symbol, + mPeriod, + bar_index); + + // + result = IsBearishCandle(candle); + + // + return result; +} + +// +// Retrieve Applied Price at Specific Candle ... +double GetAppliedPrice( + XOHCL &candle, // specified candle + ENUM_APPLIED_PRICE source = PRICE_CLOSE // specified Applied To +) +{ + // + double result = EMPTY_VALUE; + + // + switch (source) + { + // + // Open ... + case PRICE_OPEN: + result = candle.open; + break; + + // + // High ... + case PRICE_HIGH: + result = candle.high; + break; + + // + // Low ... + case PRICE_LOW: + result = candle.low; + break; + + // + // Median ((High + Low) / 2) ... + case PRICE_MEDIAN: + result = (candle.high + candle.low) / 2; + break; + + // + // Typical ((High + Low + Close)/3) ... + case PRICE_TYPICAL: + result = (candle.high + candle.low + candle.close) / 3; + break; + + // + // Weighted ((High + Low + Close + Close)/4) ... + case PRICE_WEIGHTED: + result = (candle.high + candle.low + (candle.close * 2)) / 4; + break; + + // + // Close ... + default: + case PRICE_CLOSE: + result = candle.close; + break; + } + + // + return result; +} +double GetAppliedPrice( + int bar_index, // specify candle index + ENUM_APPLIED_PRICE source = PRICE_CLOSE // specified Applied To +) +{ + // + double result = EMPTY_VALUE; + + // + XOHCL candle = GetCandle(bar_index); + result = GetAppliedPrice(candle, source); + + // + return result; +} +double GetAppliedPrice( + int bar_index, // specify candle index + ENUM_SERIESMODE mode // converts Series Mode to Applied Price ... +) +{ + // + double result = 0; + + // + ENUM_APPLIED_PRICE mAppliedTo = To(mode); + result = GetAppliedPrice( + bar_index, + mAppliedTo); + + // + return result; +} + +// +template +double GetAppliedPrice(ENUM_APPLIED_PRICE tprice, T &open[], T &high[], T &low[], T &close[], int i) +{ + switch (tprice) + { + case PRICE_CLOSE: + return (close[i]); + case PRICE_OPEN: + return (open[i]); + case PRICE_HIGH: + return (high[i]); + case PRICE_LOW: + return (low[i]); + case PRICE_MEDIAN: + return ((high[i] + low[i]) / 2.0); + case PRICE_TYPICAL: + return ((high[i] + low[i] + close[i]) / 3.0); + case PRICE_WEIGHTED: + return ((high[i] + low[i] + close[i] + close[i]) / 4.0); + } + return (0); +} + +// +// Converts ... +ENUM_APPLIED_PRICE To( + ENUM_SERIESMODE mode // converts Series Mode to Applied Price ... +) +{ + // + ENUM_APPLIED_PRICE result = PRICE_CLOSE; + + // + switch (mode) + { + // + // High ... + case MODE_HIGH: + result = PRICE_HIGH; + break; + + // + // Open ... + case MODE_OPEN: + result = PRICE_OPEN; + break; + + // + // Low ... + case MODE_LOW: + result = PRICE_LOW; + break; + + // + // Close ... + // Default ... + case MODE_CLOSE: + default: + result = PRICE_CLOSE; + break; + } + + // + return result; +} + +// +// Retrieve a Candel Data ... +XOHCL GetCandle(int bar_index) +{ + // + XOHCL result = {}; + + // + double open = iOpen(_Symbol, _Period, bar_index); + double high = iHigh(_Symbol, _Period, bar_index); + double close = iClose(_Symbol, _Period, bar_index); + double low = iLow(_Symbol, _Period, bar_index); + + // + result.low = low; + result.open = open; + result.high = high; + result.close = close; + + // + return result; +} +XOHCL GetCandle( + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // specify candle index +) +{ + // + XOHCL result = {}; + + // + double open = iOpen(_Symbol, mPeriod, bar_index); + double high = iHigh(_Symbol, mPeriod, bar_index); + double close = iClose(_Symbol, mPeriod, bar_index); + double low = iLow(_Symbol, mPeriod, bar_index); + + // + result.low = low; + result.open = open; + result.high = high; + result.close = close; + + // + return result; +} +XOHCL GetCandle( + string symbol, // specify symbol + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // specify candle index +) +{ + // + XOHCL result = {}; + + // + double open = iOpen(symbol, mPeriod, bar_index); + double high = iHigh(symbol, mPeriod, bar_index); + double close = iClose(symbol, mPeriod, bar_index); + double low = iLow(symbol, mPeriod, bar_index); + + // + result.low = low; + result.open = open; + result.high = high; + result.close = close; + + // + return result; +} + +// +// Get a Series Of Candles ... +bool GetCandles( + XOHCL &result[], // Hold Result ... + string mSymbol = NULL, // Specified Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... + int mStart = 0, // Start Bar Index ... + int mCount = 1 // Specified Number of Candles ... +) +{ + // + bool mResult = false; + + // + if (mStart < 0) + { + mStart = 0; + } + + // + if (mCount <= 0) + { + mCount = 1; + } + + // + Clean(result); + + // + for (int i = mStart; i < mStart + mCount; i++) + { + // + XOHCL iC = GetCandle( + mSymbol, + mPeriod, + i); + + // + Add( + iC, + result); + } + + // + mResult = ArraySize(result) > 0; + + // + return mResult; +} + +// +// Retrieve a candle index in current timeframe inside another timeframe ... +int GetCandleBarIndex( + int bar_index, // Specify Candle index in current timeframe + ENUM_TIMEFRAMES destPeriod // Specify destination timeframe +) +{ + // + int result = -1; + + // + datetime barTime = iTime(_Symbol, _Period, bar_index); + result = iBarShift(_Symbol, destPeriod, barTime); + + // + return result; +} + +// +// Retrieve a symbol candle index in source time frame inside dest timeframe ... +int GetCandleBarIndex( + int bar_index, // Specify Candle index in current timeframe + string symbol, // Specify desired Symbol + ENUM_TIMEFRAMES sourcePeriod, // Specify bar_index timeframe + ENUM_TIMEFRAMES destPeriod // Specify destination timeframe +) +{ + // + int result = -1; + + // + datetime barTime = iTime(symbol, sourcePeriod, bar_index); + result = iBarShift(symbol, destPeriod, barTime); + + // + return result; +} + +// +// Determines a cnadle is Swing High +// or Swing Low order block ... +ENUM_X_SWING_TYPE GetCandleSwing(int bar_index) +{ + // + ENUM_X_SWING_TYPE result = X_NO_SWING; + + // + // Reading Candle Models ... + XOHCL candles[3]; + candles[0] = GetCandle(bar_index + 1); + candles[1] = GetCandle(bar_index + 2); + candles[2] = GetCandle(bar_index + 3); + + // + // Check Swing Start Candle has Strong Body ... + bool isStrongBodyCandle = CandleHasStrongBody(candles[2]); + if (!isStrongBodyCandle) + { + return result; + } + + // + // Check Swing Low Conditions ... + bool isSwingLowOrderBlock = + candles[2].low < candles[1].low && + candles[1].low < candles[0].low && + candles[2].low < candles[0].low; + if (isSwingLowOrderBlock) + { + result = X_SWING_LOW; + } + + // + // Check Swing High Conditions ... + bool isSwingHighOrderBlock = + candles[2].high > candles[1].high && + candles[1].high > candles[0].high && + candles[2].high > candles[0].high; + if (isSwingHighOrderBlock) + { + result = X_SWING_HIGH; + } + + // + return result; +} +ENUM_X_SWING_TYPE GetCandleSwing( + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // specify candle index +) +{ + // + ENUM_X_SWING_TYPE result = X_NO_SWING; + + // + // Reading Candle Models ... + XOHCL candles[3]; + candles[0] = GetCandle(mPeriod, bar_index + 1); + candles[1] = GetCandle(mPeriod, bar_index + 2); + candles[2] = GetCandle(mPeriod, bar_index + 3); + + // + // Check Swing Start Candle has Strong Body ... + bool isStrongBodyCandle = CandleHasStrongBody(candles[2]); + if (!isStrongBodyCandle) + { + return result; + } + + // + // Check Swing Low Conditions ... + bool isSwingLowOrderBlock = + candles[2].low < candles[1].low && + candles[1].low < candles[0].low && + candles[2].low < candles[0].low; + if (isSwingLowOrderBlock) + { + result = X_SWING_LOW; + } + + // + // Check Swing High Conditions ... + bool isSwingHighOrderBlock = + candles[2].high > candles[1].high && + candles[1].high > candles[0].high && + candles[2].high > candles[0].high; + if (isSwingHighOrderBlock) + { + result = X_SWING_HIGH; + } + + // + return result; +} +ENUM_X_SWING_TYPE GetCandleSwing( + string symbol, // specify symbol + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // specify candle index +) +{ + // + ENUM_X_SWING_TYPE result = X_NO_SWING; + + // + // Reading Candle Models ... + XOHCL candles[3]; + candles[0] = GetCandle(symbol, mPeriod, bar_index + 1); + candles[1] = GetCandle(symbol, mPeriod, bar_index + 2); + candles[2] = GetCandle(symbol, mPeriod, bar_index + 3); + + // + // Check Swing Start Candle has Strong Body ... + bool isStrongBodyCandle = CandleHasStrongBody(candles[2]); + if (!isStrongBodyCandle) + { + return result; + } + + // + // Check Swing Low Conditions ... + bool isSwingLowOrderBlock = + candles[2].low < candles[1].low && + candles[1].low < candles[0].low && + candles[2].low < candles[0].low; + if (isSwingLowOrderBlock) + { + result = X_SWING_LOW; + } + + // + // Check Swing High Conditions ... + bool isSwingHighOrderBlock = + candles[2].high > candles[1].high && + candles[1].high > candles[0].high && + candles[2].high > candles[0].high; + if (isSwingHighOrderBlock) + { + result = X_SWING_HIGH; + } + + // + return result; +} + +// +// Find Swing Points ... +int FindSwing( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod, // Trading Period ... + ENUM_SERIESMODE mode, // Swing Based On Price mode ... + int mLength, // Loopback ... + int bar_index // BarIndex ... +) +{ + // + int result = -1; + + // + if (StringLen(mSymbol) == 0 || (mode != MODE_HIGH && mode != MODE_LOW)) + { + return result; + } + + // + int current = bar_index; + int founded = FindNextSwing( + mSymbol, + mPeriod, + mode, + (mLength * 2) + 1, + current - mLength); + + // + while (founded != current) + { + // + current = FindNextSwing( + mSymbol, + mPeriod, + mode, + mLength, + current + 1); + + // + founded = FindNextSwing( + mSymbol, + mPeriod, + mode, + (mLength * 2) + 1, + current - mLength); + } + + // + result = current; + + // + return result; +} + +// +// Find Next Swing ... +int FindNextSwing( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod, // Trading Period ... + ENUM_SERIESMODE mode, // Swing Based On Price mode ... + int mLength, // Loopback ... + int bar_index // BarIndex ... +) +{ + // + int result = -1; + + // + if (bar_index < 0) + { + mLength += bar_index; + bar_index = 0; + } + + // + result = mode == MODE_HIGH + ? iHighest( + mSymbol, + mPeriod, + mode, + mLength, + bar_index) + : iLowest( + mSymbol, + mPeriod, + mode, + mLength, + bar_index); + + // + return result; +} + +// +// Retrieve Market Highest High ... +double GetHighestHigh( + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iHighest( + _Symbol, + _Period, + MODE_HIGH, + mLength, + bar_index); + + // + result = iHigh( + _Symbol, + _Period, + rIdx); + + // + return result; +} +double GetHighestHigh( + int mLength, // Which market Length use + int bar_index, // bar index + ENUM_SERIESMODE mode // Calculation mode +) +{ + // + double result = -1; + + // + int rIdx = iHighest( + _Symbol, + _Period, + mode, + mLength, + bar_index); + + // + result = iHigh( + _Symbol, + _Period, + rIdx); + + // + return result; +} +double GetHighestHigh( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES mPeriod, // Specified Period + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iHighest( + symbol, + mPeriod, + MODE_HIGH, + mLength, + bar_index); + + // + result = iHigh( + symbol, + mPeriod, + rIdx); + + // + return result; +} +double GetHighestHigh( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES mPeriod, // Specified Period + ENUM_SERIESMODE mode, // Calculation mode + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iHighest( + symbol, + mPeriod, + mode, + mLength, + bar_index); + + // + result = iHigh( + symbol, + mPeriod, + rIdx); + + // + return result; +} + +// +// Retrieve Market Lowest Low ... +double GetLowestLow( + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iLowest( + _Symbol, + _Period, + MODE_LOW, + mLength, + bar_index); + + // + result = iLow( + _Symbol, + _Period, + rIdx); + + // + return result; +} +double GetLowestLow( + int mLength, // Which market Length use + int bar_index, // bar index + ENUM_SERIESMODE mode // Calculation mode +) +{ + // + double result = -1; + + // + int rIdx = iLowest( + _Symbol, + _Period, + mode, + mLength, + bar_index); + + // + result = iLow( + _Symbol, + _Period, + rIdx); + + // + return result; +} +double GetLowestLow( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES mPeriod, // Specified Period + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iLowest( + symbol, + mPeriod, + MODE_LOW, + mLength, + bar_index); + + // + result = iLow( + symbol, + mPeriod, + rIdx); + + // + return result; +} +double GetLowestLow( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES mPeriod, // Specified Period + ENUM_SERIESMODE mode, // Calculation mode + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iLowest( + symbol, + mPeriod, + mode, + mLength, + bar_index); + + // + result = iLow( + symbol, + mPeriod, + rIdx); + + // + return result; +} + +// +// Find Support and Resistance for Specific Bar based on provided Buffer ... +XOHCLSupRes ExtractSupportAndResistance( + int barIndex, // Bar Index ... + const double &pivots[], // Provided Pivot Points ... + int count = 3, // Number of Requireds ... + double step = 0, // Distance between each item with it's Last Side ... + string mSymbol = NULL, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period ... +) +{ + // + if (StringLen(mSymbol) == 0 || mSymbol == NULL) + { + mSymbol = _Symbol; + } + + // + if (mPeriod == NULL) + { + mPeriod = _Period; + } + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + XOHCLSupRes result; + Clean(result.res); + Clean(result.sup); + + // + int pivotsCount = ArraySize(pivots); + if (pivotsCount <= 0) + { + return result; + } + + // + if (count <= 0 || + count > pivotsCount - 1) + { + return result; + } + + // + XOHCL cBar = GetCandle( + mSymbol, + mPeriod, + barIndex); + + // + double lastR = 0; + double tmpR[]; + + // + double lastS = 0; + double tmpS[]; + + // + // Extract Supports ... + // which prices is under low of candle ... + // + // Extract Resistance ... + // which prices is over high of candle ... + for (int i = 0; i < pivotsCount; i++) + { + // + double iFlat = pivots[i]; + + // + if (iFlat > cBar.high) + { + // + bool canAdd = + step <= 0 + ? true + : lastR == 0 || MathAbs(iFlat - lastR) >= step; + if (canAdd) + { + // + Add( + iFlat, + tmpR); + + // + lastR = iFlat; + } + } + else if (iFlat < cBar.low) + { + // + bool canAdd = + step <= 0 + ? true + : lastS == 0 || MathAbs(iFlat - lastS) >= step; + if (canAdd) + { + // + Add( + iFlat, + tmpS); + + // + lastS = iFlat; + } + } + } + + // + // Sorting Founded Resistance and Supports ... + + // + // Since Resistance Levels must be Increasing ... + ArraySort(tmpR); + + // + // Since Support Levels must be Decreasing ... + ArraySort(tmpS); + ArrayReverse(tmpS); + + // + // Fill Resistance ... + int tmpRCount = ArraySize(tmpR); + if (tmpRCount > 0) + { + // + if (tmpRCount < count) + { + // + ArrayCopy( + result.res, + tmpR); + } + else + { + // + ArrayCopy( + result.res, + tmpR, + 0, + 0, + count); + } + } + + // + // Fill Supports ... + int tmpSCount = ArraySize(tmpS); + if (tmpSCount > 0) + { + // + if (tmpSCount < count) + { + // + ArrayCopy( + result.sup, + tmpS); + } + else + { + // + ArrayCopy( + result.sup, + tmpS, + 0, + 0, + count); + } + } + + // + return result; +} + +// +// Find Support and Resistance for Specific Price based on provided Buffer ... +XOHCLSupRes ExtractSupportAndResistance( + double price, // Price ... + const double &pivots[], // Provided Pivot Points ... + int count = 3, // Number of Requireds ... + double step = 0 // Distance between each item with it's Last Side ... +) +{ + // + XOHCLSupRes result; + Clean(result.res); + Clean(result.sup); + + // + if (price <= 0) + { + return result; + } + + // + int pivotsCount = ArraySize(pivots); + if (pivotsCount <= 0) + { + return result; + } + + // + if (count <= 0 || + count > pivotsCount - 1) + { + return result; + } + + // + double lastR = 0; + double tmpR[]; + + // + double lastS = 0; + double tmpS[]; + + // + // Extract Supports ... + // which prices is under low of candle ... + // + // Extract Resistance ... + // which prices is over high of candle ... + for (int i = 0; i < pivotsCount; i++) + { + // + double iFlat = pivots[i]; + + // + if (iFlat > price) + { + // + bool canAdd = + step <= 0 + ? true + : lastR == 0 || MathAbs(iFlat - lastR) >= step; + if (canAdd) + { + // + Add( + iFlat, + tmpR); + + // + lastR = iFlat; + } + } + else if (iFlat < price) + { + // + bool canAdd = + step <= 0 + ? true + : lastS == 0 || MathAbs(iFlat - lastS) >= step; + if (canAdd) + { + // + Add( + iFlat, + tmpS); + + // + lastS = iFlat; + } + } + } + + // + // Sorting Founded Resistance and Supports ... + + // + // Since Resistance Levels must be Increasing ... + ArraySort(tmpR); + + // + // Since Support Levels must be Decreasing ... + ArraySort(tmpS); + ArrayReverse(tmpS); + + // + // Fill Resistance ... + int tmpRCount = ArraySize(tmpR); + if (tmpRCount > 0) + { + // + if (tmpRCount < count) + { + // + ArrayCopy( + result.res, + tmpR); + } + else + { + // + ArrayCopy( + result.res, + tmpR, + 0, + 0, + count); + } + } + + // + // Fill Supports ... + int tmpSCount = ArraySize(tmpS); + if (tmpSCount > 0) + { + // + if (tmpSCount < count) + { + // + ArrayCopy( + result.sup, + tmpS); + } + else + { + // + ArrayCopy( + result.sup, + tmpS, + 0, + 0, + count); + } + } + + // + return result; +} + +// +// Find a Value less than Specified ... +double FindLesserThanValue( + double value, // Specified Value ... + const double &source[], // Source ... + bool isDescend = false // Find Biggest Lesser Value ... +) +{ + // + double result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + double tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source)); + + // + ArrayCopy( + tmp, + source); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + double iValue = tmp[i]; + + // + if (iValue < value) + { + // + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find a Value less than Specified ... +double FindBiggerThanValue( + double value, // Specified Value ... + const double &source[], // Source ... + bool isDescend = false // Find Smallest Bigger Value ... +) +{ + // + double result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + double tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source)); + + // + ArrayCopy( + tmp, + source); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (!isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + double iValue = tmp[i]; + + // + if (iValue > value) + { + // + result = iValue; + break; + } + } + + // + return result; +} + +// +// Calculate Fib Level ... +double GetFibonacciLevel( + double upPrice, + double downPrice, + double level, + int direction) +{ + // + double ling = upPrice - downPrice; + double pLevel = (ling / 100) * (level * 100); + + // + double result = direction > 0 ? upPrice - pLevel : downPrice + pLevel; + result = NormalizeDouble(result, _Digits); + + // + return result; +} + +// +// Check first Cross Over second at bar_index ... +bool IsCrossOver( + const double &first[], // the buffer which check crossing over second buffer + const double &second[], // first buffer checks based on this buffer + const int bar_index // check crosses in specific index +) +{ + // + bool result = false; + + // + ArraySetAsSeries(first, true); + ArraySetAsSeries(second, true); + + // + // Validate Args ... + if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) + { + return result; + } + + // + result = first[bar_index] > second[bar_index] && + !(first[bar_index + 1] > second[bar_index + 1]); + + // + return result; +} + +// +// Check first is Over second at bar_index ... +bool IsOver( + const double &first[], // the buffer which check over second buffer + const double &second[], // first buffer checks based on this buffer + const int bar_index // check crosses in specific index +) +{ + // + bool result = false; + + // + ArraySetAsSeries(first, true); + ArraySetAsSeries(second, true); + + // + // Validate Args ... + if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) + { + return result; + } + + // + result = first[bar_index] > second[bar_index] && + first[bar_index + 1] > second[bar_index + 1]; + + // + return result; +} + +// +// Check first Cross Under second at bar_index ... +bool IsCrossUnder( + const double &first[], // the buffer which check crossing under second buffer + const double &second[], // first buffer checks based on this buffer + const int bar_index // check crosses in specific index +) +{ + // + bool result = false; + + // + ArraySetAsSeries(first, true); + ArraySetAsSeries(second, true); + + // + // Validate Args ... + if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) + { + return result; + } + + // + result = first[bar_index] < second[bar_index] && + !(first[bar_index + 1] < second[bar_index + 1]); + + // + return result; +} + +// +// Check first is Under second at bar_index ... +bool IsUnder( + const double &first[], // the buffer which check under second buffer + const double &second[], // first buffer checks based on this buffer + const int bar_index // check crosses in specific index +) +{ + // + bool result = false; + + // + ArraySetAsSeries(first, true); + ArraySetAsSeries(second, true); + + // + // Validate Args ... + if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) + { + return result; + } + + // + result = first[bar_index] < second[bar_index] && + first[bar_index + 1] < second[bar_index + 1]; + + // + return result; +} + +// +// Calculate Slope of Specified Buffer at Specified Index ... +double GetSlope( + int from, // In Past Index ... + int to, // In Past Index ... + double &buffer[]) +{ + // + double result = 0; + + // + double toValue = buffer[to]; + double fromValue = buffer[from]; + double deltaValue = toValue - fromValue; + double deltaTime = from - to; + + // + result = deltaValue / deltaTime; + + // + return result; +} + +// +// Check if a Value Increasing in Loopback ... +bool IsIncreasing( + int from, // Last Time Index + int to, // Fisr Tima Index + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + result = toValue > fromValue; + for (int i = to + 1; i <= from - 1; i++) + { + // + double iValue = buffer[i]; + bool isPassed = toValue >= iValue; + + // + bool isIIncreasing = IsIncreasing( + from, + i, + buffer); + + // + // Check Result ... + result = result && isPassed && isIIncreasing; + if (!result) + { + break; + } + } + + // + return result; +} + +// +// Check if a Value Decreasing in Loopback ... +bool IsDecreasing( + int from, // Last Time Index + int to, // Fisr Tima Index + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + result = toValue < fromValue; + for (int i = to + 1; i <= from - 1; i++) + { + // + double iValue = buffer[i]; + bool isPassed = toValue <= iValue; + + // + bool isIDecreasing = IsDecreasing( + from, + i, + buffer); + + // + // Check Result ... + result = result && isPassed && isIDecreasing; + if (!result) + { + break; + } + } + + // + return result; +} + +// +// Get Max Value of Specific Loopback of a Buffer ... +double GetMaxValue( + int mLoopback, // loopback length + double &buffer[] // the Buffer which required to search +) +{ + // + double result = 0; + + // + // Validate Args ... + if ( + mLoopback < 2 || + ArraySize(buffer) < mLoopback) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < mLoopback; i++) + { + // + double iValue = buffer[i]; + + // + result = + // + result == 0 || result < iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} + +// +// Get Min Value of Specific Loopback of a Buffer ... +double GetMinValue( + int mLoopback, // loopback length + double &buffer[] // the Buffer which required to search +) +{ + // + double result = 0; + + // + // Validate Args ... + if ( + mLoopback < 2 || + ArraySize(buffer) < mLoopback) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < mLoopback; i++) + { + // + double iValue = buffer[i]; + + // + result = + // + result == 0 || result > iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} + +// +// Calculate a Buffer's Average ... +template +double GetAverage( + T &buffer[]) +{ + // + double result = 0; + + // + int bufferCount = ArraySize(buffer); + if (bufferCount <= 0) + { + return result; + } + + // + // Calculate Summary ... + for (int i = 0; i < bufferCount; i++) + { + result += buffer[i]; + } + + // + // Calculate Average ... + result = result / bufferCount; + + // + return result; +} + +// +// Find Same Values in Array ... +void FindSameValueInBuffer( + double &result[], // Holds Result ... + double &source[], // Source ... + int verifications = 3 // Number of Consequence Repeat ... +) +{ + // + Clean(result); + + // + // TenkanSen Flats ... + int sourceCount = ArraySize(source); + if (sourceCount > verifications) + { + // + double mLast = 0; + int mVerified = 0; + for (int i = 0; i < sourceCount; i++) + { + // + double iVal = source[i]; + if (mLast == 0) + { + mLast = iVal; + } + else if (mLast == iVal) + { + mVerified++; + } + else + { + mLast = iVal; + mVerified = 0; + } + + // + if (iVal == mLast && mVerified >= verifications) + { + // + Add( + iVal, + result); + + // + mLast = 0; + mVerified = 0; + } + } + } +} + +// +bool IsInPeak( + int mLoopback, // loopback length + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + mLoopback < 2 || + ArraySize(buffer) < mLoopback + 1) + { + return result; + } + + // + int q1Length = mLoopback / 4; + int halfLength = mLoopback / 2; + int q2Length = halfLength + q1Length; + + // + double firstValue = buffer[1]; + double q1Value = buffer[q1Length]; + double q2Value = buffer[q2Length]; + double halfValue = buffer[halfLength]; + double lastValue = buffer[ArraySize(buffer) - 1]; + + // + // Peak ... + result = + // + firstValue > lastValue + // + && + // + ( + firstValue > q1Value && + firstValue > halfValue) + // + ; + + // + return result; +} + +// +bool IsInVale( + int mLoopback, // loopback length + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + mLoopback < 2 || + ArraySize(buffer) < mLoopback + 1) + { + return result; + } + + // + int q1Length = mLoopback / 4; + int halfLength = mLoopback / 2; + int q2Length = halfLength + q1Length; + + // + double firstValue = buffer[1]; + double q1Value = buffer[q1Length]; + double q2Value = buffer[q2Length]; + double halfValue = buffer[halfLength]; + double lastValue = buffer[ArraySize(buffer) - 1]; + + // + // Peak ... + result = + // + firstValue < lastValue + // + && + // + ( + firstValue < q1Value && + firstValue < halfValue) + // + ; + + // + return result; +} + +// +// Check Sharp Happens or not ... +bool IsSharpChanged( + double fromValue, // Past Value + double toValue, // Present Value + double maxValue, // Max in Range Value + double minValue // Min in Range Value +) +{ + // + bool result = false; + + // + // This Used In Increased or Decreased Sharp Detection ... + bool isIncreased = toValue > fromValue; + + // + double toFromDelta = MathAbs(toValue - fromValue); + double minMaxDelta = maxValue - minValue; + + // + result = toFromDelta >= (minMaxDelta / 3); + + // + return result; +} +bool IsSharpChanged( + int from, // Past Index in Series + int to, // Present Index in Series + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + + // + // This Used In Increased or Decreased Sharp Detection ... + bool isIncreased = toValue > fromValue; + + // + double minValue = GetMinValue( + ArraySize(buffer) - 1, + buffer); + double maxValue = GetMaxValue( + ArraySize(buffer) - 1, + buffer); + double minMaxDelta = maxValue - minValue; + + // + // Sharp Detection ... + result = IsSharpChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} +bool IsSharpChanged( + int from, // Past Bar Index + int to, // Present Bar Index + ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To +) +{ + // + bool result = false; + + // + double toValue = GetAppliedPrice( + to, + appliedPrice); + double fromValue = GetAppliedPrice( + from, + appliedPrice); + + // + int hIdx = iHighest( + _Symbol, + _Period, + MODE_HIGH, + from, + to); + double maxValue = iHigh( + _Symbol, + _Period, + hIdx); + + // + int lIdx = iLowest( + _Symbol, + _Period, + MODE_LOW, + from, + to); + double minValue = iLow( + _Symbol, + _Period, + lIdx); + + // + result = IsSharpChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} + +// +// Check InCreased Sharp Happens or not ... +bool IsSharpIncreasedChanged( + double fromValue, // Past Value + double toValue, // Present Value + double maxValue, // Max in Range Value + double minValue // Min in Range Value +) +{ + // + bool result = false; + + // + // This Used In Increased or Decreased Sharp Detection ... + bool isIncreased = toValue > fromValue; + + // + double toFromDelta = MathAbs(toValue - fromValue); + double minMaxDelta = maxValue - minValue; + + // + result = + isIncreased && + toFromDelta >= (minMaxDelta / 3); + + // + return result; +} +bool IsSharpIncreasedChanged( + int from, // Past Index in Series + int to, // Present Index in Series + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + + // + double minValue = GetMinValue( + ArraySize(buffer) - 1, + buffer); + double maxValue = GetMaxValue( + ArraySize(buffer) - 1, + buffer); + double minMaxDelta = maxValue - minValue; + + // + // Sharp Detection ... + result = IsSharpIncreasedChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} +bool IsSharpIncreasedChanged( + int from, // Past Bar Index + int to, // Present Bar Index + ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To +) +{ + // + bool result = false; + + // + double toValue = GetAppliedPrice( + to, + appliedPrice); + double fromValue = GetAppliedPrice( + from, + appliedPrice); + + // + int hIdx = iHighest( + _Symbol, + _Period, + MODE_HIGH, + from, + to); + double maxValue = iHigh( + _Symbol, + _Period, + hIdx); + + // + int lIdx = iLowest( + _Symbol, + _Period, + MODE_LOW, + from, + to); + double minValue = iLow( + _Symbol, + _Period, + lIdx); + + // + result = IsSharpIncreasedChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} + +// +// Check Decreased Sharp Happens or not ... +bool IsSharpDecreasedChanged( + double fromValue, // Past Value + double toValue, // Present Value + double maxValue, // Max in Range Value + double minValue // Min in Range Value +) +{ + // + bool result = false; + + // + // This Used In Increased or Decreased Sharp Detection ... + bool isIncreased = toValue > fromValue; + + // + double toFromDelta = MathAbs(toValue - fromValue); + double minMaxDelta = maxValue - minValue; + + // + result = + !isIncreased && + toFromDelta >= (minMaxDelta / 3); + + // + return result; +} +bool IsSharpDecreasedChanged( + int from, // Past Index in Series + int to, // Present Index in Series + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + + // + double minValue = GetMinValue( + ArraySize(buffer) - 1, + buffer); + double maxValue = GetMaxValue( + ArraySize(buffer) - 1, + buffer); + double minMaxDelta = maxValue - minValue; + + // + // Sharp Detection ... + result = IsSharpDecreasedChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} +bool IsSharpDecreasedChanged( + int from, // Past Bar Index + int to, // Present Bar Index + ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To +) +{ + // + bool result = false; + + // + double toValue = GetAppliedPrice( + to, + appliedPrice); + double fromValue = GetAppliedPrice( + from, + appliedPrice); + + // + int hIdx = iHighest( + _Symbol, + _Period, + MODE_HIGH, + from, + to); + double maxValue = iHigh( + _Symbol, + _Period, + hIdx); + + // + int lIdx = iLowest( + _Symbol, + _Period, + MODE_LOW, + from, + to); + double minValue = iLow( + _Symbol, + _Period, + lIdx); + + // + result = IsSharpDecreasedChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} + +// +void Clean(int &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(ulong &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(string &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(double &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} + +// +template +bool GetLastItem( + T &item, // Holds Result + T &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + item = buffer[bufferSize - 1]; + + // + result = true; + return result; +} + +// +void Add( + int item, // item want to add + int &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + ulong item, // item want to add + ulong &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + string item, // item want to add + string &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + double item, // item want to add + double &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + XOHCL &item, // item want to add + XOHCL &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + datetime &item, // item want to add + datetime &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} + +// +// Add an Item to a Buffer if not Exists ... +void AddIfNotExists( + double value, + double &values[], + double smoothingPoint = 3) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int valuesCount = ArraySize(values); + if (valuesCount <= 0) + { + // + Add(value, + values); + } + else + { + // + bool isExists = false; + for (int i = 0; i < valuesCount; i++) + { + // + double iVal = values[i]; + + // + double diff = MathAbs(iVal - value); + + // + if (iVal == value || diff < smoothingValue) + { + // + isExists = true; + break; + } + } + + // + if (!isExists) + { + // + Add(value, + values); + } + } +} + +// +// Add a Buffers Child to another Buffer +// if it's not Contains them ... +void AddsIfNotExists( + double &source[], + double &dest[], + double smoothingPoint = 3) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + double iSource = source[i]; + + // + AddIfNotExists( + iSource, + dest, + smoothingPoint); + } +} + +// +// Converts a Buffer to String Representation ... +string ToString( + const int &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator + +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} +string ToString( + const double &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator + +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} +string ToString( + const string &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator + +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} +string ToString( + const datetime &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} +template +string ToString(T value) +{ + return (string)value; +} + +// +// Converts String to boolean ... +bool ToBoolean(string value) +{ + // + bool result = false; + + // + if (StringLen(value) <= 0) + { + return result; + } + + // + StringToLower(value); + result = value == "true"; + + // + return result; +} + +// +// Search Array For Specific Item ... +template +int FindIndex( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + int result = -1; + + // + int count = ArraySize(buffer); + if (count <= 0) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + T iT = buffer[i]; + + // + if (iT == item) + { + // + result = i; + break; + } + } + + // + return result; +} + +// +template +bool Contains( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + bool result = false; + + // + int idx = FindIndex( + item, + buffer); + result = idx > -1; + + // + return result; +} + +// +template +bool Remove( + T item, + T &buffer[]) +{ + // + bool result = false; + + // + int itemIndex = FindIndex( + item, + buffer); + if (itemIndex < 0) + { + return result; + } + + // + result = ArrayRemove( + buffer, + itemIndex, + 1); + + // + return result; +} + +// +// Split an String Representation of an Array ... +void SplitContent( + string &result[], // Hold Result ... + string content, // Source ... + string separator = ",", // Separator ... + bool forceCleanResult = true // Clean Result ... +) +{ + // + if (forceCleanResult) + { + Clean(result); + } + + // + if (separator == NULL || StringLen(separator) == 0) + { + separator = ","; + } + + // + if (StringLen(content) == 0) + { + return; + } + + // + StringSplit( + content, + StringGetCharacter( + separator, + 0), + result); +} + +// +// Extract Data from String ... +string ExtractString( + const string source, // Source String used for Extracting + const string startString, // Expression Start String must be Unique + const string endString // Where to End Extraction, usually a Sign +) +{ + // + string result = ""; + + // + // Validate String ... + if ( + StringLen(source) == 0 || + StringLen(endString) == 0 || + StringLen(startString) == 0) + { + return result; + } + + // + // Find Start String Position ... + int sPos = StringFind( + source, + startString); + if (sPos < 0) + { + return result; + } + + // + // Find End String Position after Start String ... + int searchEndFromPos = sPos + StringLen(startString); + int ePos = StringFind( + source, + endString, + searchEndFromPos); + if (ePos < 0) + { + return result; + } + + // + // Extract Data from Source ... + int dLength = ePos - searchEndFromPos; + result = StringSubstr( + source, + searchEndFromPos, + dLength); + + // + return result; +} + +// +// Extract an Array of Contents ... +int ExtractStrings( + string &result[], // Hold Result + const string source, // Source String used for Extracting + const string startString, // Expression Start String must be Unique + const string endString // Where to End Extraction, usually a Sign +) +{ + // + int mResult = 0; + + // + Clean(result); + + // + // Validate Args ... + int sourceLength = StringLen(source); + int startLength = StringLen(startString); + int endLength = StringLen(endString); + + // + int minRequiredLength = startLength + endLength; + + // + if ( + endLength <= 0 || + startLength <= 0 || + sourceLength <= 0 || + sourceLength < minRequiredLength) + { + return mResult; + } + + // + // Make a Copy of Source for Manipulating ... + string workStr = source; + + // + // Define a Loop ... + while (StringLen(workStr) > minRequiredLength) + { + // + // Find Item ... + string item = ExtractString( + workStr, + startString, + endString); + + // + // Breakout when couldn't find anymore item ... + int itemLength = StringLen(item); + if (itemLength <= 0) + { + break; + } + + // + // Prepare Item Source String for Replacing in Work String ... + string itemSource = startString + item + endString; + + // + // Add Item to Result Array ... + Add( + item, + result); + + // + // Replace Item Soure in Work String ... + StringReplace( + workStr, + itemSource, + ""); + } + + // + // Calculate Size of Array ... + mResult = ArraySize(result); + + // + return mResult; +} + +// +// Normalize a give Volume ... +double NormalizeVolume( + double volume, // desired volume to normalize + string symbol = NULL, // Specified Symbol for Normalization + int mLength = 2 // Length of Digits +) +{ + // + double result = volume; + + // + // Normalize Symbol ... + if (StringLen(symbol) == 0) + { + symbol = _Symbol; + } + + // + // Normalize Digits ... + int digits = GetDigits(symbol); + mLength = + mLength == 0 || mLength > digits + ? digits + : MathMin(mLength, digits); + + // + // Normalize Volume ... + result = NormalizeDouble(result, mLength); + + // + double maxAvailableVolume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); + double minAvailableVolume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); + + // + // Validate Result ... + if (result > maxAvailableVolume) + { + result = maxAvailableVolume; + } + else if (result < minAvailableVolume) + { + result = minAvailableVolume; + } + + // + return result; +} + +// +// Normallize Price ... +double NormalizePrice( + double price, // desired Price for normalization + string symbol = NULL // Specified Symbol for Normalization +) +{ + // + double result = 0; + + // + // Mormalize Symbol ... + if (StringLen(symbol) == 0) + { + symbol = _Symbol; + } + + // + double tickSize = 0; + result = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE, tickSize); + + // + int digits = GetDigits(symbol); + result = NormalizeDouble(MathRound(price / tickSize) * tickSize, digits); + + // + return result; +} + +// +// Check Expert Running in Testing Mode or not ... +bool IsRunningOnTestMode() +{ + // + bool result = false; + + // + // check programm mode ... + result = MQL5InfoInteger(MQL5_TESTING); + + // + return result; +} + +// +// Calculate Volume Weighted Moving Average ... +double iVWMA( + double price, + double volume, + int period, + int i, + int bars, + int instance = 0 // +) +{ +#define ¤ instance +#ifdef _averageInstances +#define _functionInstances _averageInstances +#else #define _functionInstances 1 +#endif + struct sVwmaArrayStruct + { + double price; + double volume; + double sump; + double sumv; + }; + static sVwmaArrayStruct m_array[][_functionInstances]; + static int m_arraySize = 0; + if (m_arraySize < bars) + { + int _res = ArrayResize(m_array, bars + 500); + if (_res <= bars) + return (0); + m_arraySize = _res; + } + + // + //--- + // + + if (volume == 0) + volume = 1; + m_array[i][¤].price = volume * price; + m_array[i][¤].volume = volume; + if (i > period) + { + m_array[i][¤].sump = m_array[i - 1][¤].sump + m_array[i][¤].price - m_array[i - period][¤].price; + m_array[i][¤].sumv = m_array[i - 1][¤].sumv + volume - m_array[i - period][¤].volume; + } + else + { + m_array[i][¤].sump = m_array[i][¤].price; + m_array[i][¤].sumv = m_array[i][¤].volume; + for (int k = 1; k < period && i >= k; k++) + { + m_array[i][¤].sump += m_array[i - k][¤].price; + m_array[i][¤].sumv += m_array[i - k][¤].volume; + } + } + return (m_array[i][¤].sump / m_array[i][¤].sumv); + + // + //--- + // + +#undef ¤ #undef _functionInstances +} + +// +// Date Time Manipulation Functions ... +// + +// +// Representation of Time Struct ... +// struct MqlDateTime +// { +// int year; // Year +// int mon; // Month +// int day; // Day +// int hour; // Hour +// int min; // Minutes +// int sec; // Seconds +// int day_of_week; // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) +// int day_of_year; // Day number of the year (January 1st is assigned the number value of zero) +// }; + +// +// Converts Time to Seconds ... +ulong TimeToSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = (ulong)time; + + // + return result; +} +ulong TimeToSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToSeconds(dTime); + + // + return result; +} + +// +// Converts Seconds To Time ... +datetime SecondsToTime( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime result = (datetime)seconds; + + // + return result; +} +MqlDateTime SecondsToStruct( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime dTime = SecondsToTime(seconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Converts Time to MilliSeconds ... +ulong TimeToMilliSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = TimeToSeconds(time) * 1000; + + // + return result; +} +ulong TimeToMilliSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToMilliSeconds(dTime); + + // + return result; +} + +// +// Converts MillisSeconds to Time ... +datetime MilliSecondsToTiem( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + ulong seconds = milliSeconds / 1000; + + // + datetime result = SecondsToTime(seconds); + + // + return result; +} +MqlDateTime MilliSecondsToStruct( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + datetime dTime = MilliSecondsToTiem(milliSeconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Retrieve DateTime Structure ... +MqlDateTime GetCurrentTime() +{ + // + MqlDateTime result = {}; + + // + TimeCurrent(result); + + // + return result; +} + +// +// Retrieve Current Time as Seconds ... +ulong GetCurrentTimeAsSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Current Time as MilliSeconds ... +ulong GetCurrentTimeAsMilliSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +// Retrieve Specified Candle Time ... +datetime GetCandleTime( + string symbol = "", // Specify Symbol + ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame + int bar_index = 0 // Specify Bar Index +) +{ + // + // Validate and Normalize Args ... + + // + // Normalize Symbol ... + symbol = StringLen(symbol) == 0 + ? _Symbol + : symbol; + + // + // Normalize Period ... + period = period == NULL + ? _Period + : period; + + // + // Retrieve Bar Time ... + datetime result = iTime( + symbol, + period, + bar_index); + + // + return result; +} + +// +// Retrieve Specified Candle Time ... +ulong GetCandleTimeAsSeconds( + string symbol = "", // Specify Symbol + ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame + int bar_index = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetCandleTime( + symbol, + period, + bar_index); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Specified Candle Time ... +ulong GetCandleTimeAsMilliSeconds( + string symbol = "", // Specify Symbol + ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame + int bar_index = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetCandleTime( + symbol, + period, + bar_index); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +// Retrieve a Candle Time Structure ... +MqlDateTime GetCandleTimeStruct( + string symbol = "", // Specify Symbol + ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame + int bar_index = 0 // Specify Bar Index +) +{ + // + MqlDateTime result = {}; + + // + // Retrieve Bar Time ... + datetime barTime = GetCandleTime( + symbol, + period, + bar_index); + + // + // Convert to Structure ... + TimeToStruct(barTime, result); + + // + return result; +} + +// +// Retrieve Number of Candles in a Day ... +int GetDailyCandleCount(ENUM_TIMEFRAMES mPeriod) +{ + // + int seconds = PeriodSeconds(mPeriod); + + // + int daySeconds = 24 * 60 * 60; + + // + int result = daySeconds / seconds; + + // + return result; +} + +int GetDailyCandleCount() +{ + // + int result = GetDailyCandleCount(_Period); + + // + return result; +} + +// +// +// + +// +// Holds Month ... +static int xMonth = -1; + +// +// Holds Day Of Week ... +static int xDayOfWeek = -1; +static int xForWeekDay = -1; + +// +// Holds Day ... +static int xDay = -1; + +// +// Holds Hour ... +static int xHour = -1; + +// +// Reset Timing Variables ... +void ResetTiming() +{ + // + xHour = -1; + xDay = -1; + xDayOfWeek = -1; + xMonth = -1; +} + +// +// Detecting New Houre ... +bool IsNewHour() +{ + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.hour != xHour; + if (result) + { + xHour = timeStruct.hour; + } + + // + return result; +} + +// +// Detecting New Day ... +bool IsNewDay() +{ + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.day_of_year != xDay; + if (result) + { + xDay = timeStruct.day_of_year; + } + + // + return result; +} + +// +// Detecting New Week ... +bool IsNewWeek() +{ + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Week ... + // Since Week Starts From Monday in Forex World ... + // we Calculate Start of Week by 1-Monday ... + result = + xDayOfWeek == -1 && + xForWeekDay == -1 + ? true + : timeStruct.day_of_week == 1 && + timeStruct.day_of_year > xForWeekDay; + + // + xForWeekDay = timeStruct.day_of_year; + xDayOfWeek = timeStruct.day_of_week; + + // + return result; +} + +// +// Detecting End Of Week ... +bool IsWeekEnd() +{ + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check WeekEnd ... + // Since Week Starts From Monday in Forex World ... + // we Calculate End of Week by 5-Friday ... + result = + xDayOfWeek != -1 && + timeStruct.day_of_week == 5 && + timeStruct.hour == 23 && + timeStruct.min == 59 && + timeStruct.sec == 59; + + // + return result; +} + +// +// Detecting New Month ... +bool IsNewMonth() +{ + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.mon != xMonth; + if (result) + { + xMonth = timeStruct.mon; + } + + // + return result; +} + +// +// Find Hindmost Time Frame ... +ENUM_TIMEFRAMES GetHindmostTimeFrame( + ENUM_TIMEFRAMES mPeriod // Specified Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + // Normalize Period ... + if ( + mPeriod < 0 || + mPeriod == NULL) + { + mPeriod = _Period; + } + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_H4; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_H8; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_H12; + break; + + // + case PERIOD_M30: + result = PERIOD_D1; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_W1; + break; + + // + case PERIOD_H4: + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_MN1; + break; + + // + case PERIOD_H12: + result = PERIOD_MN1; + break; + + // + case PERIOD_D1: + result = PERIOD_MN1; + break; + + // + case PERIOD_W1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Find Farest Time Frame ... +ENUM_TIMEFRAMES GetFarestTimeFrame( + ENUM_TIMEFRAMES mPeriod // Specified Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + // Normalize Period ... + if ( + mPeriod < 0 || + mPeriod == NULL) + { + mPeriod = _Period; + } + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_H1; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_H2; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_H3; + break; + + // + case PERIOD_M30: + result = PERIOD_H4; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H8; + break; + + // + case PERIOD_H4: + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_D1; + break; + + // + case PERIOD_H12: + result = PERIOD_MN1; + break; + + // + case PERIOD_D1: + result = PERIOD_MN1; + break; + + // + case PERIOD_W1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Find Medium Time Frame ... +ENUM_TIMEFRAMES GetMediestTimeFrame( + ENUM_TIMEFRAMES mPeriod // Specified Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + // Normalize Period ... + if ( + mPeriod < 0 || + mPeriod == NULL) + { + mPeriod = _Period; + } + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_M12; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_M30; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_H1; + break; + + // + case PERIOD_M30: + result = PERIOD_H2; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H6; + break; + + // + case PERIOD_H4: + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_H12; + break; + + // + case PERIOD_H12: + result = PERIOD_W1; + break; + + // + case PERIOD_D1: + result = PERIOD_MN1; + break; + + // + case PERIOD_W1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Find Nearest Time Frame ... +ENUM_TIMEFRAMES GetNearestTimeFrame( + ENUM_TIMEFRAMES mPeriod // Specified Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + // Normalize Period ... + if ( + mPeriod < 0 || + mPeriod == NULL) + { + mPeriod = _Period; + } + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_M5; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_M15; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_M30; + break; + + // + case PERIOD_M30: + result = PERIOD_H1; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H4; + break; + + // + case PERIOD_H4: + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_H12; + break; + + // + case PERIOD_H12: + result = PERIOD_D1; + break; + + // + case PERIOD_D1: + result = PERIOD_W1; + break; + + // + case PERIOD_W1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Get Specific Time Frame Start Candle Time ... +datetime GetPeriodStartTime( + string mSymbol = NULL, // Specified Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... + datetime mTime = NULL // Specified Bar Time ... +) +{ + // + // Normalize Arg ... + + // + if ( + mSymbol == NULL || + StringLen(mSymbol) == 0) + { + mSymbol = _Symbol; + } + + // + if ( + mPeriod < 0 || + mPeriod == NULL) + { + mPeriod = _Period; + } + + // + if ( + mTime < 0 || + mTime == NULL) + { + mTime = TimeCurrent(); + } + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false); + + // + datetime result = iTime( + mSymbol, + mPeriod, + barIndex); + + // + return result; +} + +// +struct XCandleRemains +{ + // + int days; + int hours; + int minutes; + int seconds; +}; + +// +string ToString( + XCandleRemains &item, + string dayId = "d", + string hourId = "h", + string minuteId = "m", + string secondId = "s", + string idSeparator = ": ", + string separator = ", ", + bool ignoreZeroValues = true) +{ + // + string result = ""; + + // + // Days ... + if (!ignoreZeroValues || item.days > 0) + { + result += dayId + idSeparator + (string)item.days + separator; + } + + // + // Hours ... + if (!ignoreZeroValues || item.hours > 0) + { + // + string strHour = ToString(item.hours); + if (StringLen(strHour) == 1) + { + strHour = "0" + strHour; + } + + // + result += hourId + idSeparator + strHour + separator; + } + + // + // Minutes ... + if (!ignoreZeroValues || item.minutes > 0) + { + // + string strMinute = ToString(item.minutes); + if (StringLen(strMinute) == 1) + { + strMinute = "0" + strMinute; + } + + // + result += minuteId + idSeparator + strMinute + separator; + } + + // + // Seconds ... + if (!ignoreZeroValues || item.seconds > 0) + { + // + string strSec = ToString(item.seconds); + if (StringLen(strSec) == 1) + { + strSec = "0" + strSec; + } + + // + result += secondId + idSeparator + strSec; + } + + // + return result; +} + +// +// Retrieve Specific Candles Ramained Time ... +void GetCandleRemainsTime( + XCandleRemains &result, // Holds Result ... + string mSymbol = NULL, // Specified Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... + int mBarIndex = 0 // Specified Bar Index ... +) +{ + // + int minuteSecoonds = 60; + int hourSeconds = minuteSecoonds * 60; + int daySeconds = 24 * hourSeconds; + + // + int periodSeconds = PeriodSeconds( + mPeriod); + datetime startTime = GetCandleTime( + mSymbol, + mPeriod, + mBarIndex); + + // + int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent(); + + // + int days = 0; + int hours = 0; + int minutes = 0; + int seconds = 0; + + // + int mWorkingSecondsDiff = secondsDiff; + if (mWorkingSecondsDiff > daySeconds) + { + // + days = mWorkingSecondsDiff / daySeconds; + mWorkingSecondsDiff -= days * daySeconds; + } + if (mWorkingSecondsDiff > hourSeconds) + { + // + hours = mWorkingSecondsDiff / hourSeconds; + mWorkingSecondsDiff -= hours * hourSeconds; + } + if (mWorkingSecondsDiff > minuteSecoonds) + { + // + minutes = mWorkingSecondsDiff / minuteSecoonds; + mWorkingSecondsDiff -= minutes * minuteSecoonds; + } + seconds = mWorkingSecondsDiff; + + // + result.days = days; + result.hours = hours; + result.minutes = minutes; + result.seconds = seconds; +} + +// +// Converts an String to TimeFrame ... +ENUM_TIMEFRAMES ToPeriod(string value) +{ + // + if (StringLen(value) == 0) + { + return _Period; + } + + // + StringTrimLeft(value); + StringTrimRight(value); + + // + ENUM_TIMEFRAMES result = _Period; + + // + if (value == "M1") + { + result = PERIOD_M1; + } + else if (value == "M2") + { + result = PERIOD_M2; + } + else if (value == "M3") + { + result = PERIOD_M3; + } + else if (value == "M4") + { + result = PERIOD_M4; + } + else if (value == "M5") + { + result = PERIOD_M5; + } + else if (value == "M6") + { + result = PERIOD_M6; + } + else if (value == "M10") + { + result = PERIOD_M10; + } + else if (value == "M12") + { + result = PERIOD_M12; + } + else if (value == "M15") + { + result = PERIOD_M15; + } + else if (value == "M20") + { + result = PERIOD_M20; + } + else if (value == "M30") + { + result = PERIOD_M30; + } + else if (value == "H1") + { + result = PERIOD_H1; + } + else if (value == "H2") + { + result = PERIOD_H2; + } + else if (value == "H3") + { + result = PERIOD_H3; + } + else if (value == "H4") + { + result = PERIOD_H4; + } + else if (value == "H6") + { + result = PERIOD_H6; + } + else if (value == "H8") + { + result = PERIOD_H8; + } + else if (value == "H12") + { + result = PERIOD_H12; + } + else if (value == "D1") + { + result = PERIOD_D1; + } + else if (value == "W1") + { + result = PERIOD_W1; + } + else if (value == "MN1") + { + result = PERIOD_MN1; + } + + // + return result; +} + +// +// Converts Period to String ... +string ToString(ENUM_TIMEFRAMES period) +{ + // + string result = ""; + + // + string mPStr = EnumToString(period); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[1]; + + // + return result; +} + +// +// Converts an String to it's related Market Cycle ... +ENUM_X_MARKET_CYCLES ToCycle(string value) +{ + // + ENUM_X_MARKET_CYCLES result = X_MARKET_CYCLE_UNKNOWN; + + // + ENUM_X_MARKET_CYCLES cycles[]; + int count = GetAllMarketCycles(cycles); + for (int i = 0; i < count; i++) + { + // + ENUM_X_MARKET_CYCLES iCycle = cycles[i]; + string iStr = ToString(iCycle); + + // + if (value == iStr) + { + // + result = iCycle; + break; + } + } + + // + return result; +} + +// +// Converts a Cycle to it's String Representation ... +string ToString(ENUM_X_MARKET_CYCLES cycle) +{ + // + string result = ""; + + // + string mPStr = EnumToString(cycle); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[3]; + + // + return result; +} + +// +// Retrieve all Available Cycles ... +int GetAllMarketCycles(ENUM_X_MARKET_CYCLES &result[]) +{ + // + int mResult = 0; + + // + Clean(result); + + // + ENUM_X_MARKET_CYCLES tmp[] = { + X_MARKET_CYCLE_UNKNOWN, + X_MARKET_CYCLE_SHORT, + X_MARKET_CYCLE_MEDIUM, + X_MARKET_CYCLE_LONG, + X_MARKET_CYCLE_HIND}; + + // + Copy( + tmp, + result); + + // + Clean(tmp); + + // + mResult = ArraySize(result); + + // + return mResult; +} + +// +// CYCLES ... +struct XMarketCycle +{ + // + string prefix; // Prefix Trag ... + + // + string symbol; // Market Symbol ... + + // + ENUM_TIMEFRAMES period; // Period of Cycle ... + ENUM_X_PERIOD_METHOD method; // Period Selection Method ... + ENUM_X_MARKET_CYCLES cycle; // Cycles of MArket ... + + // + int seconds; // Number of Seconds ... + XOHCL bar; // Current Candle of Cycle ... + XCandleRemains remains; // Remains Data of current Candle ... + datetime start; // Start Date of Current Candle ... + datetime next; // Next Candle Start Date ... + + // + int length; // Number Of Candles per Current Time Frame ... + ENUM_TIMEFRAMES hostPeriod; // Current Time Frame ... + + // + datetime lastStart; // Last Candle Bar Time ... + + // + // Constructor ... + XMarketCycle() + { + // + Clean(); + } + + // + // Check Structure Valid ... + bool IsValid() + { + // + bool result = false; + + // + result = IsValidCycle( + method, + period); + if (!result) + { + return result; + } + + // + result = + // + symbol != NULL && + period != NULL && + hostPeriod != NULL && + method != NULL && method != X_PERIOD_NOTHING && + seconds > 0 && + length > 0 + // + ; + + // + return result; + } + + // + // Init Cycle ... + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + int mHostBarIndex = 0, // Specified Host Period Bar Index + string mPrefix = "" // Prefix + ) + { + // + bool result = false; + + // + result = mCycle != NULL && mCycle != X_MARKET_CYCLE_UNKNOWN; + if (!result) + { + return result; + } + + // + this.cycle = mCycle; + + // + // Set Automatically Prefix ... + if (StringLen(mPrefix) == 0) + { + this.prefix = ToString(cycle); + } + + // + result = IsValidCycle( + method, + period // + ); + if (!result) + { + return result; + } + + // + this.symbol = mSymbol; + this.hostPeriod = mHostPeriod; + + // + // Find Cycle Period ... + if (method == X_PERIOD_AUTO) + { + // + // Select Period ... + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + // + this.period = GetNearestTimeFrame(mHostPeriod); + break; + + // + case X_MARKET_CYCLE_MEDIUM: + this.period = GetMediestTimeFrame(mHostPeriod); + break; + + // + case X_MARKET_CYCLE_LONG: + this.period = GetFarestTimeFrame(mHostPeriod); + break; + + // + case X_MARKET_CYCLE_HIND: + this.period = GetHindmostTimeFrame(mHostPeriod); + break; + } + } + + // + // Set Prefix if Provided ... + if (StringLen(mPrefix) > 0) + { + this.prefix = mPrefix; + } + + // + // Calculate Required Info ... + + // + // Seconds ... + this.seconds = PeriodSeconds(this.period); + + // + // Length ... + int hostPeriodSeconds = PeriodSeconds(this.hostPeriod); + this.length = this.seconds / hostPeriodSeconds; + + // + // Update Additional Data ... + result = this.Update(mHostBarIndex); + + // + return result; + } + + // + // Update Market Cycle Additional Info ... + bool Update(int hostBarIndex) + { + // + bool result = false; + + // + result = this.IsValid(); + if (!result) + { + return result; + } + + // + int barIndex = GetBarIndex(hostBarIndex); + + // + // Retrieve Current Candle ... + this.bar = GetCandle( + this.symbol, + this.period, + barIndex // + ); + + // + if (this.start != 0 && this.start != NULL) + { + this.lastStart = this.start; + } + + // + this.start = GetCandleTime( + this.symbol, + this.period, + barIndex // + ); + + // + if (this.lastStart == 0 || this.lastStart == NULL) + { + this.lastStart = this.start; + } + + // + this.next = this.start + this.seconds; + + // + // Retrieve Candle Remains ... + GetCandleRemainsTime( + this.remains, + this.symbol, + this.period, + barIndex // + ); + + // + return result; + } + + // + // Create and String Representation for Unique Taging ... + string ToString() + { + // + string result = ""; + + // + if (!this.IsValid()) + { + return result; + } + + // + result = + "XMarketCycle[" + + "PRFX(" + this.prefix + ")" + + "SMBL(" + this.symbol + ")" + + "CYC(" + ToString(this.cycle) + ")" + + "PRD(" + ToString(this.period) + ")" + + "PRDHST(" + ToString(this.hostPeriod) + ")" + + "MTH(" + EnumToString(this.method) + ")" + + "]"; + + // + return result; + } + + // + // Here we Produce a Summary brief of + // state of Cycle ... + string GenerateSummary() + { + // + string result = ""; + + // + bool hasPrefix = StringLen(this.prefix) > 0 && this.prefix != ToString(this.cycle); + result += (hasPrefix ? this.prefix + "[" : "") + + ToString(this.cycle) + + (hasPrefix ? "]" : "") + "\n"; + + // + result += " - PR: " + ToString(this.period) + "\n"; + + // + result += " - State: " + (this.IsBullish() ? "Bullish" : this.IsBearish() ? "Bearish" + : "Neutural"); + + // + return result; + } + + // + // TOOLS ... + + // + void Clean() + { + // + prefix = ""; + symbol = NULL; + period = NULL; + method = NULL; + + // + seconds = 0; + start = 0; + next = 0; + + // + length = 0; + hostPeriod = NULL; + + // + lastStart = 0; + } + + // + bool IsBullish() + { + return this.bar.open < this.bar.close; + } + + // + bool IsBearish() + { + return this.bar.open > this.bar.close; + } + + // + int Bars() + { + // + return iBars( + this.symbol, + this.period // + ); + } + + // + bool IsNewBar() + { + return this.lastStart < this.start; + } + + // + // Retrieve Current Bar Index based on Host Period bar Index ... + int GetBarIndex(int barIndex) + { + // + if (barIndex < 0) + { + return 0; + } + + // + int totalBars = this.Bars(); + if (barIndex >= totalBars) + { + return totalBars - 1; + } + + // + datetime hostBarTime = iTime( + this.symbol, + this.hostPeriod, + barIndex); + + // + int result = iBarShift( + this.symbol, + this.period, + hostBarTime); + + // + return result; + } + + // + // Retrieve Current Cycles Specific Bar ... + XOHCL GetBar(int barIndex) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int totalBars = Bars(); + if (barIndex >= totalBars) + { + barIndex = totalBars - 1; + } + + // + XOHCL result = GetCandle( + this.symbol, + this.period, + barIndex + // + ); + + // + return result; + } + + // + // Retrieve Bar Time ... + datetime GetBarTime(int barIndex) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int totalBars = Bars(); + if (barIndex >= totalBars) + { + barIndex = totalBars - 1; + } + + // + datetime result = GetCandleTime( + this.symbol, + this.period, + barIndex // + ); + + // + return result; + } + + // + // TODO: Add Shadow related and other tools here ... +}; + +// +// Validate Specific Period Mode ... +bool IsValidCycle( + ENUM_X_PERIOD_METHOD mMethod, // Period Select MEthod + ENUM_TIMEFRAMES mPeriod // Period +) +{ + // + bool result = false; + + // + result = + // + mMethod == X_PERIOD_NOTHING + ? false + : mMethod == X_PERIOD_MANUALLY + ? mPeriod != NULL + : mMethod == X_PERIOD_AUTO + ? true + : false + // + ; + + // + return result; +} + +// +// TYPES ... +// + +// +// Retrieve Specific Object Types Name ... +template +string GetTypeName(const T &t) +{ + return typename(T); +} + +// +// TAGGING ... +template +string GenerateTag( + T &model) +{ + // + string result = ""; + + // + string tag = model.ToString(); + if (StringLen(tag) == 0) + { + return result; + } + + // + static XSCMD5 md5; + + // + result = md5.Hash(tag); + + // + return result; +} + +// +// Hash Specified Content ... +template +string ToMD5(T content) +{ + // + string result = ""; + + // + string strContent = ToString(content); + if (StringLen(strContent) == 0) + { + return result; + } + + // + static XSCMD5 md5; + + // + result = md5.Hash(strContent); + + // + return result; +} + +// +// SIGNAL ... + +// +// Do All Normalization on Specific Signal ... +void NormalizeSignal(XSignal &signal) +{ + // + // ENTRY ... + if (signal.entry > 0) + { + signal.entry = NormalizePrice(signal.entry, signal.symbol); + } + + // + // TP ... + if (signal.tp > 0) + { + signal.tp = NormalizePrice(signal.tp, signal.symbol); + } + + // + // SL ... + if (signal.sl > 0) + { + signal.sl = NormalizePrice(signal.sl, signal.symbol); + } + + // + // VOLUME ... + if (signal.volume > 0) + { + signal.volume = NormalizeVolume(signal.volume, signal.symbol); + } +} + +// +// Prepare Base Signal ... +XSignal CreateSignal( + string symbol, // Trading Symbol ... + ENUM_TIMEFRAMES period, // Trading Time Frame ... + ENUM_POSITION_TYPE type, // Position Type ... + ENUM_X_ORDER_MODES mode, // Order Execution Mode ...Ù‘ + double entry, // Signal Entry Execution ... + double volume, // Volume ... + double tp = 0, // TP ... + double sl = 0 // SL ... +) +{ + // + XSignal result; + Clean(result); + + // + result.tp = tp; + result.sl = sl; + result.type = type; + result.mode = mode; + result.entry = entry; + result.period = period; + result.symbol = symbol; + result.volume = volume; + + // + NormalizeSignal(result); + + // + return result; +} + +// +// Find Changes ... +bool HandleValueChanged( + XValueChanged &holder[], // Change Holder Buffer ... + const double &state[], // Data State Buffer ... + const double &source[], // Data Source Buffer ... + datetime time = 0, // Checking Time ... + int resizeHolder = 100 // Resize Holder if had More than it ... +) +{ + // + bool result = false; + + // + if (time <= 0) + { + time = TimeCurrent(); + } + + // + if (ArraySize(source) <= 1) + { + return result; + } + + // + double from = source[1]; + double to = source[0]; + + // + result = + to != from && to != EMPTY_VALUE && + state[0] != state[1] && state[0] != EMPTY_VALUE; + if (result) + { + return result; + } + + // + XValueChanged lastChange; + bool hasLastChange = + GetLastItem( + lastChange, + holder); + result = + !hasLastChange + ? true + : lastChange.at < time && + lastChange.to != to && + lastChange.from != from; + if (!result) + { + return result; + } + + // + // Handle Resizing ... + if (resizeHolder > 0) + { + // + int holderCount = ArraySize(holder); + if (holderCount >= resizeHolder) + { + // + Clean(holder); + + // + Add( + lastChange, + holder); + } + } + + // + // Create a Model for add ... + lastChange.to = to; + lastChange.at = time; + lastChange.from = from; + + // + Add( + lastChange, + holder); + + // + return result; +} + +// +// END Provided Functions ... +// diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Libraries/x-saherelm.seriallizer.lib.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Libraries/x-saherelm.seriallizer.lib.mq5 new file mode 100644 index 0000000..2cf5e9a --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/Libraries/x-saherelm.seriallizer.lib.mq5 @@ -0,0 +1,603 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XSeriallizer +// Description: provides Seriallizing EA abilities ... +// +// +// 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 + +// +#include "../Libraries/x-saherelm.models.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" + +// +string XProviderToken = "PRV"; +string XSupportToken = "SP"; +string XSLTrailToken = "SLT"; +string XPeriodToken = "PR"; + +// +string XConfigToken = "XPV"; +string XItemSeparator = "|"; +string XItemContentSeparator = ","; + +// +string XFirstGenToken = "0"; + +// +// PERIOD ... + +// +// Detect a Comment has period or not ... +bool HasPeriod(string comment) +{ + // + bool result = false; + + // + if (StringLen(comment) == 0) + { + return result; + } + + // + int tokenPos = StringFind( + comment, + XPeriodToken); + result = tokenPos >= 0; + + // + return result; +} + +// +// Extract Period String ... +string ExtractPeriodString(string comment) +{ + // + string result = ""; + + // + bool hasPeriod = HasPeriod(comment); + if (!hasPeriod) + { + return result; + } + + // + result = ExtractString( + comment, + XPeriodToken + "(", + ")"); + + // + return result; +} + +// +// Extract Time Frame From Comment ... +ENUM_TIMEFRAMES ExtractPeriod(string comment) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + if (StringLen(comment) <= 0) + { + return result; + } + + // + string periodStr = ExtractPeriodString(comment); + if (StringLen(periodStr) <= 0) + { + return result; + } + + // + result = ToPeriod(periodStr); + + // + return result; +} + +// +// PROVIDER ... + +// +// Extract a Provider name if exists from a Comment ... +string ExtractProvider(string comment) +{ + // + string result = ""; + if (StringLen(comment) <= 0) + { + return result; + } + + // + result = ExtractString( + comment, + XProviderToken + "(", + ")"); + + // + return result; +} + +// +// Generate Provider String for Using in Positions Comment ... +// NOTE: if there is more than One Provider, it takes first +// provider as main and the others used to increase volume ... +string GenerateProvidersString(XSignal &signal) +{ + // + string result = ""; + + // + int providersCount = ArraySize(signal.providers); + if (providersCount <= 0) + { + return result; + } + + // + result = XProviderToken + "(" + signal.providers[0] + ")"; + + // + return result; +} + +// +// SLTRAIL ... + +// +string GenerateSLTrailComment(int level) +{ + // + string result = ""; + + // + if (level <= 0) + { + return result; + } + + // + result = XSLTrailToken + "(" + ToString(level) + ")"; + + // + return result; +} + +// +int ExtractSLTrailLevel(string comment) +{ + // + int result = 0; + + // + if (StringLen(comment) == 0) + { + return result; + } + + // + string levelStr = ExtractString( + comment, + XSLTrailToken + "(", + ")"); + if (StringLen(levelStr) == 0) + { + return result; + } + + // + result = (int)levelStr; + + // + return result; +} + +// +string PrepareSLTrailComment( + const string comment // Original Position Comment ... +) +{ + // + string result = ""; + + // + if (StringLen(comment) == 0) + { + return result; + } + + // + int level = 0; + result = comment; + + // + // Check Comment Contains SL Trailing or not ... + int lastTrailLevel = ExtractSLTrailLevel(comment); + if (lastTrailLevel <= 0) + { + level++; + } + else + { + // + level = lastTrailLevel + 1; + string lastLevelStr = GenerateSLTrailComment(lastTrailLevel); + StringReplace( + result, + lastLevelStr, + ""); + } + + // + // Generate level Comment ... + string levelStr = GenerateSLTrailComment(level); + result += levelStr; + + // + return result; +} + +// +// SUPPORT ... + +// +// Generate Specific Position's Support Comment +// index is number of Supports ... +string GenerateSupportSignalComment( + ulong ticket, // Position/Order Ticket + int index // Support Index ... +) +{ + // + string result = ""; + + // + result = XSupportToken + "(" + (string)ticket + "," + ToString(index) + ")"; + + // + return result; +} + +// +// Extract Support Parameters String from specified Comment ... +string ExtractSupportParam(string comment) +{ + // + string result = ""; + if (StringLen(comment) <= 0) + { + return result; + } + + // + result = ExtractString( + comment, + XSupportToken + "(", + ")"); + + // + return result; +} + +// +// Extract Support Info as String array for Specific Comment ... +bool ExtractSupportParams( + string comment, // Specified Comment ... + string ¶ms[] // Hold Result ... +) +{ + // + bool result = false; + + // + string supParam = ExtractSupportParam(comment); + if (StringLen(supParam) == 0) + { + return result; + } + + // + SplitContent( + params, + supParam); + int paramsCount = ArraySize(params); + + // + result = paramsCount == 2; + + // + return result; +} + +// +// Extract Support Parent Ticket ... +ulong ExtractParentTicket(string comment) +{ + // + ulong result = 0; + + // + string params[]; + bool isSupport = ExtractSupportParams( + comment, + params); + if (!isSupport) + { + return result; + } + + // + result = (ulong)params[0]; + + // + return result; +} + +// +// Extract Support Index ... +int ExtractSupportIndex(string comment) +{ + // + int result = -1; + + // + string params[]; + bool isSupport = ExtractSupportParams( + comment, + params); + if (!isSupport) + { + return result; + } + + // + result = (int)params[1]; + + // + return result; +} + +// +// START XEQM Support ... +// + +// +string XEQMSupportToken = "XEQM"; + +// +// Generate String Tag for EQM Support Signals ... +string GenerateXEQMSupportComment() +{ + // + string result = XEQMSupportToken; + + // + return result; +} + +// +// Check a Comment belongs to a EQM Support or not ... +bool IsEQMSupport(string comment) +{ + // + bool result = false; + + // + if (StringLen(comment) <= 0) + { + return result; + } + + // + int tokenPosition = StringFind( + comment, + XEQMSupportToken); + result = tokenPosition >= 0; + + // + return result; +} + +// +// Select EQM Support Orders ... +int GetEQMSupportOrders( + XOrder &supports[], // Hold Result ... + XOrder &orders[], // List of All Orders ... + ENUM_TIMEFRAMES period = NULL // Specified Period ... +) +{ + // + int result = 0; + + // + // Cleanup Array ... + Clean(supports); + + // + // Count Orders ... + int ordersCount = ArraySize(orders); + if (ordersCount <= 0) + { + return result; + } + + // + // Loop through Orders ... + for (int i = 0; i < ordersCount; i++) + { + // + // Select Indexed Order ... + XOrder iOrder = orders[i]; + + // + // Check Order is Support or not ... + bool isSupport = IsEQMSupport(iOrder.comment); + if (!isSupport) + { + continue; + } + + // + // Check Order is not Triggered ... + if (iOrder.state != ORDER_STATE_PLACED) + { + continue; + } + + // + // Check Period ... + if (period != NULL && iOrder.period != period) + { + continue; + } + + // + // we now sure this order is EQM Support ... + Add( + iOrder, + supports); + } + + // + // Count Result ... + result = ArraySize(supports); + + // + return result; +} + +// +// Select EQM Support Positions ... +int GetEQMSupportPositions( + XPosition &supports[], // Hold Result ... + XPosition &positions[], // List of All Positions ... + ENUM_TIMEFRAMES period = NULL // Specified Period ... +) +{ + // + int result = 0; + + // + // Cleanup Array ... + Clean(supports); + + // + // Count Positions ... + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + // Loop through Positions ... + for (int i = 0; i < positionsCount; i++) + { + // + // Select Indexed Position ... + XPosition iPosition = positions[i]; + + // + // Check Position is Support or not ... + bool isSupport = IsEQMSupport(iPosition.comment); + if (!isSupport) + { + continue; + } + + // + // Check Period ... + if (period != NULL && iPosition.period != period) + { + continue; + } + + // + // we now sure this order is EQM Support ... + Add( + iPosition, + supports); + } + + // + // Count Result ... + result = ArraySize(supports); + + // + return result; +} + +// +// END XEQM Support ... +// + +// +// START FirstGen ... +// + +// +string GenerateFirstGenIdentifier(const string signaller) +{ + // + string result = ""; + + // + if (StringLen(signaller) <= 0) + { + return result; + } + + // + return signaller + XFirstGenToken; + + // + return result; +} + +// +bool IsFirstGenOf( + const string signaller, // Specified Signaller + const string comment // Comment +) +{ + // + bool result = false; + + // + string id = GenerateFirstGenIdentifier(signaller); + + // + int idPos = StringFind( + comment, + id + ); + result = idPos >= 0; + + // + return result; +} + +// +// END FirstGen ... +// \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/ZigZag_1.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/ZigZag_1.mq5 new file mode 100644 index 0000000..4fa9c6d --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/ZigZag_1.mq5 @@ -0,0 +1,294 @@ +//+------------------------------------------------------------------+ +//| ZigZag.mq5 | +//| Copyright 2000-2024, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2000-2024, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#property indicator_chart_window +#property indicator_buffers 3 +#property indicator_plots 1 +//--- plot ZigZag +#property indicator_label1 "ZigZag" +#property indicator_type1 DRAW_SECTION +#property indicator_color1 clrYellow +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 +//--- input parameters +input int InpDepth =12; // Depth +input int InpDeviation=5; // Deviation +input int InpBackstep =3; // Back Step +//--- indicator buffers +double ZigZagBuffer[]; // main buffer +double HighMapBuffer[]; // ZigZag high extremes (peaks) +double LowMapBuffer[]; // ZigZag low extremes (bottoms) + +int ExtRecalc=3; // number of last extremes for recalculation + +enum EnSearchMode + { + Extremum=0, // searching for the first extremum + Peak=1, // searching for the next ZigZag peak + Bottom=-1 // searching for the next ZigZag bottom + }; +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ZigZagBuffer,INDICATOR_DATA); + SetIndexBuffer(1,HighMapBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,LowMapBuffer,INDICATOR_CALCULATIONS); +//--- set short name and digits + string short_name=StringFormat("ZigZag(%d,%d,%d)",InpDepth,InpDeviation,InpBackstep); + IndicatorSetString(INDICATOR_SHORTNAME,short_name); + PlotIndexSetString(0,PLOT_LABEL,short_name); + IndicatorSetInteger(INDICATOR_DIGITS,_Digits); +//--- set an empty value + PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); + } +//+------------------------------------------------------------------+ +//| ZigZag calculation | +//+------------------------------------------------------------------+ +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[]) + { + if(rates_total<100) + return(0); +//--- + int i=0; + int start=0,extreme_counter=0,extreme_search=Extremum; + int shift=0,back=0,last_high_pos=0,last_low_pos=0; + double val=0,res=0; + double curlow=0,curhigh=0,last_high=0,last_low=0; +//--- initializing + if(prev_calculated==0) + { + ArrayInitialize(ZigZagBuffer,0.0); + ArrayInitialize(HighMapBuffer,0.0); + ArrayInitialize(LowMapBuffer,0.0); + start=InpDepth; + } + +//--- ZigZag was already calculated before + if(prev_calculated>0) + { + i=rates_total-1; + //--- searching for the third extremum from the last uncompleted bar + while(extreme_counterrates_total-100) + { + res=ZigZagBuffer[i]; + if(res!=0.0) + extreme_counter++; + i--; + } + i++; + start=i; + + //--- what type of exremum we search for + if(LowMapBuffer[i]!=0.0) + { + curlow=LowMapBuffer[i]; + extreme_search=Peak; + } + else + { + curhigh=HighMapBuffer[i]; + extreme_search=Bottom; + } + //--- clear indicator values + for(i=start+1; iInpDeviation*_Point) + val=0.0; + else + { + for(back=1; back<=InpBackstep; back++) + { + res=LowMapBuffer[shift-back]; + if((res!=0) && (res>val)) + LowMapBuffer[shift-back]=0.0; + } + } + } + if(low[shift]==val) + LowMapBuffer[shift]=val; + else + LowMapBuffer[shift]=0.0; + //--- high + val=high[Highest(high,InpDepth,shift)]; + if(val==last_high) + val=0.0; + else + { + last_high=val; + if((val-high[shift])>InpDeviation*_Point) + val=0.0; + else + { + for(back=1; back<=InpBackstep; back++) + { + res=HighMapBuffer[shift-back]; + if((res!=0) && (reslast_high && LowMapBuffer[shift]==0.0) + { + ZigZagBuffer[last_high_pos]=0.0; + last_high_pos=shift; + last_high=HighMapBuffer[shift]; + ZigZagBuffer[shift]=last_high; + } + if(LowMapBuffer[shift]!=0.0 && HighMapBuffer[shift]==0.0) + { + last_low=LowMapBuffer[shift]; + last_low_pos=shift; + ZigZagBuffer[shift]=last_low; + extreme_search=Peak; + } + break; + default: + return(rates_total); + } + } + +//--- return value of prev_calculated for next call + return(rates_total); + } +//+------------------------------------------------------------------+ +//| Search for the index of the highest bar | +//+------------------------------------------------------------------+ +int Highest(const double &array[],const int depth,const int start) + { + if(start<0) + return(0); + + double max=array[start]; + int index=start; +//--- start searching + for(int i=start-1; i>start-depth && i>=0; i--) + { + if(array[i]>max) + { + index=i; + max=array[i]; + } + } +//--- return index of the highest bar + return(index); + } +//+------------------------------------------------------------------+ +//| Search for the index of the lowest bar | +//+------------------------------------------------------------------+ +int Lowest(const double &array[],const int depth,const int start) + { + if(start<0) + return(0); + + double min=array[start]; + int index=start; +//--- start searching + for(int i=start-1; i>start-depth && i>=0; i--) + { + if(array[i]= 0) + { + // + ObjectDelete(StringConcatenate("CommentLabel", CommentIndex)); + CommentIndex++; + } + return; + } + + // + while (ObjectFind(StringConcatenate("CommentLabel", CommentIndex)) >= 0) + { + CommentIndex++; + } + + // + CommentLabel = StringConcatenate("CommentLabel", CommentIndex); + ObjectCreate(CommentLabel, OBJ_LABEL, 0, 0, 0); + ObjectSet(CommentLabel, OBJPROP_CORNER, 0); + ObjectSet(CommentLabel, OBJPROP_XDISTANCE, 5); + ObjectSet(CommentLabel, OBJPROP_YDISTANCE, 15 + (CommentIndex * 15)); + ObjectSetText(CommentLabel, CommentText, 10, "Tahoma", Status_Color); +} \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.models.cleanedup.lib.ex5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.models.cleanedup.lib.ex5 new file mode 100644 index 0000000..88f0bbc Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.models.cleanedup.lib.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.models.cleanedup.lib.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.models.cleanedup.lib.mq5 new file mode 100644 index 0000000..6179c9d --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.models.cleanedup.lib.mq5 @@ -0,0 +1,102 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Models Library +// --------------------------------------- +// Name: XModels +// Description: provides all required models ... +// +// +// 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 + +// +// START Inputs ... +// + +// +// END Inputs ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// + +// +// How To Calculate Static Volume ... +enum ENUM_STATIC_VOLUME_METHODS +{ + // + // Based On Deposit ... + X_STATIC_VOLUME_BASED_ON_DEPOSIT, + // + // Based On Balance ... + X_STATIC_VOLUME_BASED_ON_BALANCE, +}; + +// +// START Model Definitions ... +// + + +// +// Select Positions Type ... +enum ENUM_X_POSITION_SELECT_METHODS +{ + X_POSITION_SELECT_NONE, // None + X_POSITION_SELECT_MAX, // Max + X_POSITION_SELECT_MIN, // Min + X_POSITION_SELECT_ALL, // Min +}; + +// +// Available Guard Action ... +enum ENUM_X_GUARD_ACTIONS +{ + X_GUARD_ACTION_NOTHING, // Nothing + X_GUARD_ACTION_HEDGE, // Hedge + X_GUARD_PARTIAL_CLOSE, // Partial Close + X_GUARD_ACTION_TRAIL_STOP, // Trail StopLoss + X_GUARD_ACTION_FORCE_CLOSE, // Force Close + X_GUARD_ACTION_ADD_SUPPORT_SIGNAL, // Add Support Signal + X_GUARD_ACTION_CANCEL_PENDING_ORDERS, // Cancel Pending Orders +}; + +// +// Model Guard Info ... +struct XGuard +{ + string symbol; + string provider; + ENUM_TIMEFRAMES period; + ENUM_POSITION_TYPE type; + ENUM_X_GUARD_ACTIONS action; + + // + double dblPayLoad; + string strPayload; +}; + +// +// EXTENSION Methods ... + +// +// END Provided Functions ... +// diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.xbe.ea copy.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.xbe.ea copy.mq5 new file mode 100644 index 0000000..50537eb --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.xbe.ea copy.mq5 @@ -0,0 +1,2270 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XBEEA MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XBEEA +// Description: an Exper Advisor which used RSI and MA +// to Analyse Market ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XBEEA" +#property strict + +// // +// enum ENUM_X_DSR_BUFFERS +// { +// // +// // Short ... +// X_DSR_SC_OPEN_LINE = 0, +// X_DSR_SC_HIGH_LINE = 2, +// X_DSR_SC_CLOSE_LINE = 3, +// X_DSR_SC_LOW_LINE = 5, +// // +// // Medium ... +// X_DSR_MC_OPEN_LINE = 6, +// X_DSR_MC_HIGH_LINE = 8, +// X_DSR_MC_CLOSE_LINE = 9, +// X_DSR_MC_LOW_LINE = 11, +// // +// // Long ... +// X_DSR_LC_OPEN_LINE = 12, +// X_DSR_LC_HIGH_LINE = 14, +// X_DSR_LC_CLOSE_LINE = 15, +// X_DSR_LC_LOW_LINE = 17, +// // +// // Hind ... +// X_DSR_HC_OPEN_LINE = 18, +// X_DSR_HC_HIGH_LINE = 20, +// X_DSR_HC_CLOSE_LINE = 21, +// X_DSR_HC_LOW_LINE = 23, +// }; + +// +#define ShortName "XBEEA" + +// +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.draw.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" + +// +// Inputs ... + +// +long xBEEAMagicNumber = 78692110; // Magic Number +int xBEEASlippage = 10; // Slippgae + +// +input double xBEEAVolume = 0.01; + +// +// Indicator Inputs ... + +// +// Maarket ... +input group "Cycles"; + +// +// Short ... +input group "Short"; +input ENUM_X_PERIOD_METHOD scMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES scPeriod = PERIOD_H4; // Period + +// +// Presentation ... +input bool xBEEADrawSCLabel = true; +input bool xBEEADrawSCCBar = true; +input bool xBEEADrawSCPBar = false; +input bool xBEEADrawSCCMid = true; +input bool xBEEADrawSCPMid = true; + +// +// Medium ... +input group "Medium"; +input ENUM_X_PERIOD_METHOD mcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES mcPeriod = PERIOD_H12; // Mid Period + +// +// Presentation ... +input bool xBEEADrawMCLabel = true; +input bool xBEEADrawMCCBar = true; +input bool xBEEADrawMCPBar = false; +input bool xBEEADrawMCCMid = true; +input bool xBEEADrawMCPMid = true; + +// +// Long ... +input group "Long"; +input ENUM_X_PERIOD_METHOD lcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES lcPeriod = PERIOD_D1; // Long Period + +// +// Presentation ... +input bool xBEEADrawLCLabel = true; +input bool xBEEADrawLCCBar = true; +input bool xBEEADrawLCPBar = false; +input bool xBEEADrawLCCMid = true; +input bool xBEEADrawLCPMid = true; + +// +// Hind ... +input group "Hind"; +input ENUM_X_PERIOD_METHOD hcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES hcPeriod = PERIOD_W1; // Hind Period + +// +// Presentation ... +input bool xBEEADrawHCLabel = true; +input bool xBEEADrawHCCBar = true; +input bool xBEEADrawHCPBar = true; +input bool xBEEADrawHCCMid = true; +input bool xBEEADrawHCPMid = true; + +// +// Vars ... + +// +string xBEEASymbol; +ENUM_TIMEFRAMES xBEEAPeriod; + +// +int maxBuys = 1; +int maxSells = 1; +int buyCount = 0; +int sellCount = 0; + +// +double _tp = 0; +double _sl = 0; +double _entry = 0; +ENUM_POSITION_TYPE _type = NULL; + +// +MqlTick xBEEATick; +XSCTrade *xBEEATrader; + +// +int xZGHandler = INVALID_HANDLE; +// int xDSRHandler = INVALID_HANDLE; + +// // +// // Short ... +// double scOpenBuffer[]; +// double scHighBuffer[]; +// double scCloseBuffer[]; +// double scLowBuffer[]; + +// // +// // Medium ... +// double mcOpenBuffer[]; +// double mcHighBuffer[]; +// double mcCloseBuffer[]; +// double mcLowBuffer[]; + +// // +// // Long ... +// double lcOpenBuffer[]; +// double lcHighBuffer[]; +// double lcCloseBuffer[]; +// double lcLowBuffer[]; + +// // +// // Hind ... +// double hcOpenBuffer[]; +// double hcHighBuffer[]; +// double hcCloseBuffer[]; +// double hcLowBuffer[]; + +// +// Cycles Definitions ... + +// +XMarketCycle sc; +XDrawSpecifications scCMidSpecs; +XDrawSpecifications scPMidSpecs; +XOHCLDrawSpecification scCBSpecs; +XOHCLDrawSpecification scPBSpecs; + +// +XMarketCycle mc; +XDrawSpecifications mcCMidSpecs; +XDrawSpecifications mcPMidSpecs; +XOHCLDrawSpecification mcCBSpecs; +XOHCLDrawSpecification mcPBSpecs; + +// +XMarketCycle lc; +XDrawSpecifications lcCMidSpecs; +XDrawSpecifications lcPMidSpecs; +XOHCLDrawSpecification lcCBSpecs; +XOHCLDrawSpecification lcPBSpecs; + +// +XMarketCycle hc; +XDrawSpecifications hcCMidSpecs; +XDrawSpecifications hcPMidSpecs; +XOHCLDrawSpecification hcCBSpecs; +XOHCLDrawSpecification hcPBSpecs; + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + if (xBEEASymbol == NULL || StringLen(xBEEASymbol) <= 0) + { + xBEEASymbol = _Symbol; + } + + // + if (xBEEAPeriod == NULL) + { + xBEEAPeriod = _Period; + } + + // + // Validate Inputs ... + if (!XBEEAValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + drawPrefix = ShortName; + + // + // Initialize XTrader ... + xBEEATrader = new XSCTrade( + xBEEASlippage, + xBEEAMagicNumber); + + // + // Init Indicators ... + if (!InitIndicators()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Prepare Style Specs ... + PrepareStyleSpecs(); + + // + // TesterHideIndicators(true); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 XBEEA Providers ... + delete xBEEATrader; + + // + IndicatorRelease(xZGHandler); + // IndicatorRelease(xDSRHandler); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + if (!IsNewCandle( + xBEEASymbol, + xBEEAPeriod)) + { + return; + } + + // + // Reading Tick ... + if (!SymbolInfoTick(xBEEASymbol, xBEEATick)) + { + return; + } + + // + // Reading Data From XDSR Indicator ... + ReadData(); + + // + // Counting Currently Open Positions ... + buyCount = xBEEATrader.CountPositions(xBEEASymbol, POSITION_TYPE_BUY); + sellCount = xBEEATrader.CountPositions(xBEEASymbol, POSITION_TYPE_SELL); + + // + if (buyCount < maxBuys) + { + // + // Check For Buy Signals ... + } + + // + if (sellCount < maxSells) + { + // + // Check for Sell Signals ... + } +} + +// +// Custom Functions ... + +// +// Validate Variables nd Inputs ... +bool XBEEAValidateInputs() +{ + // + bool result = false; + + // + result = + // + xBEEASlippage > 0 && + xBEEAMagicNumber > 0 + // + && + // + // Short ... + IsValidCycle( + scMode, + scPeriod) + // + && + // + // Medium ... + IsValidCycle( + mcMode, + mcPeriod) + // + && + // + // Long ... + IsValidCycle( + lcMode, + lcPeriod) + // + && + // + // Hind ... + IsValidCycle( + hcMode, + hcPeriod) + // + ; + + // + return result; +} + +// +// Initial Indicators ... +bool InitIndicators() +{ + // + bool result = false; + + // // + // // Short ... + // ArraySetAsSeries(scOpenBuffer, true); + // ArraySetAsSeries(scHighBuffer, true); + // ArraySetAsSeries(scCloseBuffer, true); + // ArraySetAsSeries(scLowBuffer, true); + + // // + // // Medium ... + // ArraySetAsSeries(mcOpenBuffer, true); + // ArraySetAsSeries(mcHighBuffer, true); + // ArraySetAsSeries(mcCloseBuffer, true); + // ArraySetAsSeries(mcLowBuffer, true); + + // // + // // Long ... + // ArraySetAsSeries(lcOpenBuffer, true); + // ArraySetAsSeries(lcHighBuffer, true); + // ArraySetAsSeries(lcCloseBuffer, true); + // ArraySetAsSeries(lcLowBuffer, true); + + // // + // // Hind ... + // ArraySetAsSeries(hcOpenBuffer, true); + // ArraySetAsSeries(hcHighBuffer, true); + // ArraySetAsSeries(hcCloseBuffer, true); + // ArraySetAsSeries(hcLowBuffer, true); + + // // + // // Initialize XDSR Handler ... + // xDSRHandler = iCustom( + // xBEEASymbol, + // xBEEAPeriod, + // "x-saherelm.x121.xdsr", + // // + // // Inputs ... + // // + // // Cycles ... + // "", + // // + // // Short ... + // "", + // scMode, + // scPeriod, + // // + // // Medium ... + // "", + // mcMode, + // mcPeriod, + // // + // // Long ... + // "", + // lcMode, + // lcPeriod, + // // + // // Hind ... + // "", + // hcMode, + // hcPeriod + // // + // ); + // result = xDSRHandler != INVALID_HANDLE; + // if (!result) + // { + // return result; + // } + + // + // Init XZG Indicator ... + xZGHandler = iCustom( + xBEEASymbol, + xBEEAPeriod, + "x-saherelm.x121.xzg", + // + // Inputs ... + // TODO: + // add these inputs to TODO ... + 12, // Depth ... + 5, // Deviation ... + 3, // Back Step ... + 1 // MODE ENUM_X_ZG_PRICE_MODE (X_ZG_PRICE_HIGH_LOW_MODE) ... + // + ); + result = xZGHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // Here we have to Init XMarketCycles also ... + result = InitMarketCycles(); + + // + return result; +} + +// +// Initial Market Cycles ... +bool InitMarketCycles() +{ + // + bool result = false; + + // + // Short ... + sc.method = scMode; + sc.period = scPeriod; + result = sc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_SHORT // + ); + if (!result) + { + return result; + } + + // + // Medium ... + mc.method = mcMode; + mc.period = mcPeriod; + result = mc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_MEDIUM // + ); + if (!result) + { + return result; + } + + // + // Long ... + lc.method = lcMode; + lc.period = lcPeriod; + result = lc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_LONG // + ); + if (!result) + { + return result; + } + + // + // Hind ... + hc.method = hcMode; + hc.period = hcPeriod; + result = hc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_HIND // + ); + if (!result) + { + return result; + } + + // + return result; +} + +// +// Prepare Style Specs for Drawings ... +void PrepareStyleSpecs() +{ + // + // Each Cycle has 2 Kind of Specs: + // 1- MidLines; + // 2- Candles; + // + // also for each Cycle we have 2 Series of Specs: + // 1- For Current Bar; + // 2- Prev Bar; + + // + // Short ... + + // + // Current ... + + // + // MidLine ... + scCMidSpecs.width = 1; + scCMidSpecs.style = STYLE_DOT; + scCMidSpecs.clr = clrSpringGreen; + scCMidSpecs.Label( + sc.prefix + "_C MID", + scCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + scCBSpecs.Default(); + scCBSpecs.Width(1); + scCBSpecs.Style(STYLE_DOT); + // + // scCBSpecs.openStyle.clr = clrDarkOliveGreen; + // scCBSpecs.closeStyle.clr = clrDarkOrchid; + // scCBSpecs.highStyle.clr = clrDarkSeaGreen; + // scCBSpecs.lowStyle.clr = clrPink; + // + scCBSpecs.openStyle.Label( + sc.prefix + "_C O", + scCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scCBSpecs.highStyle.Label( + sc.prefix + "_C H", + scCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scCBSpecs.closeStyle.Label( + sc.prefix + "_C C", + scCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scCBSpecs.lowStyle.Label( + sc.prefix + "_C L", + scCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + scPMidSpecs.width = 2; + scPMidSpecs.style = STYLE_SOLID; + scPMidSpecs.clr = clrLimeGreen; + scPMidSpecs.Label( + sc.prefix + "_P MID", + scPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + scPBSpecs.Default(); + scPBSpecs.Width(2); + // + // scPBSpecs.openStyle.clr = ; + // scPBSpecs.closeStyle.clr = ; + // scPBSpecs.highStyle.clr = ; + // scPBSpecs.lowStyle.clr = ; + // + scPBSpecs.openStyle.Label( + sc.prefix + "_P O", + scPBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scPBSpecs.highStyle.Label( + sc.prefix + "_P H", + scPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scPBSpecs.closeStyle.Label( + sc.prefix + "_P C", + scPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scPBSpecs.lowStyle.Label( + sc.prefix + "_P L", + scPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Medium ... + + // + // Current ... + + // + // MidLine ... + mcCMidSpecs.width = 1; + mcCMidSpecs.style = STYLE_DOT; + mcCMidSpecs.clr = clrSteelBlue; + mcCMidSpecs.Label( + mc.prefix + "_C MID", + mcCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + mcCBSpecs.Default(); + mcCBSpecs.Width(1); + mcCBSpecs.Style(STYLE_DOT); + // + // mcCBSpecs.openStyle.clr = clrDarkOliveGreen; + // mcCBSpecs.closeStyle.clr = clrDarkOrchid; + // mcCBSpecs.highStyle.clr = clrDarkSeaGreen; + // mcCBSpecs.lowStyle.clr = clrPink; + // + mcCBSpecs.openStyle.Label( + mc.prefix + "_C O", + mcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcCBSpecs.highStyle.Label( + mc.prefix + "_C H", + mcCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcCBSpecs.closeStyle.Label( + mc.prefix + "_C C", + mcCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcCBSpecs.lowStyle.Label( + mc.prefix + "_C L", + mcCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + mcPMidSpecs.width = 2; + mcPMidSpecs.style = STYLE_SOLID; + mcPMidSpecs.clr = clrRoyalBlue; + mcPMidSpecs.Label( + mc.prefix + "_P MID", + mcPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + mcPBSpecs.Default(); + mcPBSpecs.Width(2); + // + // mcPBSpecs.openStyle.clr = ; + // mcPBSpecs.closeStyle.clr = ; + // mcPBSpecs.highStyle.clr = ; + // mcPBSpecs.lowStyle.clr = ; + // + mcPBSpecs.openStyle.Label( + mc.prefix + "_P O", + mcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcPBSpecs.highStyle.Label( + mc.prefix + "_P H", + mcPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcPBSpecs.closeStyle.Label( + mc.prefix + "_P C", + mcPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcPBSpecs.lowStyle.Label( + mc.prefix + "_P L", + mcPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Long ... + + // + // Current ... + + // + // MidLine ... + lcCMidSpecs.width = 1; + lcCMidSpecs.style = STYLE_DOT; + lcCMidSpecs.clr = clrYellow; + lcCMidSpecs.Label( + lc.prefix + "_C MID", + lcCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + lcCBSpecs.Default(); + lcCBSpecs.Width(1); + lcCBSpecs.Style(STYLE_DOT); + // + // lcCBSpecs.openStyle.clr = clrDarkOliveGreen; + // lcCBSpecs.closeStyle.clr = clrDarkOrchid; + // lcCBSpecs.highStyle.clr = clrDarkSeaGreen; + // lcCBSpecs.lowStyle.clr = clrPink; + // + lcCBSpecs.openStyle.Label( + lc.prefix + "_C O", + lcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcCBSpecs.highStyle.Label( + lc.prefix + "_C H", + lcCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcCBSpecs.closeStyle.Label( + lc.prefix + "_C C", + lcCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcCBSpecs.lowStyle.Label( + lc.prefix + "_C L", + lcCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + lcPMidSpecs.width = 2; + lcPMidSpecs.style = STYLE_SOLID; + lcPMidSpecs.clr = clrOrange; + lcPMidSpecs.Label( + lc.prefix + "_P MID", + lcPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + lcPBSpecs.Default(); + lcPBSpecs.Width(2); + // + // lcPBSpecs.openStyle.clr = ; + // lcPBSpecs.closeStyle.clr = ; + // lcPBSpecs.highStyle.clr = ; + // lcPBSpecs.lowStyle.clr = ; + // + lcPBSpecs.openStyle.Label( + lc.prefix + "_P O", + lcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcPBSpecs.highStyle.Label( + lc.prefix + "_P H", + lcPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcPBSpecs.closeStyle.Label( + lc.prefix + "_P C", + lcPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcPBSpecs.lowStyle.Label( + lc.prefix + "_P L", + lcPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Hind ... + + // + // Current ... + + // + // MidLine ... + hcCMidSpecs.width = 1; + hcCMidSpecs.style = STYLE_DOT; + hcCMidSpecs.clr = clrSandyBrown; + hcCMidSpecs.Label( + hc.prefix + "_C MID", + hcCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + hcCBSpecs.Default(); + hcCBSpecs.Width(1); + hcCBSpecs.Style(STYLE_DOT); + // + // hcCBSpecs.openStyle.clr = clrDarkOliveGreen; + // hcCBSpecs.closeStyle.clr = clrDarkOrchid; + // hcCBSpecs.highStyle.clr = clrDarkSeaGreen; + // hcCBSpecs.lowStyle.clr = clrPink; + // + hcCBSpecs.openStyle.Label( + hc.prefix + "_C O", + hcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcCBSpecs.highStyle.Label( + hc.prefix + "_C H", + hcCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcCBSpecs.closeStyle.Label( + hc.prefix + "_C C", + hcCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcCBSpecs.lowStyle.Label( + hc.prefix + "_C L", + hcCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + hcPMidSpecs.width = 2; + hcPMidSpecs.style = STYLE_SOLID; + hcPMidSpecs.clr = clrSaddleBrown; + hcPMidSpecs.Label( + hc.prefix + "_P MID", + hcPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + hcPBSpecs.Default(); + hcPBSpecs.Width(2); + // + // hcPBSpecs.openStyle.clr = clrDarkOliveGreen; + // hcPBSpecs.closeStyle.clr = clrDarkOrchid; + // hcPBSpecs.highStyle.clr = clrDarkSeaGreen; + // hcPBSpecs.lowStyle.clr = clrPink; + // + hcPBSpecs.openStyle.Label( + hc.prefix + "_P O", + hcPBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcPBSpecs.highStyle.Label( + hc.prefix + "_P H", + hcPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcPBSpecs.closeStyle.Label( + hc.prefix + "_P C", + hcPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcPBSpecs.lowStyle.Label( + hc.prefix + "_P L", + hcPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); +} + +// +// Reading Data From Indicators ... +void ReadData() +{ + // + int mLoopBack = 15; + + // + // Short ... + + // // + // // Open ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_SC_OPEN_LINE, + // 0, + // mLoopBack, + // scOpenBuffer // + // ); + + // // + // // High ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_SC_HIGH_LINE, + // 0, + // mLoopBack, + // scHighBuffer // + // ); + + // // + // // Close ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_SC_CLOSE_LINE, + // 0, + // mLoopBack, + // scCloseBuffer // + // ); + + // // + // // Low ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_SC_LOW_LINE, + // 0, + // mLoopBack, + // scLowBuffer // + // ); + + // // + // // Medium ... + + // // + // // Open ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_MC_OPEN_LINE, + // 0, + // mLoopBack, + // mcOpenBuffer // + // ); + + // // + // // High ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_MC_HIGH_LINE, + // 0, + // mLoopBack, + // mcHighBuffer // + // ); + + // // + // // Close ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_MC_CLOSE_LINE, + // 0, + // mLoopBack, + // mcCloseBuffer // + // ); + + // // + // // Low ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_MC_LOW_LINE, + // 0, + // mLoopBack, + // mcLowBuffer // + // ); + + // // + // // Long ... + + // // + // // Open ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_LC_OPEN_LINE, + // 0, + // mLoopBack, + // lcOpenBuffer // + // ); + + // // + // // High ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_LC_HIGH_LINE, + // 0, + // mLoopBack, + // lcHighBuffer // + // ); + + // // + // // Close ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_LC_CLOSE_LINE, + // 0, + // mLoopBack, + // lcCloseBuffer // + // ); + + // // + // // Low ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_LC_LOW_LINE, + // 0, + // mLoopBack, + // lcLowBuffer // + // ); + + // // + // // Hind ... + + // // + // // Open ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_HC_OPEN_LINE, + // 0, + // mLoopBack, + // hcOpenBuffer // + // ); + + // // + // // High ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_HC_HIGH_LINE, + // 0, + // mLoopBack, + // hcHighBuffer // + // ); + + // // + // // Close ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_HC_CLOSE_LINE, + // 0, + // mLoopBack, + // hcCloseBuffer // + // ); + + // // + // // Low ... + // CopyBuffer( + // xDSRHandler, + // X_DSR_HC_LOW_LINE, + // 0, + // mLoopBack, + // hcLowBuffer // + // ); + + // + // Update Market Cycles ... + UpdateMarketCycles(0); + + // + // Provide all Draws ... + XBEEAHandleDraws( + // + // Short ... + xBEEADrawSCLabel, + xBEEADrawSCCBar, + xBEEADrawSCPBar, + xBEEADrawSCCMid, + xBEEADrawSCPMid, + // + // Medium ... + xBEEADrawMCLabel, + xBEEADrawMCCBar, + xBEEADrawMCPBar, + xBEEADrawMCCMid, + xBEEADrawMCPMid, + // + // Long ... + xBEEADrawLCLabel, + xBEEADrawLCCBar, + xBEEADrawLCPBar, + xBEEADrawLCCMid, + xBEEADrawLCPMid, + // + // Hind ... + xBEEADrawHCLabel, + xBEEADrawHCCBar, + xBEEADrawHCPBar, + xBEEADrawHCCMid, + xBEEADrawHCPMid + // + ); +} + +// +// Update Market Cycles ... +bool UpdateMarketCycles(int barIndex) +{ + // + bool result = false; + + // + // Short ... + result = sc.Update(barIndex); + if (!result) + { + return result; + } + + // + // Medium ... + result = mc.Update(barIndex); + if (!result) + { + return result; + } + + // + // Long ... + result = lc.Update(barIndex); + if (!result) + { + return result; + } + + // + // Hind ... + result = hc.Update(barIndex); + if (!result) + { + return result; + } + + // + return result; +} + +// +// Handle All Draws of Experts ... +void XBEEAHandleDraws( + // + // Short ... + bool drawSCLabel = true, + bool drawSCCBar = true, + bool drawSCPBar = true, + bool drawSCCMid = true, + bool drawSCPMid = true, + // + // Medium ... + bool drawMCLabel = true, + bool drawMCCBar = true, + bool drawMCPBar = true, + bool drawMCCMid = true, + bool drawMCPMid = true, + // + // Long ... + bool drawLCLabel = true, + bool drawLCCBar = true, + bool drawLCPBar = true, + bool drawLCCMid = true, + bool drawLCPMid = true, + // + // Hind ... + bool drawHCLabel = true, + bool drawHCCBar = true, + bool drawHCPBar = true, + bool drawHCCMid = true, + bool drawHCPMid = true // +) +{ + // + int offset = 0; + + // + // Short ... + + // + // Cycle ... + if (drawSCCBar || drawSCPBar) + { + // + XBEEADrawCycle( + sc.cycle, + drawSCLabel, + !drawSCCBar && drawSCPBar, + !drawSCPBar && drawSCCBar, + offset + // + ); + + // + if (drawSCLabel) + { + // + if (drawSCCBar) + { + offset += 3; + } + + // + if (drawSCPBar) + { + offset += 3; + } + + // + if (drawSCCMid) + { + offset++; + } + + // + if (drawSCPMid) + { + offset++; + } + } + } + + // + // MidLine ... + if (drawSCCMid || drawSCPMid) + { + // + XBEEADrawMidLine( + sc.cycle, + drawSCLabel, + !drawSCCMid && drawSCPMid, + !drawSCPMid && drawSCCMid, + offset + // + ); + + // + if (drawSCLabel) + { + // + if (drawSCCMid) + { + offset++; + } + + // + if (drawSCPMid) + { + offset++; + } + } + } + + // + // Medium ... + + // + // Cycle ... + if (drawMCCBar || drawMCPBar) + { + // + XBEEADrawCycle( + mc.cycle, + drawMCLabel, + !drawMCCBar && drawMCPBar, + !drawMCPBar && drawMCCBar, + offset + // + ); + + // + if (drawMCLabel) + { + // + if (drawMCCBar) + { + offset += 3; + } + + // + if (drawMCPBar) + { + offset += 3; + } + + // + if (drawMCCMid) + { + offset++; + } + + // + if (drawMCPMid) + { + offset++; + } + } + } + + // + // Mid Line ... + if (drawMCCMid || drawMCPMid) + { + // + XBEEADrawMidLine( + mc.cycle, + drawMCLabel, + !drawMCCMid && drawMCPMid, + !drawMCPMid && drawMCCMid, + offset + // + ); + + // + if (drawMCLabel) + { + // + if (drawMCCMid) + { + offset++; + } + + // + if (drawMCPMid) + { + offset++; + } + } + } + + // + // Long ... + + // + // Cycle ... + if (drawLCCBar || drawLCPBar) + { + // + XBEEADrawCycle( + lc.cycle, + drawLCLabel, + !drawLCCBar && drawLCPBar, + !drawLCPBar && drawLCCBar, + offset + // + ); + + // + if (drawLCLabel) + { + // + if (drawLCCBar) + { + offset += 3; + } + + // + if (drawLCPBar) + { + offset += 3; + } + + // + if (drawLCCMid) + { + offset++; + } + + // + if (drawLCPMid) + { + offset++; + } + } + } + + // + // MidLine ... + if (drawLCCMid || drawLCPMid) + { + // + XBEEADrawMidLine( + lc.cycle, + drawLCLabel, + !drawLCCMid && drawLCPMid, + !drawLCPMid && drawLCCMid, + offset + // + ); + + // + if (drawLCLabel) + { + // + if (drawLCCMid) + { + offset++; + } + + // + if (drawLCPMid) + { + offset++; + } + } + } + + // + // Hind ... + + // + // Cycle ... + if (drawHCCBar || drawHCPBar) + { + // + XBEEADrawCycle( + hc.cycle, + drawHCLabel, + !drawHCCBar && drawHCPBar, + !drawHCPBar && drawHCCBar, + offset + // + ); + + // + if (drawHCLabel) + { + // + if (drawHCCBar) + { + offset += 3; + } + + // + if (drawHCPBar) + { + offset += 3; + } + + // + if (drawHCCMid) + { + offset++; + } + + // + if (drawHCPMid) + { + offset++; + } + } + } + + // + // MidLine ... + if (drawHCCMid || drawHCPMid) + { + // + XBEEADrawMidLine( + hc.cycle, + drawHCLabel, + !drawHCCMid && drawHCPMid, + !drawHCPMid && drawHCCMid, + offset + // + ); + } +} + +// +// Draw Middle Line of Cycle ... +void XBEEADrawCycle( + ENUM_X_MARKET_CYCLES cycle, // Specify Which Cycle to Draw ... + bool drawLabel = false, // Specify Draw Label of Mid Line or not ... + bool drawOnlyPrev = false, // Specify Draw Only Prev Bar of Cycle ... + bool drawOnlyCurrent = false, // Specify Draw Only Current Bar of Cycle ... + int offset = 0 // Distance used for Labels ... +) +{ + // + if (offset < 0) + { + offset = 0; + } + + // + XMarketCycle cycleModel; + XOHCLDrawSpecification cycleCBarSpecs; + XOHCLDrawSpecification cyclePBarSpecs; + + // + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + // + cycleModel = sc; + cycleCBarSpecs = scCBSpecs; + cyclePBarSpecs = scPBSpecs; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + // + cycleModel = mc; + cycleCBarSpecs = mcCBSpecs; + cyclePBarSpecs = mcPBSpecs; + break; + + // + case X_MARKET_CYCLE_LONG: + // + cycleModel = lc; + cycleCBarSpecs = lcCBSpecs; + cyclePBarSpecs = lcPBSpecs; + break; + + // + case X_MARKET_CYCLE_HIND: + // + cycleModel = hc; + cycleCBarSpecs = hcCBSpecs; + cyclePBarSpecs = hcPBSpecs; + break; + } + + // + string baseTag = ToString(cycle); + + // + XOHCL cBar = cycleModel.GetBar(0); + XOHCL pBar = cycleModel.GetBar(1); + + // + datetime fromCDate = cycleModel.GetBarTime(0); + datetime fromPDate = cycleModel.GetBarTime(1); + + // + datetime cTime = TimeCurrent(); + + // + // Try to Draw ... + + // + bool canDrawPrev = !drawOnlyCurrent; + bool canDrawCurrent = !drawOnlyPrev; + + // + // Set Cycles Color based on Current Candle ... + + // + bool isCBarBullish = + cBar.open < cBar.close; + + // + bool isPBarBullish = + pBar.open < pBar.close; + + // + color clrTemoBullishColor = cycleCBarSpecs.openStyle.clr; + color clrTemoBearishColor = cycleCBarSpecs.closeStyle.clr; + + // + color cBarSelectedColor = isCBarBullish ? clrTemoBullishColor : clrTemoBearishColor; + color pBarSelectedColor = isPBarBullish ? clrTemoBullishColor : clrTemoBearishColor; + + // + cycleCBarSpecs.openStyle.clr = cBarSelectedColor; + cycleCBarSpecs.openStyle.labelColor = cBarSelectedColor; + + // + cycleCBarSpecs.closeStyle.clr = cBarSelectedColor; + cycleCBarSpecs.closeStyle.labelColor = cBarSelectedColor; + + // + cyclePBarSpecs.openStyle.clr = pBarSelectedColor; + cyclePBarSpecs.openStyle.labelColor = pBarSelectedColor; + + // + cyclePBarSpecs.closeStyle.clr = pBarSelectedColor; + cyclePBarSpecs.closeStyle.labelColor = pBarSelectedColor; + + // + if (canDrawPrev) + { + offset++; + } + + // + // Label ... + if (drawLabel) + { + // + if (canDrawPrev) + { + // + // Draw Prev Bar Lables ... + + // + XBEEADrawCycleXOHCLLabel( + cycleModel, + pBar, + cyclePBarSpecs, + "P", + cTime, + offset - 1 + // + ); + + // + offset += 3; + } + + // + if (canDrawCurrent) + { + // + // Draw Current Bar Lables ... + + // + XBEEADrawCycleXOHCLLabel( + cycleModel, + cBar, + cycleCBarSpecs, + "C", + cTime, + offset + // + ); + } + } + + // + // Line ... + + // + if (canDrawPrev) + { + // + // Draw Cycle Prev Bar ... + XBEEADrawCycleXOHCLContent( + cycleModel, + pBar, + cyclePBarSpecs, + "P", + fromPDate + // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Cycle Current Bar ... + XBEEADrawCycleXOHCLContent( + cycleModel, + cBar, + cycleCBarSpecs, + "C", + fromCDate + // + ); + } +} + +// +// Draw Middle Line of Cycle ... +void XBEEADrawMidLine( + ENUM_X_MARKET_CYCLES cycle, // Specify Which Cycle to Draw ... + bool drawLabel = false, // Specify Draw Label of Mid Line or not ... + bool drawOnlyPrev = false, // Specify Draw Only Prev Bar of Cycle ... + bool drawOnlyCurrent = false, // Specify Draw Only Current Bar of Cycle ... + int offset = 0 // Distance used for Labels ... +) +{ + // + if (offset < 0) + { + offset = 0; + } + + // + XMarketCycle cycleModel; + XDrawSpecifications cycleCMidSpecs; + XDrawSpecifications cyclePMidSpecs; + + // + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + // + cycleModel = sc; + cycleCMidSpecs = scCMidSpecs; + cyclePMidSpecs = scPMidSpecs; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + // + cycleModel = mc; + cycleCMidSpecs = mcCMidSpecs; + cyclePMidSpecs = mcPMidSpecs; + break; + + // + case X_MARKET_CYCLE_LONG: + // + cycleModel = lc; + cycleCMidSpecs = lcCMidSpecs; + cyclePMidSpecs = lcPMidSpecs; + break; + + // + case X_MARKET_CYCLE_HIND: + // + cycleModel = hc; + cycleCMidSpecs = hcCMidSpecs; + cyclePMidSpecs = hcPMidSpecs; + break; + } + + // + // Calculate Mid Line ... + double midLine = (cycleModel.bar.high + cycleModel.bar.low) / 2; + + // + XOHCL cyclePrevBar = cycleModel.GetBar(1); + double midLinePrev = (cyclePrevBar.high + cyclePrevBar.low) / 2; + + // + string baseTag = ToString(cycle); + + // + string midCTag = baseTag + "|MID|C|"; + string midPTag = baseTag + "|MID|P|"; + + // + string midCLblTag = midCTag + "lbl"; + string midPLblTag = midPTag + "lbl"; + + // + datetime fromCDate = cycleModel.GetBarTime(0); + datetime fromPDate = cycleModel.GetBarTime(1); + + // + datetime cTime = TimeCurrent(); + + // + // Try to Draw ... + + // + bool canDrawPrev = !drawOnlyCurrent; + bool canDrawCurrent = !drawOnlyPrev; + + // + if (canDrawPrev) + { + offset++; + } + + // + // Label ... + if (drawLabel) + { + // + if (canDrawPrev) + { + // + // Draw Prev Candle MidLine Lable ... + XBEEADrawLabel( + cyclePMidSpecs, + midPLblTag, + cTime, + midLinePrev, + offset // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Current Candle MidLine Label ... + XBEEADrawLabel( + cycleCMidSpecs, + midCLblTag, + cTime, + midLine, + offset - 1 // + ); + } + } + + // + // Line ... + + // + if (canDrawPrev) + { + // + // Draw Prev Candle MidLine ... + XBEEADrawTrendLine( + cyclePMidSpecs, + midPTag, + fromPDate, + midLinePrev // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Current Candle MidLine ... + XBEEADrawTrendLine( + cycleCMidSpecs, + midCTag, + fromCDate, + midLine // + ); + } +} + +// + +// +// Custom DRAW(s) ... + +// +// Draw OHCL Labels ... +void XBEEADrawCycleXOHCLLabel( + XMarketCycle &cycleModel, // Specify Which Cycle to Draw ... + XOHCL &bar, // Specify Cycle XOHCL Model to Draw ... + XOHCLDrawSpecification &specs, // Specify Cycle XOHCL Draw Specifications ... + string baseTag, // Specify a Unique Tag ... + datetime time, // Draw Time ... + int offset = 0 // +) +{ + // + // Open ... + string openTag = cycleModel.prefix + "_" + baseTag + "_O_lbl"; + XBEEADrawLabel( + specs.openStyle, + openTag, + time, + bar.open, + offset + // + ); + + // + // High ... + string highTag = cycleModel.prefix + "_" + baseTag + "_H_lbl"; + XBEEADrawLabel( + specs.highStyle, + highTag, + time, + bar.high, + offset + 1 + // + ); + + // + // Close ... + string closeTag = cycleModel.prefix + "_" + baseTag + "_C_lbl"; + XBEEADrawLabel( + specs.closeStyle, + closeTag, + time, + bar.close, + offset + 2 + // + ); + + // + // Low ... + string lowTag = cycleModel.prefix + "_" + baseTag + "_L_lbl"; + XBEEADrawLabel( + specs.lowStyle, + lowTag, + time, + bar.low, + offset + 3 + // + ); +} + +// +// Draw OHCL Content ... +void XBEEADrawCycleXOHCLContent( + XMarketCycle &cycleModel, // Specify Which Cycle to Draw ... + XOHCL &bar, // Specify Cycle XOHCL Model to Draw ... + XOHCLDrawSpecification &specs, // Specify Cycle XOHCL Draw Specifications ... + string baseTag, // Specify a Unique Tag ... + datetime time // Draw Time ... +) +{ + // + // Open ... + string openTag = cycleModel.prefix + "_" + baseTag + "_O"; + XBEEADrawTrendLine( + specs.openStyle, + openTag, + time, + bar.open + // + ); + + // + // High ... + string highTag = cycleModel.prefix + "_" + baseTag + "_H"; + XBEEADrawTrendLine( + specs.highStyle, + highTag, + time, + bar.high + // + ); + + // + // Close ... + string closeTag = cycleModel.prefix + "_" + baseTag + "_C"; + XBEEADrawTrendLine( + specs.closeStyle, + closeTag, + time, + bar.close + // + ); + + // + // Low ... + string lowTag = cycleModel.prefix + "_" + baseTag + "_L"; + XBEEADrawTrendLine( + specs.lowStyle, + lowTag, + time, + bar.low + // + ); +} + +// +// Draw Label Using Specifications ... +void XBEEADrawLabel( + XDrawSpecifications &specs, + string tag, + datetime time, + double price, + int offset = 0 // +) +{ + // + long chartId = ChartID(); + int subWindow = 0; + + // + if (offset < 0) + { + offset = 0; + } + + // + int offsetSeconds = PeriodSeconds(xBEEAPeriod) * offset; + + // + string value = specs.label; + + // + DrawText( + chartId, + tag, + subWindow, + time - offsetSeconds, + price, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); +} + +// +// Draw TrendLine Using Specifications ... +void XBEEADrawTrendLine( + XDrawSpecifications &specs, + string tag, + datetime fromDate, + double fromPrice, + datetime toDate = NULL, + double toPrice = 0 // +) +{ + // + long chartId = ChartID(); + int subWindow = 0; + + // + if (toPrice <= 0) + { + toPrice = fromPrice; + } + + // + if (toDate == 0 || toDate == NULL) + { + toDate = TimeCurrent(); + } + + // + DrawTrendLine( + chartId, + tag, + subWindow, + fromDate, + fromPrice, + toDate, + toPrice, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); +} diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.xbe.ea.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.xbe.ea.mq5 new file mode 100644 index 0000000..68ffb0f --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.xbe.ea.mq5 @@ -0,0 +1,1824 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XBEEA MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XBEEA +// Description: an Exper Advisor which used RSI and MA +// to Analyse Market ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XBEEA" +#property strict + +// +// TODO: +// -[] Create Some Trendial Conditions Variables ... +// -[] Comment them ... +// -[] Open 2 Position for each Signal ... +// -[] Close 2nd Position by Stop Trailing ... +// -[] implement Long conditions ... +// -[] add also Provider to Signals for Sepcied them ... +// -[] Implement Same Senario by Other Time Frames ... + +// +#define ShortName "XBEEA" + +// +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.draw.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" + +// +// Inputs ... +long xBEEAMagicNumber = 78692110; // Magic Number +int xBEEASlippage = 10; // Slippgae + +// +double xBEEAVolume = 0.05; // Volume Per Trade + +// +ENUM_TIMEFRAMES xBEEASCPeriod = PERIOD_H4; +ENUM_TIMEFRAMES xBEEAMCPeriod = PERIOD_H12; +ENUM_TIMEFRAMES xBEEALCPeriod = PERIOD_D1; +ENUM_TIMEFRAMES xBEEAHCPeriod = PERIOD_W1; + +// +bool xBEEADrawAsBox = false; // Draw Candles As Box ... +// +bool xBEEAUpdate = true; // Update Candles based On Time ... +// +bool xBEEADrawLabels = false; // Draw Line Labels ... +// +bool xBEEADrawCandle0 = false; // Draw 0 Time Candles ... +bool xBEEADrawCandle1 = true; // Draw 1 Time Candles ... +// +bool xBEEADrawBody = true; // Show Candle Bodies ... +bool xBEEADrawShadows = true; // Show Candle Shadows ... +// +// Candles ... +bool xBEEADrawCurrent = false; // Draw Current Candle ... +bool xBEEADrawSC = false; // Draw Short Candle ... +bool xBEEADrawMC = false; // Draw Medium Candle ... +bool mDrawLC = false; // Draw Long Candle ... +bool mDrawHC = true; // Draw Hind Candle ... +// +// MidLines ... +bool mDraw0MidLine = false; +bool mDraw1MidLine = false; +bool xBEEADrawSC0MidLine = false; +bool xBEEADrawSC1MidLine = false; +bool xBEEADrawMC0MidLine = false; +bool xBEEADrawMC1MidLine = false; +bool xBEEADrawLC0MidLine = false; +bool xBEEADrawLC1MidLine = false; +bool xBEEADrawHC0MidLine = true; +bool xBEEADrawHC1MidLine = true; + +// +// Vars ... +string xBEEASymbol; +ENUM_TIMEFRAMES xBEEAPeriod; + +// +int maxBuys = 1; +int maxSells = 1; +int buyCount = 0; +int sellCount = 0; + +// +XOHCL candle0; +datetime candle0Time; +datetime nextCandle0Time; +string c0TagPrefix = "CC0"; +XOHCLDrawSpecification candle0Style; +bool isCandle0Bullish; +bool isCandle0Bearish; + +// +XOHCL candle1; +datetime candle1Time; +datetime nextCandle1Time; +string c1TagPrefix = "CC1"; +XOHCLDrawSpecification candle1Style; +bool isCandle1Bullish; +bool isCandle1Bearish; + +// +XOHCL scCandle0; +datetime scCandle0Time; +datetime nextSCCandle0Time; +string sc0TagPrefix = "SC0"; +XOHCLDrawSpecification scCandle0Style; +bool isSCCandle0Bullish; +bool isSCCandle0Bearish; + +// +XOHCL scCandle1; +datetime scCandle1Time; +datetime nextSCCandle1Time; +string sc1TagPrefix = "SC1"; +XOHCLDrawSpecification scCandle1Style; +bool isSCCandle1Bullish; +bool isSCCandle1Bearish; + +// +XOHCL mcCandle0; +datetime mcCandle0Time; +datetime nextMCCandle0Time; +string mc0TagPrefix = "MC0"; +XOHCLDrawSpecification mcCandle0Style; +bool isMCCandle0Bullish; +bool isMCCandle0Bearish; + +// +XOHCL mcCandle1; +datetime mcCandle1Time; +datetime nextMCCandle1Time; +string mc1TagPrefix = "MC1"; +XOHCLDrawSpecification mcCandle1Style; +bool isMCCandle1Bullish; +bool isMCCandle1Bearish; + +// +XOHCL lcCandle0; +datetime lcCandle0Time; +datetime nextLCCandle0Time; +string lc0TagPrefix = "L0"; +XOHCLDrawSpecification lcCandle0Style; +bool isLCCandle0Bullish; +bool isLCCandle0Bearish; + +// +XOHCL lcCandle1; +datetime lcCandle1Time; +datetime nextLCCandle1Time; +string lc1TagPrefix = "L1"; +XOHCLDrawSpecification lcCandle1Style; +bool isLCCandle1Bullish; +bool isLCCandle1Bearish; + +// +XOHCL hcCandle0; +datetime hcCandle0Time; +datetime nextHCCandle0Time; +string hc0TagPrefix = "H0"; +XOHCLDrawSpecification hcCandle0Style; +bool isHCCandle0Bullish; +bool isHCCandle0Bearish; + +// +XOHCL hcCandle1; +datetime hcCandle1Time; +datetime nextHCCandle1Time; +string hc1TagPrefix = "H1"; +XOHCLDrawSpecification hcCandle1Style; +bool isHCCandle1Bullish; +bool isHCCandle1Bearish; + +// +// +// + +// +bool canBuy = false; +bool canSell = false; + +// +datetime buyTime = 0; +datetime sellTime = 0; + +// +datetime lastBuyTime = 0; +datetime lastSellTime = 0; + +// +XSignal xSamepleEAExecutedSignals[]; + +// +bool isHCSignal = false; +bool hcWaitsOnNextSession = false; + +// +double _tp = 0; +double _sl = 0; +double _r2r = 2; +double _entry = 0; +ENUM_POSITION_TYPE _type = NULL; + +// +MqlTick xBEEATick; +XSCTrade *xBEEATrader; + +// +// Event Handlers ... +// +// Initialization ... +int OnInit() +{ + // + if (xBEEASymbol == NULL || StringLen(xBEEASymbol) <= 0) + { + xBEEASymbol = _Symbol; + } + + // + if (xBEEAPeriod == NULL) + { + xBEEAPeriod = _Period; + } + + // + // Validate Inputs ... + if (!XBEEAValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + drawPrefix = ShortName; + + // + XBEEAConfigureCandleStyles(); + + // + // Initialize XTrader ... + xBEEATrader = new XSCTrade( + xBEEASlippage, + xBEEAMagicNumber); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 XBEEA Providers ... + delete xBEEATrader; +} + +// +// On Tick Handler ... +void OnTick() +{ + // + if (!IsNewCandle( + xBEEASymbol, + xBEEAPeriod)) + { + return; + } + + // + // Reading Tick ... + if (!SymbolInfoTick(xBEEASymbol, xBEEATick)) + { + return; + } + + // + // Counting Currently Open Positions ... + buyCount = xBEEATrader.CountPositions(xBEEASymbol, POSITION_TYPE_BUY); + sellCount = xBEEATrader.CountPositions(xBEEASymbol, POSITION_TYPE_SELL); + + // + XBEEACalculateTick(); + + // + // TODO: Complete One Position in Each Section ... + + // + // Do Buy Trade ... + bool canDoBuyTrade = + canBuy && + (maxBuys <= 0 || + (maxBuys > 0 && buyCount < maxBuys)); + if (canDoBuyTrade) + { + // + XSignal signal = CreateSignal( + xBEEASymbol, + xBEEAPeriod, + _type, + X_ORDER_MODE_MARKET, + _entry, + xBEEAVolume, + _tp, + _sl); + + // + string comment = "XBEEA,Lo"; + + // + bool canExecute = + // + (isHCSignal && !hcWaitsOnNextSession) + // + ; + + // + bool isExecuted = + !canExecute + ? false + : xBEEATrader + .ExecuteSignal( + signal, + comment); + if (isExecuted) + { + // + Add( + signal, + xSamepleEAExecutedSignals); + + // + buyTime = TimeCurrent(); + + // + if (isHCSignal) + { + // + isHCSignal = false; + hcWaitsOnNextSession = true; + } + + // + // TODO: Log ... + string message = "Do Buy Trade ..."; + } + } + + // + // Do Sell Trade ... + bool canDoSellTrade = + canSell && + (maxSells <= 0 || + (maxSells > 0 && sellCount < maxSells)); + if (canDoSellTrade) + { + // + XSignal signal = CreateSignal( + xBEEASymbol, + xBEEAPeriod, + _type, + X_ORDER_MODE_MARKET, + _entry, + xBEEAVolume, + _tp, + _sl); + + // + string comment = "XBEEA,Sh"; + + // + bool canExecute = + // + (isHCSignal && !hcWaitsOnNextSession) + // + ; + + // + bool isExecuted = + !canExecute + ? false + : xBEEATrader + .ExecuteSignal( + signal, + comment); + if (isExecuted) + { + // + Add( + signal, + xSamepleEAExecutedSignals); + + // + sellTime = TimeCurrent(); + + // + if (isHCSignal) + { + // + isHCSignal = false; + hcWaitsOnNextSession = true; + } + + // + // TODO: Log ... + string message = "Do Sell Trade ..."; + } + } + + // + // Reset Conditions ... + lastBuyTime = buyTime; + lastSellTime = sellTime; + + // + buyTime = 0; + sellTime = 0; + + // + canBuy = false; + canSell = false; + + // + _sl = 0; + _tp = 0; + _entry = 0; + _type = NULL; + + // + XBEEAProvideInfo(); +} + +// +// Custom Functions ... + +// +// Validate Variables nd Inputs ... +bool XBEEAValidateInputs() +{ + // + bool result = false; + + // + result = + // + xBEEASlippage > 0 && + xBEEAMagicNumber > 0 + // + ; + + // + return result; +} + +// +void PrepareCandleStyle( + XOHCLDrawSpecification &source, + int width = 1, + color clr = CLR_NONE, + ENUM_LINE_STYLE style = STYLE_SOLID, + bool ray = false, + bool fill = false, + bool back = false // +) +{ + // + source.Default(); + + // + source.Width(width); + + // + if (clr != CLR_NONE) + { + source.Color(clr); + } + + // + source.Style(style); + source.RayRight(ray); + source.Fill(fill); + source.Back(back); +} + +// +// Configure Default Styles for Candle Drawing ... +void XBEEAConfigureCandleStyles() +{ + // + PrepareCandleStyle( + candle0Style, + 1, + CLR_NONE, + STYLE_DOT, + false, + false, + true // + ); + candle0Style.SetLabelPrefix(c0TagPrefix); + + // + PrepareCandleStyle( + candle1Style, + 1, + CLR_NONE, + STYLE_DOT, + false, + false, + true // + ); + candle1Style.SetLabelPrefix(c1TagPrefix); + + // + PrepareCandleStyle( + scCandle0Style, + 1, + CLR_NONE, + STYLE_DASH, + false, + false, + true // + ); + scCandle0Style.SetLabelPrefix(sc0TagPrefix); + + // + PrepareCandleStyle( + scCandle1Style, + 1, + CLR_NONE, + STYLE_DASH, + false, + false, + true // + ); + scCandle1Style.SetLabelPrefix(sc1TagPrefix); + + // + PrepareCandleStyle( + mcCandle0Style, + 1, + CLR_NONE, + STYLE_DASHDOT, + false, + false, + true // + ); + mcCandle0Style.SetLabelPrefix(mc0TagPrefix); + + // + PrepareCandleStyle( + mcCandle1Style, + 1, + CLR_NONE, + STYLE_DASHDOT, + false, + false, + true // + ); + mcCandle1Style.SetLabelPrefix(mc1TagPrefix); + + // + PrepareCandleStyle( + lcCandle0Style, + 1, + CLR_NONE, + STYLE_DASHDOTDOT, + false, + false, + true // + ); + lcCandle0Style.SetLabelPrefix(lc0TagPrefix); + + // + PrepareCandleStyle( + lcCandle1Style, + 1, + CLR_NONE, + STYLE_DASHDOTDOT, + false, + false, + true // + ); + lcCandle1Style.SetLabelPrefix(lc1TagPrefix); + + // + PrepareCandleStyle( + hcCandle0Style, + 1, + CLR_NONE, + STYLE_DOT, + false, + false, + true // + ); + hcCandle0Style.highStyle.clr = clrLightSkyBlue; + hcCandle0Style.openStyle.clr = clrDarkOliveGreen; + hcCandle0Style.closeStyle.clr = clrCoral; + hcCandle0Style.lowStyle.clr = clrPink; + hcCandle0Style.SetLabelPrefix(hc0TagPrefix); + + // + PrepareCandleStyle( + hcCandle1Style, + 2, + CLR_NONE, + STYLE_DOT, + false, + false, + true // + ); + hcCandle1Style.SetLabelPrefix(hc1TagPrefix); + + // + if (!xBEEADrawLabels) + { + // + candle0Style.Label(""); + candle1Style.Label(""); + // + scCandle0Style.Label(""); + scCandle1Style.Label(""); + // + mcCandle0Style.Label(""); + mcCandle1Style.Label(""); + // + lcCandle0Style.Label(""); + lcCandle1Style.Label(""); + // + hcCandle0Style.Label(""); + hcCandle1Style.Label(""); + } +} + +// +void XBEEACalculateTick() +{ + // + // Calculate Candles ... + + // + XBEEACalculateCandles(); + + // + XBEEACheckGuards(); + + // + XBEEACheckConditions(); + + // + // Drawing Candles ... + XBEEADrawCandles(); + + // + XBEEACheckForSignals(); +} + +// +// Here we Chack all Guards ... +void XBEEACheckGuards() +{ + // + // Implement All Guards here ... +} + +// +void XBEEACalculateCandles() +{ + // + // SC ... + scCandle0 = GetCandle( + xBEEASymbol, + xBEEASCPeriod, + 0 // Current Candle + ); + scCandle1 = GetCandle( + xBEEASymbol, + xBEEASCPeriod, + 1 // Before Candle + ); + + // + scCandle0Time = GetCandleTime( + xBEEASymbol, + xBEEASCPeriod, + 0); + scCandle1Time = GetCandleTime( + xBEEASymbol, + xBEEASCPeriod, + 1); + + // + // MC ... + mcCandle0 = GetCandle( + xBEEASymbol, + xBEEAMCPeriod, + 0 // Current Candle + ); + mcCandle1 = GetCandle( + xBEEASymbol, + xBEEAMCPeriod, + 1 // Before Candle + ); + + // + mcCandle0Time = GetCandleTime( + xBEEASymbol, + xBEEAMCPeriod, + 0); + mcCandle1Time = GetCandleTime( + xBEEASymbol, + xBEEAMCPeriod, + 1); + + // + // LC ... + lcCandle0 = GetCandle( + xBEEASymbol, + xBEEALCPeriod, + 0 // Current Candle + ); + lcCandle1 = GetCandle( + xBEEASymbol, + xBEEALCPeriod, + 1 // Before Candle + ); + + // + lcCandle0Time = GetCandleTime( + xBEEASymbol, + xBEEALCPeriod, + 0); + lcCandle1Time = GetCandleTime( + xBEEASymbol, + xBEEALCPeriod, + 1); + + // + // HC ... + hcCandle0 = GetCandle( + xBEEASymbol, + xBEEAHCPeriod, + 0 // Current Candle + ); + hcCandle1 = GetCandle( + xBEEASymbol, + xBEEAHCPeriod, + 1 // Before Candle + ); + + // + hcCandle0Time = GetCandleTime( + xBEEASymbol, + xBEEAHCPeriod, + 0); + hcCandle1Time = GetCandleTime( + xBEEASymbol, + xBEEAHCPeriod, + 1); + + // + // Now Reading Current Candle ... + candle0 = GetCandle( + xBEEASymbol, + xBEEAPeriod, + 0 // Current Candle + ); + candle1 = GetCandle( + xBEEASymbol, + xBEEAPeriod, + 1 // Before Candle + ); + + // + candle0Time = GetCandleTime( + xBEEASymbol, + xBEEAPeriod, + 0); + candle1Time = GetCandleTime( + xBEEASymbol, + xBEEAPeriod, + 1); + + // + // Find Candle Start Time ... + + // + // current .. + nextCandle0Time = candle0Time + PeriodSeconds(xBEEAPeriod); + nextCandle1Time = candle1Time + PeriodSeconds(xBEEAPeriod); + + // + // SC .. + nextSCCandle0Time = scCandle0Time + PeriodSeconds(xBEEASCPeriod); + nextSCCandle1Time = scCandle1Time + PeriodSeconds(xBEEASCPeriod); + + // + // MC .. + nextMCCandle0Time = mcCandle0Time + PeriodSeconds(xBEEAMCPeriod); + nextMCCandle1Time = mcCandle1Time + PeriodSeconds(xBEEAMCPeriod); + + // + // LC .. + nextLCCandle0Time = lcCandle0Time + PeriodSeconds(xBEEALCPeriod); + nextLCCandle1Time = lcCandle1Time + PeriodSeconds(xBEEALCPeriod); + + // + // HC .. + nextHCCandle0Time = hcCandle0Time + PeriodSeconds(xBEEAHCPeriod); + nextHCCandle1Time = hcCandle1Time + PeriodSeconds(xBEEAHCPeriod); + + // + isCandle0Bullish = IsBullishCandle(candle0); + isCandle0Bearish = IsBearishCandle(candle0); + isCandle1Bullish = IsBullishCandle(candle1); + isCandle1Bearish = IsBearishCandle(candle1); + + // + isSCCandle0Bullish = IsBullishCandle(scCandle0); + isSCCandle0Bearish = IsBearishCandle(scCandle0); + isSCCandle1Bullish = IsBullishCandle(scCandle1); + isSCCandle1Bearish = IsBearishCandle(scCandle1); + + // + isMCCandle0Bullish = IsBullishCandle(mcCandle0); + isMCCandle0Bearish = IsBearishCandle(mcCandle0); + isMCCandle1Bullish = IsBullishCandle(mcCandle1); + isMCCandle1Bearish = IsBearishCandle(mcCandle1); + + // + isLCCandle0Bullish = IsBullishCandle(lcCandle0); + isLCCandle0Bearish = IsBearishCandle(lcCandle0); + isLCCandle1Bullish = IsBullishCandle(lcCandle1); + isLCCandle1Bearish = IsBearishCandle(lcCandle1); + + // + isHCCandle0Bullish = IsBullishCandle(hcCandle0); + isHCCandle0Bearish = IsBearishCandle(hcCandle0); + isHCCandle1Bullish = IsBullishCandle(hcCandle1); + isHCCandle1Bearish = IsBearishCandle(hcCandle1); +} + +// +void XBEEACheckConditions() +{ + // + // Here we Check all Conditions states ... + // for Enable or Disable conditions ... + + // + // HC based Signalling ... + // + + // + double point5 = PointToPrice( + xBEEASymbol, + 5 // + ); + + // + double hcCandle0Mid = (hcCandle0.open + hcCandle0.close) / 2; + double hcCandle1Mid = (hcCandle1.open + hcCandle1.close) / 2; + + // + double hcCandle1DownPrice = MathMin(hcCandle1.open, hcCandle1.close); + + // + bool hcHasBreakeout = hcCandle0Mid >= hcCandle1DownPrice + point5; + if (hcHasBreakeout && hcWaitsOnNextSession) + { + hcWaitsOnNextSession = false; + } +} + +// +void XBEEACheckForSignals() +{ + // + // Parse Conditions ... + // + double point5 = PointToPrice( + xBEEASymbol, + 5 // + ); + + // + // HC Base ... + // + + // + double hcCandle0Mid = (hcCandle0.open + hcCandle0.close) / 2; + double hcCandle1Mid = (hcCandle1.open + hcCandle1.close) / 2; + + // + double hcCandle1UpPrice = MathMax(hcCandle1.open, hcCandle1.close); + double hcCandle1DownPrice = MathMin(hcCandle1.open, hcCandle1.close); + + // + bool hcHasShortSignal = hcCandle0Mid < hcCandle1DownPrice - point5; + if (hcHasShortSignal) + { + // + _type = POSITION_TYPE_SELL; + _entry = GetEntry( + xBEEASymbol, + _type); + + // + // Set TP and SL ... + + // + _sl = hcCandle1Mid; + + // + double risk = MathAbs(_entry - _sl); + double reward = risk * _r2r; + + // + _tp = _entry - reward; + + // + canSell = true; + isHCSignal = true; + + // + // This id for Preventing Other Sections ... + return; + } + + // + bool hcHasLongSignal = hcCandle0Mid > hcCandle1UpPrice + point5; + if (hcHasLongSignal) + { + // + _type = POSITION_TYPE_BUY; + _entry = GetEntry( + xBEEASymbol, + _type); + + // + // Set TP and SL ... + + // + _sl = hcCandle1Mid; + + // + double risk = MathAbs(_entry - _sl); + double reward = risk * _r2r; + + // + _tp = _entry + reward; + + // + canBuy = true; + isHCSignal = true; + + // + // This id for Preventing Other Sections ... + return; + } +} + +// +// DRAW Functions ... +void XBEEADrawCandles() +{ + // + int subWindow = 0; + long chartId = ChartID(); + + // + // Configure Styles for Draw Shadows and Bodies of Candles + // based On Configurations ... + + // + candle0Style.openStyle.draw = xBEEADrawCandle0 && xBEEADrawBody; + candle0Style.closeStyle.draw = xBEEADrawCandle0 && xBEEADrawBody; + + // + candle1Style.openStyle.draw = xBEEADrawCandle1 && xBEEADrawBody; + candle1Style.closeStyle.draw = xBEEADrawCandle1 && xBEEADrawBody; + + // + scCandle0Style.openStyle.draw = xBEEADrawCandle0 && xBEEADrawBody; + scCandle0Style.closeStyle.draw = xBEEADrawCandle0 && xBEEADrawBody; + + // + scCandle1Style.openStyle.draw = xBEEADrawCandle1 && xBEEADrawBody; + scCandle1Style.closeStyle.draw = xBEEADrawCandle1 && xBEEADrawBody; + + // + mcCandle0Style.openStyle.draw = xBEEADrawCandle0 && xBEEADrawBody; + mcCandle0Style.closeStyle.draw = xBEEADrawCandle0 && xBEEADrawBody; + + // + mcCandle1Style.openStyle.draw = xBEEADrawCandle1 && xBEEADrawBody; + mcCandle1Style.closeStyle.draw = xBEEADrawCandle1 && xBEEADrawBody; + + // + lcCandle0Style.openStyle.draw = xBEEADrawCandle0 && xBEEADrawBody; + lcCandle0Style.closeStyle.draw = xBEEADrawCandle0 && xBEEADrawBody; + + // + lcCandle1Style.openStyle.draw = xBEEADrawCandle1 && xBEEADrawBody; + lcCandle1Style.closeStyle.draw = xBEEADrawCandle1 && xBEEADrawBody; + + // + hcCandle0Style.openStyle.draw = xBEEADrawCandle0 && xBEEADrawBody; + hcCandle0Style.closeStyle.draw = xBEEADrawCandle0 && xBEEADrawBody; + + // + hcCandle1Style.openStyle.draw = xBEEADrawCandle1 && xBEEADrawBody; + hcCandle1Style.closeStyle.draw = xBEEADrawCandle1 && xBEEADrawBody; + + // + candle0Style.highStyle.draw = xBEEADrawCandle0 && xBEEADrawShadows; + candle0Style.lowStyle.draw = xBEEADrawCandle0 && xBEEADrawShadows; + + // + candle1Style.highStyle.draw = xBEEADrawCandle1 && xBEEADrawShadows; + candle1Style.lowStyle.draw = xBEEADrawCandle1 && xBEEADrawShadows; + + // + scCandle0Style.highStyle.draw = xBEEADrawCandle0 && xBEEADrawShadows; + scCandle0Style.lowStyle.draw = xBEEADrawCandle0 && xBEEADrawShadows; + + // + scCandle1Style.highStyle.draw = xBEEADrawCandle1 && xBEEADrawShadows; + scCandle1Style.lowStyle.draw = xBEEADrawCandle1 && xBEEADrawShadows; + + // + mcCandle0Style.highStyle.draw = xBEEADrawCandle0 && xBEEADrawShadows; + mcCandle0Style.lowStyle.draw = xBEEADrawCandle0 && xBEEADrawShadows; + + // + mcCandle1Style.highStyle.draw = xBEEADrawCandle1 && xBEEADrawShadows; + mcCandle1Style.lowStyle.draw = xBEEADrawCandle1 && xBEEADrawShadows; + + // + lcCandle0Style.highStyle.draw = xBEEADrawCandle0 && xBEEADrawShadows; + lcCandle0Style.lowStyle.draw = xBEEADrawCandle0 && xBEEADrawShadows; + + // + lcCandle1Style.highStyle.draw = xBEEADrawCandle1 && xBEEADrawShadows; + lcCandle1Style.lowStyle.draw = xBEEADrawCandle1 && xBEEADrawShadows; + + // + hcCandle0Style.highStyle.draw = xBEEADrawCandle0 && xBEEADrawShadows; + hcCandle0Style.lowStyle.draw = xBEEADrawCandle0 && xBEEADrawShadows; + + // + hcCandle1Style.highStyle.draw = xBEEADrawCandle1 && xBEEADrawShadows; + hcCandle1Style.lowStyle.draw = xBEEADrawCandle1 && xBEEADrawShadows; + + // + // Default Mid Line Specs ... + XDrawSpecifications specs; + specs.width = 2; + specs.rayRight = false; + specs.clr = clrYellow; + specs.style = STYLE_DOT; + + // + if (xBEEADrawCurrent) + { + // + if (!xBEEADrawAsBox) + { + // + if (xBEEADrawCandle0) + { + // + DrawCandleAsLine( + chartId, + subWindow, + candle0, + candle0Time, + candle0Style, + c0TagPrefix, + xBEEAUpdate // + ); + } + + // + if (xBEEADrawCandle1) + { + // + if (xBEEADrawCandle1) + { + // + DrawCandleAsLine( + chartId, + subWindow, + candle1, + candle1Time, + candle1Style, + c1TagPrefix, + xBEEAUpdate // + ); + } + } + } + else + { + // + if (xBEEADrawCandle0) + { + // + DrawCandleAsBox( + chartId, + subWindow, + candle0, + candle0Time, + candle0Style, + c0TagPrefix, + xBEEADrawBody, + xBEEADrawShadows, + xBEEAUpdate // + ); + } + + // + if (xBEEADrawCandle1) + { + // + DrawCandleAsBox( + chartId, + subWindow, + candle1, + candle1Time, + candle1Style, + c1TagPrefix, + xBEEADrawBody, + xBEEADrawShadows, + xBEEAUpdate // + ); + } + } + } + + // + if (xBEEADrawSC) + { + // + if (!xBEEADrawAsBox) + { + // + if (xBEEADrawCandle0) + { + // + DrawCandleAsLine( + chartId, + subWindow, + scCandle0, + scCandle0Time, + scCandle0Style, + sc0TagPrefix, + xBEEAUpdate // + ); + } + + // + if (xBEEADrawCandle1) + { + // + DrawCandleAsLine( + chartId, + subWindow, + scCandle1, + scCandle1Time, + scCandle1Style, + sc1TagPrefix, + xBEEAUpdate // + ); + } + } + else + { + // + if (xBEEADrawCandle0) + { + // + DrawCandleAsBox( + chartId, + subWindow, + scCandle0, + scCandle0Time, + scCandle0Style, + sc0TagPrefix, + xBEEADrawBody, + xBEEADrawShadows, + xBEEAUpdate // + ); + } + + // + if (xBEEADrawCandle1) + { + // + DrawCandleAsBox( + chartId, + subWindow, + scCandle1, + scCandle1Time, + scCandle1Style, + sc1TagPrefix, + xBEEADrawBody, + xBEEADrawShadows, + xBEEAUpdate // + ); + } + } + } + + // + if (xBEEADrawMC) + { + // + if (!xBEEADrawAsBox) + { + // + if (xBEEADrawCandle0) + { + // + DrawCandleAsLine( + chartId, + subWindow, + mcCandle0, + mcCandle0Time, + mcCandle0Style, + mc0TagPrefix, + xBEEAUpdate // + ); + } + + // + if (xBEEADrawCandle1) + { + // + DrawCandleAsLine( + chartId, + subWindow, + mcCandle1, + mcCandle1Time, + mcCandle1Style, + mc1TagPrefix, + xBEEAUpdate // + ); + } + } + else + { + // + if (xBEEADrawCandle0) + { + // + DrawCandleAsBox( + chartId, + subWindow, + mcCandle0, + mcCandle0Time, + mcCandle0Style, + mc0TagPrefix, + xBEEADrawBody, + xBEEADrawShadows, + xBEEAUpdate // + ); + } + + // + if (xBEEADrawCandle1) + { + // + DrawCandleAsBox( + chartId, + subWindow, + mcCandle1, + mcCandle1Time, + mcCandle1Style, + mc1TagPrefix, + xBEEADrawBody, + xBEEADrawShadows, + xBEEAUpdate // + ); + } + } + } + + // + if (mDrawLC) + { + // + if (!xBEEADrawAsBox) + { + // + if (xBEEADrawCandle0) + { + // + DrawCandleAsLine( + chartId, + subWindow, + lcCandle0, + lcCandle0Time, + lcCandle0Style, + lc0TagPrefix, + xBEEAUpdate // + ); + } + + // + if (xBEEADrawCandle1) + { + // + DrawCandleAsLine( + chartId, + subWindow, + lcCandle1, + lcCandle1Time, + lcCandle1Style, + lc1TagPrefix, + xBEEAUpdate // + ); + } + } + else + { + // + if (xBEEADrawCandle0) + { + // + DrawCandleAsBox( + chartId, + subWindow, + lcCandle0, + lcCandle0Time, + lcCandle0Style, + lc0TagPrefix, + xBEEADrawBody, + xBEEADrawShadows, + xBEEAUpdate // + ); + } + + // + if (xBEEADrawCandle1) + { + // + DrawCandleAsBox( + chartId, + subWindow, + lcCandle1, + lcCandle1Time, + lcCandle1Style, + lc1TagPrefix, + xBEEADrawBody, + xBEEADrawShadows, + xBEEAUpdate // + ); + } + } + } + + // + if (mDrawHC) + { + // + if (!xBEEADrawAsBox) + { + // + if (xBEEADrawCandle0) + { + // + DrawCandleAsLine( + chartId, + subWindow, + hcCandle0, + hcCandle0Time, + hcCandle0Style, + hc0TagPrefix, + xBEEAUpdate // + ); + } + + // + if (xBEEADrawCandle1) + { + // + DrawCandleAsLine( + chartId, + subWindow, + hcCandle1, + hcCandle1Time, + hcCandle1Style, + hc1TagPrefix, + xBEEAUpdate // + ); + } + } + else + { + // + if (xBEEADrawCandle0) + { + // + DrawCandleAsBox( + chartId, + subWindow, + hcCandle0, + hcCandle0Time, + hcCandle0Style, + hc0TagPrefix, + xBEEADrawBody, + xBEEADrawShadows, + xBEEAUpdate // + ); + } + + // + if (xBEEADrawCandle1) + { + // + DrawCandleAsBox( + chartId, + subWindow, + hcCandle1, + hcCandle1Time, + hcCandle1Style, + hc1TagPrefix, + xBEEADrawBody, + xBEEADrawShadows, + xBEEAUpdate // + ); + } + } + } + + // + // Draw MidLines ... + + // + string candel0MidLineTag = GenerateCandleMidLineTag( + candle0, + c0TagPrefix // + ); + string candel1MidLineTag = GenerateCandleMidLineTag( + candle1, + c1TagPrefix // + ); + string scCandel0MidLineTag = GenerateCandleMidLineTag( + scCandle0, + sc0TagPrefix // + ); + string scCandel1MidLineTag = GenerateCandleMidLineTag( + scCandle1, + sc1TagPrefix // + ); + string mcCandel0MidLineTag = GenerateCandleMidLineTag( + mcCandle0, + mc0TagPrefix // + ); + string mcCandel1MidLineTag = GenerateCandleMidLineTag( + mcCandle1, + mc1TagPrefix // + ); + string lcCandel0MidLineTag = GenerateCandleMidLineTag( + lcCandle0, + lc0TagPrefix // + ); + string lcCandel1MidLineTag = GenerateCandleMidLineTag( + lcCandle1, + lc1TagPrefix // + ); + string hcCandel0MidLineTag = GenerateCandleMidLineTag( + hcCandle0, + hc0TagPrefix // + ); + string hcCandel1MidLineTag = GenerateCandleMidLineTag( + hcCandle1, + hc1TagPrefix // + ); + + // + // Current ... + + // + // Candle 0 ... + specs.style = STYLE_DOT; + specs.clr = clrTurquoise; + DrawCandleMidLine( + candle0, + candle0Time, + specs, + candel0MidLineTag, + c0TagPrefix, + mDraw0MidLine // + ); + + // + // Candle 1 ... + specs.width = 2; + specs.style = STYLE_SOLID; + DrawCandleMidLine( + candle1, + candle1Time, + specs, + candel1MidLineTag, + c1TagPrefix, + mDraw1MidLine // + ); + + // + // Short ... + + // + // Candle 0 ... + specs.width = 1; + specs.style = STYLE_DOT; + specs.clr = clrSpringGreen; + DrawCandleMidLine( + scCandle0, + scCandle0Time, + specs, + scCandel0MidLineTag, + sc0TagPrefix, + xBEEADrawSC0MidLine // + ); + + // + // Candle 1 ... + specs.width = 2; + specs.style = STYLE_SOLID; + DrawCandleMidLine( + scCandle1, + scCandle1Time, + specs, + scCandel1MidLineTag, + sc1TagPrefix, + xBEEADrawSC1MidLine // + ); + + // + // Medium ... + + // + // Candle 0 ... + specs.width = 1; + specs.clr = clrCornflowerBlue; + specs.style = STYLE_DOT; + DrawCandleMidLine( + mcCandle0, + mcCandle0Time, + specs, + mcCandel0MidLineTag, + mc0TagPrefix, + xBEEADrawMC0MidLine // + ); + + // + // Candle 1 ... + specs.width = 2; + specs.style = STYLE_SOLID; + DrawCandleMidLine( + mcCandle1, + mcCandle1Time, + specs, + mcCandel1MidLineTag, + mc1TagPrefix, + xBEEADrawMC1MidLine // + ); + + // + // Long ... + + // + // Candle 0 ... + specs.width = 1; + specs.style = STYLE_DOT; + specs.clr = clrYellow; + DrawCandleMidLine( + lcCandle0, + lcCandle0Time, + specs, + lcCandel0MidLineTag, + lc0TagPrefix, + xBEEADrawLC0MidLine // + ); + + // + // Candle 1 ... + specs.width = 2; + specs.style = STYLE_SOLID; + DrawCandleMidLine( + lcCandle1, + lcCandle1Time, + specs, + lcCandel1MidLineTag, + lc1TagPrefix, + xBEEADrawLC1MidLine // + ); + + // + // Hind ... + + // + // Candle 0 ... + specs.clr = clrDarkOrange; + specs.width = 1; + specs.style = STYLE_DOT; + DrawCandleMidLine( + hcCandle0, + hcCandle0Time, + specs, + hcCandel0MidLineTag, + hc0TagPrefix, + xBEEADrawHC0MidLine // + ); + + // + // Candle 1 ... + specs.width = 2; + specs.style = STYLE_SOLID; + DrawCandleMidLine( + hcCandle1, + hcCandle1Time, + specs, + hcCandel1MidLineTag, + hc1TagPrefix, + xBEEADrawHC1MidLine // + ); +} + +// +// Generate States and Comment to User ... +void XBEEAProvideInfo() +{ + // + string periodMsg = + // + "SC: " + ToString(xBEEASCPeriod) + "\n" + + "MC: " + ToString(xBEEAMCPeriod) + "\n" + + "LC: " + ToString(xBEEALCPeriod) + "\n" + + "HC: " + ToString(xBEEAHCPeriod) + // + ; + + // + string buySellMsg = + // + (buyTime > 0 && buyTime != NULL + ? "Last Buy: " + ToString(buyTime) + "\n" + : "") + + (sellTime > 0 && sellTime != NULL + ? "Last Sell: " + ToString(sellTime) + "\n" + : "") + // + ; + + // + string hcStateMsg = "HC waits for reversal Conditions: " + ToString(hcWaitsOnNextSession); + + // + string hcCandlestickMsg = "HC Candle 1: " + + (isHCCandle1Bullish + ? "Bullish" + : isHCCandle1Bearish + ? "Bearish" + : "Neutural" // + ); + + // + string lcCandlestickMsg = "LC Candle 1: " + + (isLCCandle1Bullish + ? "Bullish" + : isLCCandle1Bearish + ? "Bearish" + : "Neutural" // + ); + + // + string mcCandlestickMsg = "MC Candle 1: " + + (isMCCandle1Bullish + ? "Bullish" + : isMCCandle1Bearish + ? "Bearish" + : "Neutural" // + ); + + // + string candlestickMsg = + // + lcCandlestickMsg + "\n" + + hcCandlestickMsg + // + ; + + // + string comment = ""; + + // + comment += + // + periodMsg + "\n" + + buySellMsg + "\n" + + hcStateMsg + "\n" + + candlestickMsg + // + ; + + // + Comment(comment); +} + +// +void DrawCandleMidLine( + XOHCL &c, // Candle ... + const datetime time, // Candle Time ... + XDrawSpecifications &specs, // Draw Specifications ... + string tag = "", // Tag ... + string label = "", // Label ... + bool draw = false // Draw MidLine ... +) +{ + // + if (!draw) + { + return; + } + + // + long chartId = ChartID(); + int subWindow = 0; + + // + double value = (c.open + c.close) / 2; + + // + datetime cTime = TimeCurrent(); + + // + string lblTag = tag + "_lbl"; + if (xBEEADrawLabels) + { + DrawText( + chartId, + lblTag, + subWindow, + cTime, + value, + label, + "Arial", + 20, + specs.clr, + 90, + ANCHOR_LEFT_UPPER, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw ... + DrawTrendLine( + chartId, + tag, + subWindow, + time, + value, + cTime, + value, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); +} + +// +string GenerateCandleMidLineTag( + XOHCL &c, // Candle ... + string tag = "" // Tag ... +) +{ + // + double value = (c.open + c.close) / 2; + + // + string result = tag + "_" + "|MID|"; + + // + return result; +} diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.xtrade.class.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.xtrade.class.mq5 new file mode 100644 index 0000000..3b302a3 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-saherelm.xtrade.class.mq5 @@ -0,0 +1,5012 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCTrade +// Description: provides all Trade 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 + +// +// START Definitions ... +// + +// +// Model an Open Position ... +struct XPosition +{ + // + // Magic Number ... + ulong magic; + + // + // Ticket ID ... + ulong ticket; + + // + // Tradinng Symbol ... + string symbol; + + // + // Trading Period ... + ENUM_TIMEFRAMES period; + + // + // Position Type ... + ENUM_POSITION_TYPE type; + + // + // Take Profit ... + double tp; + + // + // Stop Loss ... + double sl; + + // + // Position Current Profit ... + double profit; + + // + // Position Open Price ... + double entry; + + // + // Current Symbol Price ... + double price; + + // + // Position Swap ... + double swap; + + // + // Position Commission ... + double commission; + + // + // Volume ... + double volume; + + // + // Position Open Time ... + datetime openAt; + + // + // Position Comment ... + string comment; +}; + +// +// Model an Order ... +struct XOrder +{ + // + // Time of order placement ... + datetime setupAt; + + // + // Time of order expiration ... + datetime expiredAt; + + // + // Time of order execution or cancellation ... + datetime executedAt; + + // + // Order type ... + ENUM_ORDER_TYPE type; + + // + // Order state ... + ENUM_ORDER_STATE state; + + // + // Type of execution by remainder ... + ENUM_ORDER_TYPE_FILLING filling; + + // + // Order lifetime ... + ENUM_ORDER_TYPE_TIME lifetime; + + // + // Order ticket ... + ulong ticket; + + // + // Magic Number ... + long magic; + + // + // Position id, that is placed on order, + // when it is executed. Each executed order invokes a + // deal, that opens new or changes existing + // position. Id of that position is placed on + // executed order in this moment. + long pocitionID; + + // + // Initial volume on order placement ... + double initialVolume; + + // + // Unfilled volume ... + double currentVolume; + + // + // Price, specified in the order ... + double openPrice; + + // + // Current price by order symbol ... + double currentPrice; + + // + // Price of placing Limit order when StopLimit order is triggered ... + double stopLimitPrice; + + // + // Take Profit level ... + double tp; + + // + // Stop Loss level ... + double sl; + + // + // Trading Symbol ... + string smybol; + + // + // Order Comment ... + string comment; + + // + ENUM_TIMEFRAMES period; +}; + +// +// Model a Deal ... +struct XDeal +{ + // + // the ID of the Expert Advisor, that executed the deal ... + ulong magic; + + // + // the ID of position, in which the deal was involved ... + ulong positionId; + + // + // Ticket ... + ulong ticket; + + // + // the name of the deal symbol ... + string symbol; + + // + // order by which the deal is executed ... + ulong order; + + // + // the time of deal execution ... + datetime time; + + // + // Deal price ... + double price; + + // + // the financial result of the deal (in deposit currency) ... + double profit; + + // + // the amount of swap when position is closed ... + double swap; + + // + // the amount of commission of the deal ... + double commission; + + // + // the volume of deal ... + double volume; + + // + // the deal comment ... + string comment; + + // + // the deal type ... + // ------------------------------------------------------------------ + // DEAL_TYPE_BUY => Buy ... + // DEAL_TYPE_SELL => Sell ... + // DEAL_TYPE_BUY_CANCELED => Canceled buy deal ... + // There can be a situation when a previously executed buy deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ... + // + // DEAL_TYPE_SELL_CANCELED => Canceled sell deal ... + // There can be a situation when a previously executed sell deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation + // + // DEAL_TYPE_BALANCE => Balance ... + // DEAL_TYPE_CREDIT => Credit ... + // DEAL_TYPE_CHARGE => Additional charge ... + // DEAL_TYPE_CORRECTION => Correction ... + // DEAL_TAX => Tax charges ... + // DEAL_TYPE_BONUS => Bonus ... + // DEAL_TYPE_INTEREST => Interest rate ... + // DEAL_DIVIDEND => Dividend operations... + // DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ... + // DEAL_TYPE_COMMISSION => Additional commission ... + // DEAL_TYPE_COMMISSION_DAILY => Daily commission ... + // DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ... + // DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ... + // DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission + ENUM_DEAL_TYPE type; + + // + // the deal direction ... + // ---------------------------------- + // DEAL_ENTRY_IN => Entry in ... + // DEAL_ENTRY_OUT => Entry out ... + // DEAL_ENTRY_INOUT => Reverse ... + // DEAL_ENTRY_OUT_BY => Close a position by an opposite one ... + ENUM_DEAL_ENTRY entry; + + // + // deal reson ... + // --------------------- + // DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ... + // DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ... + // DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ... + // DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ... + // DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ... + // DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ... + // DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ... + // DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ... + // DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ... + // DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ... + ENUM_DEAL_REASON reason; +}; + +// +// Model a Position with all of it's Supports ... +struct XPositionPack +{ + // + ulong ticket; + + // + XPosition position; + + // + int supportOrdersCount; + int supportPositionsCount; + + // + XOrder supportOrders[]; + XPosition supportPositions[]; +}; + +// +// Model OnTrade Event Handler Result on XCTrade Class ... +struct XOnTradeHandlerState +{ + // + bool hasNewDeal; + int newDeals; + + // + bool hasNewOrder; + int newOrders; + + // + bool hasNewPosition; + int newPositions; + + // + bool hasNewHistoryOrder; + int newHistoryOrders; +}; + +// +typedef void (*TOnDealsChanged)(int count); + +// +typedef void (*TOnOrdersChanged)(int count); + +// +typedef void (*TOnPositionsChanged)(int count); + +// +typedef void (*TOnStopLoss)(const XDeal &deal); +typedef void (*TOnTakeProfit)(const XDeal &deal); + +// +typedef void (*TOnTradeStateChanged)(const XOnTradeHandlerState &state); + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Libraries/x-saherelm.seriallizer.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// XCTrade Base Class ... +class XSCTradeBase : public CTrade +{ +public: + // + // Modify Specific Position, by Specific Comment ... + bool PositionModify( + const string symbol, // Symbol + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!SelectPosition(symbol)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.symbol = symbol; + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + bool PositionModify( + const ulong ticket, // Position Ticket + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.position = ticket; + m_request.symbol = PositionGetString(POSITION_SYMBOL); + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + + // + // Close Specific Position, by Specific Comment ... + bool PositionClose( + const string symbol, // Symbol + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + bool partial_close = false; + int retry_count = 10; + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + do + { + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specify Comment ... + m_request.comment = comment; + + // + // check volume + double max_volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); + if (m_request.volume > max_volume) + { + // + m_request.volume = max_volume; + partial_close = true; + } + else + { + partial_close = false; + } + + // + // hedging? just send order + if (IsHedging()) + { + return (OrderSend(m_request, m_result)); + } + + // + // order send + if (!OrderSend(m_request, m_result)) + { + // + if (--retry_count != 0) + { + continue; + } + + // + if (retcode == TRADE_RETCODE_DONE_PARTIAL) + { + m_result.retcode = retcode; + } + + // + return (false); + } + + // + //--- WARNING. If position volume exceeds the maximum volume allowed for deal, + //--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely, + //--- but partially. It is decreased by the maximum volume allowed for deal. + if (m_async_mode) + { + break; + } + + // + retcode = TRADE_RETCODE_DONE_PARTIAL; + if (partial_close) + { + Sleep(1000); + } + } while (partial_close); + + // + // succeed + return (true); + } + bool PositionClose( + const ulong ticket, // Position Ticket + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specify Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } + + // + // Partial Close Specific Position, by Specific Comment ... + bool PositionClosePartial( + const string symbol, // Symbol + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // hedging? just send order + return (OrderSend(m_request, m_result)); + } + bool PositionClosePartial( + const ulong ticket, // Position Ticket + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } +}; + +// +// END Overrides ... +// + +// +// a Class for Manage Trades ... +class XSCTrade +{ + // + // Public ... +public: + // + // Constructor ... + void XSCTrade( + int slippage, // Specify Slippage + ulong magicNumber // Specify Magic Number + ) + { + // + mSlippage = slippage; + mMagicNumber = magicNumber; + + // + mPeriodPrefix = "PR"; + + // + mTrader = new XSCTradeBase(); + + // + mTrader.SetAsyncMode(false); + mTrader.SetDeviationInPoints(mSlippage); + mTrader.SetExpertMagicNumber(mMagicNumber); + + // + // Setting Log Level ... + mTrader.LogLevel(LOG_LEVEL_ERRORS); + + // + // Prepare Trade Event Materials ... + // + mDaysForRead = 1; + mScanStarted = false; + + // + // Reset On Trade Counter ... + ResetOnTradeContext(); + + // + // Init On Trade Context ... + InitOnTradeContext(); + } + + // + // Deconstructor ... + void ~XSCTrade() + { + } + + // + // START Event Processing ... + // + + // + // This Must be Called Every time OnTrade Event Happening ... + XOnTradeHandlerState HandleOnTrade() + { + // + // Handle OnTrade Event ... + XOnTradeHandlerState state = {}; + HandleOnTradeEvent(state); + if ( + !state.hasNewDeal && + !state.hasNewOrder && + !state.hasNewPosition && + !state.hasNewHistoryOrder) + { + return state; + } + + // + // STATE ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(state); + + // + // DEALS ... + if (state.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(state.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + GetDeals(deals); + int dealsCount = ArraySize(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // ORDERS ... + if (state.hasNewOrder || state.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(state.newOrders + state.newHistoryOrders); + } + + // + // POSITIONS ... + if (state.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(state.newPositions); + } + + // + return state; + } + + // + // Process On Trade Requirement + void HandleOnTradeEvent( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + if (mScanStarted) + { + ProcessOnTradeContext(result); + } + else + { + InitOnTradeContext(); + } + } + + // + // Event Emitters ... + + // + // STATE Changed ... + + // + // Clear Trade State Changed Event Handlers ... + void ClearOnTradeStateChangedEventHandlers() + { + // + ArrayFree(mTradeStateChangedEventHandlers); + + // + ArrayResize(mTradeStateChangedEventHandlers, 0); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) + { + // + ArrayResize( + mTradeStateChangedEventHandlers, + ArraySize(mTradeStateChangedEventHandlers) + 1); + + // + mTradeStateChangedEventHandlers[ArraySize(mTradeStateChangedEventHandlers) - 1] = handler; + } + + // + // DEALS ... + + // + // Clear Deals Changed Event Handlers ... + void ClearOnDealsChangedEventHandlers() + { + // + ArrayFree(mDealsChangedEventHandlers); + + // + ArrayResize(mDealsChangedEventHandlers, 0); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnDealsChangedEventHandler(TOnDealsChanged handler) + { + // + ArrayResize( + mDealsChangedEventHandlers, + ArraySize(mDealsChangedEventHandlers) + 1); + + // + mDealsChangedEventHandlers[ArraySize(mDealsChangedEventHandlers) - 1] = handler; + } + + // + // ORDERS ... + + // + // Clear Orders Changed Event Handlers ... + void ClearOnOrdersChangedEventHandlers() + { + // + ArrayFree(mOrdersChangedEventHandlers); + + // + ArrayResize(mOrdersChangedEventHandlers, 0); + } + + // + // Add New Orders Changed Event Handler ... + void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) + { + // + ArrayResize( + mOrdersChangedEventHandlers, + ArraySize(mOrdersChangedEventHandlers) + 1); + + // + mOrdersChangedEventHandlers[ArraySize(mOrdersChangedEventHandlers) - 1] = handler; + } + + // + // POSITIONS ... + + // + // Clear Positions Changed Event Handlers ... + void ClearOnPositionsChangedEventHandlers() + { + // + ArrayFree(mPositionsChangedEventHandlers); + + // + ArrayResize(mPositionsChangedEventHandlers, 0); + } + + // + // Add New Positions Changed Event Handler ... + void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) + { + // + ArrayResize( + mPositionsChangedEventHandlers, + ArraySize(mPositionsChangedEventHandlers) + 1); + + // + mPositionsChangedEventHandlers[ArraySize(mPositionsChangedEventHandlers) - 1] = handler; + } + + // + // TPSL ... + + // + // Clear Stop Loss Event Handlers ... + void ClearOnStopLossEventHandlers() + { + // + ArrayFree(mStopLossEventHandlers); + + // + ArrayResize(mStopLossEventHandlers, 0); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + ArrayResize( + mStopLossEventHandlers, + ArraySize(mStopLossEventHandlers) + 1); + + // + mStopLossEventHandlers[ArraySize(mStopLossEventHandlers) - 1] = handler; + } + + // + // Clear Take Profit Event Handlers ... + void ClearOnTakeProfitEventHandlers() + { + // + ArrayFree(mTakeProfitEventHandlers); + + // + ArrayResize(mTakeProfitEventHandlers, 0); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + ArrayResize( + mTakeProfitEventHandlers, + ArraySize(mTakeProfitEventHandlers) + 1); + + // + mTakeProfitEventHandlers[ArraySize(mTakeProfitEventHandlers) - 1] = handler; + } + + // + // END Event Processing ... + // + + // + // START Provided Functions ... + // + + // + // Count Currently Open Positions ... + int CountPositions( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + int result = 0; + + // + int allPositions = 0; + int longPositions = 0; + int shortPositions = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + allPositions++; + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + longPositions++; + } + else + { + shortPositions++; + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + allPositions++; + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + longPositions++; + } + else + { + shortPositions++; + } + + // + continue; + } + } + } + + // + // Specify Result ... + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + result = allPositions; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == POSITION_TYPE_BUY) + { + result = longPositions; + } + else + { + result = shortPositions++; + } + } + else if (StringLen(symbol) > 0) + { + // + result = allPositions; + } + else if (type != NULL) + { + // + if (type == POSITION_TYPE_BUY) + { + result = longPositions; + } + else + { + result = shortPositions; + } + } + + // + return result; + } + + // + // Retrieve Max In Profit Position Ticket ... + ulong GetMaxInProfitPosition( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + ulong result = -1; + + // + double profit = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + double positionAbsProfit = MathAbs(positionProfit); + if (positionProfit <= 0) + { + continue; + } + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Retrieve Max In DrawDown Position Ticket ... + ulong GetMaxInDrawDownPosition( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + ulong result = -1; + + // + double profit = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + double positionAbsProfit = MathAbs(positionProfit); + if (positionProfit >= 0) + { + continue; + } + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Retrieve Specific Position's Profit ... + double GetPositionProfit( + const ulong ticket // Specified Position Ticket + ) + { + // + double result = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + result = mPositionInfo.Profit(); + break; + } + + // + return result; + } + + // + // Retrieve Specific Position's OpenDate ... + datetime GetPositionOpenDate( + const ulong ticket // Specified Position Ticket + ) + { + // + datetime result = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + result = mPositionInfo.Time(); + break; + } + + // + return result; + } + + // + // Retrieve Specific Position's Comment ... + string GetPositionComment( + const ulong ticket // Specified Position Ticket + ) + { + // + string result = ""; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + result = mPositionInfo.Comment(); + break; + } + + // + return result; + } + + // + // Retrieve All Open Positions Profit ... + double GetPositionsProfit( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + double result = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + result += positionProfit; + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + result += positionProfit; + } + else + { + result += positionProfit; + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + result += positionProfit; + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + result += positionProfit; + } + else + { + result += positionProfit; + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Find Oldes Position ... + ulong GetOldestPosition( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + ulong result = 0; + + // + int age = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + double positionAbsProfit = MathAbs(positionProfit); + if (positionProfit >= 0) + { + continue; + } + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + string positionComment = mPositionInfo.Comment(); + ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(positionComment); + + // + // Calculate Position's Age ... + datetime positionOpenTime = mPositionInfo.Time(); + + // + // Retrieve Trade Open Bar Index based on Current Period ... + int positionOpenBarIndex = iBarShift( + positionSymbol, + positionPeriod, + positionOpenTime); + + // + // Calculate Trade Life ... + int positionAge = MathAbs(0 - positionOpenBarIndex); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + else + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + else + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Force Open a Buy/Long Position ... + bool Buy( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.Buy( + volume, + symbol, + price, + sl, + tp, + comment); + + // + return result; + } + + // + // Send BUY LIMIT order ... + bool BuyLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.BuyLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Send BUY STOP order ... + bool BuyStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.BuyStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Force Open a Sell/Short Position ... + bool Sell( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.Sell( + volume, + symbol, + price, + sl, + tp, + comment); + + // + return result; + } + + // + // Send SELL LIMIT order ... + bool SellLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.SellLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Send SELL STOP order ... + bool SellStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.SellStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Modify Position ... + bool Modify( + const ulong ticket, // position ticket + double sl = 0, // stop loss price + double tp = 0, // take profit + string comment = "" // comment + ) + { + // + bool result = false; + + // + // Validate Args ... + if (tp <= 0 && sl <= 0) + { + result = false; + return result; + } + + // + // Use Position Comment when there isn't new One ... + if (StringLen(comment) == 0) + { + comment = GetPositionComment(ticket); + } + + // + result = mTrader.PositionModify( + ticket, + sl, + tp, + comment); + + // + return result; + } + + // + // Close Position By Ticket ... + bool Close( + ulong ticket, // Position Ticket + string comment = "" // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + // Try to Select Position ... + if (!mPositionInfo.SelectByTicket(ticket)) + { + return result; + } + + // + // Close Position By Specific Comment ... + result = mTrader.PositionClose( + ticket, + mSlippage, + comment); + + // + return result; + } + + // + // Close All Positions ... + void CloseAllPositions( + string comment = "" // Close Position By Specific Comment + ) + { + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + Close( + positionTicket, + comment); + } + } + + // + // Close Partial By Ticket ... + bool ClosePartial( + ulong ticket, // Position Ticket + double volume, // Volume Size for Partial Closing + string comment = "" // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + if (!mPositionInfo.SelectByTicket(ticket)) + { + return result; + } + + // + result = mTrader.PositionClosePartial( + ticket, + volume, + mSlippage, + comment); + + // + return result; + } + + // + // Find Position Open Bar Index ... + int GetPositionOpenBarIndex( + const ulong ticket // position ticket + ) + { + // + int result = -1; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + string symbol = mPositionInfo.Symbol(); + datetime openAt = mPositionInfo.Time(); + string comment = mPositionInfo.Comment(); + ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment); + + // + result = iBarShift( + symbol, + period, + openAt); + } + + // + return result; + } + + // + bool GetPosition( + XPosition &position, // Holds result ... + ulong ticket // Required Position Ticket ... + ) + { + // + bool result = false; + + // + XPosition positions[]; + GetPositions(positions); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + result = iPosition.ticket == ticket; + if (!result) + { + continue; + } + + // + position = iPosition; + break; + } + + // + return result; + } + + // + // Retrieve Positions as an Array ... + void GetPositions( + XPosition &result[] // Hold Result ... + ) + { + // + Clean(result); + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong magic = mPositionInfo.Magic(); + ulong ticket = mPositionInfo.Ticket(); + string symbol = mPositionInfo.Symbol(); + datetime openAt = mPositionInfo.Time(); + double swap = mPositionInfo.Swap(); + double sl = mPositionInfo.StopLoss(); + double tp = mPositionInfo.TakeProfit(); + double profit = mPositionInfo.Profit(); + double volume = mPositionInfo.Volume(); + string comment = mPositionInfo.Comment(); + double entry = mPositionInfo.PriceOpen(); + double price = mPositionInfo.PriceCurrent(); + double commission = mPositionInfo.Commission(); + ENUM_POSITION_TYPE type = mPositionInfo.PositionType(); + ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment); + + // + XPosition iPosition = {}; + + // + iPosition.tp = tp; + iPosition.sl = sl; + iPosition.swap = swap; + iPosition.type = type; + iPosition.magic = magic; + iPosition.entry = entry; + iPosition.price = price; + iPosition.ticket = ticket; + iPosition.symbol = symbol; + iPosition.period = period; + iPosition.volume = volume; + iPosition.openAt = openAt; + iPosition.profit = profit; + iPosition.comment = comment; + iPosition.commission = commission; + + // + Add( + iPosition, + result); + } + } + + // + void GetPositions( + XPosition &result[], // Hold Result ... + string symbol, // Trading Symbol ... + ENUM_TIMEFRAMES period // Trading Period ... + ) + { + // + Clean(result); + + // + bool hasPeriod = period != NULL; + bool hasSymbol = symbol != NULL && StringLen(symbol) > 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return; + } + + // + XPosition allPositions[]; + GetPositions(allPositions); + + // + if (!hasPeriod && !hasSymbol) + { + // + Copy( + allPositions, + result); + + // + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = allPositions[i]; + + // + if (hasSymbol && + symbol != iPosition.symbol) + { + continue; + } + + // + ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(iPosition.comment); + if (hasPeriod && + period != positionPeriod) + { + continue; + } + + // + Add( + iPosition, + result); + } + } + + // + // Execute a Signal ... + bool ExecuteSignal( + XSignal &signal, // Signal ... + string comment = "", // Position Comment ... + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ... + datetime expiration = 0 // order expiration time + ) + { + // + bool result = false; + + // + double currentEntry = GetEntry( + signal.symbol, + signal.type); + bool isLong = IsLong(signal.type); + + // + ResetLastError(); + + // + if (signal.mode == X_ORDER_MODE_MARKET) + { + // + // Execute MArket Orders ... + if (isLong) + { + // + result = Buy( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + comment); + } + else + { + // + result = Sell( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + comment); + } + } + else if (signal.mode == X_ORDER_MODE_LIMIT) + { + // + // Execute Limit Orders ... + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? signal.entry < currentEntry + : signal.entry > currentEntry; + if (!result) + { + return result; + } + + // + // Check Expiration Date ... + result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY) + ? expiration > 0 + : true; + if (!result) + { + return result; + } + + // + if (isLong) + { + // + result = BuyLimit( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + else + { + // + result = SellLimit( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + } + else if (signal.mode == X_ORDER_MODE_STOP) + { + // + // Execute Stop Orders ... + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? signal.entry > currentEntry + : signal.entry < currentEntry; + if (!result) + { + return result; + } + + // + // Check Expiration Date ... + result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY) + ? expiration > 0 + : true; + if (!result) + { + return result; + } + + // + if (isLong) + { + // + result = BuyStop( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + else + { + // + result = SellStop( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + } + + // + if (!result) + { + LogMessage("Error: " + (string)GetLastError() + ", " + GetErrorDescription(GetLastError())); + } + else + { + // + // Retrieve Last Position Ticket ... + ulong ticket = GetLastOpenPositionTicket(); + + // + // Check Position have Support Signals or not ... + int supportsCount = ArraySize(signal.supports); + if (supportsCount > 0) + { + // + int executed = 0; + for (int i = 0; i < supportsCount; i++) + { + // + XSignal iSupport = signal.supports[i]; + + // + int supIndex = i + 1; + string iComment = GenerateSupportSignalComment( + ticket, + supIndex); + + // + bool isExecuted = ExecuteSignal( + iSupport, + iComment); + if (isExecuted) + { + executed++; + } + } + + // + result = executed == supportsCount; + } + } + + // + return result; + } + + // + // Execute a Collection of Signals ... + int ExecuteSignals( + const XSignal &signals[], // an Array of Signals ... + string comment = "", // Position Comment ... + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ... + datetime expiration = 0 // order expiration time + ) + { + // + int result = 0; + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < signalsCount; i++) + { + // + XSignal iSignal = signals[i]; + + // + if (StringLen(comment) == 0) + { + comment = GenerateProvidersString(iSignal); + } + + // + bool isExecuted = ExecuteSignal( + iSignal, + comment, + lifetime, + expiration); + + // + if (isExecuted) + { + result++; + } + } + + // + return result; + } + + // + // Retrieve in Profit Positions ... + void GetInProfitPositions( + XPosition &result[] // Hold Result ... + ) + { + // + Clean(result); + + // + XPosition allPositions[]; + GetPositions(allPositions); + int positionsCount = ArraySize(allPositions); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = allPositions[i]; + + // + if (iPosition.profit > 0) + { + Add( + iPosition, + result); + } + } + } + + // + // Retrieve in Drawdown Positions ... + void GetInDrawdownPositions( + XPosition &result[] // Hold Result ... + ) + { + // + Clean(result); + + // + XPosition allPositions[]; + GetPositions(allPositions); + int positionsCount = ArraySize(allPositions); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = allPositions[i]; + + // + if (iPosition.profit < 0) + { + Add( + iPosition, + result); + } + } + } + + // + // Close a Collection Of Positions ... + int ClosePositions( + XPosition &positions[], // Positions to Close ... + string comment = "" // Specified Comment ... + ) + { + // + int result = 0; + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isClosed = Close( + iPosition.ticket, + comment); + if (isClosed) + { + result++; + } + } + + // + return result; + } + + // + // Retrieve All Orders ... + void GetOrders( + XOrder &result[], // Holdes Result .... + string symbol, // Trading Symbol ... + ENUM_TIMEFRAMES period, // Trading TimeFrame ... + ENUM_ORDER_STATE state = NULL // Order State ... + ) + { + // + Clean(result); + + // + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return; + } + + // + // Since Orders may be so more than positions ... + // start Orders Collectiong Loops reverse ... + for (int i = ordersCount - 1; i >= 0; i--) + { + // + if (!mOrderInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mOrderInfo.Magic() != mMagicNumber) + { + continue; + } + + // + // Reading Order Info ... + long magic = mOrderInfo.Magic(); + double sl = mOrderInfo.StopLoss(); + ulong ticket = mOrderInfo.Ticket(); + double tp = mOrderInfo.TakeProfit(); + string oSymbol = mOrderInfo.Symbol(); + string comment = mOrderInfo.Comment(); + long positionID = mOrderInfo.PositionId(); + double openPrice = mOrderInfo.PriceOpen(); + datetime setupAt = mOrderInfo.TimeSetup(); + datetime executedAt = mOrderInfo.TimeDone(); + ENUM_ORDER_STATE oState = mOrderInfo.State(); + ENUM_ORDER_TYPE type = mOrderInfo.OrderType(); + double currentPrice = mOrderInfo.PriceCurrent(); + datetime expiredAt = mOrderInfo.TimeExpiration(); + double initialVolume = mOrderInfo.VolumeInitial(); + double currentVolume = mOrderInfo.VolumeCurrent(); + double stopLimitPrice = mOrderInfo.PriceStopLimit(); + ENUM_ORDER_TYPE_TIME lifetime = mOrderInfo.TypeTime(); + ENUM_ORDER_TYPE_FILLING filling = mOrderInfo.TypeFilling(); + + // + if (StringLen(symbol) > 0 && symbol != oSymbol) + { + continue; + } + + // + ENUM_TIMEFRAMES oPeriod = ExtractPositionPeriod(comment); + if (period != NULL && period != oPeriod) + { + continue; + } + + // + if (state != NULL && oState != state) + { + continue; + } + + // + // Now Create an instance of XOrder struct and fill it by + // retrieved data, and add it to results ... + XOrder iOrder = {}; + + // + iOrder.sl = sl; + iOrder.tp = tp; + iOrder.type = type; + iOrder.magic = magic; + iOrder.state = oState; + iOrder.ticket = ticket; + iOrder.smybol = oSymbol; + iOrder.period = oPeriod; + iOrder.setupAt = setupAt; + iOrder.comment = comment; + iOrder.filling = filling; + iOrder.lifetime = lifetime; + iOrder.expiredAt = expiredAt; + iOrder.openPrice = openPrice; + iOrder.pocitionID = positionID; + iOrder.executedAt = executedAt; + iOrder.currentPrice = currentPrice; + iOrder.initialVolume = initialVolume; + iOrder.currentVolume = currentVolume; + iOrder.stopLimitPrice = stopLimitPrice; + + // + Add( + iOrder, + result); + } + } + + // + int CountOrders() + { + return OrdersTotal(); + } + + // + // Cancel Specific Order ... + bool CancelOrder(ulong ticket) + { + return mTrader.OrderDelete(ticket); + } + + // + // Cancel Specific Orders ... + bool CancelOrders( + XOrder &orders[]) + { + // + bool result = false; + + // + int ordersCount = ArraySize(orders); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + bool isDeleted = mTrader.OrderDelete(iOrder.ticket); + if (isDeleted && !result) + { + result = isDeleted; + } + } + + // + return result; + } + + // + // Retrieve All Deals ... + void GetDeals(XDeal &result[]) + { + // + Clean(result); + + // + int dealsCount = HistoryDealsTotal(); + if (dealsCount <= 0) + { + return; + } + + // + for (int i = dealsCount - 1; i >= 0; i--) + { + // + if (!mDealInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mDealInfo.Magic() != mMagicNumber) + { + continue; + } + + // + // Reading Order Info ... + double swap = mDealInfo.Swap(); + ulong magic = mDealInfo.Magic(); + ulong order = mDealInfo.Order(); + ulong ticket = mDealInfo.Ticket(); + datetime time = mDealInfo.Time(); + double price = mDealInfo.Price(); + string symbol = mDealInfo.Symbol(); + double profit = mDealInfo.Profit(); + double volume = mDealInfo.Volume(); + string comment = mDealInfo.Comment(); + ulong positionId = mDealInfo.PositionId(); + ENUM_DEAL_ENTRY entry = mDealInfo.Entry(); + double commission = mDealInfo.Commission(); + ENUM_DEAL_TYPE type = mDealInfo.DealType(); + ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( + ticket, + DEAL_REASON); + + // + XDeal iDeal = {}; + + // + iDeal.swap = swap; + iDeal.time = time; + iDeal.type = type; + iDeal.magic = magic; + iDeal.entry = entry; + iDeal.order = order; + iDeal.price = price; + iDeal.ticket = ticket; + iDeal.symbol = symbol; + iDeal.profit = profit; + iDeal.volume = volume; + iDeal.reason = reason; + iDeal.comment = comment; + iDeal.positionId = positionId; + iDeal.commission = commission; + + // + Add( + iDeal, + result); + } + } + + // + // Retrieve all History Orders of Specific Deal ... + int GetDealHistory( + const XDeal &deal, // Specified Deal + XOrder &history[] // Hold Result + ) + { + // + int result = 0; + + // + Clean(history); + + // + bool isHistorySelected = HistorySelectByPosition(deal.positionId); + if (!isHistorySelected) + { + return result; + } + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + if (!mHistoryOrderInfo.SelectByIndex(i)) + { + continue; + } + + // + ulong ticket = mHistoryOrderInfo.Ticket(); + + // + long positionId = mHistoryOrderInfo.PositionId(); + if (positionId != deal.positionId) + { + continue; + } + + // + // Reading Order Info ... + long magic = mHistoryOrderInfo.Magic(); + double sl = mHistoryOrderInfo.StopLoss(); + double tp = mHistoryOrderInfo.TakeProfit(); + string oSymbol = mHistoryOrderInfo.Symbol(); + string comment = mHistoryOrderInfo.Comment(); + double openPrice = mHistoryOrderInfo.PriceOpen(); + datetime setupAt = mHistoryOrderInfo.TimeSetup(); + datetime executedAt = mHistoryOrderInfo.TimeDone(); + ENUM_ORDER_STATE oState = mHistoryOrderInfo.State(); + ENUM_ORDER_TYPE type = mHistoryOrderInfo.OrderType(); + double currentPrice = mHistoryOrderInfo.PriceCurrent(); + datetime expiredAt = mHistoryOrderInfo.TimeExpiration(); + double initialVolume = mHistoryOrderInfo.VolumeInitial(); + double currentVolume = mHistoryOrderInfo.VolumeCurrent(); + double stopLimitPrice = mHistoryOrderInfo.PriceStopLimit(); + ENUM_ORDER_TYPE_TIME lifetime = mHistoryOrderInfo.TypeTime(); + ENUM_ORDER_TYPE_FILLING filling = mHistoryOrderInfo.TypeFilling(); + + // + ENUM_TIMEFRAMES oPeriod = ExtractPositionPeriod(comment); + + // + // Now Create an instance of XOrder struct and fill it by + // retrieved data, and add it to results ... + XOrder iOrder = {}; + + // + iOrder.sl = sl; + iOrder.tp = tp; + iOrder.type = type; + iOrder.magic = magic; + iOrder.state = oState; + iOrder.ticket = ticket; + iOrder.smybol = oSymbol; + iOrder.period = oPeriod; + iOrder.setupAt = setupAt; + iOrder.comment = comment; + iOrder.filling = filling; + iOrder.lifetime = lifetime; + iOrder.expiredAt = expiredAt; + iOrder.openPrice = openPrice; + iOrder.pocitionID = positionId; + iOrder.executedAt = executedAt; + iOrder.currentPrice = currentPrice; + iOrder.initialVolume = initialVolume; + iOrder.currentVolume = currentVolume; + iOrder.stopLimitPrice = stopLimitPrice; + + // + Add( + iOrder, + history); + } + + // + result = ArraySize(history); + + // + return result; + } + + // + // Retrieve Specific Dates History Orders ... + int GetHistoryOrders( + XOrder &orders[], // Hold Result + string symbol = NULL, // Specify Symbol + ENUM_TIMEFRAMES period = NULL, // Speify Period + ENUM_ORDER_TYPE type = NULL, // Trading Type + ENUM_ORDER_STATE state = NULL, // Trading State + datetime startDate = 0, // Start Date + datetime endDate = 0 // End Date + ) + { + // + int result = 0; + + // + Clean(orders); + + // + if (startDate <= 0) + { + startDate = TimeCurrent() - (3 * PeriodSeconds(PERIOD_D1)); + } + + // + if (endDate <= 0) + { + endDate = TimeCurrent(); + } + + // + if (endDate <= startDate) + { + return result; + } + + // + bool isSelected = HistorySelect(startDate, endDate); + if (!isSelected) + { + return result; + } + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + if (!mHistoryOrderInfo.SelectByIndex(i)) + { + continue; + } + + // + // + // Reading Order Info ... + + // + long magic = mHistoryOrderInfo.Magic(); + if (magic != mMagicNumber) + { + continue; + } + + // + string oSymbol = mHistoryOrderInfo.Symbol(); + if (StringLen(symbol) > 0 && symbol != NULL && oSymbol != symbol) + { + continue; + } + + // + string comment = mHistoryOrderInfo.Comment(); + ENUM_TIMEFRAMES oPeriod = ExtractPositionPeriod(comment); + if (period != NULL && oPeriod != period) + { + continue; + } + + // + ENUM_ORDER_TYPE oType = mHistoryOrderInfo.OrderType(); + if (type != NULL && oType != type) + { + continue; + } + + // + ENUM_ORDER_STATE oState = mHistoryOrderInfo.State(); + if (state != NULL && oState != state) + { + continue; + } + + // + double sl = mHistoryOrderInfo.StopLoss(); + ulong ticket = mHistoryOrderInfo.Ticket(); + double tp = mHistoryOrderInfo.TakeProfit(); + long positionId = mHistoryOrderInfo.PositionId(); + double openPrice = mHistoryOrderInfo.PriceOpen(); + datetime setupAt = mHistoryOrderInfo.TimeSetup(); + datetime executedAt = mHistoryOrderInfo.TimeDone(); + double currentPrice = mHistoryOrderInfo.PriceCurrent(); + datetime expiredAt = mHistoryOrderInfo.TimeExpiration(); + double initialVolume = mHistoryOrderInfo.VolumeInitial(); + double currentVolume = mHistoryOrderInfo.VolumeCurrent(); + double stopLimitPrice = mHistoryOrderInfo.PriceStopLimit(); + ENUM_ORDER_TYPE_TIME lifetime = mHistoryOrderInfo.TypeTime(); + ENUM_ORDER_TYPE_FILLING filling = mHistoryOrderInfo.TypeFilling(); + + // + + // + // Now Create an instance of XOrder struct and fill it by + // retrieved data, and add it to results ... + XOrder iOrder = {}; + + // + iOrder.sl = sl; + iOrder.tp = tp; + iOrder.type = type; + iOrder.magic = magic; + iOrder.state = oState; + iOrder.ticket = ticket; + iOrder.smybol = oSymbol; + iOrder.period = oPeriod; + iOrder.setupAt = setupAt; + iOrder.comment = comment; + iOrder.filling = filling; + iOrder.lifetime = lifetime; + iOrder.expiredAt = expiredAt; + iOrder.openPrice = openPrice; + iOrder.pocitionID = positionId; + iOrder.executedAt = executedAt; + iOrder.currentPrice = currentPrice; + iOrder.initialVolume = initialVolume; + iOrder.currentVolume = currentVolume; + iOrder.stopLimitPrice = stopLimitPrice; + + // + Add( + iOrder, + orders); + } + + // + result = ArraySize(orders); + + // + return result; + } + + // + // Retrieve Specific Dates History Deals ... + int GetHistoryDeals( + XDeal &deals[], // Hold Result + string symbol = NULL, // Specify Symbol + ENUM_DEAL_TYPE type = NULL, // Specify Deal Type + ENUM_DEAL_REASON reason = NULL, // Specify Deal Reason + datetime startDate = 0, // Start Date + datetime endDate = 0 // End Date + ) + { + // + int result = 0; + + // + Clean(deals); + + // + if (startDate <= 0) + { + startDate = TimeCurrent() - (3 * PeriodSeconds(PERIOD_D1)); + } + + // + if (endDate <= 0) + { + endDate = TimeCurrent(); + } + + // + if (endDate <= startDate) + { + return result; + } + + // + bool isSelected = HistorySelect(startDate, endDate); + if (!isSelected) + { + return result; + } + + // + int dealsCount = HistoryDealsTotal(); + if (dealsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < dealsCount; i++) + { + // + if (!mDealInfo.SelectByIndex(i)) + { + continue; + } + + // + // Reading Deal Info ... + + // + long magic = mDealInfo.Magic(); + if (magic != mMagicNumber) + { + continue; + } + + // + string oSymbol = mDealInfo.Symbol(); + if (StringLen(symbol) > 0 && symbol != NULL && oSymbol != symbol) + { + continue; + } + + // + ENUM_DEAL_TYPE oType = mDealInfo.DealType(); + if (type != NULL && oType != type) + { + continue; + } + + // + ulong ticket = mDealInfo.Ticket(); + ENUM_DEAL_REASON oReason = (ENUM_DEAL_REASON)HistoryDealGetInteger( + ticket, + DEAL_REASON); + if (reason != NULL && oReason != reason) + { + continue; + } + + // + double swap = mDealInfo.Swap(); + ulong order = mDealInfo.Order(); + datetime time = mDealInfo.Time(); + double price = mDealInfo.Price(); + double profit = mDealInfo.Profit(); + double volume = mDealInfo.Volume(); + string comment = mDealInfo.Comment(); + ulong positionId = mDealInfo.PositionId(); + ENUM_DEAL_ENTRY entry = mDealInfo.Entry(); + double commission = mDealInfo.Commission(); + + // + XDeal iDeal; + + // + iDeal.swap = swap; + iDeal.time = time; + iDeal.type = type; + iDeal.magic = magic; + iDeal.entry = entry; + iDeal.order = order; + iDeal.price = price; + iDeal.ticket = ticket; + iDeal.symbol = symbol; + iDeal.profit = profit; + iDeal.volume = volume; + iDeal.reason = reason; + iDeal.comment = comment; + iDeal.positionId = positionId; + iDeal.commission = commission; + + // + Add( + iDeal, + deals); + } + + // + result = ArraySize(deals); + + // + return result; + } + + // + // Find Deal Period ... + ENUM_TIMEFRAMES GetDealPeriod(const XDeal &deal) + { + // + ENUM_TIMEFRAMES result = NULL; + + // + XOrder history[]; + int historyCount = GetDealHistory( + deal, + history); + if (historyCount <= 0) + { + return result; + } + + // + for (int i = 0; i < historyCount; i++) + { + // + XOrder iOrder = history[i]; + + // + if (StringLen(iOrder.comment) == 0) + { + continue; + } + + // + string periodStr = ExtractPositionPeriodString(iOrder.comment); + if (StringLen(periodStr) > 0) + { + // + result = ToPeriod(periodStr); + break; + } + } + + // + return result; + } + + // + // Find Deal Position Comment ... + string GetDealPositionComment(const XDeal &deal) + { + // + string result = ""; + + // + XOrder history[]; + int historyCount = GetDealHistory( + deal, + history); + if (historyCount <= 0) + { + return result; + } + + // + for (int i = 0; i < historyCount; i++) + { + // + XOrder iOrder = history[i]; + + // + if (StringLen(iOrder.comment) > 0) + { + // + result = iOrder.comment; + break; + } + } + + // + return result; + } + + // + // Generate String Representation Of Position's Time Frame ... + string GeneratePositionPeriodComment(ENUM_TIMEFRAMES period) + { + // + string result = mPeriodPrefix + "(" + ToString(period) + ")"; + + // + return result; + } + + // + string ExtractPositionPeriodString(string comment) + { + // + string result = ""; + + // + if (StringLen(comment) <= 0) + { + return result; + } + + // + result = ExtractString( + comment, + mPeriodPrefix + "(", + ")"); + + // + return result; + } + + // + // Extract Position Time Frame From it's Comment ... + ENUM_TIMEFRAMES ExtractPositionPeriod(string comment) + { + // + ENUM_TIMEFRAMES result = NULL; + + // + string periodStr = ExtractPositionPeriodString(comment); + if (StringLen(periodStr) <= 0) + { + return result; + } + + // + result = ToPeriod(periodStr); + + // + return result; + } + + // + // Retrieve Last Open Position Ticket ... + ulong GetLastOpenPositionTicket() + { + // + ulong result = 0; + + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + result = PositionGetTicket(PositionsTotal() - 1); + + // + return result; + } + + // + // Retrieve Last Placed Order Ticket ... + ulong GetLastPlacedOrderTicket() + { + // + ulong result = 0; + + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + if (mOrderInfo.SelectByIndex(ordersCount - 1)) + { + result = mOrderInfo.Ticket(); + } + + // + return result; + } + + // + // SUPPORT Signals ... + + // + // Retrieve a Position if Exists + // by all of it's Supported Positon/Order (s) ... + bool GetPositionPack( + ulong ticket, // Sepcified Position's Ticket + XPositionPack &pack // Hold Result ... + ) + { + // + bool result = false; + + // + int positionsCount = CountPositions(); + int ordersCount = CountOrders(); + if (ordersCount <= 0 && positionsCount <= 0) + { + return result; + } + + // + XPosition position; + result = GetPosition( + position, + ticket); + if (!result) + { + return result; + } + + // + XOrder supportOrders[]; + XPosition supportPositions[]; + + // + XOrder orders[]; + GetOrders( + orders, + position.symbol, + position.period, + ORDER_STATE_PLACED); + ordersCount = ArraySize(orders); + + // + // Select Orders ... + if (ordersCount > 0) + { + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + string params[]; + bool hasSupport = ExtractSupportParams( + iOrder.comment, + params); + if (hasSupport) + { + // + ulong parentTicket = ExtractParentTicket(iOrder.comment); + if (parentTicket == ticket) + { + // + Add( + iOrder, + supportOrders); + } + } + } + } + + // + XPosition positions[]; + GetPositions( + positions, + position.symbol, + position.period); + positionsCount = ArraySize(positions); + + // + // Select Positions ... + if (positionsCount > 0) + { + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + string params[]; + bool hasSupport = ExtractSupportParams( + iPosition.comment, + params); + if (hasSupport) + { + // + ulong parentTicket = ExtractParentTicket(iPosition.comment); + if (parentTicket == ticket) + { + // + Add( + iPosition, + supportPositions); + } + } + } + } + + // + int supportOrdersCount = ArraySize(supportOrders); + int supportPositionsCount = ArraySize(supportPositions); + + // + pack.ticket = ticket; + pack.position = position; + + // + Copy(supportOrders, + pack.supportOrders); + Copy(supportPositions, + pack.supportPositions); + + // + pack.supportOrdersCount = supportOrdersCount; + pack.supportPositionsCount = supportPositionsCount; + + // + result = true; + + // + return result; + } + + // + // Extract specific Positions Pack ... + // in this senario there is no need to Position exists itself ... + bool GetPositionPack( + ulong ticket, // Specified Positions Ticket ... + string symbol, // Specified Position Symbol ... + ENUM_TIMEFRAMES period, // Specified Position Period ... + XPositionPack &pack // Hold Result ... + ) + { + // + bool result = false; + + // + // NOTE: We Have to Force Retrieve Position's pack event + // it's parent Position not Eists ... + pack.ticket = ticket; + pack.supportOrdersCount = 0; + Clean(pack.supportOrders); + pack.supportPositionsCount = 0; + Clean(pack.supportPositions); + + // + XPosition position; + bool hasPosition = GetPosition( + position, + ticket); + if (hasPosition) + { + pack.position = position; + } + + // + XOrder supportOrders[]; + XPosition supportPositions[]; + + // + XOrder orders[]; + GetOrders( + orders, + symbol, // Specified Symbol ... + period, // Specified Period + ORDER_STATE_PLACED // Just UnTriggered Orders ... + ); + int ordersCount = ArraySize(orders); + + // + // Select Orders ... + if (ordersCount > 0) + { + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + string params[]; + bool hasSupport = ExtractSupportParams( + iOrder.comment, + params); + if (hasSupport) + { + // + ulong parentTicket = ExtractParentTicket(iOrder.comment); + if (parentTicket == ticket) + { + // + Add( + iOrder, + supportOrders); + } + } + } + } + + // + int supportOrdersCount = ArraySize(supportOrders); + if (supportOrdersCount > 0) + { + // + pack.supportOrdersCount = supportOrdersCount; + + // + Copy( + supportOrders, + pack.supportOrders); + } + + // + XPosition positions[]; + GetPositions( + positions, + symbol, // Specified Symbol ... + period // Specified Period ... + ); + int positionsCount = ArraySize(positions); + + // + // Select Positions ... + if (positionsCount > 0) + { + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + string params[]; + bool hasSupport = ExtractSupportParams( + iPosition.comment, + params); + if (hasSupport) + { + // + ulong parentTicket = ExtractParentTicket(iPosition.comment); + if (parentTicket == ticket) + { + // + Add( + iPosition, + supportPositions); + } + } + } + } + + // + int supportPositionsCount = ArraySize(supportPositions); + if (supportPositionsCount > 0) + { + // + pack.supportPositionsCount = supportPositionsCount; + + // + Copy( + supportPositions, + pack.supportPositions); + } + + // + result = supportOrdersCount > 0 || supportPositionsCount > 0; + + // + return result; + } + + // + // Extract Specific Deals Position's Pack ... + // this used when a Position SL or TP triggered and we want to close + // all it's Supported Packs ... + bool GetDealPack( + const XDeal &deal, + XPositionPack &pack) + { + // + bool result = false; + + // + ulong ticket = deal.positionId; + ENUM_TIMEFRAMES dealPeriod = GetDealPeriod(deal); + string dealSymbol = deal.symbol; + + // + // So We Have to Get Positions Pack ... + result = GetPositionPack( + ticket, + dealSymbol, + dealPeriod, + pack); + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... +protected: + // + // Private ... + + // + // EVENTS Handlers Notifiers ... + + // + // STATE ... + void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) + { + // + int count = ArraySize(mTradeStateChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i]; + iHandler(state); + } + } + + // + // DEALS ... + void NotifyDealsChangeEvent(int changes) + { + // + int count = ArraySize(mDealsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnDealsChanged iHandler = mDealsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // ORDERS ... + void NotifyOrdersChangeEvent(int changes) + { + // + int count = ArraySize(mOrdersChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnOrdersChanged iHandler = mOrdersChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // POSITIONS ... + void NotifyPositionsChangeEvent(int changes) + { + // + int count = ArraySize(mPositionsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // TPSL ... + + // + void NotifyStopLossEvent(const XDeal &deal) + { + // + int count = ArraySize(mStopLossEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnStopLoss iHandler = mStopLossEventHandlers[i]; + iHandler(deal); + } + } + + // + void NotifyTakeProfitEvent(const XDeal &deal) + { + // + int count = ArraySize(mTakeProfitEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTakeProfit iHandler = mTakeProfitEventHandlers[i]; + iHandler(deal); + } + } + +private: + // + // using deviation, it must be in Point ... + int mSlippage; + + // + // using magic number ... + ulong mMagicNumber; + + // + // using CTrade instance ... + XSCTradeBase mTrader; + + // + // Deals Info ... + CDealInfo mDealInfo; + + // + // Order Info ... + COrderInfo mOrderInfo; + + // + // using PositionInfo instance ... + CPositionInfo mPositionInfo; + + // + // History Orders ... + CHistoryOrderInfo mHistoryOrderInfo; + + // + // ADDITIONAL Data ... + + // + string mPeriodPrefix; + + // + // START Trade Processing ... + // + + // + int mDaysForRead; + + // + // set the limits of the trade history on the global scope ... + + // + // // start date for trade history in cache ... + datetime mStartDate; + + // + // end date for trade history in cache ... + datetime mEndDate; + + // + // global OnTrade counters ... + + // + // number of active orders ... + int mOrdersCount; + + // + // number of open positions ... + int mPositionsCount; + + // + // number of deals in the trade history cache ... + int mDealsCount; + + // + // number of orders in the trade history cache ... + int mHistoryOrdersCount; + + // + // flag of counter relevance ... + bool mScanStarted; + + // + // Check Statrt Date In Trade History ... + void CheckStartDateInTradeHistory() + { + // + // initial interval, if we were to start working right now .. + datetime currStart = TimeCurrent() - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + + // + // make sure that the start limit of the trade history has not gone + // more than 1 day over the intended date ... + if (currStart - mStartDate > PeriodSeconds(PERIOD_D1)) + { + // + // correct the start date of history to be loaded in the cache ... + mStartDate = currStart; + + // + // now reload the trade history for the updated interval ... + HistorySelect(mStartDate, mEndDate); + + // + // correct the deal and order counters in history for further comparison + mHistoryOrdersCount = HistoryOrdersTotal(); + mDealsCount = HistoryDealsTotal(); + } + } + + // + // Process On Trade Context ... + void ProcessOnTradeContext( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + mEndDate = TimeCurrent(); + + // + ResetLastError(); + + // + // download trading history from the specified interval to the program cache ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current values ... + int currOrders = OrdersTotal(); + int currPositions = PositionsTotal(); + int currDeals = HistoryDealsTotal(); + int currHistoryOrders = HistoryOrdersTotal(); + + // + // Orders ... + // check if the number of active orders has been changed ... + if (currOrders != mOrdersCount) + { + // + // number of active orders has been changed ... + result.hasNewOrder = true; + result.newOrders = currOrders - mOrdersCount; + + // + // update the value ... + mOrdersCount = currOrders; + } + + // + // Positions ... + // changes in the number of open positions ... + if (currPositions != mPositionsCount) + { + // + // number of open positions has been changed ... + result.hasNewPosition = true; + result.newPositions = currPositions - mPositionsCount; + + // + // update the value ... + mPositionsCount = currPositions; + } + + // + // Deals ... + // changes in the number of deals in the trade history cache ... + if (currDeals != mDealsCount) + { + // + // number of deals in the trade history cache has been changed ... + result.hasNewDeal = true; + result.newDeals = currDeals - mDealsCount; + + // + // update the value ... + mDealsCount = currDeals; + } + + // + // History Orders ... + // changes in the number of history orders in the trade history cache ... + if (currHistoryOrders != mHistoryOrdersCount) + { + // + // number of history orders in the trade history cache has been changed ... + result.hasNewHistoryOrder = true; + result.newHistoryOrders = currHistoryOrders - mHistoryOrdersCount; + + // + // update the value ... + mHistoryOrdersCount = currHistoryOrders; + } + + // + // checking if it is necessary to change the limits of the trade history to be requested in cache ... + CheckStartDateInTradeHistory(); + } + + // + // Reset On Trade Scanner Context ... + void ResetOnTradeContext() + { + // + mEndDate = TimeCurrent(); + mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + } + + // + // Initial Context Of Trade Scanner ... + void InitOnTradeContext() + { + // + ResetLastError(); + + // + mOrdersCount = OrdersTotal(); + mPositionsCount = PositionsTotal(); + + // + // load history ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current value ... + mDealsCount = HistoryDealsTotal(); + mHistoryOrdersCount = HistoryOrdersTotal(); + + // + mScanStarted = true; + } + + // + // Deals Changed Event Handlers ... + TOnDealsChanged mDealsChangedEventHandlers[]; + + // + // Orders Changed Event Handlers ... + TOnOrdersChanged mOrdersChangedEventHandlers[]; + + // + // Positions Changed Event Handlers ... + TOnPositionsChanged mPositionsChangedEventHandlers[]; + + // + // Trade State Changed Event Handlers ... + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + // TPSL ... + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + + // + // END Trade Processing ... + // +}; + +// +// START Usefull Functions ... +// + +// +// Add Specific XPosition to Specified Array ... +void Add( + XDeal &item, + XDeal &buffer[]) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + XOrder &item, + XOrder &buffer[]) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + XPosition &item, + XPosition &buffer[]) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} + +// +// Clear All Items Inside Array ... +void Clean(XDeal &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(XOrder &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(XPosition &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} + +// +// Generate Identifier Tag ... +string GenerateTag(XSignal &info) +{ + // + string result = ""; + + // + result = info.symbol + "," + ToString(info.period); + + // + return result; +} + +// +// Convert Position to Signal ... +XSignal ToSignalInfo( + XPosition &position) +{ + // + XSignal result; + + // + result.tp = position.tp; + result.sl = position.sl; + result.type = position.type; + result.entry = position.entry; + result.symbol = position.symbol; + result.period = position.period; + result.volume = position.volume; + + // + return result; +} + +// +// AGE Calculations ... +// + +// +// Retrieve a Position Age ... +int GetAge( + XPosition &position, // Selected Position ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + position.symbol, + period, + position.openAt); + + // + return result; +} + +// +// Retrieve an Order Age ... +int GetAge( + XOrder &order, // Selected Order ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + order.smybol, + period, + order.setupAt); + + // + return result; +} + +// +// Retrieve a Deal Age ... +int GetAge( + XDeal &deal, // Selected Deal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + deal.symbol, + period, + deal.time); + + // + return result; +} + +// +// OLDEST Detection ... + +// +// Get Oldest Deal ... +int GetOldest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Deal ... +int GetYoungest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldest Order ... +int GetOldest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Order ... +int GetYoungest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldes Position ... +int GetOldest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Position ... +int GetYoungest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-sample.ea copy.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-sample.ea copy.mq5 new file mode 100644 index 0000000..76f3280 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-sample.ea copy.mq5 @@ -0,0 +1,728 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XSAMPLE MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XSAMPLE +// Description: an Exper Advisor which used RSI and MA +// to Analyse Market ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XSAMPLE" +#property strict + +// +#define ShortName "XSAMPLE" + +// +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.draw.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" + +// +#include "../Helpers/x-saherelm.x121.xmc.helper.mq5" +#include "../Helpers/x-saherelm.x121.xstr.helper.mq5" +#include "../Helpers/x-saherelm.x121.xche.helper.mq5" +#include "../Helpers/x-saherelm.x121.xosc.helper.mq5" + +// +#include "../Classes/x-saherelm.x121.xmcycle.class.mq5" + +// +// Inputs ... +long xSampleEAMagicNumber = 78692110; // Magic Number +int xSampleEASlippage = 10; // Slippgae + +// +double xSampleEAVolume = 0.01; + +// +// Vars ... +string xSampleEASymbol; +ENUM_TIMEFRAMES xSampleEAPeriod; + +// +int maxBuys = 1; +int maxSells = 1; +int buyCount = 0; +int sellCount = 0; + +// +double _tp = 0; +double _sl = 0; +double _entry = 0; +ENUM_POSITION_TYPE _type = NULL; + +// +MqlTick xSampleEATick; +XSCTrade *xSampleEATrader; + +// // +// // XCHE ... +// X121CHEInputs xSampleEACHEInputs; +// XSCX121CHEHelper xSampleEACHEHelper; + +// // +// // XMC ... +// X121MCInputs xSampleEAMCInputs; +// XSCX121MCHelper xSampleEAMCHelper; + +// // +// // XSTR ... +// X121STRInputs xSampleEASTRInputs; +// XSCX121STRHelper xSampleEASTRHelper; + +// // +// // XOSC ... +// X121OSCInputs xSampleEAOSCInputs; +// XSCX121OSCHelper xSampleEAOSCHelper; + +// // +// // XICH ... +// X121ICHInputs xSampleEAICHInputs; +// XSCX121ICHHelper xSampleEAICHHelper; + +// +// X121MCycle ... +X121MCycleInputs xSampleEA121MCInputs; +XSC121Market xSampleEA121MC; + +// +// Event Handlers ... +// +// Initialization ... +int OnInit() +{ + // + if (xSampleEASymbol == NULL || StringLen(xSampleEASymbol) <= 0) + { + xSampleEASymbol = _Symbol; + } + + // + if (xSampleEAPeriod == NULL) + { + xSampleEAPeriod = _Period; + } + + // + // Validate Inputs ... + if (!XSampleEAValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + drawPrefix = ShortName; + + // // + // // XCHE ... + + // // + // xSampleEACHEInputs.Default(); + // if (!xSampleEACHEInputs.IsValid()) + // { + // return INIT_PARAMETERS_INCORRECT; + // } + + // // + // if (!xSampleEACHEHelper.Init( + // xSampleEASymbol, + // xSampleEAPeriod, + // xSampleEACHEInputs)) + // { + // return INIT_PARAMETERS_INCORRECT; + // } + + // // + // // XMC ... + + // // + // xSampleEAMCInputs.Default(); + // if (!xSampleEAMCInputs.IsValid()) + // { + // return INIT_PARAMETERS_INCORRECT; + // } + + // // + // if (!xSampleEAMCHelper.Init( + // xSampleEASymbol, + // xSampleEAPeriod, + // xSampleEAMCInputs)) + // { + // return INIT_PARAMETERS_INCORRECT; + // } + + // // + // // XSTR ... + + // // + // xSampleEASTRInputs.Default(); + // if (!xSampleEASTRInputs.IsValid()) + // { + // return INIT_PARAMETERS_INCORRECT; + // } + + // // + // if (!xSampleEASTRHelper.Init( + // xSampleEASymbol, + // xSampleEAPeriod, + // xSampleEASTRInputs)) + // { + // return INIT_PARAMETERS_INCORRECT; + // } + + // // + // // XOSC ... + + // // + // xSampleEAOSCInputs.Default(); + // if (!xSampleEAOSCInputs.IsValid()) + // { + // return INIT_PARAMETERS_INCORRECT; + // } + + // // + // if (!xSampleEAOSCHelper.Init( + // xSampleEASymbol, + // xSampleEAPeriod, + // xSampleEAOSCInputs)) + // { + // return INIT_PARAMETERS_INCORRECT; + // } + + // + // XICH ... + + // // + // xSampleEAICHInputs.Default(); + // if (!xSampleEAICHInputs.IsValid()) + // { + // return INIT_PARAMETERS_INCORRECT; + // } + + // // + // if (!xSampleEAICHHelper.Init( + // xSampleEASymbol, + // xSampleEAPeriod, + // xSampleEAICHInputs)) + // { + // return INIT_PARAMETERS_INCORRECT; + // } + + // + // X121Market Cycle ... + bool result = xSampleEA121MCInputs.Init( + xSampleEASymbol, + xSampleEAPeriod, + X_MARKET_CYCLE_SHORT, + PERIOD_H1, + X_PERIOD_MANUALLY // + ); + + // + // after Inputs Initialize Successfully we must prepare Styling for Draw ... + ApplyMCDrawStyles(); + + // + result = xSampleEA121MC.Init( + xSampleEA121MCInputs + // + ); + if (!result) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize XTrader ... + xSampleEATrader = new XSCTrade( + xSampleEASlippage, + xSampleEAMagicNumber); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 XSampleEA Providers ... + delete xSampleEATrader; +} + +// +// On Tick Handler ... +void OnTick() +{ + // + if (!IsNewCandle( + xSampleEASymbol, + xSampleEAPeriod)) + { + return; + } + + // + // Reading Tick ... + if (!SymbolInfoTick(xSampleEASymbol, xSampleEATick)) + { + return; + } + + // + // Counting Currently Open Positions ... + buyCount = xSampleEATrader.CountPositions(xSampleEASymbol, POSITION_TYPE_BUY); + sellCount = xSampleEATrader.CountPositions(xSampleEASymbol, POSITION_TYPE_SELL); + + // + // TestMC(); + // TestCHE(); + // TestSTR(); + // TestOSC(); + // TestICH(); + + // + // TestMCycle(); + + // + // Draw Market Cycle Bars On Chart ... + int offset = 0; + xSampleEA121MC.Draw( + ChartID(), + 0, + offset + // + ); + + // + if (buyCount < maxBuys) + { + // + // Check For Buy Signals ... + } + + // + if (sellCount < maxSells) + { + // + // Check for Sell Signals ... + } +} + +// +// Custom Functions ... + +// +// Validate Variables nd Inputs ... +bool XSampleEAValidateInputs() +{ + // + bool result = false; + + // + result = + // + xSampleEASlippage > 0 && + xSampleEAMagicNumber > 0 + // + ; + + // + return result; +} + +// +// Tools ... + +// // +// void TestCHE() +// { +// // +// double longExit1 = xSampleEACHEHelper.GetLongExit1(0); +// if (NotEmpty(longExit1)) +// { +// Print("LE1: " + ToString(longExit1)); +// } + +// // +// double lEs[]; +// int lEsCount = xSampleEACHEHelper.CopyLongExit1( +// 0, +// 2, +// lEs); +// if (lEsCount > 0) +// { +// // +// for (int i = 0; i < lEsCount; i++) +// { +// // +// double iVal = lEs[i]; + +// // +// if (NotEmpty(iVal)) +// { +// // +// Print("LE " + ToString(i) + ": " + ToString(iVal)); +// } +// } + +// // +// Print(" "); +// } +// } + +// // +// void TestMC() +// { +// // +// double fast = xSampleEAMCHelper.GetFast(0); +// if (NotEmpty(fast)) +// { +// Print("Fast: " + ToString(fast)); +// } + +// // +// double slow = xSampleEAMCHelper.GetSlow(0); +// if (NotEmpty(slow)) +// { +// Print("Slow: " + ToString(slow)); +// } +// } + +// // +// void TestSTR() +// { +// // +// double trend = xSampleEASTRHelper.GetTrend(0); +// if (NotEmpty(trend)) +// { +// Print("Trend: " + ToString(trend)); +// } + +// // +// double state = xSampleEASTRHelper.GetState(0); +// if (NotEmpty(state)) +// { +// Print("State: " + EnumToString(xSampleEASTRHelper.ToState(state))); +// } +// } + +// // +// void TestOSC() +// { +// // +// double rsi = xSampleEAOSCHelper.GetRSI(0); +// if (NotEmpty(rsi)) +// { +// Print("RSI: " + ToString(rsi)); +// } + +// // +// double cci = xSampleEAOSCHelper.GetCCI(0); +// if (NotEmpty(cci)) +// { +// Print("CCI: " + ToString(cci)); +// } +// } + +// // +// void TestICH() +// { +// // +// double tenkanSen = xSampleEAICHHelper.GetTenkanSen(1); +// double tenkanSenLast = xSampleEAICHHelper.GetTenkanSen(2); +// // +// double kijunSen = xSampleEAICHHelper.GetKijunSen(1); +// double kijunSenLast = xSampleEAICHHelper.GetKijunSen(2); +// // +// double chikouSpan = xSampleEAICHHelper.GetChikouSpan(1); +// // +// double senkouSpanA = xSampleEAICHHelper.GetSenkouSpanA(1); +// double senkouSpanALast = xSampleEAICHHelper.GetSenkouSpanA(2); +// // +// double senkouSpanB = xSampleEAICHHelper.GetSenkouSpanB(1); +// double senkouSpanBLast = xSampleEAICHHelper.GetSenkouSpanB(2); +// // +// double futureSenkouSpanA = xSampleEAICHHelper.GetFutureSenkouSpanA(1); +// double futureSenkouSpanALast = xSampleEAICHHelper.GetFutureSenkouSpanA(2); +// // +// double futureSenkouSpanB = xSampleEAICHHelper.GetFutureSenkouSpanB(1); +// double futureSenkouSpanBLast = xSampleEAICHHelper.GetFutureSenkouSpanB(2); + +// // +// bool isTenkanSenCrossedOverKijunSen = +// // +// tenkanSen > kijunSen && +// tenkanSenLast <= kijunSenLast +// // +// ; +// if (isTenkanSenCrossedOverKijunSen) +// { +// Print("isTenkanSenCrossedOverKijunSen"); +// } + +// // +// bool isTenkanSenCrossedUnderKijunSen = +// // +// tenkanSen < kijunSen && +// tenkanSenLast >= kijunSenLast +// // +// ; +// if (isTenkanSenCrossedUnderKijunSen) +// { +// Print("isTenkanSenCrossedUnderKijunSen"); +// } + +// // +// bool isKumoSwitchedToBullish = +// // +// senkouSpanA > senkouSpanB && +// senkouSpanALast <= senkouSpanBLast +// // +// ; +// if (isKumoSwitchedToBullish) +// { +// Print("isKumoSwitchedToBullish"); +// } + +// // +// bool isKumoSwitchedToBearish = +// // +// senkouSpanA < senkouSpanB && +// senkouSpanALast >= senkouSpanBLast +// // +// ; +// if (isKumoSwitchedToBearish) +// { +// Print("isKumoSwitchedToBearish"); +// } + +// // +// bool isFutureKumoSwitchedToBullish = +// // +// futureSenkouSpanA > futureSenkouSpanB && +// futureSenkouSpanALast <= futureSenkouSpanBLast +// // +// ; +// if (isFutureKumoSwitchedToBullish) +// { +// Print("isFutureKumoSwitchedToBullish"); +// } + +// // +// bool isFutureKumoSwitchedToBearish = +// // +// futureSenkouSpanA < futureSenkouSpanB && +// futureSenkouSpanALast >= futureSenkouSpanBLast +// // +// ; +// if (isFutureKumoSwitchedToBearish) +// { +// Print("isFutureKumoSwitchedToBearish"); +// } +// } + +// // +// void TestMCycle() +// { +// // +// // double fast0 = xSampleEA121MC.mc.GetFast(0); +// // double fast1 = xSampleEA121MC.mc.GetFast(1); + +// // // +// // double slow0 = xSampleEA121MC.mc.GetSlow(0); +// // double slow1 = xSampleEA121MC.mc.GetSlow(1); + +// // // +// // double tenkanSen = xSampleEA121MC.ich.GetTenkanSen(0); + +// // // +// // Print("Fast0: " + ToString(fast0)); +// // Print("Slow0: " + ToString(slow0)); + +// // // +// // Print("Fast1: " + ToString(fast1)); +// // Print("Slow1: " + ToString(slow1)); + +// // // +// // Print("TenkanSen: " + ToString(tenkanSen)); + +// // // +// // bool isFastCrossedOverSlow = +// // // +// // fast0 > slow0 && +// // fast1 <= slow1 +// // // +// // ; +// // if (isFastCrossedOverSlow) +// // { +// // // +// // Print("Fast Crossed Over Slow"); +// // } + +// // +// X121MCycleConditions conditions = xSampleEA121MC.GetMarketConditions(0); +// string mcSummary = conditions.GenerateSummary(); +// Print(mcSummary); + +// // +// Print(" "); +// } + +void ApplyMCDrawStyles() +{ + // + // Here we Apply All Draw Styles on Input of Market Cycle ... + xSampleEA121MCInputs.drawCBar = true; + xSampleEA121MCInputs.drawPBar = true; + xSampleEA121MCInputs.drawLabels = true; + xSampleEA121MCInputs.drawCBarMid = true; + xSampleEA121MCInputs.drawPBarMid = true; + + // + // Current ... + + // + // MidLine ... + xSampleEA121MCInputs.cBarMidDrawSpecs.width = 1; + xSampleEA121MCInputs.cBarMidDrawSpecs.style = STYLE_DOT; + xSampleEA121MCInputs.cBarMidDrawSpecs.clr = clrSpringGreen; + xSampleEA121MCInputs.cBarMidDrawSpecs.Label( + xSampleEA121MCInputs.cycle.prefix + "_C MID", + xSampleEA121MCInputs.cBarMidDrawSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + xSampleEA121MCInputs.cBarDrawSpecs.Default(); + xSampleEA121MCInputs.cBarDrawSpecs.Width(1); + xSampleEA121MCInputs.cBarDrawSpecs.Style(STYLE_DOT); + // + xSampleEA121MCInputs.cBarDrawSpecs.openStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C O", + xSampleEA121MCInputs.cBarDrawSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.cBarDrawSpecs.highStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C H", + xSampleEA121MCInputs.cBarDrawSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.cBarDrawSpecs.closeStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C C", + xSampleEA121MCInputs.cBarDrawSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.cBarDrawSpecs.lowStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C L", + xSampleEA121MCInputs.cBarDrawSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + xSampleEA121MCInputs.pBarMidDrawSpecs.width = 2; + xSampleEA121MCInputs.pBarMidDrawSpecs.style = STYLE_SOLID; + xSampleEA121MCInputs.pBarMidDrawSpecs.clr = clrLimeGreen; + xSampleEA121MCInputs.pBarMidDrawSpecs.Label( + xSampleEA121MCInputs.cycle.prefix + "_P MID", + xSampleEA121MCInputs.pBarMidDrawSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + xSampleEA121MCInputs.pBarDrawSpecs.Default(); + xSampleEA121MCInputs.pBarDrawSpecs.Width(2); + // + xSampleEA121MCInputs.pBarDrawSpecs.openStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P O", + xSampleEA121MCInputs.pBarDrawSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.pBarDrawSpecs.highStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P H", + xSampleEA121MCInputs.pBarDrawSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.pBarDrawSpecs.closeStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P C", + xSampleEA121MCInputs.pBarDrawSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.pBarDrawSpecs.lowStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P L", + xSampleEA121MCInputs.pBarDrawSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); +} \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-sample.ea.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-sample.ea.mq5 new file mode 100644 index 0000000..b0e98b3 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/x-sample.ea.mq5 @@ -0,0 +1,180 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XSAMPLE MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XSAMPLE +// Description: an Exper Advisor which used RSI and MA +// to Analyse Market ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XSAMPLE" +#property strict + +// +#define ShortName "XSAMPLE" + +// +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.draw.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" + +// +// Inputs ... +long xSampleEAMagicNumber = 78692110; // Magic Number +int xSampleEASlippage = 10; // Slippgae + +// +double xSampleEAVolume = 0.01; + +// +// Vars ... +string xSampleEASymbol; +ENUM_TIMEFRAMES xSampleEAPeriod; + +// +int maxBuys = 1; +int maxSells = 1; +int buyCount = 0; +int sellCount = 0; + +// +double _tp = 0; +double _sl = 0; +double _entry = 0; +ENUM_POSITION_TYPE _type = NULL; + +// +MqlTick xSampleEATick; +XSCTrade *xSampleEATrader; + +// +// Event Handlers ... +// +// Initialization ... +int OnInit() +{ + // + if (xSampleEASymbol == NULL || StringLen(xSampleEASymbol) <= 0) + { + xSampleEASymbol = _Symbol; + } + + // + if (xSampleEAPeriod == NULL) + { + xSampleEAPeriod = _Period; + } + + // + // Validate Inputs ... + if (!XSampleEAValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + drawPrefix = ShortName; + + // + // Initialize XTrader ... + xSampleEATrader = new XSCTrade( + xSampleEASlippage, + xSampleEAMagicNumber); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 XSampleEA Providers ... + delete xSampleEATrader; +} + +// +// On Tick Handler ... +void OnTick() +{ + // + if (!IsNewCandle( + xSampleEASymbol, + xSampleEAPeriod)) + { + return; + } + + // + // Reading Tick ... + if (!SymbolInfoTick(xSampleEASymbol, xSampleEATick)) + { + return; + } + + // + // Counting Currently Open Positions ... + buyCount = xSampleEATrader.CountPositions(xSampleEASymbol, POSITION_TYPE_BUY); + sellCount = xSampleEATrader.CountPositions(xSampleEASymbol, POSITION_TYPE_SELL); + + // + if (buyCount < maxBuys) + { + // + // Check For Buy Signals ... + } + + // + if (sellCount < maxSells) + { + // + // Check for Sell Signals ... + } +} + +// +// Custom Functions ... + +// +// Validate Variables nd Inputs ... +bool XSampleEAValidateInputs() +{ + // + bool result = false; + + // + result = + // + xSampleEASlippage > 0 && + xSampleEAMagicNumber > 0 + // + ; + + // + return result; +} diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/BKP/zigzag.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/zigzag.mq5 new file mode 100644 index 0000000..8c0d69a --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/BKP/zigzag.mq5 @@ -0,0 +1,297 @@ +//+------------------------------------------------------------------+ +//| ZigZag.mq5 | +//| Copyright 2009, MetaQuotes Software Corp. | +//| http://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "2009, MetaQuotes Software Corp." +#property link "http://www.mql5.com" +#property version "1.00" +#property indicator_chart_window +#property indicator_buffers 3 +#property indicator_plots 1 +//---- plot Zigzag +#property indicator_label1 "Zigzag" +#property indicator_type1 DRAW_SECTION +#property indicator_color1 Red +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 +//--- input parameters +input int ExtDepth=12; +input int ExtDeviation=5; +input int ExtBackstep=3; +//--- indicator buffers +double ZigzagBuffer[]; // main buffer +double HighMapBuffer[]; // highs +double LowMapBuffer[]; // lows +int level=3; // recounting depth +double deviation; // deviation in points +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- indicator buffers mapping + SetIndexBuffer(0,ZigzagBuffer,INDICATOR_DATA); + SetIndexBuffer(1,HighMapBuffer,INDICATOR_CALCULATIONS); + SetIndexBuffer(2,LowMapBuffer,INDICATOR_CALCULATIONS); + +//--- set short name and digits + PlotIndexSetString(0,PLOT_LABEL,"ZigZag("+(string)ExtDepth+","+(string)ExtDeviation+","+(string)ExtBackstep+")"); + IndicatorSetInteger(INDICATOR_DIGITS,_Digits); +//--- set empty value + PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); +//--- to use in cycle + deviation=ExtDeviation*_Point; +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| searching index of the highest bar | +//+------------------------------------------------------------------+ +int iHighest(const double &array[], + int depth, + int startPos) + { + int index=startPos; +//--- start index validation + if(startPos<0) + { + Print("Invalid parameter in the function iHighest, startPos =",startPos); + return 0; + } + int size=ArraySize(array); +//--- depth correction if need + if(startPos-depth<0) depth=startPos; + double max=array[startPos]; +//--- start searching + for(int i=startPos;i>startPos-depth;i--) + { + if(array[i]>max) + { + index=i; + max=array[i]; + } + } +//--- return index of the highest bar + return(index); + } +//+------------------------------------------------------------------+ +//| searching index of the lowest bar | +//+------------------------------------------------------------------+ +int iLowest(const double &array[], + int depth, + int startPos) + { + int index=startPos; +//--- start index validation + if(startPos<0) + { + Print("Invalid parameter in the function iLowest, startPos =",startPos); + return 0; + } + int size=ArraySize(array); +//--- depth correction if need + if(startPos-depth<0) depth=startPos; + double min=array[startPos]; +//--- start searching + for(int i=startPos;i>startPos-depth;i--) + { + if(array[i]0) + { + i=rates_total-1; + //--- searching third extremum from the last uncompleted bar + while(counterZrates_total-100) + { + res=ZigzagBuffer[i]; + if(res!=0) counterZ++; + i--; + } + i++; + limit=i; + + //--- what type of exremum we are going to find + if(LowMapBuffer[i]!=0) + { + curlow=LowMapBuffer[i]; + whatlookfor=Pike; + } + else + { + curhigh=HighMapBuffer[i]; + whatlookfor=Sill; + } + //--- chipping + for(i=limit+1;ideviation) val=0.0; + else + { + for(back=1;back<=ExtBackstep;back++) + { + res=LowMapBuffer[shift-back]; + if((res!=0) && (res>val)) LowMapBuffer[shift-back]=0.0; + } + } + } + if(low[shift]==val) LowMapBuffer[shift]=val; else LowMapBuffer[shift]=0.0; + //--- high + val=high[iHighest(high,ExtDepth,shift)]; + if(val==lasthigh) val=0.0; + else + { + lasthigh=val; + if((val-high[shift])>deviation) val=0.0; + else + { + for(back=1;back<=ExtBackstep;back++) + { + res=HighMapBuffer[shift-back]; + if((res!=0) && (reslasthigh && LowMapBuffer[shift]==0.0) + { + ZigzagBuffer[lasthighpos]=0.0; + lasthighpos=shift; + lasthigh=HighMapBuffer[shift]; + ZigzagBuffer[shift]=lasthigh; + } + if(LowMapBuffer[shift]!=0.0 && HighMapBuffer[shift]==0.0) + { + lastlow=LowMapBuffer[shift]; + lastlowpos=shift; + ZigzagBuffer[shift]=lastlow; + whatlookfor=Pike; + } + break; + default: return(rates_total); + } + } + +//--- return value of prev_calculated for next call + return(rates_total); + } +//+------------------------------------------------------------------+ diff --git a/MQLTestWorkspace/X121/14030217/Documents/JsModules/x-color.tools.js b/MQLTestWorkspace/BKPS/14030228/Documents/JsModules/x-color.tools.js similarity index 100% rename from MQLTestWorkspace/X121/14030217/Documents/JsModules/x-color.tools.js rename to MQLTestWorkspace/BKPS/14030228/Documents/JsModules/x-color.tools.js diff --git a/MQLTestWorkspace/X121/14030217/Documents/JsModules/x-file.tools.js b/MQLTestWorkspace/BKPS/14030228/Documents/JsModules/x-file.tools.js similarity index 100% rename from MQLTestWorkspace/X121/14030217/Documents/JsModules/x-file.tools.js rename to MQLTestWorkspace/BKPS/14030228/Documents/JsModules/x-file.tools.js diff --git a/MQLTestWorkspace/X121/14030217/Documents/JsModules/x-shell.tools.js b/MQLTestWorkspace/BKPS/14030228/Documents/JsModules/x-shell.tools.js similarity index 100% rename from MQLTestWorkspace/X121/14030217/Documents/JsModules/x-shell.tools.js rename to MQLTestWorkspace/BKPS/14030228/Documents/JsModules/x-shell.tools.js diff --git a/MQLTestWorkspace/X121/14030217/Documents/JsModules/x-type-detector.tools.js b/MQLTestWorkspace/BKPS/14030228/Documents/JsModules/x-type-detector.tools.js similarity index 100% rename from MQLTestWorkspace/X121/14030217/Documents/JsModules/x-type-detector.tools.js rename to MQLTestWorkspace/BKPS/14030228/Documents/JsModules/x-type-detector.tools.js diff --git a/MQLTestWorkspace/X121/14030217/Documents/JsModules/x-value.tools.js b/MQLTestWorkspace/BKPS/14030228/Documents/JsModules/x-value.tools.js similarity index 100% rename from MQLTestWorkspace/X121/14030217/Documents/JsModules/x-value.tools.js rename to MQLTestWorkspace/BKPS/14030228/Documents/JsModules/x-value.tools.js diff --git a/MQLTestWorkspace/X121/14030217/Documents/Temp/multi.asset.configs.yml b/MQLTestWorkspace/BKPS/14030228/Documents/Temp/multi.asset.configs.yml similarity index 100% rename from MQLTestWorkspace/X121/14030217/Documents/Temp/multi.asset.configs.yml rename to MQLTestWorkspace/BKPS/14030228/Documents/Temp/multi.asset.configs.yml diff --git a/MQLTestWorkspace/BKPS/14030228/Documents/Templates/arrays.price.mq5 b/MQLTestWorkspace/BKPS/14030228/Documents/Templates/arrays.price.mq5 new file mode 100644 index 0000000..6389481 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Documents/Templates/arrays.price.mq5 @@ -0,0 +1,22 @@ + const int rates_total, // total calculated Candles on charts ... + const int prev_calculated, // total calculated Candles on charts ... + const datetime &time[], // history of Candles Open Time ... + const double &open[], // history of Candles Open Price ... + const double &high[], // history of Candles High Price ... + const double &low[], // history of Candles Low Price ... + const double &close[], // history of Candles Close Price ... + const long &tick_volume[], // history of Tick Volumes on Candle ... + const long &volume[], // history of Trade Volumes ... + const int &spread[] // history of Candles Spread Price ... + + + // // + // // XICH ... + // string ich = + // // + // "" + "\n" + + // "-------------" + "\n" + + // (( || !ignoreFalseConditions) ? ": " + ToString() + "\n" : "") + + // "\n" + // // + // ; diff --git a/MQLTestWorkspace/BKPS/14030228/Experts/x-saherelm.xbe.ea.ex5 b/MQLTestWorkspace/BKPS/14030228/Experts/x-saherelm.xbe.ea.ex5 new file mode 100644 index 0000000..8667591 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Experts/x-saherelm.xbe.ea.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Experts/x-saherelm.xbe.ea.mq5 b/MQLTestWorkspace/BKPS/14030228/Experts/x-saherelm.xbe.ea.mq5 new file mode 100644 index 0000000..651546b --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Experts/x-saherelm.xbe.ea.mq5 @@ -0,0 +1,3365 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XBEEA MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XBEEA +// Description: an Exper Advisor which used RSI and MA +// to Analyse Market ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XBEEA" +#property strict + +// +#define ShortName "XBEEA" + +// +enum ENUM_X_ZIGZAG_BUFFERS +{ + X_ZIGZAG_MAIN_LINE = 0, + X_ZIGZAG_PIVOTS_LINE = 1, +}; + +// +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.draw.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" + +// +#include "../Helpers/x-saherelm.xche.helper.mq5" + +// +// Inputs ... + +// +long xBEEAMagicNumber = 78692110; // Magic Number +int xBEEASlippage = 10; // Slippgae + +// +input double xBEEAVolume = 0.01; + +// +// Indicator Inputs ... + +// +// Maarket ... +input group "Cycles"; + +// +// Short ... +input group "Short"; +input ENUM_X_PERIOD_METHOD scMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES scPeriod = PERIOD_H4; // Period + +// +// Presentation ... +input bool xBEEADrawSCLabel = true; +input bool xBEEADrawSCCBar = true; +input bool xBEEADrawSCPBar = false; +input bool xBEEADrawSCCMid = true; +input bool xBEEADrawSCPMid = true; + +// +// Medium ... +input group "Medium"; +input ENUM_X_PERIOD_METHOD mcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES mcPeriod = PERIOD_H12; // Mid Period + +// +// Presentation ... +input bool xBEEADrawMCLabel = true; +input bool xBEEADrawMCCBar = true; +input bool xBEEADrawMCPBar = false; +input bool xBEEADrawMCCMid = true; +input bool xBEEADrawMCPMid = true; + +// +// Long ... +input group "Long"; +input ENUM_X_PERIOD_METHOD lcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES lcPeriod = PERIOD_D1; // Long Period + +// +// Presentation ... +input bool xBEEADrawLCLabel = true; +input bool xBEEADrawLCCBar = true; +input bool xBEEADrawLCPBar = false; +input bool xBEEADrawLCCMid = true; +input bool xBEEADrawLCPMid = true; + +// +// Hind ... +input group "Hind"; +input ENUM_X_PERIOD_METHOD hcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES hcPeriod = PERIOD_W1; // Hind Period + +// +// Moving Averages ... +input group "Moving Average"; +input int xBEEAMaFastLength = 9; // Fast Length +input int xBEEAMaSlowLength = 18; // Slow Length +input int xBEEAMaShift = 0; // Shift +input ENUM_MA_METHOD xBEEAMaMethod = MODE_EMA; // Method +input ENUM_APPLIED_PRICE xBEEAMaAppliedTo = PRICE_CLOSE; // AppliedTo + +// +// Presentation ... +input bool xBEEADrawHCLabel = true; +input bool xBEEADrawHCCBar = true; +input bool xBEEADrawHCPBar = true; +input bool xBEEADrawHCCMid = true; +input bool xBEEADrawHCPMid = true; + +// +// Vars ... + +// +string xBEEASymbol; +ENUM_TIMEFRAMES xBEEAPeriod; + +// +int maxBuys = 1; +int maxSells = 1; +int buyCount = 0; +int sellCount = 0; + +// +double _tp = 0; +double _sl = 0; +double _entry = 0; +ENUM_POSITION_TYPE _type = NULL; + +// +MqlTick xBEEATick; +XSCTrade *xBEEATrader; + +// +// ZigZag ... +int zigZagHandler = INVALID_HANDLE; +double zigZagBuffer[]; +bool isZigZagInPeak; + +// +// Cycles Definitions ... + +// +XMarketCycle sc; +XDrawSpecifications scCMidSpecs; +XDrawSpecifications scPMidSpecs; +XOHCLDrawSpecification scCBSpecs; +XOHCLDrawSpecification scPBSpecs; +// +XOHCL scCBar; +double scCMidLine; +XOHCL scPBar; +double scPMidLine; +// +double scTrndBuffer[]; +double scFastBuffer[]; +double scSlowBuffer[]; +double scLongExit1[]; +double scLongExit2[]; +double scShortExit1[]; +double scShortExit2[]; +int scCheHandler = INVALID_HANDLE; +int scFastHandler = INVALID_HANDLE; +int scSlowHandler = INVALID_HANDLE; +int scTrndHandler = INVALID_HANDLE; + +// +bool isSCCBullish; +bool isSCPBullish; +bool isSCFastOverSlow; +bool isSCFastUnderSlow; + +// +XMarketCycle mc; +XDrawSpecifications mcCMidSpecs; +XDrawSpecifications mcPMidSpecs; +XOHCLDrawSpecification mcCBSpecs; +XOHCLDrawSpecification mcPBSpecs; +// +XOHCL mcCBar; +double mcCMidLine; +XOHCL mcPBar; +double mcPMidLine; +// +double mcTrndBuffer[]; +double mcFastBuffer[]; +double mcSlowBuffer[]; +double mcLongExit1[]; +double mcLongExit2[]; +double mcShortExit1[]; +double mcShortExit2[]; +int mcFastHandler = INVALID_HANDLE; +int mcSlowHandler = INVALID_HANDLE; +int mcTrndHandler = INVALID_HANDLE; +int mcCheHandler = INVALID_HANDLE; +// +bool isMCCBullish; +bool isMCPBullish; +bool isMCFastOverSlow; +bool isMCFastUnderSlow; + +// +XMarketCycle lc; +XDrawSpecifications lcCMidSpecs; +XDrawSpecifications lcPMidSpecs; +XOHCLDrawSpecification lcCBSpecs; +XOHCLDrawSpecification lcPBSpecs; +// +XOHCL lcCBar; +double lcCMidLine; +XOHCL lcPBar; +double lcPMidLine; +// +double lcTrndBuffer[]; +double lcFastBuffer[]; +double lcSlowBuffer[]; +double lcLongExit1[]; +double lcLongExit2[]; +double lcShortExit1[]; +double lcShortExit2[]; +int lcFastHandler = INVALID_HANDLE; +int lcSlowHandler = INVALID_HANDLE; +int lcTrndHandler = INVALID_HANDLE; +int lcCheHandler = INVALID_HANDLE; +// +bool isLCCBullish; +bool isLCPBullish; +bool isLCFastOverSlow; +bool isLCFastUnderSlow; + +// +XMarketCycle hc; +XDrawSpecifications hcCMidSpecs; +XDrawSpecifications hcPMidSpecs; +XOHCLDrawSpecification hcCBSpecs; +XOHCLDrawSpecification hcPBSpecs; +// +XOHCL hcCBar; +double hcCMidLine; +XOHCL hcPBar; +double hcPMidLine; +// +double hcTrndBuffer[]; +double hcFastBuffer[]; +double hcSlowBuffer[]; +double hcLongExit1[]; +double hcLongExit2[]; +double hcShortExit1[]; +double hcShortExit2[]; +int hcFastHandler = INVALID_HANDLE; +int hcSlowHandler = INVALID_HANDLE; +int hcTrndHandler = INVALID_HANDLE; +int hcCheHandler = INVALID_HANDLE; +// +bool isHCCBullish; +bool isHCPBullish; +bool isHCFastOverSlow; +bool isHCFastUnderSlow; + +// +int mBullishScore; +int mBearishScore; +bool xBEEAIsSummaryTrendBullish; +bool xBEEALastIsSummaryTrendBullish; +string mLastCommentHash; + +// +int mMaxBullishScore = 0; +int mMinBullishScore = 0; +int mMaxBearishScore = 0; +int mMinBearishScore = 0; + +// +double mPivots[]; +bool mPivotsScanStart; +int mPivotsLoopback = 52; +int mMinRequiredPivots = 400; +int mNumberPivotsSequential = 10; + +// +X121CHEInputs xBEEACheInputs; +XSCX121CHEHelper xBEEACheHelper; + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + if (xBEEASymbol == NULL || StringLen(xBEEASymbol) <= 0) + { + xBEEASymbol = _Symbol; + } + + // + if (xBEEAPeriod == NULL) + { + xBEEAPeriod = _Period; + } + + // + // Validate Inputs ... + if (!XBEEAValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + drawPrefix = ShortName; + + // + // Initialize XTrader ... + xBEEATrader = new XSCTrade( + xBEEASlippage, + xBEEAMagicNumber); + + // + // Init Indicators ... + if (!InitIndicators()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Prepare Style Specs ... + PrepareStyleSpecs(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 XBEEA Providers ... + delete xBEEATrader; + + // + // Short ... + IndicatorRelease(scCheHandler); + IndicatorRelease(scTrndHandler); + IndicatorRelease(scFastHandler); + IndicatorRelease(scSlowHandler); + + // + // Medium ... + IndicatorRelease(mcCheHandler); + IndicatorRelease(mcTrndHandler); + IndicatorRelease(mcFastHandler); + IndicatorRelease(mcSlowHandler); + + // + // Long ... + IndicatorRelease(lcCheHandler); + IndicatorRelease(lcTrndHandler); + IndicatorRelease(lcFastHandler); + IndicatorRelease(lcSlowHandler); + + // + // Hind ... + IndicatorRelease(hcCheHandler); + IndicatorRelease(hcTrndHandler); + IndicatorRelease(hcFastHandler); + IndicatorRelease(hcSlowHandler); + + // + IndicatorRelease(zigZagHandler); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + if (!HasEnoughPivots()) + { + // + if (!mPivotsScanStart) + { + ProcessPivots(); + } + + // + return; + } + + // + if (!IsNewCandle( + xBEEASymbol, + xBEEAPeriod)) + { + return; + } + + // + // Reading Tick ... + if (!SymbolInfoTick(xBEEASymbol, xBEEATick)) + { + return; + } + + // + // Reading Data From XDSR Indicator ... + ReadData(); + + // + // Counting Currently Open Positions ... + buyCount = xBEEATrader.CountPositions(xBEEASymbol, POSITION_TYPE_BUY); + sellCount = xBEEATrader.CountPositions(xBEEASymbol, POSITION_TYPE_SELL); + + // + if (buyCount < maxBuys) + { + // + // Check For Buy Signals ... + } + + // + if (sellCount < maxSells) + { + // + // Check for Sell Signals ... + } + + // + UpdatePivots(); + + // + string comment = XBEEAGenerateState(); + Comment(comment); +} + +// +// Custom Functions ... + +// +// Validate Variables nd Inputs ... +bool XBEEAValidateInputs() +{ + // + bool result = false; + + // + result = + // + xBEEASlippage > 0 && + xBEEAMagicNumber > 0 + // + && + // + // Short ... + IsValidCycle( + scMode, + scPeriod) + // + && + // + // Medium ... + IsValidCycle( + mcMode, + mcPeriod) + // + && + // + // Long ... + IsValidCycle( + lcMode, + lcPeriod) + // + && + // + // Hind ... + IsValidCycle( + hcMode, + hcPeriod) + // + ; + + // + return result; +} + +// +// Initial Indicators ... +bool InitIndicators() +{ + // + bool result = false; + + // + // Init XZG Indicator ... + zigZagHandler = iCustom( + xBEEASymbol, + xBEEAPeriod, + "x-saherelm.x121.xzg", + // + // Inputs ... + // TODO: + // add these inputs to TODO ... + 12, // Depth ... + 5, // Deviation ... + 3, // Back Step ... + 1 // MODE ENUM_X_ZG_PRICE_MODE (X_ZG_PRICE_HIGH_LOW_MODE) ... + // + ); + result = zigZagHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // Here we have to Init XMarketCycles also ... + result = InitMarketCycles(); + + // + xBEEACheInputs.Default(); + result = xBEEACheInputs.IsValid(); + if (!result) + { + return result; + } + + // + result = xBEEACheHelper.Init( + xBEEASymbol, + xBEEAPeriod, + xBEEACheInputs); + if (!result) + { + return result; + } + + // + return result; +} + +// +// Initial Market Cycles ... +bool InitMarketCycles() +{ + // + bool result = false; + + // + // Short ... + sc.method = scMode; + sc.period = scPeriod; + result = sc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_SHORT // + ); + if (!result) + { + return result; + } + + // + // Trend ... + ArraySetAsSeries(scTrndBuffer, true); + scTrndHandler = iCustom( + xBEEASymbol, + sc.period, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // ATR ... + "", + 14, // Length + 3.5, // Multiplier + PRICE_MEDIAN, // Applied To + // + // Presentation ... + "", + true, // Show Trends + false // Fill Trends + // + ); + + // + // Che ... + ArraySetAsSeries(scLongExit1, true); + ArraySetAsSeries(scLongExit2, true); + ArraySetAsSeries(scShortExit1, true); + ArraySetAsSeries(scShortExit2, true); + scCheHandler = iCustom( + xBEEASymbol, + sc.period, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + 35, + 26, + 3.0, + 3.5, + // + // Calculations ... + "", + PRICE_HIGH, + PRICE_LOW, + // + // Presentation ... + "", + true, + true, + true, + true + // + ); + + // + // MA's ... + ArraySetAsSeries(scFastBuffer, true); + scFastHandler = iMA( + xBEEASymbol, + sc.period, + xBEEAMaFastLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + ArraySetAsSeries(scSlowBuffer, true); + scSlowHandler = iMA( + xBEEASymbol, + sc.period, + xBEEAMaSlowLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + + // + result = + // + scCheHandler != INVALID_HANDLE && + scTrndHandler != INVALID_HANDLE && + scFastHandler != INVALID_HANDLE && + scSlowHandler != INVALID_HANDLE + // + ; + if (!result) + { + return result; + } + + // + // Medium ... + mc.method = mcMode; + mc.period = mcPeriod; + result = mc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_MEDIUM // + ); + if (!result) + { + return result; + } + + // + // Trend ... + ArraySetAsSeries(mcTrndBuffer, true); + mcTrndHandler = iCustom( + xBEEASymbol, + mc.period, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // ATR ... + "", + 14, // Length + 3.5, // Multiplier + PRICE_MEDIAN, // Applied To + // + // Presentation ... + "", + true, // Show Trends + false // Fill Trends + // + ); + + // + // Che ... + ArraySetAsSeries(mcLongExit1, true); + ArraySetAsSeries(mcLongExit2, true); + ArraySetAsSeries(mcShortExit1, true); + ArraySetAsSeries(mcShortExit2, true); + mcCheHandler = iCustom( + xBEEASymbol, + mc.period, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + 35, + 26, + 3.0, + 3.5, + // + // Calculations ... + "", + PRICE_HIGH, + PRICE_LOW, + // + // Presentation ... + "", + true, + true, + true, + true + // + ); + + // + // MA's ... + ArraySetAsSeries(mcFastBuffer, true); + mcFastHandler = iMA( + xBEEASymbol, + mc.period, + xBEEAMaFastLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + ArraySetAsSeries(mcSlowBuffer, true); + mcSlowHandler = iMA( + xBEEASymbol, + mc.period, + xBEEAMaSlowLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + + // + result = + // + mcTrndHandler != INVALID_HANDLE && + mcFastHandler != INVALID_HANDLE && + mcSlowHandler != INVALID_HANDLE + // + ; + if (!result) + { + return result; + } + + // + // Long ... + lc.method = lcMode; + lc.period = lcPeriod; + result = lc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_LONG // + ); + if (!result) + { + return result; + } + + // + // Trend ... + ArraySetAsSeries(lcTrndBuffer, true); + lcTrndHandler = iCustom( + xBEEASymbol, + lc.period, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // ATR ... + "", + 14, // Length + 3.5, // Multiplier + PRICE_MEDIAN, // Applied To + // + // Presentation ... + "", + true, // Show Trends + false // Fill Trends + // + ); + + // + // Che ... + ArraySetAsSeries(lcLongExit1, true); + ArraySetAsSeries(lcLongExit2, true); + ArraySetAsSeries(lcShortExit1, true); + ArraySetAsSeries(lcShortExit2, true); + lcCheHandler = iCustom( + xBEEASymbol, + lc.period, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + 35, + 26, + 3.0, + 3.5, + // + // Calculations ... + "", + PRICE_HIGH, + PRICE_LOW, + // + // Presentation ... + "", + true, + true, + true, + true + // + ); + + // + // MA's ... + ArraySetAsSeries(lcFastBuffer, true); + lcFastHandler = iMA( + xBEEASymbol, + lc.period, + xBEEAMaFastLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + ArraySetAsSeries(lcSlowBuffer, true); + lcSlowHandler = iMA( + xBEEASymbol, + lc.period, + xBEEAMaSlowLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + + // + result = + // + lcTrndHandler != INVALID_HANDLE && + lcFastHandler != INVALID_HANDLE && + lcSlowHandler != INVALID_HANDLE + // + ; + if (!result) + { + return result; + } + + // + // Hind ... + hc.method = hcMode; + hc.period = hcPeriod; + result = hc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_HIND // + ); + if (!result) + { + return result; + } + + // + // Trend ... + ArraySetAsSeries(hcTrndBuffer, true); + hcTrndHandler = iCustom( + xBEEASymbol, + hc.period, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // ATR ... + "", + 14, // Length + 3.5, // Multiplier + PRICE_MEDIAN, // Applied To + // + // Presentation ... + "", + true, // Show Trends + false // Fill Trends + // + ); + + // + // Che ... + ArraySetAsSeries(hcLongExit1, true); + ArraySetAsSeries(hcLongExit2, true); + ArraySetAsSeries(hcShortExit1, true); + ArraySetAsSeries(hcShortExit2, true); + hcCheHandler = iCustom( + xBEEASymbol, + hc.period, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + 35, + 26, + 3.0, + 3.5, + // + // Calculations ... + "", + PRICE_HIGH, + PRICE_LOW, + // + // Presentation ... + "", + true, + true, + true, + true + // + ); + + // + // MA's ... + ArraySetAsSeries(hcFastBuffer, true); + hcFastHandler = iMA( + xBEEASymbol, + hc.period, + xBEEAMaFastLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + ArraySetAsSeries(hcSlowBuffer, true); + hcSlowHandler = iMA( + xBEEASymbol, + hc.period, + xBEEAMaSlowLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + + // + result = + // + hcTrndHandler != INVALID_HANDLE && + hcFastHandler != INVALID_HANDLE && + hcSlowHandler != INVALID_HANDLE + // + ; + if (!result) + { + return result; + } + + // + return result; +} + +// +// Prepare Style Specs for Drawings ... +void PrepareStyleSpecs() +{ + // + // Each Cycle has 2 Kind of Specs: + // 1- MidLines; + // 2- Candles; + // + // also for each Cycle we have 2 Series of Specs: + // 1- For Current Bar; + // 2- Prev Bar; + + // + // Short ... + + // + // Current ... + + // + // MidLine ... + scCMidSpecs.width = 1; + scCMidSpecs.style = STYLE_DOT; + scCMidSpecs.clr = clrSpringGreen; + scCMidSpecs.Label( + sc.prefix + "_C MID", + scCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + scCBSpecs.Default(); + scCBSpecs.Width(1); + scCBSpecs.Style(STYLE_DOT); + // + // scCBSpecs.openStyle.clr = clrDarkOliveGreen; + // scCBSpecs.closeStyle.clr = clrDarkOrchid; + // scCBSpecs.highStyle.clr = clrDarkSeaGreen; + // scCBSpecs.lowStyle.clr = clrPink; + // + scCBSpecs.openStyle.Label( + sc.prefix + "_C O", + scCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scCBSpecs.highStyle.Label( + sc.prefix + "_C H", + scCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scCBSpecs.closeStyle.Label( + sc.prefix + "_C C", + scCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scCBSpecs.lowStyle.Label( + sc.prefix + "_C L", + scCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + scPMidSpecs.width = 2; + scPMidSpecs.style = STYLE_SOLID; + scPMidSpecs.clr = clrLimeGreen; + scPMidSpecs.Label( + sc.prefix + "_P MID", + scPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + scPBSpecs.Default(); + scPBSpecs.Width(2); + // + // scPBSpecs.openStyle.clr = ; + // scPBSpecs.closeStyle.clr = ; + // scPBSpecs.highStyle.clr = ; + // scPBSpecs.lowStyle.clr = ; + // + scPBSpecs.openStyle.Label( + sc.prefix + "_P O", + scPBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scPBSpecs.highStyle.Label( + sc.prefix + "_P H", + scPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scPBSpecs.closeStyle.Label( + sc.prefix + "_P C", + scPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scPBSpecs.lowStyle.Label( + sc.prefix + "_P L", + scPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Medium ... + + // + // Current ... + + // + // MidLine ... + mcCMidSpecs.width = 1; + mcCMidSpecs.style = STYLE_DOT; + mcCMidSpecs.clr = clrSteelBlue; + mcCMidSpecs.Label( + mc.prefix + "_C MID", + mcCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + mcCBSpecs.Default(); + mcCBSpecs.Width(1); + mcCBSpecs.Style(STYLE_DOT); + // + // mcCBSpecs.openStyle.clr = clrDarkOliveGreen; + // mcCBSpecs.closeStyle.clr = clrDarkOrchid; + // mcCBSpecs.highStyle.clr = clrDarkSeaGreen; + // mcCBSpecs.lowStyle.clr = clrPink; + // + mcCBSpecs.openStyle.Label( + mc.prefix + "_C O", + mcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcCBSpecs.highStyle.Label( + mc.prefix + "_C H", + mcCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcCBSpecs.closeStyle.Label( + mc.prefix + "_C C", + mcCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcCBSpecs.lowStyle.Label( + mc.prefix + "_C L", + mcCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + mcPMidSpecs.width = 2; + mcPMidSpecs.style = STYLE_SOLID; + mcPMidSpecs.clr = clrRoyalBlue; + mcPMidSpecs.Label( + mc.prefix + "_P MID", + mcPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + mcPBSpecs.Default(); + mcPBSpecs.Width(2); + // + // mcPBSpecs.openStyle.clr = ; + // mcPBSpecs.closeStyle.clr = ; + // mcPBSpecs.highStyle.clr = ; + // mcPBSpecs.lowStyle.clr = ; + // + mcPBSpecs.openStyle.Label( + mc.prefix + "_P O", + mcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcPBSpecs.highStyle.Label( + mc.prefix + "_P H", + mcPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcPBSpecs.closeStyle.Label( + mc.prefix + "_P C", + mcPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcPBSpecs.lowStyle.Label( + mc.prefix + "_P L", + mcPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Long ... + + // + // Current ... + + // + // MidLine ... + lcCMidSpecs.width = 1; + lcCMidSpecs.style = STYLE_DOT; + lcCMidSpecs.clr = clrYellow; + lcCMidSpecs.Label( + lc.prefix + "_C MID", + lcCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + lcCBSpecs.Default(); + lcCBSpecs.Width(1); + lcCBSpecs.Style(STYLE_DOT); + // + // lcCBSpecs.openStyle.clr = clrDarkOliveGreen; + // lcCBSpecs.closeStyle.clr = clrDarkOrchid; + // lcCBSpecs.highStyle.clr = clrDarkSeaGreen; + // lcCBSpecs.lowStyle.clr = clrPink; + // + lcCBSpecs.openStyle.Label( + lc.prefix + "_C O", + lcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcCBSpecs.highStyle.Label( + lc.prefix + "_C H", + lcCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcCBSpecs.closeStyle.Label( + lc.prefix + "_C C", + lcCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcCBSpecs.lowStyle.Label( + lc.prefix + "_C L", + lcCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + lcPMidSpecs.width = 2; + lcPMidSpecs.style = STYLE_SOLID; + lcPMidSpecs.clr = clrOrange; + lcPMidSpecs.Label( + lc.prefix + "_P MID", + lcPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + lcPBSpecs.Default(); + lcPBSpecs.Width(2); + // + // lcPBSpecs.openStyle.clr = ; + // lcPBSpecs.closeStyle.clr = ; + // lcPBSpecs.highStyle.clr = ; + // lcPBSpecs.lowStyle.clr = ; + // + lcPBSpecs.openStyle.Label( + lc.prefix + "_P O", + lcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcPBSpecs.highStyle.Label( + lc.prefix + "_P H", + lcPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcPBSpecs.closeStyle.Label( + lc.prefix + "_P C", + lcPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcPBSpecs.lowStyle.Label( + lc.prefix + "_P L", + lcPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Hind ... + + // + // Current ... + + // + // MidLine ... + hcCMidSpecs.width = 1; + hcCMidSpecs.style = STYLE_DOT; + hcCMidSpecs.clr = clrSandyBrown; + hcCMidSpecs.Label( + hc.prefix + "_C MID", + hcCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + hcCBSpecs.Default(); + hcCBSpecs.Width(1); + hcCBSpecs.Style(STYLE_DOT); + // + // hcCBSpecs.openStyle.clr = clrDarkOliveGreen; + // hcCBSpecs.closeStyle.clr = clrDarkOrchid; + // hcCBSpecs.highStyle.clr = clrDarkSeaGreen; + // hcCBSpecs.lowStyle.clr = clrPink; + // + hcCBSpecs.openStyle.Label( + hc.prefix + "_C O", + hcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcCBSpecs.highStyle.Label( + hc.prefix + "_C H", + hcCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcCBSpecs.closeStyle.Label( + hc.prefix + "_C C", + hcCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcCBSpecs.lowStyle.Label( + hc.prefix + "_C L", + hcCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + hcPMidSpecs.width = 2; + hcPMidSpecs.style = STYLE_SOLID; + hcPMidSpecs.clr = clrSaddleBrown; + hcPMidSpecs.Label( + hc.prefix + "_P MID", + hcPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + hcPBSpecs.Default(); + hcPBSpecs.Width(2); + // + // hcPBSpecs.openStyle.clr = clrDarkOliveGreen; + // hcPBSpecs.closeStyle.clr = clrDarkOrchid; + // hcPBSpecs.highStyle.clr = clrDarkSeaGreen; + // hcPBSpecs.lowStyle.clr = clrPink; + // + hcPBSpecs.openStyle.Label( + hc.prefix + "_P O", + hcPBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcPBSpecs.highStyle.Label( + hc.prefix + "_P H", + hcPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcPBSpecs.closeStyle.Label( + hc.prefix + "_P C", + hcPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcPBSpecs.lowStyle.Label( + hc.prefix + "_P L", + hcPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); +} + +// +// Reading Data From Indicators ... +void ReadData() +{ + // + int mLoopBack = 15; + + // + // Update Market Cycles ... + UpdateMarketCycles(0); + + // + // Short ... + CopyBuffer( + scFastHandler, + 0, + 0, + mLoopBack, + scFastBuffer + // + ); + CopyBuffer( + scSlowHandler, + 0, + 0, + mLoopBack, + scSlowBuffer + // + ); + isSCFastOverSlow = scFastBuffer[1] > scSlowBuffer[1]; + isSCFastUnderSlow = scFastBuffer[1] > scSlowBuffer[1]; + + // + // Medium ... + CopyBuffer( + mcFastHandler, + 0, + 0, + mLoopBack, + mcFastBuffer + // + ); + CopyBuffer( + mcSlowHandler, + 0, + 0, + mLoopBack, + mcSlowBuffer + // + ); + isMCFastOverSlow = mcFastBuffer[1] > mcSlowBuffer[1]; + isMCFastUnderSlow = mcFastBuffer[1] > mcSlowBuffer[1]; + + // + // Long ... + CopyBuffer( + lcFastHandler, + 0, + 0, + mLoopBack, + lcFastBuffer + // + ); + CopyBuffer( + lcSlowHandler, + 0, + 0, + mLoopBack, + lcSlowBuffer + // + ); + isLCFastOverSlow = lcFastBuffer[1] > lcSlowBuffer[1]; + isLCFastUnderSlow = lcFastBuffer[1] > lcSlowBuffer[1]; + + // + // Hind ... + CopyBuffer( + hcFastHandler, + 0, + 0, + mLoopBack, + hcFastBuffer + // + ); + CopyBuffer( + hcSlowHandler, + 0, + 0, + mLoopBack, + hcSlowBuffer + // + ); + isHCFastOverSlow = hcFastBuffer[1] > hcSlowBuffer[1]; + isHCFastUnderSlow = hcFastBuffer[1] > hcSlowBuffer[1]; + + // + // XZigZag ... + CopyBuffer( + zigZagHandler, + X_ZIGZAG_PIVOTS_LINE, + 0, + mLoopBack, + zigZagBuffer + // + ); + + // + isZigZagInPeak = zigZagBuffer[0] < MathMax(xBEEATick.ask, xBEEATick.bid); + + // + // Summary ... + CalculateSummary(); + + // + // Provide all Draws ... + XBEEAHandleDraws( + // + // Short ... + xBEEADrawSCLabel, + xBEEADrawSCCBar, + xBEEADrawSCPBar, + xBEEADrawSCCMid, + xBEEADrawSCPMid, + // + // Medium ... + xBEEADrawMCLabel, + xBEEADrawMCCBar, + xBEEADrawMCPBar, + xBEEADrawMCCMid, + xBEEADrawMCPMid, + // + // Long ... + xBEEADrawLCLabel, + xBEEADrawLCCBar, + xBEEADrawLCPBar, + xBEEADrawLCCMid, + xBEEADrawLCPMid, + // + // Hind ... + xBEEADrawHCLabel, + xBEEADrawHCCBar, + xBEEADrawHCPBar, + xBEEADrawHCCMid, + xBEEADrawHCPMid + // + ); +} + +// +// Update Market Cycles ... +bool UpdateMarketCycles(int barIndex) +{ + // + bool result = false; + + // + XOHCL cBar; + XOHCL pBar; + + // + // Short ... + result = sc.Update(barIndex); + if (!result) + { + return result; + } + // + cBar = sc.GetBar(0); + pBar = sc.GetBar(1); + scCBar = cBar; + scPBar = pBar; + scCMidLine = (cBar.high - cBar.low) / 2; + scPMidLine = (pBar.high - pBar.low) / 2; + isSCCBullish = cBar.close > cBar.open; + isSCPBullish = pBar.close > pBar.open; + + // + // Medium ... + result = mc.Update(barIndex); + if (!result) + { + return result; + } + // + cBar = mc.GetBar(0); + pBar = mc.GetBar(1); + mcCBar = cBar; + mcPBar = pBar; + mcCMidLine = (cBar.high - cBar.low) / 2; + mcPMidLine = (pBar.high - pBar.low) / 2; + isMCCBullish = cBar.close > cBar.open; + isMCPBullish = pBar.close > pBar.open; + + // + // Long ... + result = lc.Update(barIndex); + if (!result) + { + return result; + } + // + cBar = lc.GetBar(0); + pBar = lc.GetBar(1); + lcCBar = cBar; + lcPBar = pBar; + lcCMidLine = (cBar.high - cBar.low) / 2; + lcPMidLine = (pBar.high - pBar.low) / 2; + isLCCBullish = cBar.close > cBar.open; + isLCPBullish = pBar.close > pBar.open; + + // + // Hind ... + result = hc.Update(barIndex); + if (!result) + { + return result; + } + // + cBar = hc.GetBar(0); + pBar = hc.GetBar(1); + hcCBar = cBar; + hcPBar = pBar; + hcCMidLine = (cBar.high - cBar.low) / 2; + hcPMidLine = (pBar.high - pBar.low) / 2; + isHCCBullish = cBar.close > cBar.open; + isHCPBullish = pBar.close > pBar.open; + + // + return result; +} + +// +// Pivots ... + +// +int CountPivots() +{ + return ArraySize(mPivots); +} + +// +bool HasEnoughPivots() +{ + return CountPivots() >= mMinRequiredPivots; +} + +// +// First time Scan for Previous Pivots ... +void ProcessPivots() +{ + // + if (mPivotsScanStart) + { + return; + } + + // + mPivotsScanStart = true; + + // + ArraySetAsSeries(mPivots, true); + + // + double tmpPivots[]; + + // + int count = iBars( + xBEEASymbol, + xBEEAPeriod) - + mPivotsLoopback * 2; + + // + // Reading Pivots based on ZigZag ... + int bIdx = 0; + while (!HasEnoughPivots() && bIdx < count) + { + // + UpdatePivots(bIdx); + + // + bIdx++; + } +} + +// +// Update Pivots on Running ... +void UpdatePivots(int barIndex = 0) +{ + // + double tmpPivots[]; + + // + CopyBuffer( + zigZagHandler, + X_ZIGZAG_PIVOTS_LINE, + barIndex, + mPivotsLoopback, + tmpPivots); + + // + int valueVerifications = 0; + double selectedValue = tmpPivots[0]; + + // + int start = 1; + int end = ArraySize(tmpPivots) - 1; + for (int i = start; i < end; i++) + { + // + double iValue = tmpPivots[i]; + + // + if (iValue == selectedValue) + { + valueVerifications++; + } + } + + // + if (valueVerifications >= mNumberPivotsSequential) + { + // + AddIfNotExists( + selectedValue, + mPivots + // + ); + } + + // + ArrayFree(tmpPivots); +} + +// +// Other ... + +// +// Calculated Suggested States ... +void CalculateSummary() +{ + // + // Summary ... + + // + int bullishSigns = 0; + int bearishSigns = 0; + + // + // Short ... + + // + if (isSCCBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isSCPBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isSCFastOverSlow) + { + bullishSigns++; + } + else if (isSCFastUnderSlow) + { + bearishSigns++; + } + + // + if (scCMidLine < MathMin(scCBar.open, scCBar.close)) + { + bearishSigns++; + } + + if (scCMidLine < scCBar.low) + { + bearishSigns++; + } + + if (scPMidLine < MathMin(scPBar.open, scPBar.close)) + { + bearishSigns++; + } + + if (scPMidLine < scPBar.low) + { + bearishSigns++; + } + + if (scCMidLine < MathMin(scPBar.open, scPBar.close)) + { + bearishSigns++; + } + + if (scCMidLine < scPBar.low) + { + bearishSigns++; + } + + // + if (scCMidLine > MathMax(scCBar.open, scCBar.close)) + { + bullishSigns++; + } + + if (scCMidLine > scCBar.high) + { + bullishSigns++; + } + + if (scPMidLine > MathMax(scPBar.open, scPBar.close)) + { + bullishSigns++; + } + + if (scPMidLine > scPBar.high) + { + bullishSigns++; + } + + if (scCMidLine > MathMax(scPBar.open, scPBar.close)) + { + bullishSigns++; + } + + if (scCMidLine > scPBar.high) + { + bullishSigns++; + } + + // + // Medium ... + + // + if (isMCCBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isMCPBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isMCFastOverSlow) + { + bullishSigns++; + } + else if (isMCFastUnderSlow) + { + bearishSigns++; + } + + // + if (mcCMidLine < MathMin(mcCBar.open, mcCBar.close)) + { + bearishSigns++; + } + + if (mcCMidLine < mcCBar.low) + { + bearishSigns++; + } + + if (mcPMidLine < MathMin(mcPBar.open, mcPBar.close)) + { + bearishSigns++; + } + + if (mcPMidLine < mcPBar.low) + { + bearishSigns++; + } + + if (mcCMidLine < MathMin(mcPBar.open, mcPBar.close)) + { + bearishSigns++; + } + + if (mcCMidLine < mcPBar.low) + { + bearishSigns++; + } + + // + if (mcCMidLine > MathMax(mcCBar.open, mcCBar.close)) + { + bullishSigns++; + } + + if (mcCMidLine > mcCBar.high) + { + bullishSigns++; + } + + if (mcPMidLine > MathMax(mcPBar.open, mcPBar.close)) + { + bullishSigns++; + } + + if (mcPMidLine > mcPBar.high) + { + bullishSigns++; + } + + if (mcCMidLine > MathMax(mcPBar.open, mcPBar.close)) + { + bullishSigns++; + } + + if (mcCMidLine > mcPBar.high) + { + bullishSigns++; + } + + // + // Long ... + + // + if (isLCCBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isLCPBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isLCFastOverSlow) + { + bullishSigns++; + } + else if (isLCFastUnderSlow) + { + bearishSigns++; + } + + // + if (lcCMidLine < MathMin(lcCBar.open, lcCBar.close)) + { + bearishSigns++; + } + + if (lcCMidLine < lcCBar.low) + { + bearishSigns++; + } + + if (lcPMidLine < MathMin(lcPBar.open, lcPBar.close)) + { + bearishSigns++; + } + + if (lcPMidLine < lcPBar.low) + { + bearishSigns++; + } + + if (lcCMidLine < MathMin(lcPBar.open, lcPBar.close)) + { + bearishSigns++; + } + + if (lcCMidLine < lcPBar.low) + { + bearishSigns++; + } + + // + if (lcCMidLine > MathMax(lcCBar.open, lcCBar.close)) + { + bullishSigns++; + } + + if (lcCMidLine > lcCBar.high) + { + bullishSigns++; + } + + if (lcPMidLine > MathMax(lcPBar.open, lcPBar.close)) + { + bullishSigns++; + } + + if (lcPMidLine > lcPBar.high) + { + bullishSigns++; + } + + if (lcCMidLine > MathMax(lcPBar.open, lcPBar.close)) + { + bullishSigns++; + } + + if (lcCMidLine > lcPBar.high) + { + bullishSigns++; + } + + // + // Hind ... + + // + if (isHCCBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isHCPBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isHCFastOverSlow) + { + bullishSigns++; + } + else if (isHCFastUnderSlow) + { + bearishSigns++; + } + + // + if (hcCMidLine < MathMin(hcCBar.open, hcCBar.close)) + { + bearishSigns++; + } + + if (hcCMidLine < hcCBar.low) + { + bearishSigns++; + } + + if (hcPMidLine < MathMin(hcPBar.open, hcPBar.close)) + { + bearishSigns++; + } + + if (hcPMidLine < hcPBar.low) + { + bearishSigns++; + } + + if (hcCMidLine < MathMin(hcPBar.open, hcPBar.close)) + { + bearishSigns++; + } + + if (hcCMidLine < hcPBar.low) + { + bearishSigns++; + } + + // + if (hcCMidLine > MathMax(hcCBar.open, hcCBar.close)) + { + bullishSigns++; + } + + if (hcCMidLine > hcCBar.high) + { + bullishSigns++; + } + + if (hcPMidLine > MathMax(hcPBar.open, hcPBar.close)) + { + bullishSigns++; + } + + if (hcPMidLine > hcPBar.high) + { + bullishSigns++; + } + + if (hcCMidLine > MathMax(hcPBar.open, hcPBar.close)) + { + bullishSigns++; + } + + if (hcCMidLine > hcPBar.high) + { + bullishSigns++; + } + + // + // ZigZag ... + if (isZigZagInPeak) + { + bearishSigns++; + } + else + { + bullishSigns++; + } + + // + mBullishScore = bullishSigns; + mBearishScore = bearishSigns; + xBEEAIsSummaryTrendBullish = bullishSigns > bearishSigns; + + // + // Calculate Max an Min Scores ... + + // + mMinBullishScore = + // + mMinBullishScore == 0 || mMinBullishScore > mBullishScore + ? mBullishScore + : mMinBullishScore + // + ; + + // + mMinBearishScore = + // + mMinBearishScore == 0 || mMinBearishScore > mBearishScore + ? mBearishScore + : mMinBearishScore + // + ; + + // + mMaxBullishScore = + // + mMaxBullishScore == 0 || mMaxBullishScore < mBullishScore + ? mBullishScore + : mMaxBullishScore + // + ; + + // + mMaxBearishScore = + // + mMaxBearishScore == 0 || mMaxBearishScore < mBearishScore + ? mBearishScore + : mMaxBearishScore + // + ; + + // + if (xBEEAIsSummaryTrendBullish != xBEEALastIsSummaryTrendBullish) + { + // + // TODO: Summary Trend Change Alert ... + LogMessage("Majour Trend Changed Happens: " + (xBEEAIsSummaryTrendBullish ? "Bullish" : "Bearish")); + } + + // + xBEEALastIsSummaryTrendBullish = xBEEAIsSummaryTrendBullish; +} + +// +// Handle All Draws of Experts ... +void XBEEAHandleDraws( + // + // Short ... + bool drawSCLabel = true, + bool drawSCCBar = true, + bool drawSCPBar = true, + bool drawSCCMid = true, + bool drawSCPMid = true, + // + // Medium ... + bool drawMCLabel = true, + bool drawMCCBar = true, + bool drawMCPBar = true, + bool drawMCCMid = true, + bool drawMCPMid = true, + // + // Long ... + bool drawLCLabel = true, + bool drawLCCBar = true, + bool drawLCPBar = true, + bool drawLCCMid = true, + bool drawLCPMid = true, + // + // Hind ... + bool drawHCLabel = true, + bool drawHCCBar = true, + bool drawHCPBar = true, + bool drawHCCMid = true, + bool drawHCPMid = true // +) +{ + // + int offset = 0; + + // + // Short ... + + // + // Cycle ... + if (drawSCCBar || drawSCPBar) + { + // + XBEEADrawCycle( + sc.cycle, + drawSCLabel, + !drawSCCBar && drawSCPBar, + !drawSCPBar && drawSCCBar, + offset + // + ); + + // + if (drawSCLabel) + { + // + if (drawSCCBar) + { + offset += 3; + } + + // + if (drawSCPBar) + { + offset += 3; + } + + // + if (drawSCCMid) + { + offset++; + } + + // + if (drawSCPMid) + { + offset++; + } + } + } + + // + // MidLine ... + if (drawSCCMid || drawSCPMid) + { + // + XBEEADrawMidLine( + sc.cycle, + drawSCLabel, + !drawSCCMid && drawSCPMid, + !drawSCPMid && drawSCCMid, + offset + // + ); + + // + if (drawSCLabel) + { + // + if (drawSCCMid) + { + offset++; + } + + // + if (drawSCPMid) + { + offset++; + } + } + } + + // + // Medium ... + + // + // Cycle ... + if (drawMCCBar || drawMCPBar) + { + // + XBEEADrawCycle( + mc.cycle, + drawMCLabel, + !drawMCCBar && drawMCPBar, + !drawMCPBar && drawMCCBar, + offset + // + ); + + // + if (drawMCLabel) + { + // + if (drawMCCBar) + { + offset += 3; + } + + // + if (drawMCPBar) + { + offset += 3; + } + + // + if (drawMCCMid) + { + offset++; + } + + // + if (drawMCPMid) + { + offset++; + } + } + } + + // + // Mid Line ... + if (drawMCCMid || drawMCPMid) + { + // + XBEEADrawMidLine( + mc.cycle, + drawMCLabel, + !drawMCCMid && drawMCPMid, + !drawMCPMid && drawMCCMid, + offset + // + ); + + // + if (drawMCLabel) + { + // + if (drawMCCMid) + { + offset++; + } + + // + if (drawMCPMid) + { + offset++; + } + } + } + + // + // Long ... + + // + // Cycle ... + if (drawLCCBar || drawLCPBar) + { + // + XBEEADrawCycle( + lc.cycle, + drawLCLabel, + !drawLCCBar && drawLCPBar, + !drawLCPBar && drawLCCBar, + offset + // + ); + + // + if (drawLCLabel) + { + // + if (drawLCCBar) + { + offset += 3; + } + + // + if (drawLCPBar) + { + offset += 3; + } + + // + if (drawLCCMid) + { + offset++; + } + + // + if (drawLCPMid) + { + offset++; + } + } + } + + // + // MidLine ... + if (drawLCCMid || drawLCPMid) + { + // + XBEEADrawMidLine( + lc.cycle, + drawLCLabel, + !drawLCCMid && drawLCPMid, + !drawLCPMid && drawLCCMid, + offset + // + ); + + // + if (drawLCLabel) + { + // + if (drawLCCMid) + { + offset++; + } + + // + if (drawLCPMid) + { + offset++; + } + } + } + + // + // Hind ... + + // + // Cycle ... + if (drawHCCBar || drawHCPBar) + { + // + XBEEADrawCycle( + hc.cycle, + drawHCLabel, + !drawHCCBar && drawHCPBar, + !drawHCPBar && drawHCCBar, + offset + // + ); + + // + if (drawHCLabel) + { + // + if (drawHCCBar) + { + offset += 3; + } + + // + if (drawHCPBar) + { + offset += 3; + } + + // + if (drawHCCMid) + { + offset++; + } + + // + if (drawHCPMid) + { + offset++; + } + } + } + + // + // MidLine ... + if (drawHCCMid || drawHCPMid) + { + // + XBEEADrawMidLine( + hc.cycle, + drawHCLabel, + !drawHCCMid && drawHCPMid, + !drawHCPMid && drawHCCMid, + offset + // + ); + } +} + +// +// Draw Middle Line of Cycle ... +void XBEEADrawCycle( + ENUM_X_MARKET_CYCLES cycle, // Specify Which Cycle to Draw ... + bool drawLabel = false, // Specify Draw Label of Mid Line or not ... + bool drawOnlyPrev = false, // Specify Draw Only Prev Bar of Cycle ... + bool drawOnlyCurrent = false, // Specify Draw Only Current Bar of Cycle ... + int offset = 0 // Distance used for Labels ... +) +{ + // + if (offset < 0) + { + offset = 0; + } + + // + XMarketCycle cycleModel; + XOHCLDrawSpecification cycleCBarSpecs; + XOHCLDrawSpecification cyclePBarSpecs; + + // + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + // + cycleModel = sc; + cycleCBarSpecs = scCBSpecs; + cyclePBarSpecs = scPBSpecs; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + // + cycleModel = mc; + cycleCBarSpecs = mcCBSpecs; + cyclePBarSpecs = mcPBSpecs; + break; + + // + case X_MARKET_CYCLE_LONG: + // + cycleModel = lc; + cycleCBarSpecs = lcCBSpecs; + cyclePBarSpecs = lcPBSpecs; + break; + + // + case X_MARKET_CYCLE_HIND: + // + cycleModel = hc; + cycleCBarSpecs = hcCBSpecs; + cyclePBarSpecs = hcPBSpecs; + break; + } + + // + string baseTag = ToString(cycle); + + // + XOHCL cBar = cycleModel.GetBar(0); + XOHCL pBar = cycleModel.GetBar(1); + + // + datetime fromCDate = cycleModel.GetBarTime(0); + datetime fromPDate = cycleModel.GetBarTime(1); + + // + datetime cTime = TimeCurrent(); + + // + // Try to Draw ... + + // + bool canDrawPrev = !drawOnlyCurrent; + bool canDrawCurrent = !drawOnlyPrev; + + // + // Set Cycles Color based on Current Candle ... + + // + bool isCBarBullish = + cBar.open < cBar.close; + + // + bool isPBarBullish = + pBar.open < pBar.close; + + // + color clrTemoBullishColor = cycleCBarSpecs.openStyle.clr; + color clrTemoBearishColor = cycleCBarSpecs.closeStyle.clr; + + // + color cBarSelectedColor = isCBarBullish ? clrTemoBullishColor : clrTemoBearishColor; + color pBarSelectedColor = isPBarBullish ? clrTemoBullishColor : clrTemoBearishColor; + + // + cycleCBarSpecs.openStyle.clr = cBarSelectedColor; + cycleCBarSpecs.openStyle.labelColor = cBarSelectedColor; + + // + cycleCBarSpecs.closeStyle.clr = cBarSelectedColor; + cycleCBarSpecs.closeStyle.labelColor = cBarSelectedColor; + + // + cyclePBarSpecs.openStyle.clr = pBarSelectedColor; + cyclePBarSpecs.openStyle.labelColor = pBarSelectedColor; + + // + cyclePBarSpecs.closeStyle.clr = pBarSelectedColor; + cyclePBarSpecs.closeStyle.labelColor = pBarSelectedColor; + + // + if (canDrawPrev) + { + offset++; + } + + // + // Label ... + if (drawLabel) + { + // + if (canDrawPrev) + { + // + // Draw Prev Bar Lables ... + + // + XBEEADrawCycleXOHCLLabel( + cycleModel, + pBar, + cyclePBarSpecs, + "P", + cTime, + offset - 1 + // + ); + + // + offset += 3; + } + + // + if (canDrawCurrent) + { + // + // Draw Current Bar Lables ... + + // + XBEEADrawCycleXOHCLLabel( + cycleModel, + cBar, + cycleCBarSpecs, + "C", + cTime, + offset + // + ); + } + } + + // + // Line ... + + // + if (canDrawPrev) + { + // + // Draw Cycle Prev Bar ... + XBEEADrawCycleXOHCLContent( + cycleModel, + pBar, + cyclePBarSpecs, + "P", + fromPDate + // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Cycle Current Bar ... + XBEEADrawCycleXOHCLContent( + cycleModel, + cBar, + cycleCBarSpecs, + "C", + fromCDate + // + ); + } +} + +// +// Draw Middle Line of Cycle ... +void XBEEADrawMidLine( + ENUM_X_MARKET_CYCLES cycle, // Specify Which Cycle to Draw ... + bool drawLabel = false, // Specify Draw Label of Mid Line or not ... + bool drawOnlyPrev = false, // Specify Draw Only Prev Bar of Cycle ... + bool drawOnlyCurrent = false, // Specify Draw Only Current Bar of Cycle ... + int offset = 0 // Distance used for Labels ... +) +{ + // + if (offset < 0) + { + offset = 0; + } + + // + XMarketCycle cycleModel; + XDrawSpecifications cycleCMidSpecs; + XDrawSpecifications cyclePMidSpecs; + + // + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + // + cycleModel = sc; + cycleCMidSpecs = scCMidSpecs; + cyclePMidSpecs = scPMidSpecs; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + // + cycleModel = mc; + cycleCMidSpecs = mcCMidSpecs; + cyclePMidSpecs = mcPMidSpecs; + break; + + // + case X_MARKET_CYCLE_LONG: + // + cycleModel = lc; + cycleCMidSpecs = lcCMidSpecs; + cyclePMidSpecs = lcPMidSpecs; + break; + + // + case X_MARKET_CYCLE_HIND: + // + cycleModel = hc; + cycleCMidSpecs = hcCMidSpecs; + cyclePMidSpecs = hcPMidSpecs; + break; + } + + // + // Calculate Mid Line ... + double midLine = (cycleModel.bar.high + cycleModel.bar.low) / 2; + + // + XOHCL cyclePrevBar = cycleModel.GetBar(1); + double midLinePrev = (cyclePrevBar.high + cyclePrevBar.low) / 2; + + // + string baseTag = ToString(cycle); + + // + string midCTag = baseTag + "|MID|C|"; + string midPTag = baseTag + "|MID|P|"; + + // + string midCLblTag = midCTag + "lbl"; + string midPLblTag = midPTag + "lbl"; + + // + datetime fromCDate = cycleModel.GetBarTime(0); + datetime fromPDate = cycleModel.GetBarTime(1); + + // + datetime cTime = TimeCurrent(); + + // + // Try to Draw ... + + // + bool canDrawPrev = !drawOnlyCurrent; + bool canDrawCurrent = !drawOnlyPrev; + + // + if (canDrawPrev) + { + offset++; + } + + // + // Label ... + if (drawLabel) + { + // + if (canDrawPrev) + { + // + // Draw Prev Candle MidLine Lable ... + XBEEADrawLabel( + cyclePMidSpecs, + midPLblTag, + cTime, + midLinePrev, + offset // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Current Candle MidLine Label ... + XBEEADrawLabel( + cycleCMidSpecs, + midCLblTag, + cTime, + midLine, + offset - 1 // + ); + } + } + + // + // Line ... + + // + if (canDrawPrev) + { + // + // Draw Prev Candle MidLine ... + XBEEADrawTrendLine( + cyclePMidSpecs, + midPTag, + fromPDate, + midLinePrev // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Current Candle MidLine ... + XBEEADrawTrendLine( + cycleCMidSpecs, + midCTag, + fromCDate, + midLine // + ); + } +} + +// +// Generate Expert State ... +string XBEEAGenerateState() +{ + // + string result = ""; + + // + // Summary ... + result += + // + "Summary: \n" + + "------------------\n" + + "Pivots: " + ToString(CountPivots()) + "\n" + + "BullishScore: " + ToString(mBullishScore) + ", min: " + ToString(mMinBullishScore) + ", max: " + ToString(mMaxBullishScore) + "\n" + + "BearishScore: " + ToString(mBearishScore) + ", min: " + ToString(mMinBearishScore) + ", max: " + ToString(mMaxBearishScore) + "\n" + + "isSUmmaryBullish: " + ToString(xBEEAIsSummaryTrendBullish) + "\n" + + "\n" + // + ; + + // + // ZigZag ... + result += + // + "Peaks and Vales: \n" + + "------------------\n" + + "Looking for New: " + (isZigZagInPeak ? "Vale" : "Peak") + "\n" + + "\n" + // + ; + + // + // Short ... + result += + // + "Short: \n" + + "------------------\n" + + "Period: " + ToString(sc.period) + "\n" + + "Bar 0: " + (isSCCBullish ? "Bullish" : "Bearish") + "\n" + + "Bar 1: " + (isSCPBullish ? "Bullish" : "Bearish") + "\n" + + "Trend MA: " + (isSCFastOverSlow ? "Bullish" : "Bearish") + "\n" + + "\n" + // + ; + + // + // Long ... + result += + // + "Medium: \n" + + "------------------\n" + + "Period: " + ToString(mc.period) + "\n" + + "Bar 0: " + (isMCCBullish ? "Bullish" : "Bearish") + "\n" + + "Bar 1: " + (isMCPBullish ? "Bullish" : "Bearish") + "\n" + + "Trend MA: " + (isMCFastOverSlow ? "Bullish" : "Bearish") + "\n" + + "\n" + // + ; + + // + // Medium ... + result += + // + "Long: \n" + + "------------------\n" + + "Period: " + ToString(lc.period) + "\n" + + "Bar 0: " + (isLCCBullish ? "Bullish" : "Bearish") + "\n" + + "Bar 1: " + (isLCPBullish ? "Bullish" : "Bearish") + "\n" + + "Trend MA: " + (isLCFastOverSlow ? "Bullish" : "Bearish") + "\n" + + "\n" + // + ; + + // + // Hind ... + result += + // + "Hind: \n" + + "------------------\n" + + "Period: " + ToString(hc.period) + "\n" + + "Bar 0: " + (isHCCBullish ? "Bullish" : "Bearish") + "\n" + + "Bar 1: " + (isHCPBullish ? "Bullish" : "Bearish") + "\n" + + "Trend MA: " + (isHCFastOverSlow ? "Bullish" : "Bearish") + "\n" + + "\n" + // + ; + + // + // Test CHE ... + double shortExit1s[]; + xBEEACheHelper.CopyShortExit1( + 0, + 2, + shortExit1s // + ); + + // + string shortExit1sStr = + // + "[0] => " + (shortExit1s[0] != EMPTY_VALUE ? ToString(shortExit1s[0]) : "EMPTY") + "\n" + + "[1] => " + (shortExit1s[1] != EMPTY_VALUE ? ToString(shortExit1s[1]) : "EMPTY") + "\n" + + "\n" + // + ; + + // + result = shortExit1sStr; + + // + string hash = ToMD5(result); + if (hash != mLastCommentHash) + { + // + LogMessage(result); + + // + LogMessage(hash); + + // + mLastCommentHash = hash; + } + + // + return result; +} + +// +// Custom DRAW(s) ... + +// +// Draw OHCL Labels ... +void XBEEADrawCycleXOHCLLabel( + XMarketCycle &cycleModel, // Specify Which Cycle to Draw ... + XOHCL &bar, // Specify Cycle XOHCL Model to Draw ... + XOHCLDrawSpecification &specs, // Specify Cycle XOHCL Draw Specifications ... + string baseTag, // Specify a Unique Tag ... + datetime time, // Draw Time ... + int offset = 0 // +) +{ + // + // Open ... + string openTag = cycleModel.prefix + "_" + baseTag + "_O_lbl"; + XBEEADrawLabel( + specs.openStyle, + openTag, + time, + bar.open, + offset + // + ); + + // + // High ... + string highTag = cycleModel.prefix + "_" + baseTag + "_H_lbl"; + XBEEADrawLabel( + specs.highStyle, + highTag, + time, + bar.high, + offset + 1 + // + ); + + // + // Close ... + string closeTag = cycleModel.prefix + "_" + baseTag + "_C_lbl"; + XBEEADrawLabel( + specs.closeStyle, + closeTag, + time, + bar.close, + offset + 2 + // + ); + + // + // Low ... + string lowTag = cycleModel.prefix + "_" + baseTag + "_L_lbl"; + XBEEADrawLabel( + specs.lowStyle, + lowTag, + time, + bar.low, + offset + 3 + // + ); +} + +// +// Draw OHCL Content ... +void XBEEADrawCycleXOHCLContent( + XMarketCycle &cycleModel, // Specify Which Cycle to Draw ... + XOHCL &bar, // Specify Cycle XOHCL Model to Draw ... + XOHCLDrawSpecification &specs, // Specify Cycle XOHCL Draw Specifications ... + string baseTag, // Specify a Unique Tag ... + datetime time // Draw Time ... +) +{ + // + // Open ... + string openTag = cycleModel.prefix + "_" + baseTag + "_O"; + XBEEADrawTrendLine( + specs.openStyle, + openTag, + time, + bar.open + // + ); + + // + // High ... + string highTag = cycleModel.prefix + "_" + baseTag + "_H"; + XBEEADrawTrendLine( + specs.highStyle, + highTag, + time, + bar.high + // + ); + + // + // Close ... + string closeTag = cycleModel.prefix + "_" + baseTag + "_C"; + XBEEADrawTrendLine( + specs.closeStyle, + closeTag, + time, + bar.close + // + ); + + // + // Low ... + string lowTag = cycleModel.prefix + "_" + baseTag + "_L"; + XBEEADrawTrendLine( + specs.lowStyle, + lowTag, + time, + bar.low + // + ); +} + +// +// Draw Label Using Specifications ... +void XBEEADrawLabel( + XDrawSpecifications &specs, + string tag, + datetime time, + double price, + int offset = 0 // +) +{ + // + long chartId = ChartID(); + int subWindow = 0; + + // + if (offset < 0) + { + offset = 0; + } + + // + int offsetSeconds = PeriodSeconds(xBEEAPeriod) * offset; + + // + string value = specs.label; + + // + DrawText( + chartId, + tag, + subWindow, + time - offsetSeconds, + price, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); +} + +// +// Draw TrendLine Using Specifications ... +void XBEEADrawTrendLine( + XDrawSpecifications &specs, + string tag, + datetime fromDate, + double fromPrice, + datetime toDate = NULL, + double toPrice = 0 // +) +{ + // + long chartId = ChartID(); + int subWindow = 0; + + // + if (toPrice <= 0) + { + toPrice = fromPrice; + } + + // + if (toDate == 0 || toDate == NULL) + { + toDate = TimeCurrent(); + } + + // + DrawTrendLine( + chartId, + tag, + subWindow, + fromDate, + fromPrice, + toDate, + toPrice, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); +} diff --git a/MQLTestWorkspace/BKPS/14030228/Experts/x-sample.ea.ex5 b/MQLTestWorkspace/BKPS/14030228/Experts/x-sample.ea.ex5 new file mode 100644 index 0000000..b99e398 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Experts/x-sample.ea.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Experts/x-sample.ea.mq5 b/MQLTestWorkspace/BKPS/14030228/Experts/x-sample.ea.mq5 new file mode 100644 index 0000000..85503e2 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Experts/x-sample.ea.mq5 @@ -0,0 +1,398 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XSAMPLE MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XSAMPLE +// Description: an Exper Advisor which used RSI and MA +// to Analyse Market ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XSAMPLE" +#property strict + +// +#define ShortName "XSAMPLE" + +// +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +#include "../Helpers/x-saherelm.x121.xmc.helper.mq5" +#include "../Helpers/x-saherelm.x121.xstr.helper.mq5" +#include "../Helpers/x-saherelm.x121.xche.helper.mq5" +#include "../Helpers/x-saherelm.x121.xosc.helper.mq5" + +// +#include "../Classes/x-saherelm.xtrade.class.mq5" +#include "../Classes/x-saherelm.x121.xmcycle.class.mq5" + +// +// Inputs ... +long xSampleEAMagicNumber = 78692110; // Magic Number +int xSampleEASlippage = 10; // Slippgae + +// +double xSampleEAVolume = 0.01; + +// +// Vars ... +string xSampleEASymbol; +ENUM_TIMEFRAMES xSampleEAPeriod; + +// +int maxBuys = 1; +int maxSells = 1; +int buyCount = 0; +int sellCount = 0; + +// +double _tp = 0; +double _sl = 0; +double _entry = 0; +ENUM_POSITION_TYPE _type = NULL; + +// +MqlTick xSampleEATick; + +// +XBarTracker xSamplEABarTracker; + +// +// X121MCycle ... +X121MCycleInputs xSampleEA121MCInputs; +XSC121Market xSampleEA121MC; + +// +XSCSignalCollector signalCollector; + +// +// Event Handlers ... +// +// Initialization ... +int OnInit() +{ + // + if (xSampleEASymbol == NULL || StringLen(xSampleEASymbol) <= 0) + { + xSampleEASymbol = _Symbol; + } + + // + if (xSampleEAPeriod == NULL) + { + xSampleEAPeriod = _Period; + } + + // + // Validate Inputs ... + if (!XSampleEAValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + drawPrefix = ShortName; + + // + bool result = xSamplEABarTracker.Init( + xSampleEASymbol, + xSampleEAPeriod); + if (!result) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // X121Market Cycle ... + result = xSampleEA121MCInputs.Init( + xSampleEASymbol, + xSampleEAPeriod, + X_MARKET_CYCLE_SHORT, + PERIOD_H1, + X_PERIOD_MANUALLY // + ); + if (!result) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // after Inputs Initialize Successfully we must prepare Styling for Draw ... + ApplyMCDrawStyles(); + + // + result = xSampleEA121MC.Init( + xSampleEA121MCInputs + // + ); + if (!result) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 XSampleEA Providers ... +} + +// +// On Tick Handler ... +void OnTick() +{ + // + if (!xSamplEABarTracker.IsNewBar()) + { + return; + } + + // + // Reading Tick ... + if (!SymbolInfoTick(xSampleEASymbol, xSampleEATick)) + { + return; + } + + // + // Draw Market Cycle Bars On Chart ... + int offset = 0; + xSampleEA121MC.Draw( + ChartID(), + 0, + offset + // + ); + + // + // TestXSignalCollector(); +} + +// +// Custom Functions ... + +// +// Validate Variables nd Inputs ... +bool XSampleEAValidateInputs() +{ + // + bool result = false; + + // + result = + // + xSampleEASlippage > 0 && + xSampleEAMagicNumber > 0 + // + ; + + // + return result; +} + +// +// Tools ... + +// +void TestXSignalCollector() +{ + // + XSignal signal; + bool isPrepared = signal.Prepare( + xSampleEASymbol, + "XTest", + xSampleEAPeriod, + POSITION_TYPE_BUY, + X_ORDER_MODE_MARKET, + GetEntry( + xSampleEASymbol, + POSITION_TYPE_BUY), + 0.01, + 0, + 0 + // + ); + if (isPrepared) + { + // + bool isAdded = signalCollector + .Add(signal); + + // + if (isAdded) + { + LogMessage("Signal Added Successfully ..."); + } + } + + // + // Try to Reading Collection ... + XSignal collectedSignals[]; + int collectedSignalsCount = signalCollector.Collect(collectedSignals); + if (collectedSignalsCount > 0) + { + LogMessage("Number of Loaded Signals: " + ToString(collectedSignalsCount)); + } +} + +// +void ApplyMCDrawStyles() +{ + // + // Here we Apply All Draw Styles on Input of Market Cycle ... + xSampleEA121MCInputs.drawCBar = true; + xSampleEA121MCInputs.drawPBar = true; + xSampleEA121MCInputs.drawLabels = true; + xSampleEA121MCInputs.drawCBarMid = true; + xSampleEA121MCInputs.drawPBarMid = true; + + // + // Current ... + + // + // MidLine ... + xSampleEA121MCInputs.cBarMidDrawSpecs.width = 1; + xSampleEA121MCInputs.cBarMidDrawSpecs.style = STYLE_DOT; + xSampleEA121MCInputs.cBarMidDrawSpecs.clr = clrSpringGreen; + xSampleEA121MCInputs.cBarMidDrawSpecs.Label( + xSampleEA121MCInputs.cycle.prefix + "_C MID", + xSampleEA121MCInputs.cBarMidDrawSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + xSampleEA121MCInputs.cBarDrawSpecs.Default(); + xSampleEA121MCInputs.cBarDrawSpecs.Width(1); + xSampleEA121MCInputs.cBarDrawSpecs.Style(STYLE_DOT); + // + xSampleEA121MCInputs.cBarDrawSpecs.openStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C O", + xSampleEA121MCInputs.cBarDrawSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.cBarDrawSpecs.highStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C H", + xSampleEA121MCInputs.cBarDrawSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.cBarDrawSpecs.closeStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C C", + xSampleEA121MCInputs.cBarDrawSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.cBarDrawSpecs.lowStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C L", + xSampleEA121MCInputs.cBarDrawSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + xSampleEA121MCInputs.pBarMidDrawSpecs.width = 2; + xSampleEA121MCInputs.pBarMidDrawSpecs.style = STYLE_SOLID; + xSampleEA121MCInputs.pBarMidDrawSpecs.clr = clrLimeGreen; + xSampleEA121MCInputs.pBarMidDrawSpecs.Label( + xSampleEA121MCInputs.cycle.prefix + "_P MID", + xSampleEA121MCInputs.pBarMidDrawSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + xSampleEA121MCInputs.pBarDrawSpecs.Default(); + xSampleEA121MCInputs.pBarDrawSpecs.Width(2); + // + xSampleEA121MCInputs.pBarDrawSpecs.openStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P O", + xSampleEA121MCInputs.pBarDrawSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.pBarDrawSpecs.highStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P H", + xSampleEA121MCInputs.pBarDrawSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.pBarDrawSpecs.closeStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P C", + xSampleEA121MCInputs.pBarDrawSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.pBarDrawSpecs.lowStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P L", + xSampleEA121MCInputs.pBarDrawSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); +} diff --git a/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xche.helper.mq5 b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xche.helper.mq5 new file mode 100644 index 0000000..73a2d3d --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xche.helper.mq5 @@ -0,0 +1,492 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121CHEHelper +// 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 + +// +#include "../Classes/x-saherelm.xhelper.class.mq5" + +// +// Definitions ... + +// +enum ENUM_XCHE_BUFFERS +{ + X_CHE_LONG_EXIT_1_LINE = 0, + X_CHE_SHORT_EXIT_1_LINE = 1, + X_CHE_LONG_EXIT_2_LINE = 2, + X_CHE_SHORT_EXIT_2_LINE = 3, +}; + +// +// Input Models ... +struct X121CHEInputs +{ + // + // Props ... + + // + // Market ... + int length; // Length + int loopback; // Loopback + double multiplier1; // 1st Multiplier + double multiplier2; // 2nd Multiplier + + // + // Calculation ... + ENUM_APPLIED_PRICE upAppliedTo; // Up Zone Applied To + ENUM_APPLIED_PRICE downAppliedTo; // Down Zone Applied To + + // + // Constructor(s) ... + X121CHEInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + length = 0; + loopback = 0; + multiplier1 = 0; + multiplier2 = 0; + + // + upAppliedTo = PRICE_HIGH; + downAppliedTo = PRICE_LOW; + } + + // + // Default ... + void Default() + { + // + length = 35; + loopback = 26; + multiplier1 = 3.0; + multiplier2 = 3.5; + + // + upAppliedTo = PRICE_HIGH; + downAppliedTo = PRICE_LOW; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + length > 0 && + loopback < length && + multiplier1 > 0 && + multiplier2 > multiplier1 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(length, loopback); + + // + return result; + } +}; + +// +// Class ... +class XSCX121CHEHelper : public XSCBaseHelper +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + XSCX121CHEHelper() : XSCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XSCX121CHEHelper() {} + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121CHEInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + ArraySetAsSeries(longExit1Buffer, true); + ArraySetAsSeries(longExit2Buffer, true); + ArraySetAsSeries(shortExit1Buffer, true); + ArraySetAsSeries(shortExit2Buffer, true); + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + mInputs.length, + mInputs.loopback, + mInputs.multiplier1, + mInputs.multiplier2, + // + // Calculations ... + "", + mInputs.upAppliedTo, + mInputs.downAppliedTo, + // + // Presentation ... + "", + false, + false, + false, + false + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121CHEInputs GetInputs() { + return mInputs; + } + + // + bool SetInputs( + X121CHEInputs &inputs // Configs + ) { + // + return Init( + mSymbol, + mPeriod, + inputs + ); + } + + // + // Buffers ... + + // + double GetLongExit1( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return longExit1Buffer[barIndex]; + } + + // + // Copy Required Long Exits 1 ... + int CopyLongExit1( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + longExit1Buffer, + buffer, + forceClean + // + ); + } + + // + double GetLongExit2( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return longExit2Buffer[barIndex]; + } + + // + // Copy Required Long Exits 2 ... + int CopyLongExit2( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + longExit2Buffer, + buffer, + forceClean + // + ); + } + + // + double GetShortExit1( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return shortExit1Buffer[barIndex]; + } + + // + // Copy Required Short Exits 1 ... + int CopyShortExit1( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + shortExit1Buffer, + buffer, + forceClean + // + ); + } + + // + double GetShortExit2( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return shortExit2Buffer[barIndex]; + } + + // + // Copy Required Short Exits 2 ... + int CopyShortExit2( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + shortExit2Buffer, + buffer, + forceClean + // + ); + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + X121CHEInputs mInputs; // Inputs ... + + // + // Buffers ... + // + double longExit1Buffer[]; + double longExit2Buffer[]; + double shortExit1Buffer[]; + double shortExit2Buffer[]; + + // + // Tools ... + + // + // Calculate Values Until Now ... + void Calculate() + { + // + int totalBars = CountBars(); + int calculatedBars = CountCalculatedBars(); + + // + // Long Exit 1 ... + CopyBuffer( + mHandler, + X_CHE_LONG_EXIT_1_LINE, + 0, + totalBars, + longExit1Buffer + // + ); + + // + // Long Exit 2 ... + CopyBuffer( + mHandler, + X_CHE_LONG_EXIT_2_LINE, + 0, + totalBars, + longExit2Buffer + // + ); + + // + // Short Exit 1 ... + CopyBuffer( + mHandler, + X_CHE_SHORT_EXIT_1_LINE, + 0, + totalBars, + shortExit1Buffer + // + ); + + // + // Short Exit 2 ... + CopyBuffer( + mHandler, + X_CHE_SHORT_EXIT_2_LINE, + 0, + totalBars, + shortExit2Buffer + // + ); + } +}; + +// +// Tools ... diff --git a/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xich.helper.ex5 b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xich.helper.ex5 new file mode 100644 index 0000000..089e402 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xich.helper.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xich.helper.mq5 b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xich.helper.mq5 new file mode 100644 index 0000000..74957a4 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xich.helper.mq5 @@ -0,0 +1,717 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121ICHHelper +// 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 + +// +#include "../Classes/x-saherelm.xhelper.class.mq5" + +// +// Definitions ... +// +// Ichimoku Lines Calculator Mode ... +enum ENUM_XICH_CALCULATION_MODE +{ + // + X_XICH_HH_LL_MODE = 1, // Highest High and Lowest Low + X_XICH_HO_LC_MODE = 2, // Highest Open and Lowest Close +}; + +// +enum ENUM_XICH_BUFFERS +{ + X_ICH_TEANKANSEN_LINE = 0, + X_ICH_KIJUNSEN_LINE = 1, + X_ICH_CHIKOUSPAN_LINE = 4, + X_ICH_SENKOUSPANA_LINE = 5, + X_ICH_SENKOUSPANB_LINE = 6, +}; + +// +// Input Models ... +struct X121ICHInputs +{ + // + // Props ... + + // + // Market ... + // + // Tenkan Sen ... + int tenkanSenLength; // Length + ENUM_XICH_CALCULATION_MODE tenkanSenMode; // Calculation Mode + + // + // Kijun Sen ... + int kijunSenLength; // Length + ENUM_XICH_CALCULATION_MODE kijunSenMode; // Calculation Mode + + // + // Senkou Span B ... + int senkouSpanBLength; // Length + ENUM_XICH_CALCULATION_MODE senkouSpanBMode; // Calculation Mode + + // + // Chikou Span ... + ENUM_APPLIED_PRICE chikuoSpanAppliedTo; // Price Type + + // + // Constructor(s) ... + X121ICHInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + kijunSenLength = 0; + tenkanSenLength = 0; + senkouSpanBLength = 0; + + // + kijunSenMode = X_XICH_HH_LL_MODE; + tenkanSenMode = X_XICH_HH_LL_MODE; + senkouSpanBMode = X_XICH_HH_LL_MODE; + + // + chikuoSpanAppliedTo = PRICE_CLOSE; + } + + // + // Default ... + void Default() + { + // + kijunSenLength = 26; + tenkanSenLength = 9; + senkouSpanBLength = 52; + + // + kijunSenMode = X_XICH_HH_LL_MODE; + tenkanSenMode = X_XICH_HH_LL_MODE; + senkouSpanBMode = X_XICH_HH_LL_MODE; + + // + chikuoSpanAppliedTo = PRICE_CLOSE; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + tenkanSenLength > 2 && + kijunSenLength > tenkanSenLength && + senkouSpanBLength > kijunSenLength + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(result, tenkanSenLength); + result = MathMax(result, kijunSenLength); + result = MathMax(result, senkouSpanBLength); + + // + return result; + } +}; + +// +// Class ... +class XSCX121ICHHelper : public XSCBaseHelper +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + XSCX121ICHHelper() : XSCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XSCX121ICHHelper() {} + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121ICHInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + ArraySetAsSeries(tenkanSenBuffer, true); + ArraySetAsSeries(kijunSenBuffer, true); + ArraySetAsSeries(chikouSpanBuffer, true); + ArraySetAsSeries(senkouSpanABuffer, true); + ArraySetAsSeries(senkouSpanBBuffer, true); + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xich", + // + // Inputs ... + // + // TenkanSen ... + "", + mInputs.tenkanSenLength, + mInputs.tenkanSenMode, + // + // KijunSen ... + "", + mInputs.kijunSenLength, + mInputs.kijunSenMode, + // + // SenkouSpan B ... + "", + mInputs.senkouSpanBLength, + mInputs.senkouSpanBMode, + // + // ChikouSpan ... + "", + mInputs.chikuoSpanAppliedTo, + // + // Presentation ... + "", + false, + false, + false, + false, + false, + false, + false, + false, + false, + true // Push Kumo to Future ... + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121ICHInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121ICHInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs); + } + + // + // Buffers ... + + // + // TenkanSen ... + + // + double GetTenkanSen( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return tenkanSenBuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopyTenkanSen( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + tenkanSenBuffer, + buffer, + forceClean + // + ); + } + + // + // KijunSen ... + + // + double GetKijunSen( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return kijunSenBuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopyKijunSen( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + kijunSenBuffer, + buffer, + forceClean + // + ); + } + + // + // ChikouSpan ... + + // + double GetChikouSpan( + int barIndex // Bar Index + ) + { + // + barIndex -= mInputs.kijunSenLength; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex > ArraySize(chikouSpanBuffer)) { + barIndex = ArraySize(chikouSpanBuffer) - 1; + } + + // + Calculate(); + + // + return chikouSpanBuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopyChikouSpan( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start - mInputs.kijunSenLength, + count, + chikouSpanBuffer, + buffer, + forceClean + // + ); + } + + // + // SenkouSpanA ... + + // + double GetSenkouSpanA( + int barIndex // Bar Index + ) + { + // + barIndex += mInputs.kijunSenLength; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex > ArraySize(senkouSpanABuffer)) { + barIndex = ArraySize(senkouSpanABuffer) - 1; + } + + // + Calculate(); + + // + return senkouSpanABuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopySenkouSpanA( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start + mInputs.kijunSenLength, + count, + senkouSpanABuffer, + buffer, + forceClean + // + ); + } + + // + // SenkouSpanB ... + + // + double GetSenkouSpanB( + int barIndex // Bar Index + ) + { + // + barIndex += mInputs.kijunSenLength; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex > ArraySize(senkouSpanBBuffer)) { + barIndex = ArraySize(senkouSpanBBuffer) - 1; + } + + // + Calculate(); + + // + return senkouSpanBBuffer[barIndex + mInputs.kijunSenLength]; + } + + // + // Copy Required Items ... + int CopySenkouSpanB( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start + mInputs.kijunSenLength, + count, + senkouSpanBBuffer, + buffer, + forceClean + // + ); + } + + // + // Future SenkouSpanA ... + + // + double GetFutureSenkouSpanA( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return senkouSpanABuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopyFutureSenkouSpanA( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + senkouSpanABuffer, + buffer, + forceClean + // + ); + } + + // + // SenkouSpanB ... + + // + double GetFutureSenkouSpanB( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return senkouSpanBBuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopyFutureSenkouSpanB( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + senkouSpanBBuffer, + buffer, + forceClean + // + ); + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + X121ICHInputs mInputs; // Inputs ... + + // + // Buffers ... + double tenkanSenBuffer[]; + double kijunSenBuffer[]; + double chikouSpanBuffer[]; + double senkouSpanABuffer[]; + double senkouSpanBBuffer[]; + + // + // Tools ... + + // + // Calculate Values Until Now ... + void Calculate() + { + // + int totalBars = CountBars(); + int calculatedBars = CountCalculatedBars(); + + // + // TenkanSen ... + CopyBuffer( + mHandler, + X_ICH_TEANKANSEN_LINE, + 0, + totalBars, + tenkanSenBuffer + // + ); + + // + // KijunSen ... + CopyBuffer( + mHandler, + X_ICH_KIJUNSEN_LINE, + 0, + totalBars, + kijunSenBuffer + // + ); + + // + // ChikouSpan ... + CopyBuffer( + mHandler, + X_ICH_CHIKOUSPAN_LINE, + 0, + totalBars, + chikouSpanBuffer + // + ); + + // + // SenkouSpan A ... + CopyBuffer( + mHandler, + X_ICH_SENKOUSPANA_LINE, + 0, + totalBars, + senkouSpanABuffer + // + ); + + // + // SenkouSpan B ... + CopyBuffer( + mHandler, + X_ICH_SENKOUSPANB_LINE, + 0, + totalBars, + senkouSpanBBuffer + // + ); + } +}; + +// +// Tools ... diff --git a/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xmc.helper.mq5 b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xmc.helper.mq5 new file mode 100644 index 0000000..f8c48b2 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xmc.helper.mq5 @@ -0,0 +1,481 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121MCHelper +// 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 + +// +#include "../Classes/x-saherelm.xhelper.class.mq5" + +// +// Definitions ... + +// +enum ENUM_XMC_BUFFERS +{ + X_MC_FAST_LINE = 0, + X_MC_SLOW_LINE = 1, + X_MC_VERIFIER_LINE = 2, +}; + +// +// Input Models ... +struct X121MCInputs +{ + // + // Props ... + + // + // Market ... + + // + // Fast ... + int fastLength; // Length + int fastShift; // Shift + ENUM_MA_METHOD fastMethod; // Method + ENUM_APPLIED_PRICE fastAppliedTo; // Applied To + + // + // Slow ... + int slowLength; // Length + int slowShift; // Shift + ENUM_MA_METHOD slowMethod; // Method + ENUM_APPLIED_PRICE slowAppliedTo; // Applied To + + // + // Verifier ... + int verifierLength; // Length + int verifierShift; // Shift + ENUM_MA_METHOD verifierMethod; // Method + ENUM_APPLIED_PRICE verifierAppliedTo; // Applied To + + // + // Constructor(s) ... + X121MCInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + fastLength = 0; + fastShift = 0; + fastMethod = 0; + fastAppliedTo = PRICE_CLOSE; + + // + slowLength = 0; + slowShift = 0; + slowMethod = 0; + slowAppliedTo = PRICE_CLOSE; + + // + verifierLength = 0; + verifierShift = 0; + verifierMethod = 0; + verifierAppliedTo = PRICE_CLOSE; + } + + // + // Default ... + void Default() + { + // + fastLength = 9; + fastShift = 0; + fastMethod = MODE_EMA; + fastAppliedTo = PRICE_CLOSE; + + // + slowLength = 18; + slowShift = 0; + slowMethod = MODE_EMA; + slowAppliedTo = PRICE_CLOSE; + + // + verifierLength = 200; + verifierShift = 0; + verifierMethod = MODE_EMA; + verifierAppliedTo = PRICE_CLOSE; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + fastLength > 1 && + slowLength > fastLength && + verifierLength > slowLength + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(fastLength, slowLength); + result = MathMax(result, verifierLength); + + // + return result; + } +}; + +// +// Class ... +class XSCX121MCHelper : public XSCBaseHelper +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + XSCX121MCHelper() : XSCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XSCX121MCHelper() {} + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121MCInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + ArraySetAsSeries(fastBuffer, true); + ArraySetAsSeries(slowBuffer, true); + ArraySetAsSeries(verifierBuffer, true); + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xmc", + // + // Inputs ... + // + // Fast ... + "", + mInputs.fastLength, + mInputs.fastShift, + mInputs.fastMethod, + mInputs.fastAppliedTo, + // + // Slow ... + "", + mInputs.slowLength, + mInputs.slowShift, + mInputs.slowMethod, + mInputs.slowAppliedTo, + // + // Verifier ... + "", + mInputs.verifierLength, + mInputs.verifierShift, + mInputs.verifierMethod, + mInputs.verifierAppliedTo, + // + // Presentation ... + "", + false, + false, + false + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121MCInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121MCInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs); + } + + // + // Buffers ... + + // + // Fast ... + + // + double GetFast( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return fastBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyFast( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + fastBuffer, + buffer, + forceClean + // + ); + } + + // + // Slow ... + + // + double GetSlow( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return slowBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopySlow( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + slowBuffer, + buffer, + forceClean + // + ); + } + + // + // Verifier ... + + // + double GetVerifier( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return verifierBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyVerifier( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + verifierBuffer, + buffer, + forceClean + // + ); + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + X121MCInputs mInputs; // Inputs ... + + // + // Buffers ... + // + double fastBuffer[]; + double slowBuffer[]; + double verifierBuffer[]; + + // + // Tools ... + + // + // Calculate Values Until Now ... + void Calculate() + { + // + int totalBars = CountBars(); + int calculatedBars = CountCalculatedBars(); + + // + // Fast ... + CopyBuffer( + mHandler, + X_MC_FAST_LINE, + 0, + totalBars, + fastBuffer + // + ); + + // + // Slow ... + CopyBuffer( + mHandler, + X_MC_SLOW_LINE, + 0, + totalBars, + slowBuffer + // + ); + + // + // Verifier ... + CopyBuffer( + mHandler, + X_MC_VERIFIER_LINE, + 0, + totalBars, + verifierBuffer + // + ); + } +}; + +// +// Tools ... diff --git a/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xosc.helper.mq5 b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xosc.helper.mq5 new file mode 100644 index 0000000..3c33097 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xosc.helper.mq5 @@ -0,0 +1,1319 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121OSCHelper +// 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 + +// +#include "../Classes/x-saherelm.xhelper.class.mq5" + +// +// Definitions ... + +// +enum ENUM_XOSC_BUFFERS +{ + X_OSC_ATR_LINE = 0, + X_OSC_RVI_MAIN_LINE = 1, + X_OSC_RVI_SIGNAL_LINE = 2, + X_OSC_BULL_POWER_LINE = 3, + X_OSC_BEAR_POWER_LINE = 4, + X_OSC_VOLUME_LINE = 5, + X_OSC_RSI_LINE = 6, + X_OSC_CCI_LINE = 7, + X_OSC_MOMENTUM_LINE = 8, + X_OSC_SAR_LINE = 9, + X_OSC_MACD_MAIN_LINE = 10, + X_OSC_MACD_SIGNAL_LINE = 11, + X_OSC_STOCH_MAIN_LINE = 12, + X_OSC_STOCH_SIGNAL_LINE = 13, + X_OSC_STDDEV_LINE = 14, +}; + +// +// Input Models ... +struct X121OSCInputs +{ + // + // Props ... + + // + // ATR ... + int atrLength; // Length + + // + // RVI ... + int rviLength; // Length + + // + // BULLPOWER ... + int bullpLength; // Length + + // + // BEARPOWER ... + int bearpLength; // Length + + // + // VOLUME ... + ENUM_APPLIED_VOLUME volumeAppliedTo; // Applied To + + // + // RSI ... + int rsiLength; // Length + ENUM_APPLIED_PRICE rsiAppliedTo; // Applied To + + // + // CCI ... + int cciLength; // Length + ENUM_APPLIED_PRICE cciAppliedTo; // Applied To + + // + // STDDEV ... + int stddevLength; // Length + int stddevShift; // Shift + ENUM_MA_METHOD stddevMethod; // Mode + ENUM_APPLIED_PRICE stddevAppliedTo; // AppliedTo + + // + // MOMENTUM ... + int momentumLength; // Length + ENUM_APPLIED_PRICE momentumAppliedTo; // Applied To + + // + // SAR ... + double sarStep; // Step + double sarMaximum; // Maximum + + // + // MACD ... + int macdFastLength; // Fast Length + int macdSlowLength; // Slow Length + int macdSignaLength; // Signal Length + ENUM_APPLIED_PRICE macdAppliedTo; // Applied To + + // + // STOCHASTIC ... + // The buffer numbers: 0 - MAIN_LINE, 1 - SIGNAL_LINE. + int stochKLength; // K Length + int stochDLength; // D Length + int stochSlowing; // Slowing + ENUM_MA_METHOD stochMaMethod; // Ma Method + ENUM_STO_PRICE stochMode; // Calculation Mode + + // + // Constructor(s) ... + X121OSCInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + atrLength = 0; // Length + rviLength = 0; // Length + bullpLength = 0; // Length + bearpLength = 0; // Length + volumeAppliedTo = VOLUME_TICK; // Applied To + rsiLength = 0; // Length + rsiAppliedTo = PRICE_CLOSE; // Applied To + cciLength = 0; // Length + cciAppliedTo = PRICE_TYPICAL; // Applied To + stddevLength = 0; // Length + stddevShift = 0; // Shift + stddevMethod = MODE_SMA; // Mode + stddevAppliedTo = PRICE_CLOSE; // AppliedTo + momentumLength = 0; // Length + momentumAppliedTo = PRICE_CLOSE; // Applied To + sarStep = 0; // Step + sarMaximum = 0; // Maximum + macdFastLength = 0; // Fast Length + macdSlowLength = 0; // Slow Length + macdSignaLength = 0; // Signal Length + macdAppliedTo = PRICE_CLOSE; // Applied To + stochKLength = 0; // K Length + stochDLength = 0; // D Length + stochSlowing = 0; // Slowing + stochMaMethod = MODE_SMA; // Ma Method + stochMode = STO_LOWHIGH; // Calculation Mode + } + + // + // Default ... + void Default() + { + // + atrLength = 14; // Length + rviLength = 10; // Length + bullpLength = 13; // Length + bearpLength = 13; // Length + volumeAppliedTo = VOLUME_TICK; // Applied To + rsiLength = 14; // Length + rsiAppliedTo = PRICE_CLOSE; // Applied To + cciLength = 14; // Length + cciAppliedTo = PRICE_TYPICAL; // Applied To + stddevLength = 20; // Length + stddevShift = 0; // Shift + stddevMethod = MODE_SMA; // Mode + stddevAppliedTo = PRICE_CLOSE; // AppliedTo + momentumLength = 14; // Length + momentumAppliedTo = PRICE_CLOSE; // Applied To + sarStep = 0.02; // Step + sarMaximum = 0.2; // Maximum + macdFastLength = 12; // Fast Length + macdSlowLength = 26; // Slow Length + macdSignaLength = 9; // Signal Length + macdAppliedTo = PRICE_CLOSE; // Applied To + stochKLength = 5; // K Length + stochDLength = 3; // D Length + stochSlowing = 3; // Slowing + stochMaMethod = MODE_SMA; // Ma Method + stochMode = STO_LOWHIGH; // Calculation Mode + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + atrLength >= 2 && + rviLength >= 2 && + bullpLength >= 2 && + bearpLength >= 2 && + rsiLength >= 2 && + cciLength >= 2 && + momentumLength >= 2 && + sarStep > 0 && + sarStep < sarMaximum && + macdFastLength >= 2 && + macdSlowLength > macdFastLength && + macdSignaLength >= 2 && + stochKLength >= 2 && + stochDLength >= 2 && + stochSlowing >= 2 && + stddevLength >= 2 && + stddevShift >= 0 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(atrLength, rviLength); + result = MathMax(result, bullpLength); + result = MathMax(result, bearpLength); + result = MathMax(result, rsiLength); + result = MathMax(result, cciLength); + result = MathMax(result, momentumLength); + result = MathMax(result, macdFastLength); + result = MathMax(result, macdSlowLength); + result = MathMax(result, macdSignaLength); + result = MathMax(result, stochKLength); + result = MathMax(result, stochDLength); + result = MathMax(result, stochSlowing); + result = MathMax(result, stddevLength); + + // + return result; + } +}; + +// +// Class ... +class XSCX121OSCHelper : public XSCBaseHelper +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + XSCX121OSCHelper() : XSCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XSCX121OSCHelper() {} + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121OSCInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(rviMainBuffer, true); + ArraySetAsSeries(rviSignalBuffer, true); + ArraySetAsSeries(bullPBuffer, true); + ArraySetAsSeries(bearPBuffer, true); + ArraySetAsSeries(volumeBuffer, true); + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(cciBuffer, true); + ArraySetAsSeries(momentumBuffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(macdMainBuffer, true); + ArraySetAsSeries(macdSignalBuffer, true); + ArraySetAsSeries(stochMainBuffer, true); + ArraySetAsSeries(stochSignalBuffer, true); + ArraySetAsSeries(stddevBuffer, true); + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xosc", + // + // Inputs ... + // + // ATR ... + "", + mInputs.atrLength, + // + // RVI ... + "", + mInputs.rviLength, + // + // Bulls Power ... + "", + mInputs.bullpLength, + // + // Bears Power ... + "", + mInputs.bearpLength, + // + // Voluem ... + "", + mInputs.volumeAppliedTo, + // + // RSI ... + "", + mInputs.rsiLength, + mInputs.rsiAppliedTo, + // + // CCI ... + "", + mInputs.cciLength, + mInputs.cciAppliedTo, + // + // STDDev ... + "", + mInputs.stddevLength, + mInputs.stddevShift, + mInputs.stddevMethod, + mInputs.stddevAppliedTo, + // + // Momentum ... + "", + mInputs.momentumLength, + mInputs.momentumAppliedTo, + // + // SAR ... + "", + mInputs.sarStep, + mInputs.sarMaximum, + // + // MACD ... + "", + mInputs.macdFastLength, + mInputs.macdSlowLength, + mInputs.macdSignaLength, + mInputs.macdAppliedTo, + // + // Stochastic ... + "", + mInputs.stochKLength, + mInputs.stochDLength, + mInputs.stochSlowing, + mInputs.stochMaMethod, + mInputs.stochMode + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121OSCInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121OSCInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs); + } + + // + // Buffers ... + + // + // ATR ... + + // + double GetATR( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return atrBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyATR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrBuffer, + buffer, + forceClean + // + ); + } + + // + // RVI ... + + // + double GetRVI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return rviMainBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyRVI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + rviMainBuffer, + buffer, + forceClean + // + ); + } + + // + double GetRVISignal( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return rviSignalBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyRVISignal( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + rviSignalBuffer, + buffer, + forceClean + // + ); + } + + // + // BULLP ... + + // + double GetBullPower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return bullPBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyBullPower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + bullPBuffer, + buffer, + forceClean + // + ); + } + + // + // BEARP ... + + // + double GetBearPower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return bearPBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyBearPower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + bearPBuffer, + buffer, + forceClean + // + ); + } + + // + // VOLUME ... + + // + double GetVolume( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return volumeBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyVolume( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + volumeBuffer, + buffer, + forceClean + // + ); + } + + // + // RSI ... + + // + double GetRSI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return rsiBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyRSI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + rsiBuffer, + buffer, + forceClean + // + ); + } + + // + // CCI ... + + // + double GetCCI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return cciBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyCCI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + cciBuffer, + buffer, + forceClean + // + ); + } + + // + // MOMENTUM ... + + // + double GetMomentum( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return momentumBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyMomentum( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + momentumBuffer, + buffer, + forceClean + // + ); + } + + // + // SAR ... + + // + double GetSAR( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return sarBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopySAR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sarBuffer, + buffer, + forceClean + // + ); + } + + // + // STDDEV ... + + // + double GetSTDDEV( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return stddevBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopySTDDEV( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + stddevBuffer, + buffer, + forceClean + // + ); + } + + // + // MACD ... + + // + double GetMACD( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return macdMainBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyMACD( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + macdMainBuffer, + buffer, + forceClean + // + ); + } + + // + double GetMACDSignal( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return macdSignalBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyMACDSignal( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + macdSignalBuffer, + buffer, + forceClean + // + ); + } + + // + // STOCH ... + + // + double GetSTOCH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return stochMainBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopySTOCH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + stochMainBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTOCHSignal( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return stochSignalBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopySTOCHSignal( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + stochSignalBuffer, + buffer, + forceClean + // + ); + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + X121OSCInputs mInputs; // Inputs ... + + // + // Buffers ... + double atrBuffer[]; + double rviMainBuffer[]; + double rviSignalBuffer[]; + double bullPBuffer[]; + double bearPBuffer[]; + double volumeBuffer[]; + double rsiBuffer[]; + double cciBuffer[]; + double momentumBuffer[]; + double sarBuffer[]; + double macdMainBuffer[]; + double macdSignalBuffer[]; + double stochMainBuffer[]; + double stochSignalBuffer[]; + double stddevBuffer[]; + + // + // Tools ... + + // + // Calculate Values Until Now ... + void Calculate() + { + // + int totalBars = CountBars(); + int calculatedBars = CountCalculatedBars(); + + // + // ATR ... + CopyBuffer( + mHandler, + X_OSC_ATR_LINE, + 0, + totalBars, + atrBuffer + // + ); + + // + // BULLP ... + CopyBuffer( + mHandler, + X_OSC_BULL_POWER_LINE, + 0, + totalBars, + bullPBuffer + // + ); + + // + // BEARP ... + CopyBuffer( + mHandler, + X_OSC_BEAR_POWER_LINE, + 0, + totalBars, + bearPBuffer + // + ); + + // + // VOLUME ... + CopyBuffer( + mHandler, + X_OSC_VOLUME_LINE, + 0, + totalBars, + volumeBuffer + // + ); + + // + // RSI ... + CopyBuffer( + mHandler, + X_OSC_RSI_LINE, + 0, + totalBars, + rsiBuffer + // + ); + + // + // CCI ... + CopyBuffer( + mHandler, + X_OSC_CCI_LINE, + 0, + totalBars, + cciBuffer + // + ); + + // + // MOMENTUM ... + CopyBuffer( + mHandler, + X_OSC_MOMENTUM_LINE, + 0, + totalBars, + momentumBuffer + // + ); + + // + // SAR ... + CopyBuffer( + mHandler, + X_OSC_SAR_LINE, + 0, + totalBars, + sarBuffer + // + ); + + // + // STDDEV ... + CopyBuffer( + mHandler, + X_OSC_STDDEV_LINE, + 0, + totalBars, + stddevBuffer + // + ); + + // + // RVI ... + + // + // RVI Main ... + CopyBuffer( + mHandler, + X_OSC_RVI_MAIN_LINE, + 0, + totalBars, + rviMainBuffer + // + ); + + // + // RVI Signal ... + CopyBuffer( + mHandler, + X_OSC_RVI_SIGNAL_LINE, + 0, + totalBars, + rviSignalBuffer + // + ); + + // + // MACD ... + + // + // MACD Main ... + CopyBuffer( + mHandler, + X_OSC_MACD_MAIN_LINE, + 0, + totalBars, + macdMainBuffer + // + ); + + // + // MACD Signal ... + CopyBuffer( + mHandler, + X_OSC_MACD_SIGNAL_LINE, + 0, + totalBars, + macdSignalBuffer + // + ); + + // + // STOCH ... + + // + // STOCH Main ... + CopyBuffer( + mHandler, + X_OSC_STOCH_MAIN_LINE, + 0, + totalBars, + stochMainBuffer + // + ); + + // + // STOCH Signal ... + CopyBuffer( + mHandler, + X_OSC_STOCH_SIGNAL_LINE, + 0, + totalBars, + stochSignalBuffer + // + ); + } +}; + +// +// Tools ... diff --git a/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xstr.helper.ex5 b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xstr.helper.ex5 new file mode 100644 index 0000000..00b7cd2 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xstr.helper.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xstr.helper.mq5 b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xstr.helper.mq5 new file mode 100644 index 0000000..d1c5446 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Helpers/x-saherelm.x121.xstr.helper.mq5 @@ -0,0 +1,408 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121STRHelper +// 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 + +// +#include "../Classes/x-saherelm.xhelper.class.mq5" + +// +// Definitions ... + +// +enum ENUM_XSTR_BUFFERS +{ + X_STR_TREND_LINE = 0, + X_STR_STATE_LINE = 5, +}; + +// +enum ENUM_XSTR_TREND_STATES +{ + X_STR_BULLISH = 1, // Bullish + X_STR_BEARISH = -1, // Bearish +}; + +// +// Input Models ... +struct X121STRInputs +{ + // + // Props ... + + // + // ATR ... + int length; // Length + double multiplier; // Multiplier + ENUM_APPLIED_PRICE appliedTo; // Applied To + + // + // Constructor(s) ... + X121STRInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + length = 0; + multiplier = 0; + appliedTo = PRICE_CLOSE; + } + + // + // Default ... + void Default() + { + // + length = 14; + multiplier = 3.5; + appliedTo = PRICE_MEDIAN; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + length > 0 && + multiplier > 0 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = length; + + // + return result; + } +}; + +// +// Class ... +class XSCX121STRHelper : public XSCBaseHelper +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + XSCX121STRHelper() : XSCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XSCX121STRHelper() {} + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121STRInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + ArraySetAsSeries(trendBuffer, true); + ArraySetAsSeries(stateBuffer, true); + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // ATR ... + "", + mInputs.length, + mInputs.multiplier, + mInputs.appliedTo, + // + // Presentation ... + "", + false, + false + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121STRInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121STRInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs); + } + + // + // Buffers ... + + // + // Trend ... + + // + double GetTrend( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return trendBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyTrend( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + trendBuffer, + buffer, + forceClean + // + ); + } + + // + // State ... + + // + ENUM_XSTR_TREND_STATES GetState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return (ENUM_XSTR_TREND_STATES)((int)stateBuffer[barIndex]); + } + + // + // Copy Required Buffer ... + int CopyState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + stateBuffer, + buffer, + forceClean + // + ); + } + + // + // Tools ... + + // + ENUM_XSTR_TREND_STATES ToState(double state) + { + return (ENUM_XSTR_TREND_STATES)((int)state); + } + + // + bool IsBullish(double state) + { + // + bool result = false; + + // + result = + // + ToState(state) == X_STR_BULLISH; + // + ; + + // + return result; + } + + // + bool IsBearish(double state) + { + // + bool result = false; + + // + result = + // + ToState(state) == X_STR_BEARISH; + // + ; + + // + return result; + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + X121STRInputs mInputs; // Inputs ... + + // + // Buffers ... + double trendBuffer[]; + double stateBuffer[]; + + // + // Tools ... + + // + // Calculate Values Until Now ... + void Calculate() + { + // + int totalBars = CountBars(); + int calculatedBars = CountCalculatedBars(); + + // + // Trend ... + CopyBuffer( + mHandler, + X_STR_TREND_LINE, + 0, + totalBars, + trendBuffer + // + ); + + // + // State ... + CopyBuffer( + mHandler, + X_STR_STATE_LINE, + 0, + totalBars, + stateBuffer + // + ); + } +}; + +// +// Tools ... diff --git a/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xche.ex5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xche.ex5 new file mode 100644 index 0000000..e91cf47 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xche.ex5 differ diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xche.mq5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xche.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xche.mq5 rename to MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xche.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xich.ex5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xich.ex5 new file mode 100644 index 0000000..79f9628 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xich.ex5 differ diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xich.mq5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xich.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xich.mq5 rename to MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xich.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xmc.ex5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xmc.ex5 new file mode 100644 index 0000000..d63fc53 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xmc.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xmc.mq5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xmc.mq5 new file mode 100644 index 0000000..61dffd2 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xmc.mq5 @@ -0,0 +1,469 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121_XMC MA Cross Indicator +// --------------------------------------------------- +// Name: X121_XMC +// Description: Moving Average Crosses +// Market Analysor ... +// +// +// 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_XMC Indicator" +#property strict + +// +// START Constants ... +// + +// +// Indicator Short Name ... +#define ShortName "X121_XMC" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input group "Fast"; +input int fastMaLength = 9; // Length +input int fastMaShift = 0; // Shift +input ENUM_MA_METHOD fastMaMethod = MODE_EMA; // Method +input ENUM_APPLIED_PRICE fastMaAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "Slow"; +input int slowMaLength = 18; // Length +input int slowMaShift = 0; // Shift +input ENUM_MA_METHOD slowMaMethod = MODE_EMA; // Method +input ENUM_APPLIED_PRICE slowMaAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "Verifier"; +input int verifierMaLength = 50; // Length +input int verifierMaShift = 0; // Shift +input ENUM_MA_METHOD verifierMaMethod = MODE_EMA; // Method +input ENUM_APPLIED_PRICE verifierMaAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "Presentation"; +input bool showFastMa = true; // Show Fast +input bool showSlowMa = true; // Show Slow +input bool showVerifierMa = true; // Show Verifier + +// +// END Inputs ... +// + +// +// START Includes and Imports ... +// + +// +// Includes Logging Library ... +#include "../Libraries/x-saherelm.log.lib.mq5" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Includes and Imports ... +// + +// +// START Buffers ... +// +#property indicator_chart_window + +// +#property indicator_buffers 3 +#property indicator_plots 3 + +// +// PLOTTED Buffers ... + +// +// MA ... + +// +// FAST ... +#define fastMaBufferIndex 0 +double fastMaBuffer[]; + +// +#property indicator_label1 "X121_XMC MA F" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrYellow +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +// +// SLOW ... +#define slowMaBufferIndex 1 +double slowMaBuffer[]; + +// +#property indicator_label2 "X121_XMC MA S" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrDarkOrange +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +// +// VERIFIER ... +#define verifierMaBufferIndex 2 +double verifierMaBuffer[]; + +// +#property indicator_label3 "X121_XMC MA V" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrDarkBlue +#property indicator_style3 STYLE_SOLID +#property indicator_width3 2 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +int fastMaHandler = INVALID_HANDLE; +int slowMaHandler = INVALID_HANDLE; +int verifierMaHandler = INVALID_HANDLE; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + + // + // 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(); + + // + // MA Initialization ... + + // + // FAST ... + fastMaHandler = iMA( + _Symbol, + _Period, + fastMaLength, + fastMaShift, + fastMaMethod, + fastMaAppliedTo); + if (fastMaHandler == INVALID_HANDLE) + { + // + string msg = "Error in Initilizing Indicator ..."; + LogMessage(msg); + + // + return INIT_FAILED; + } + + // + // SLOW ... + slowMaHandler = iMA( + _Symbol, + _Period, + slowMaLength, + slowMaShift, + slowMaMethod, + slowMaAppliedTo); + if (slowMaHandler == INVALID_HANDLE) + { + // + string msg = "Error in Initilizing Indicator ..."; + LogMessage(msg); + + // + return INIT_FAILED; + } + + // + // VERIFIER ... + verifierMaHandler = iMA( + _Symbol, + _Period, + verifierMaLength, + verifierMaShift, + verifierMaMethod, + verifierMaAppliedTo); + if (verifierMaHandler == INVALID_HANDLE) + { + // + string msg = "Error in Initilizing Indicator ..."; + LogMessage(msg); + + // + return INIT_FAILED; + } + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 + + // + // Here we can handle De Initialization Reasons ... + IndicatorRelease(fastMaHandler); + IndicatorRelease(slowMaHandler); + IndicatorRelease(verifierMaHandler); +} + +// +// Calculations ... +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + 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); + + // + // this counts Available Bars ... + int limit; + + // + // Check Calculated Bars ... + int fastMaCalculatedBars = BarsCalculated(fastMaHandler); + int slowMaCalculatedBars = BarsCalculated(slowMaHandler); + int verifierMaCalculatedBars = BarsCalculated(verifierMaHandler); + if (fastMaCalculatedBars < maxLength || + slowMaCalculatedBars < maxLength || + verifierMaCalculatedBars < maxLength) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + int copiedFastMas = CopyBuffer(fastMaHandler, 0, 0, limit, fastMaBuffer); + int copiedSlowMas = CopyBuffer(slowMaHandler, 0, 0, limit, slowMaBuffer); + int copiedVerifierMas = CopyBuffer(verifierMaHandler, 0, 0, limit, verifierMaBuffer); + if (copiedFastMas <= 0 || + copiedSlowMas <= 0 || + copiedVerifierMas <= 0 + ) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + CalculateBuffers(i); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = + // + // Validate Ma ... + (fastMaLength > 2 && + slowMaLength > fastMaLength && + verifierMaLength > slowMaLength) + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // Ma ... + result = MathMax(result, fastMaLength); + result = MathMax(result, slowMaLength); + result = MathMax(result, verifierMaLength); + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // MA ... + + // + // FAST ... + ENUM_DRAW_TYPE fastMaDrawType = showFastMa ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(fastMaBuffer, true); + SetIndexBuffer(fastMaBufferIndex, fastMaBuffer, INDICATOR_DATA); + PlotIndexSetInteger(fastMaBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(fastMaBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(fastMaBufferIndex, PLOT_DRAW_TYPE, fastMaDrawType); + + // + // SLOW ... + ENUM_DRAW_TYPE slowMaDrawType = showSlowMa ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(slowMaBuffer, true); + SetIndexBuffer(slowMaBufferIndex, slowMaBuffer, INDICATOR_DATA); + PlotIndexSetInteger(slowMaBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(slowMaBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(slowMaBufferIndex, PLOT_DRAW_TYPE, slowMaDrawType); + + // + // VERIFIER ... + ENUM_DRAW_TYPE verifierMaDrawType = showVerifierMa ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(verifierMaBuffer, true); + SetIndexBuffer(verifierMaBufferIndex, verifierMaBuffer, INDICATOR_DATA); + PlotIndexSetInteger(verifierMaBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(verifierMaBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(verifierMaBufferIndex, PLOT_DRAW_TYPE, verifierMaDrawType); +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + // + string indicatorShortName = ""; + StringConcatenate(indicatorShortName, ShortName, ""); + + // + IndicatorSetString(INDICATOR_SHORTNAME, indicatorShortName); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index // Selected Bar Index +) +{ +} + +// +// END Functions ... +// diff --git a/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xosc.ex5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xosc.ex5 new file mode 100644 index 0000000..d71114c Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xosc.ex5 differ diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xosc.mq5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xosc.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xosc.mq5 rename to MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xosc.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xstr.ex5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xstr.ex5 new file mode 100644 index 0000000..eab2381 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xstr.ex5 differ diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xstr.mq5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xstr.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xstr.mq5 rename to MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xstr.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xzg.ex5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xzg.ex5 new file mode 100644 index 0000000..015d297 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xzg.ex5 differ diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xzg.mq5 b/MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xzg.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xzg.mq5 rename to MQLTestWorkspace/BKPS/14030228/Indicators/x-saherelm.x121.xzg.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.alert.lib.ex5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.alert.lib.ex5 new file mode 100644 index 0000000..daa322c Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.alert.lib.ex5 differ diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.alert.lib.mq5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.alert.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.alert.lib.mq5 rename to MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.alert.lib.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.common.lib.ex5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.common.lib.ex5 new file mode 100644 index 0000000..7535376 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.common.lib.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.common.lib.mq5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.common.lib.mq5 new file mode 100644 index 0000000..96b33e6 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.common.lib.mq5 @@ -0,0 +1,5618 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: XCommonLib +// Description: provide all commonly used 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 ... + +// +// Models ... + +// +// Specified Price Type ... +enum ENUM_X_PRICE +{ + X_PRICE_HIGH, + X_PRICE_OPEN, + X_PRICE_CLOSE, + X_PRICE_LOW +}; + +// +// Swing Types Enum ... +enum ENUM_X_SWING_TYPE +{ + X_NO_SWING = 0, + X_SWING_HIGH = 1, + X_SWING_LOW = -1, +}; + +// +// XPERIOD Calculation Method ... +enum ENUM_X_PERIOD_METHOD +{ + // + X_PERIOD_NOTHING, // Nothing + X_PERIOD_AUTO, // Auto Select + X_PERIOD_MANUALLY // Manually +}; + +// +// Available Market Cycles ... +enum ENUM_X_MARKET_CYCLES +{ + // + X_MARKET_CYCLE_UNKNOWN, // Unknown Cycle + X_MARKET_CYCLE_SHORT, // Short Cycle + X_MARKET_CYCLE_MEDIUM, // Medium Cycle + X_MARKET_CYCLE_LONG, // Long Cycle + X_MARKET_CYCLE_HIND, // Hind Cycle +}; + +// +// Structs ... + +// +// Model a Bar Remains Time ... +struct XBarRemainsTime +{ + // + int days; + int hours; + int minutes; + int seconds; + + // + // Constructor ... + XBarRemainsTime() + { + Clean(); + } + + // + // Always Calculate Current 0 Bar Timing ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int minuteSecoonds = 60; + int hourSeconds = minuteSecoonds * 60; + int daySeconds = 24 * hourSeconds; + + // + int periodSeconds = PeriodSeconds( + mPeriod); + datetime startTime = GetBarTime( + mSymbol, + mPeriod, + 0 + // + ); + + // + int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent(); + + // + int mWorkingSecondsDiff = secondsDiff; + if (mWorkingSecondsDiff > daySeconds) + { + // + days = mWorkingSecondsDiff / daySeconds; + mWorkingSecondsDiff -= days * daySeconds; + } + if (mWorkingSecondsDiff > hourSeconds) + { + // + hours = mWorkingSecondsDiff / hourSeconds; + mWorkingSecondsDiff -= hours * hourSeconds; + } + if (mWorkingSecondsDiff > minuteSecoonds) + { + // + minutes = mWorkingSecondsDiff / minuteSecoonds; + mWorkingSecondsDiff -= minutes * minuteSecoonds; + } + seconds = mWorkingSecondsDiff; + + // + result = true; + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + days = 0; + hours = 0; + minutes = 0; + seconds = 0; + } + + // + // To String Representation ... + string ToString( + string dayId = "d", + string hourId = "h", + string minuteId = "m", + string secondId = "s", + string idSeparator = ": ", + string separator = ", ", + bool ignoreZeroValues = true + // + ) + { + // + string result = ""; + + // + // Days ... + if (!ignoreZeroValues || days > 0) + { + result += dayId + idSeparator + (string)days + separator; + } + + // + // Hours ... + if (!ignoreZeroValues || hours > 0) + { + // + string strHour = ToString(hours); + if (StringLen(strHour) == 1) + { + strHour = "0" + strHour; + } + + // + result += hourId + idSeparator + strHour + separator; + } + + // + // Minutes ... + if (!ignoreZeroValues || minutes > 0) + { + // + string strMinute = ToString(minutes); + if (StringLen(strMinute) == 1) + { + strMinute = "0" + strMinute; + } + + // + result += minuteId + idSeparator + strMinute + separator; + } + + // + // Seconds ... + if (!ignoreZeroValues || seconds > 0) + { + // + string strSec = ToString(seconds); + if (StringLen(strSec) == 1) + { + strSec = "0" + strSec; + } + + // + result += secondId + idSeparator + strSec; + } + + // + return result; + } +}; + +// +// Describe an Specific Candle ... +struct XOHCL +{ + // + // Props ... + + // + double high; + double open; + double close; + double low; + + // + string symbol; + datetime time; + ENUM_TIMEFRAMES period; + + // + // Constructor ... + XOHCL() + { + Clean(); + } + + // + // Init a Bar ... + // Using Bar Index ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + int barIndex = 0 // Bar Index + ) + { + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + symbol = mSymbol; + period = mPeriod; + + // + time = iTime( + mSymbol, + mPeriod, + barIndex + // + ); + + // + open = iOpen( + mSymbol, + mPeriod, + barIndex + // + ); + + // + close = iClose( + mSymbol, + mPeriod, + barIndex + // + ); + + // + high = iHigh( + mSymbol, + mPeriod, + barIndex); + + // + low = iLow( + mSymbol, + mPeriod, + barIndex + // + ); + + // + bool result = IsValid(); + + // + return result; + } + + // + // Init a Bar ... + // Using Bar Time ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + datetime mTime = NULL // Bar Time + ) + { + // + mTime = NormalizeTime(mTime); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false // + ); + + // + bool result = Init( + mSymbol, + mPeriod, + barIndex + // + ); + + // + return result; + } + + // + // Tools ... + + // + void Clean() + { + // + high = 0; + open = 0; + close = 0; + low = 0; + + // + time = NULL; + symbol = NULL; + period = NULL; + } + + // + // Validate Bar ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + high > 0 && + open > 0 && + close > 0 && + low > 0 + // + ; + + // + return result; + } + + // + // Calculate X_PRICE Specified Type ... + double GetPrice(ENUM_X_PRICE mPType) + { + // + double result = 0; + + // + if (mPType == NULL) + { + mPType = X_PRICE_CLOSE; + } + + // + if (!IsValid()) + { + return result; + } + + // + switch (mPType) + { + // + case X_PRICE_OPEN: + result = open; + break; + // + case X_PRICE_HIGH: + result = high; + break; + // + case X_PRICE_CLOSE: + result = close; + break; + // + case X_PRICE_LOW: + result = low; + break; + } + + // + return result; + } + + // + // Calculate Applied Price ... + double GetPrice( + ENUM_APPLIED_PRICE appliedTo // Select Application Method + ) + { + // + double result = 0; + + // + // Calculate Applied Price ... + switch (appliedTo) + { + // + case PRICE_CLOSE: + result = close; + break; + + // + case PRICE_OPEN: + result = open; + break; + + // + case PRICE_HIGH: + result = high; + break; + + // + case PRICE_LOW: + result = low; + break; + + // + case PRICE_MEDIAN: + result = (high + low) / 2; + break; + + // + case PRICE_TYPICAL: + result = (high + low + close) / 3; + break; + + // + case PRICE_WEIGHTED: + result = (high + low + close + close) / 4; + break; + } + + // + return result; + } + + // + // Calculate Bar Mid Line ... + double GetMid() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = (high + low) / 2; + + // + return result; + } + + // + // Calculate up Price ... + double GetUp() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathMax(open, close); + + // + return result; + } + + // + // Calculate Down Price ... + double GetDown() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathMin(open, close); + + // + return result; + } + + // + // Calculate Bar Body ... + double GetBody() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetUp() - GetDown(); + + // + return result; + } + + // + // Calculate Bar Range ... + double GetRange() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = high - low; + + // + return result; + } + + // + // Calculate Bar Shadows ... + double GetShadows() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetRange() - GetBody(); + + // + return result; + } + + // + // Calculate Bar High Shadow ... + double GetHighShadow() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + high - GetUp() + // + ; + + // + return result; + } + + // + // Calculate Bar Low Shadow ... + double GetLowShadow() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + GetDown() - low; + // + ; + + // + return result; + } + + // + // Check Bar is Bullish ... + bool IsBullish() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = open < close; + + // + return result; + } + + // + // Check Bar is Bearish ... + bool IsBearish() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = open > close; + + // + return result; + } + + // + // Find Next Bar Time ... + datetime NextAt() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int prSeconds = PeriodSeconds(period); + + // + result = time + prSeconds; + + // + return result; + } + + // + // Find Prev Bar Time ... + datetime BeforeOn() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int prSeconds = PeriodSeconds(period); + + // + result = time - prSeconds; + + // + return result; + } + + // + // Find Current Bar Index on Chart ... + int Index() + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + result = iBarShift( + symbol, + period, + time + // + ); + + // + return result; + } + + // + // Check Bar has Strong Body or Not ... + bool HasStrongBody() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + double body = GetBody(); + double shadow = GetShadows(); + + // + result = body > shadow * 1.5; + + // + return result; + } + + // + // Determines Swings based On this Bar ... + // Calculates Based on atleast 3 Bars Prev ... + ENUM_X_SWING_TYPE GetSwingType() + { + // + ENUM_X_SWING_TYPE result = X_NO_SWING; + + // + // Find Current Index of Bar ... + int barIndex = Index(); + if (barIndex <= -1) + { + return result; + } + + // + // First we have to Retrieve atleast 3 Bars before this bar ... + XOHCL bars[]; + int barsCount = GetBars( + bars, + symbol, + period, + barIndex + 1, + 3 + // + ); + if (barsCount < 3) + { + return result; + } + + // + // Check Swing Start Candle has Strong Body ... + bool isStrongBodyCandle = bars[2].HasStrongBody(); + if (!isStrongBodyCandle) + { + return result; + } + + // + // Check Swing Low Conditions ... + bool isSwingLowOrderBlock = + bars[2].low < bars[1].low && + bars[1].low < bars[0].low && + bars[2].low < bars[0].low; + if (isSwingLowOrderBlock) + { + result = X_SWING_LOW; + } + + // + // Check Swing High Conditions ... + bool isSwingHighOrderBlock = + bars[2].high > bars[1].high && + bars[1].high > bars[0].high && + bars[2].high > bars[0].high; + if (isSwingHighOrderBlock) + { + result = X_SWING_HIGH; + } + + // + return result; + } + + // + // Find Swings (Highs nd Lows) ... + int FindSwing( + ENUM_X_SWING_TYPE swing, // Swing Based On Price mode ... + int mLength // Loopback ... + ) + { + // + int result = -1; + + // + if (!IsValid() || + !IsValid(swing)) + { + return result; + } + + // + int current = Index(); + int founded = FindNextSwing( + swing, + (mLength * 2) + 1, + current - mLength + // + ); + + // + while (founded != current) + { + // + current = FindNextSwing( + swing, + mLength, + current + 1 + // + ); + + // + founded = FindNextSwing( + swing, + (mLength * 2) + 1, + current - mLength + // + ); + } + + // + result = current; + + // + return result; + } + + // + // Find Next Swing ... + int FindNextSwing( + ENUM_X_SWING_TYPE swing, // Swing Based On Price mode ... + int from, // from Bar Index + int mLength // Loopback ... + ) + { + // + int result = -1; + + // + if (!IsValid() || + !IsValid(swing)) + { + return result; + } + + // + if (from < 0) + { + mLength += from; + from = 0; + } + + // + ENUM_SERIESMODE mode = swing == X_SWING_HIGH + ? MODE_HIGH + : MODE_LOW; + + // + result = swing == X_SWING_HIGH + ? iHighest( + symbol, + period, + mode, + mLength, + from) + : iLowest( + symbol, + period, + mode, + mLength, + from); + + // + return result; + } + + // + // Find Lowest Bar Index ... + int FindHighestIndex( + int mLength, // Loopback ... + ENUM_SERIESMODE mode // Calculation mode + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (mLength < 2) + { + mLength = 2; + } + + // + result = iHighest( + symbol, + period, + mode, + mLength, + Index()); + + // + return result; + } + + // + // Find Lowest ... + double FindHighest( + int mLength, // Loopback ... + ENUM_SERIESMODE mode // Calculation mode + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + int idx = FindHighestIndex( + mLength, + mode); + if (idx <= -1) + { + return result; + } + + // + ENUM_X_PRICE pMode = ToPrice(mode); + + // + XOHCL iH; + result = iH.Init( + symbol, + period, + idx + // + ); + if (!result) + { + return result; + } + + // + result = iH.GetPrice(pMode); + + // + return result; + } + + // + // Find Lowest Bar Index ... + int FindLowestIndex( + int mLength, // Loopback ... + ENUM_SERIESMODE mode // Calculation mode + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (mLength < 2) + { + mLength = 2; + } + + // + result = iLowest( + symbol, + period, + mode, + mLength, + Index()); + + // + return result; + } + + // + // Find Lowest ... + double FindLowest( + int mLength, // Loopback ... + ENUM_SERIESMODE mode // Calculation mode + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + int idx = FindLowestIndex( + mLength, + mode); + if (idx <= -1) + { + return result; + } + + // + ENUM_X_PRICE pMode = ToPrice(mode); + + // + XOHCL iL; + result = iL.Init( + symbol, + period, + idx + // + ); + if (!result) + { + return result; + } + + // + result = iL.GetPrice(pMode); + + // + return result; + } + + // + // Convert to String Representation ... + string ToString() + { + // + string result = ""; + + // + result = GetTypeName(this) + + "(O(" + ToString(open) + "),H(" + ToString(high) + "),C(" + ToString(close) + "),L(" + ToString(low) + "))"; + + // + return result; + } +}; + +// +// Model Support and Resistance +// for Specific Bar ... +struct XOHCLSupRes +{ + // + // Props ... + + // + /// Resistances ... + double res[]; + + // + // Supports ... + double sup[]; + + // + // Constructor ... + XOHCLSupRes() + { + Clean(); + } + + // + // Init ... + bool Init( + double price, // Price ... + const double &pivots[], // Provided Pivot Points ... + int count = 3, // Number of Requireds ... + double step = 0 // Distance between each item with it's Last Side ... + ) + { + // + bool result = false; + + // + Clean(); + + // + if (price <= 0) + { + return result; + } + + // + int pivotsCount = ArraySize(pivots); + if (pivotsCount <= 0) + { + return result; + } + + // + if (count <= 0 || + count > pivotsCount - 1) + { + return result; + } + + // + double lastR = 0; + double tmpR[]; + + // + double lastS = 0; + double tmpS[]; + + // + // Extract Supports ... + // which prices is under low of candle ... + // + // Extract Resistance ... + // which prices is over high of candle ... + for (int i = 0; i < pivotsCount; i++) + { + // + double iFlat = pivots[i]; + + // + if (iFlat > price) + { + // + bool canAdd = + step <= 0 + ? true + : lastR == 0 || MathAbs(iFlat - lastR) >= step; + if (canAdd) + { + // + Add( + iFlat, + tmpR); + + // + lastR = iFlat; + } + } + else if (iFlat < price) + { + // + bool canAdd = + step <= 0 + ? true + : lastS == 0 || MathAbs(iFlat - lastS) >= step; + if (canAdd) + { + // + Add( + iFlat, + tmpS); + + // + lastS = iFlat; + } + } + } + + // + // Sorting Founded Resistance and Supports ... + + // + // Since Resistance Levels must be Increasing ... + ArraySort(tmpR); + + // + // Since Support Levels must be Decreasing ... + ArraySort(tmpS); + ArrayReverse(tmpS); + + // + // Fill Resistance ... + int tmpRCount = ArraySize(tmpR); + if (tmpRCount > 0) + { + // + if (tmpRCount < count) + { + // + ArrayCopy( + res, + tmpR); + } + else + { + // + ArrayCopy( + res, + tmpR, + 0, + 0, + count); + } + } + + // + // Fill Supports ... + int tmpSCount = ArraySize(tmpS); + if (tmpSCount > 0) + { + // + if (tmpSCount < count) + { + // + ArrayCopy( + sup, + tmpS); + } + else + { + // + ArrayCopy( + sup, + tmpS, + 0, + 0, + count); + } + } + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + Clean(sup); + Clean(res); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + CountSupports() > 0 || + CountResistances() > 0 + // + ; + + // + return result; + } + + // + int CountSupports() + { + return ArraySize(sup); + } + + // + int CountResistances() + { + return ArraySize(res); + } +}; + +// +// Tracking Times ... +struct XTimeTracker +{ + // + // Props ... + int xMonth; + int xDayOfWeek; + int xForWeekDay; + int xDay; + int xHour; + + // + // Constructor ... + XTimeTracker() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + xDay = -1; + xHour = -1; + xMonth = -1; + xDayOfWeek = -1; + xForWeekDay = -1; + } + + // + // Detecting New Houre ... + bool IsNewHour() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.hour != xHour; + if (result) + { + xHour = timeStruct.hour; + } + + // + return result; + } + + // + // Detecting New Day ... + bool IsNewDay() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.day_of_year != xDay; + if (result) + { + xDay = timeStruct.day_of_year; + } + + // + return result; + } + + // + // Detecting New Week ... + bool IsNewWeek() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Week ... + // Since Week Starts From Monday in Forex World ... + // we Calculate Start of Week by 1-Monday ... + result = + xDayOfWeek == -1 && + xForWeekDay == -1 + ? true + : timeStruct.day_of_week == 1 && + timeStruct.day_of_year > xForWeekDay; + + // + xForWeekDay = timeStruct.day_of_year; + xDayOfWeek = timeStruct.day_of_week; + + // + return result; + } + + // + // Detecting End Of Week ... + bool IsWeekEnd() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check WeekEnd ... + // Since Week Starts From Monday in Forex World ... + // we Calculate End of Week by 5-Friday ... + result = + xDayOfWeek != -1 && + timeStruct.day_of_week == 5 && + timeStruct.hour == 23 && + timeStruct.min == 59 && + timeStruct.sec == 59; + + // + return result; + } + + // + // Detecting New Month ... + bool IsNewMonth() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.mon != xMonth; + if (result) + { + xMonth = timeStruct.mon; + } + + // + return result; + } +}; + +// +// Tracking Bars on Specified Environment ... +struct XBarTracker +{ + // + string symbol; // Tracking Symbol + ENUM_TIMEFRAMES period; // Tracking Time Frame + + // + int lastTrackedBar; // Last Tracked Bar ... + + // + // Constructor ... + XBarTracker() + { + Clean(); + } + + // + // Initializer ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + this.symbol = mSymbol; + this.period = mPeriod; + + // + this.lastTrackedBar = 0; + + // + result = true; + + // + return result; + } + + // + // Retrieve all Bars ... + int CountBars() + { + // + return Bars( + symbol, + period + // + ); + } + + // + // Check if it's New Bar ... + bool IsNewBar() + { + // + bool result = false; + + // + int currentBars = CountBars(); + + // + result = currentBars > lastTrackedBar; + if (result) + { + lastTrackedBar = currentBars; + } + + // + return result; + } + + // + // Tools ... + void Clean() + { + // + symbol = NormalizeSymbol(NULL); + period = NormalizePeriod(NULL); + } +}; + +// +// Track Value Changes ... +template +struct XValueTracker +{ + // + // Definitions ... + + // + // Model a Value Change ... + struct XValueChange + { + // + // Props ... + datetime at; // Change Time + T from; // Before Change Value + T to; // After Change Value + + // + // Constructor ... + XValueChange() + { + Clean(); + } + + // + // Cleanup ... + void Clean() + { + // + at = NULL; + from = NULL; + to = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = IsValid(at); + if (!result) + { + return result; + } + + // + result = NotEmpty(from) && + NotEmpty(to); + + // + return result; + } + }; + + // + // Props ... + XValueChange changes[]; // Hold Changes + + // + // Constructor ... + XValueTracker() + { + Clean(); + } + + // + // Track a Change Happens Or Not ... + bool Track( + const T &source[] // Data Source for Track Changes + ) + { + // + bool result = false; + + // + if (ArraySize(source) <= 1) + { + return result; + } + + // + datetime time = TimeCurrent(); + + // + double from = source[1]; + double to = source[0]; + + // + result = to != from; + if (result) + { + return result; + } + + // + XValueChange lastChange; + bool hasLastChange = + GetLastItem( + lastChange, + changes + // + ); + result = + !hasLastChange + ? true + : lastChange.at < time && + lastChange.to != to && + lastChange.from != from; + if (!result) + { + return result; + } + + // + lastChange.Clean(); + + // + lastChange.to = to; + lastChange.at = time; + lastChange.from = from; + + // + AddRef( + lastChange, + changes + // + ); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + Clean(changes); + } +}; + +// +// Model a Market Cycle ... +struct XMarketCycle +{ + // + // Props ... + + // + string prefix; // Prefix Trag ... + + // + string symbol; // Market Symbol ... + + // + ENUM_TIMEFRAMES period; // Period of Cycle ... + ENUM_X_PERIOD_METHOD method; // Period Selection Method ... + ENUM_X_MARKET_CYCLES cycle; // Cycles of MArket ... + + // + int length; // Number Of Candles per Current Time Frame ... + ENUM_TIMEFRAMES hostPeriod; // Current Time Frame ... + + // + datetime lastStart; // Last Candle Bar Time ... + + // + XBarTracker barTracker; // Bar Tracker ... + XBarRemainsTime remains; // Current Bar Remains Model ... + + // + // Constructor ... + XMarketCycle() + { + Clean(); + } + + // + // Init Cycle ... + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + string mPrefix = "" // Prefix + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mHostPeriod = NormalizePeriod(mHostPeriod); + + // + result = IsValid(mCycle); + if (!result) + { + return result; + } + + // + this.cycle = mCycle; + + // + // Set Automatically Prefix ... + if (StringLen(mPrefix) == 0) + { + this.prefix = ToString(cycle); + } + + // + result = IsValid( + method, + period // + ); + if (!result) + { + return result; + } + + // + this.symbol = mSymbol; + this.hostPeriod = mHostPeriod; + + // + // Find Cycle Period ... + if (method == X_PERIOD_AUTO) + { + // + // Select Period ... + this.period = GetCyclePeriod( + this.cycle, + this.hostPeriod); + } + + // + // Set Prefix if Provided ... + if (StringLen(mPrefix) > 0) + { + this.prefix = mPrefix; + } + + // + // Calculate Required Info ... + + // + // Length ... + this.length = PeriodSeconds(this.period) / PeriodSeconds(this.hostPeriod); + + // + // Update Additional Data ... + result = this.Update(0); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + length = 0; + lastStart = 0; + + // + cycle = NULL; + prefix = NULL; + symbol = NULL; + period = NULL; + method = NULL; + hostPeriod = NULL; + + // + remains.Clean(); + barTracker.Clean(); + } + + // + // Check Structure Valid ... + bool IsValid() + { + // + bool result = false; + + // + result = IsValid( + method, + period); + if (!result) + { + return result; + } + + // + result = + // + length > 0 && + symbol != NULL && + period != NULL && + method != NULL && + hostPeriod != NULL && + method != X_PERIOD_NOTHING + // + ; + + // + return result; + } + + // + // Update Market Cycle Additional Info ... + bool Update(int hostBarIndex) + { + // + bool result = false; + + // + result = this.IsValid(); + if (!result) + { + return result; + } + + // + // Init Remains ... + result = remains.Init( + this.symbol, + this.period); + if (!result) + { + return result; + } + + // + // Init Bar Tracker ... + result = barTracker.Init( + this.symbol, + this.period); + if (!result) + { + return result; + } + + // + return result; + } + + // + // Count Bars ... + int CountBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = barTracker.CountBars(); + + // + return result; + } + + // + // Check New Bar ... + bool IsNewBar() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = barTracker.IsNewBar(); + + // + return result; + } + + // + // Retrieve Current Bar Index based on Host Period bar Index ... + int GetBarIndex(int barIndex) + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + if (barIndex < 0) + { + return result; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + // + result = totalBars - 1; + return result; + } + + // + datetime hostBarTime = iTime( + this.symbol, + this.hostPeriod, + barIndex + // + ); + + // + result = iBarShift( + this.symbol, + this.period, + hostBarTime + // + ); + + // + return result; + } + + // + // Retrieve Current Cycles Specific Bar ... + XOHCL GetBar(int barIndex) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + barIndex = totalBars - 1; + } + + // + XOHCL result; + result.Init( + this.symbol, + this.period, + barIndex + // + ); + + // + return result; + } + + // + // Retrieve Bar Time ... + datetime GetBarTime(int barIndex) + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + barIndex = totalBars - 1; + } + + // + result = iTime( + this.symbol, + this.period, + barIndex + // + ); + + // + return result; + } + + // + // Create and String Representation for Unique Taging ... + string ToString() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = + GetTypeName(this) + "(" + + "PRFX(" + this.prefix + ")" + + "SMBL(" + this.symbol + ")" + + "CYC(" + ToString(this.cycle) + ")" + + "PRD(" + ToString(this.period) + ")" + + "PRDHST(" + ToString(this.hostPeriod) + ")" + + "MTH(" + EnumToString(this.method) + ")" + + ")"; + + // + return result; + } + + // + // Here we Produce a Summary brief of + // state of Cycle ... + string GenerateSummary() + { + // + string result = ""; + + // + bool hasPrefix = + StringLen(this.prefix) > 0 && + this.prefix != ToString(this.cycle); + result += (hasPrefix ? this.prefix + "[" : "") + + ToString(this.cycle) + + (hasPrefix ? "]" : "") + "\n"; + + // + result += " - PR: " + ToString(this.period) + "\n"; + + // + XOHCL cBar = GetBar(0); + + // + result += " - State: " + (cBar.IsBullish() ? "Bullish" : cBar.IsBearish() ? "Bearish" + : "Neutural"); + + // + return result; + } +}; + +// +// Functions ... + +// +// Validators ... + +// +// Validate an String has length and not NULL ... +bool IsValid(string value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + StringLen(value) > 0 + // + ; + + // + return result; +} + +// +// Validate a Date ... +bool IsValid(datetime value) +{ + // + bool result = false; + + // + result = NotEmpty(value) && value != NULL; + + // + return result; +} + +// +// Validate a Period Param ... +bool IsValid(ENUM_TIMEFRAMES value) +{ + // + bool result = false; + + // + result = + // + value != NULL + // + ; + + // + return result; +} + +// +// Validate Specified Cycle ... +bool IsValid(ENUM_X_MARKET_CYCLES value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + value != X_MARKET_CYCLE_UNKNOWN + // + ; + + // + return result; +} + +// +// Validate Specific Period Mode ... +bool IsValid( + ENUM_X_PERIOD_METHOD mMethod, // Period Select Method + ENUM_TIMEFRAMES mPeriod // Selected Period +) +{ + // + bool result = false; + + // + result = + // + mMethod == X_PERIOD_NOTHING + ? false + : mMethod == X_PERIOD_MANUALLY + ? mPeriod != NULL + : mMethod == X_PERIOD_AUTO + ? true + : false + // + ; + + // + return result; +} + +// +// Validate Swing Mode ... +bool IsValid(ENUM_X_SWING_TYPE value) +{ + // + bool result = false; + + // + result = + // + value == X_SWING_HIGH || + value == X_SWING_LOW + // + ; + + // + return result; +} + +// +// As IS ... + +// +// Determine a Position type is Long or not ... +bool IsLong(ENUM_POSITION_TYPE type) +{ + // + bool result = type == POSITION_TYPE_BUY; + + // + return result; +} +bool IsLong(ENUM_ORDER_TYPE type) +{ + // + bool result = type == ORDER_TYPE_BUY; + + // + return result; +} + +// +// Determine a Position type is Short or not ... +bool IsShort(ENUM_POSITION_TYPE type) +{ + // + bool result = type == POSITION_TYPE_SELL; + + // + return result; +} +bool IsShort(ENUM_ORDER_TYPE type) +{ + // + bool result = type == ORDER_TYPE_SELL; + + // + return result; +} + +// +// Check Expert Running in Testing Mode or not ... +bool IsRunningOnTestMode() +{ + // + bool result = false; + + // + // check programm mode ... + result = MQL5InfoInteger(MQL5_TESTING); + + // + return result; +} + +// +// Normalizers ... + +// +// Check a Symbol provided or not ... +// if not use Default ... +string NormalizeSymbol(string value) +{ + // + string result = value; + + // + if (!IsValid(result)) + { + result = _Symbol; + } + + // + return result; +} + +// +// Check a Datetime provided or not ... +// if not use Current ... +datetime NormalizeTime(datetime value) +{ + // + datetime result = value; + + // + if (!IsValid(result)) + { + result = TimeCurrent(); + } + + // + return result; +} + +// +// Check a Period provided or not ... +// if not use Default ... +ENUM_TIMEFRAMES NormalizePeriod(ENUM_TIMEFRAMES value) +{ + // + ENUM_TIMEFRAMES result = value; + + // + if (!IsValid(value)) + { + result = _Period; + } + + // + return result; +} + +// +// Normalize Cycle ... +ENUM_X_MARKET_CYCLES NormalizeCycle(ENUM_X_MARKET_CYCLES value) +{ + // + ENUM_X_MARKET_CYCLES result = value; + + // + if (!IsValid(result)) + { + result = X_MARKET_CYCLE_SHORT; + } + + // + return value; +} + +// +// Normalize a give Volume ... +double NormalizeVolume( + double mVolume, // desired volume to normalize + string mSymbol = NULL, // Trading Symbol + int mLength = 2 // Length of Digits +) +{ + // + double result = mVolume; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + // Normalize Digits ... + int digits = GetDigits(mSymbol); + + // + mLength = + mLength == 0 || mLength > digits + ? digits + : MathMin(mLength, digits); + + // + // Normalize Volume ... + result = NormalizeDouble(result, mLength); + + // + double maxAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MAX); + double minAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MIN); + + // + // Validate Result ... + if (result > maxAvailableVolume) + { + result = maxAvailableVolume; + } + else if (result < minAvailableVolume) + { + result = minAvailableVolume; + } + + // + return result; +} + +// +// Normallize Price ... +double NormalizePrice( + double mPrice, // desired Price for normalization + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double tickSize = 0; + result = SymbolInfoDouble(mSymbol, SYMBOL_TRADE_TICK_SIZE, tickSize); + + // + int digits = GetDigits(mSymbol); + result = NormalizeDouble(MathRound(mPrice / tickSize) * tickSize, digits); + + // + return result; +} + +// +// Prices ... + +// +// Retrieve Ask Price ... +double GetAsk( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_ASK); + + // + return result; +} + +// +// Retrieve Bid Price ... +double GetBid( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_BID); + + // + return result; +} + +// +// Retrieve Spread Price ... +double GetSpread( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double ask = GetAsk(mSymbol); + double bid = GetBid(mSymbol); + + // + double result = MathAbs(ask - bid); + + // + return result; +} + +// +// Retrieve Point Value ... +double GetPoints( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_POINT); + + // + return result; +} + +// +// Retrieve Point Digits ... +int GetDigits( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + int result = (int)SymbolInfoInteger(mSymbol, SYMBOL_DIGITS); + + // + return result; +} + +// +// Retrieve Entry Price ... +double GetEntry( + string mSymbol = NULL, // Trading Symbol + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? GetAsk(mSymbol) + : GetBid(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Retrieve Exit Price ... +double GetExit( + string mSymbol = NULL, // Trading Symbol + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? GetBid(mSymbol) + : GetAsk(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Get 1 Pip in Price Value ... +double GetPipPrice( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double symbolPoint = GetPoints(mSymbol); + int symbolDigits = GetDigits(mSymbol); + + // + double result = symbolPoint; + if (symbolDigits == 3 || symbolDigits == 5) + { + result *= 10; + } + + // + return result; +} + +// +// Converts Pips To Price ... +double PipsToPrice( + double mPips, // pips amount + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + int digits = GetDigits(mSymbol); + double pipValue = GetPipPrice(mSymbol); + double result = mPips * pipValue; + + // + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Converts Price to Pips ... +double PriceToPips( + double mPrice, // the price amount which required to calculate + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + mPrice = NormalizePrice(mPrice, mSymbol); + + // + int digits = GetDigits(mSymbol); + double pipPrice = GetPipPrice(mSymbol); + + // + double result = mPrice / pipPrice; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +// Convert Price to Point ... +double PriceToPoint( + double price, // the price amount which required to calculate + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + price = NormalizePrice(price, mSymbol); + + // + double point = GetPoints(mSymbol); + result = price / point; + + // + return result; +} + +// +// Converts Point to Price ... +double PointToPrice( + double points, // Points Amount + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double point = GetPoints(mSymbol); + result = points * point; + + // + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Converts Series Mode to XPRICE ... +ENUM_X_PRICE ToPrice( + ENUM_SERIESMODE mode // Specified Series Mode ... +) +{ + // + ENUM_X_PRICE result = X_PRICE_CLOSE; + + // + switch (mode) + { + // + // High ... + case MODE_HIGH: + result = X_PRICE_HIGH; + break; + + // + // Open ... + case MODE_OPEN: + result = X_PRICE_OPEN; + break; + + // + // Low ... + case MODE_LOW: + result = X_PRICE_LOW; + break; + + // + // Close ... + // Default ... + case MODE_CLOSE: + default: + result = X_PRICE_CLOSE; + break; + } + + // + return result; +} + +// +// Retrieve Applied Price ... +template +double GetAppliedPrice( + ENUM_APPLIED_PRICE tprice, // Type of Price Selection + T &open[], // Open Prices + T &high[], // High Preices + T &low[], // Low Prices + T &close[], // Close Prices + int i // Bar Index +) +{ + switch (tprice) + { + case PRICE_CLOSE: + return (close[i]); + case PRICE_OPEN: + return (open[i]); + case PRICE_HIGH: + return (high[i]); + case PRICE_LOW: + return (low[i]); + case PRICE_MEDIAN: + return ((high[i] + low[i]) / 2.0); + case PRICE_TYPICAL: + return ((high[i] + low[i] + close[i]) / 3.0); + case PRICE_WEIGHTED: + return ((high[i] + low[i] + close[i] + close[i]) / 4.0); + } + return (0); +} + +// +// Time / Date ... + +// +// Representation of Time Struct ... +// struct MqlDateTime +// { +// int year; // Year +// int mon; // Month +// int day; // Day +// int hour; // Hour +// int min; // Minutes +// int sec; // Seconds +// int day_of_week; // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) +// int day_of_year; // Day number of the year (January 1st is assigned the number value of zero) +// }; + +// +// Converts Time to Seconds ... +ulong TimeToSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = (ulong)time; + + // + return result; +} +ulong TimeToSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToSeconds(dTime); + + // + return result; +} + +// +// Converts Seconds To Time ... +datetime SecondsToTime( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime result = (datetime)seconds; + + // + return result; +} +MqlDateTime SecondsToStruct( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime dTime = SecondsToTime(seconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Converts Time to MilliSeconds ... +ulong TimeToMilliSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = TimeToSeconds(time) * 1000; + + // + return result; +} +ulong TimeToMilliSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToMilliSeconds(dTime); + + // + return result; +} + +// +// Converts MillisSeconds to Time ... +datetime MilliSecondsToTiem( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + ulong seconds = milliSeconds / 1000; + + // + datetime result = SecondsToTime(seconds); + + // + return result; +} +MqlDateTime MilliSecondsToStruct( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + datetime dTime = MilliSecondsToTiem(milliSeconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Retrieve DateTime Structure ... +MqlDateTime GetCurrentTime() +{ + // + MqlDateTime result = {}; + + // + TimeCurrent(result); + + // + return result; +} + +// +// Retrieve Current Time as Seconds ... +ulong GetCurrentTimeAsSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Current Time as MilliSeconds ... +ulong GetCurrentTimeAsMilliSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +// Bar Times ... + +// +// Retrieve Specified Bar Time ... +datetime GetBarTime( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Validate and Normalize Args ... + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + // Retrieve Bar Time ... + datetime result = iTime( + mSymbol, + mPeriod, + barIndex); + + // + return result; +} + +// +// Retrieve Specified Bar Time ... +ulong GetBarTimeAsSeconds( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Specified Bar Time ... +ulong GetBarTimeAsMilliSeconds( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +// Retrieve a Bar Time Structure ... +MqlDateTime GetBarTimeStruct( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + MqlDateTime result = {}; + + // + // Retrieve Bar Time ... + datetime barTime = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + // Convert to Structure ... + TimeToStruct(barTime, result); + + // + return result; +} + +// +// Other Tools ... + +// +// Check first Cross Over second at index ... +bool IsCrossedOver( + const double &first[], // the buffer which check crossing over second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] > second[index] && + !(first[index + 1] > second[index + 1]); + + // + return result; +} + +// +// Check first is Over second at index ... +bool IsOver( + const double &first[], // the buffer which check over second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] > second[index] && + first[index + 1] > second[index + 1]; + + // + return result; +} + +// +// Check first Cross Under second at index ... +bool IsCrossedUnder( + const double &first[], // the buffer which check crossing under second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] < second[index] && + !(first[index + 1] < second[index + 1]); + + // + return result; +} + +// +// Check first is Under second at index ... +bool IsUnder( + const double &first[], // the buffer which check under second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] < second[index] && + first[index + 1] < second[index + 1]; + + // + return result; +} + +// +// Calculate Slope of Specified Buffer at Specified Index ... +double GetSlope( + const double &buffer[], // Buffer + int from, // In Past Index ... + int to // In Past Index ... +) +{ + // + double result = 0; + + // + if (from > ArraySize(buffer) || to > ArraySize(buffer)) + { + return result; + } + + // + double toValue = buffer[to]; + double fromValue = buffer[from]; + double deltaValue = toValue - fromValue; + double deltaTime = from - to; + + // + result = deltaValue / deltaTime; + + // + return result; +} + +// +// Calculate Fib Level ... +double GetFibonacciLevel( + double upPrice, // Upper Bound + double downPrice, // Downer Bound + double level, // Level Multiplier Factor + int direction // From Down to Up < 0, other wise Vice Versa + // +) +{ + // + double ling = upPrice - downPrice; + double pLevel = (ling / 100) * (level * 100); + + // + double result = direction > 0 ? upPrice - pLevel : downPrice + pLevel; + + // + return result; +} + +// +// Templates ... + +// +// Retrieve Specific Object Types Name ... +template +string GetTypeName(const T &t) +{ + return typename(T); +} + +// +// Generate Unique Tags ... +template +string GenerateTag(T &model) +{ + // + string result = ""; + + // + string tag = model.ToString(); + if (StringLen(tag) == 0) + { + return result; + } + + // + static XSCMD5 md5; + + // + result = md5.Hash(tag); + + // + return result; +} + +// +// Hash Specified Content ... +template +string ToMD5(T content) +{ + // + string result = ""; + + // + string strContent = ToString(content); + if (StringLen(strContent) == 0) + { + return result; + } + + // + static XSCMD5 md5; + + // + result = md5.Hash(strContent); + + // + return result; +} + +// +// Check a Value Not Empty ... +template +bool NotEmpty(T value) +{ + return value != EMPTY_VALUE; +} + +// +// Add Specified Item to Array ... +template +int Add( + T item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + int result = 0; + + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; + + // + result = ArraySize(buffer); + + // + return result; +} +template +int AddRef( + T &item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + int result = 0; + + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; + + // + result = ArraySize(buffer); + + // + return result; +} + +// +// Remove Specified Item from an Array ... +template +bool Remove( + T item, + T &buffer[]) +{ + // + bool result = false; + + // + int itemIndex = FindIndex( + item, + buffer); + if (itemIndex < 0) + { + return result; + } + + // + result = ArrayRemove( + buffer, + itemIndex, + 1); + + // + return result; +} + +// +// Clean Specified Array ... +template +void Clean(T &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} + +// +// Copy Whole Content of Source to Dest array ... +template +void Copy( + T &source[], // Source Buffer ... + T &dest[], // Dest Buffer ... + bool cleanDest = true // Force Clen Dest Buffer ... +) +{ + // + if (cleanDest) + { + Clean(dest); + } + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + AddRef( + iSource, + dest); + } +} + +// +// Copy Items from a Buffer ... +template +int Copy( + int start, // Start + int count, // Number of Items for read + T &source[], // Source Buffer + T &dest[], // Dest Buffer + bool forceClean = true // Force To Clean buffer +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(dest); + } + + // + if (start < 0) + { + start = 0; + } + + // + if (start >= ArraySize(source)) + { + start = ArraySize(source) - 1; + } + + // + int beforeSize = ArraySize(dest); + + // + bool asSeriesDest = ArrayGetAsSeries(dest); + bool asSeriesSource = ArrayGetAsSeries(source); + + // + ArraySetAsSeries(dest, true); + ArraySetAsSeries(source, true); + + // + ArrayCopy( + dest, + source, + 0, + start, + count + // + ); + + // + int afterSize = ArraySize(dest); + + // + result = afterSize - beforeSize; + + // + ArraySetAsSeries(dest, asSeriesDest); + ArraySetAsSeries(source, asSeriesSource); + + // + return result; +} + +// +// Retrive Last Item of Specified Buffer ... +template +bool GetLastItem( + T &item, // Holds Result + T &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + item = buffer[bufferSize - 1]; + + // + result = true; + return result; +} + +// +// Search Array For Specific Item ... +template +int FindIndex( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + int result = -1; + + // + int count = ArraySize(buffer); + if (count <= 0) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + T iT = buffer[i]; + + // + if (iT == item) + { + // + result = i; + break; + } + } + + // + return result; +} + +// +// Check an Array Contains Specified Value ... +template +bool Contains( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + bool result = false; + + // + int idx = FindIndex( + item, + buffer); + result = idx > -1; + + // + return result; +} + +// +// Calculate a Buffer's Average ... +template +double GetAverage( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Calculate Summary ... + for (int i = 0; i < tmpCount; i++) + { + result += buffer[i]; + } + + // + // Calculate Average ... + result = result / tmpCount; + + // + return result; +} + +// +// Get Max of Specific Loopback of a Buffer ... +template +double GetMax( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + double iValue = tmp[i]; + + // + result = + // + result == 0 || result < iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} + +// +// Get Min of Specific Loopback of a Buffer ... +template +double GetMinValue( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + double iValue = tmp[i]; + + // + result = + // + result == 0 || result > iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} + +// +// Find a Value less than Specified ... +template +T FindLesserThanValue( + T value, // Specified Value ... + const T &source[], // Source ... + bool isDescend = false // Find Biggest Lesser Value ... +) +{ + // + T result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source)); + + // + ArrayCopy( + tmp, + source); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue < value) + { + // + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find a Value less than Specified ... +template +T FindBiggerThanValue( + T value, // Specified Value ... + const T &source[], // Source ... + bool isDescend = false // Find Smallest Bigger Value ... +) +{ + // + T result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source)); + + // + ArrayCopy( + tmp, + source); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (!isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue > value) + { + // + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find Same Values in Array ... +template +void FindSameValues( + T &result[], // Holds Result ... + T &source[], // Source ... + int verifications = 3 // Number of Consequence Repeat ... +) +{ + // + Clean(result); + + // + // TenkanSen Flats ... + int sourceCount = ArraySize(source); + if (sourceCount > verifications) + { + // + T mLast = 0; + int mVerified = 0; + for (int i = 0; i < sourceCount; i++) + { + // + T iVal = source[i]; + if (mLast == 0) + { + mLast = iVal; + } + else if (mLast == iVal) + { + mVerified++; + } + else + { + mLast = iVal; + mVerified = 0; + } + + // + if (iVal == mLast && mVerified >= verifications) + { + // + Add( + iVal, + result); + + // + mLast = 0; + mVerified = 0; + } + } + } +} + +// +// Add an Item to a Buffer if not Exists ... +void AddIfNotExists( + double value, + double &values[], + double smoothingPoint = 3) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int valuesCount = ArraySize(values); + if (valuesCount <= 0) + { + // + Add(value, + values); + } + else + { + // + bool isExists = false; + for (int i = 0; i < valuesCount; i++) + { + // + double iVal = values[i]; + + // + double diff = MathAbs(iVal - value); + + // + if (iVal == value || diff < smoothingValue) + { + // + isExists = true; + break; + } + } + + // + if (!isExists) + { + // + Add(value, + values); + } + } +} + +// +// Add a Buffers Child to another Buffer +// if it's not Contains them ... +void AddsIfNotExists( + double &source[], + double &dest[], + double smoothingPoint = 3) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + double iSource = source[i]; + + // + AddIfNotExists( + iSource, + dest, + smoothingPoint); + } +} + +// +// Bar XOHCL ... + +// +// Extract Specific Range of Bars ... +// using Start Bar Index ... +int GetBars( + XOHCL &result[], // Hold Result + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame + int from = 0, // Start Bar Index + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array +) +{ + // + int mResult = 0; + + // + if (from < 0) + { + from = 0; + } + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int total = Bars( + mSymbol, + mPeriod); + if (from > total - 2) + { + from = total - 2; + } + + // + if (count < 0) + { + count = 1; + } + + // + int start = from; + int end = start + count; + if (end > total - 1) + { + end = total - 1; + } + + // + if (forceClean) + { + Clean(result); + } + + // + int beforeSize = ArraySize(result); + + // + for (int i = start; i < end; i++) + { + // + XOHCL iBar; + bool isValid = iBar.Init( + mSymbol, + mPeriod, + i + // + ); + + // + if (isValid) + { + // + AddRef( + iBar, + result + // + ); + } + } + + // + int afterSize = ArraySize(result); + + // + mResult = afterSize - beforeSize; + + // + return mResult; +} + +// +// Extract Specific Range of Bars ... +// using Start Bar Time ... +int GetBars( + XOHCL &result[], // Hold Result + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame + datetime from = NULL, // Start Bar Time + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + from = NormalizeTime(from); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + from, + false + // + ); + + // + return GetBars( + result, + mSymbol, + mPeriod, + barIndex, + count, + forceClean + // + ); +} + +// +// String ... + +// +// Convert From String ... +template +T FromString(string value) +{ + // + T result = NULL; + + // + if (!IsValid(value)) + { + return result; + } + + // + result = (T)value; + + // + return result; +} + +// +// Converts an item to String ... +template +string ToString(T value) +{ + return (string)value; +} + +// +// Converts a Buffer to String Representation ... +template +string ToString( + const T &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} + +// +// Converts String to boolean ... +bool ToBoolean(string value) +{ + // + bool result = false; + + // + if (StringLen(value) <= 0) + { + return result; + } + + // + StringToLower(value); + result = value == "true"; + + // + return result; +} + +// +// Split an String Representation of an Array ... +int SplitContent( + string &result[], // Hold Result ... + string content, // Source ... + string separator = ",", // Separator ... + bool forceCleanResult = true // Clean Result ... +) +{ + // + int mResult = 0; + + // + if (forceCleanResult) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + if (separator == NULL || StringLen(separator) == 0) + { + separator = ","; + } + + // + if (StringLen(content) == 0) + { + return mResult; + } + + // + StringSplit( + content, + StringGetCharacter( + separator, + 0), + result); + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; +} + +// +// Extract Data from String ... +string ExtractString( + const string source, // Source String used for Extracting + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + string result = ""; + + // + // Validate String ... + if ( + StringLen(source) == 0 || + StringLen(endString) == 0 || + StringLen(startString) == 0) + { + return result; + } + + // + // Find Start String Position ... + int sPos = StringFind( + source, + startString); + if (sPos < 0) + { + return result; + } + + // + // Find End String Position after Start String ... + int searchEndFromPos = sPos + StringLen(startString); + int ePos = StringFind( + source, + endString, + searchEndFromPos); + if (ePos < 0) + { + return result; + } + + // + // Extract Data from Source ... + int dLength = ePos - searchEndFromPos; + result = StringSubstr( + source, + searchEndFromPos, + dLength); + + // + return result; +} + +// +// Extract an Array of Contents ... +int ExtractStrings( + string &result[], // Hold Result + const string source, // Source String used for Extracting + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + int mResult = 0; + + // + Clean(result); + + // + // Validate Args ... + int sourceLength = StringLen(source); + int startLength = StringLen(startString); + int endLength = StringLen(endString); + + // + int minRequiredLength = startLength + endLength; + + // + if ( + endLength <= 0 || + startLength <= 0 || + sourceLength <= 0 || + sourceLength < minRequiredLength) + { + return mResult; + } + + // + // Make a Copy of Source for Manipulating ... + string workStr = source; + + // + // Define a Loop ... + while (StringLen(workStr) > minRequiredLength) + { + // + // Find Item ... + string item = ExtractString( + workStr, + startString, + endString); + + // + // Breakout when couldn't find anymore item ... + int itemLength = StringLen(item); + if (itemLength <= 0) + { + break; + } + + // + // Prepare Item Source String for Replacing in Work String ... + string itemSource = startString + item + endString; + + // + // Add Item to Result Array ... + Add( + item, + result); + + // + // Replace Item Soure in Work String ... + StringReplace( + workStr, + itemSource, + ""); + } + + // + // Calculate Size of Array ... + mResult = ArraySize(result); + + // + return mResult; +} + +// +string ExtractSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + return ExtractString( + surrounded, + mToken + startString, + endString + // + ); +} + +// +int ParseIntSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + int result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (int)strContent; + + // + return result; +} +long ParseLongSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + long result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (long)strContent; + + // + return result; +} +string ParseStringSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + string result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (string)strContent; + + // + return result; +} +double ParseDoubleSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + double result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (double)strContent; + + // + return result; +} +datetime ParseTimeSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + datetime result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (datetime)strContent; + + // + return result; +} + +// +int ParseIntArraySurrounded( + int &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + int iValue = (int)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} +int ParseLongArraySurrounded( + long &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + long iValue = (long)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} +int ParseDoubleArraySurrounded( + double &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + double iValue = (double)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} + +// +// Surround an String by Specific Token ... +template +string Surround( + string mToken, // an String which used to Tokenize + T &value, // a Value for Tokenize it + string startString = "(", // Token Start Content + string endString = ")" // Token End Content +) +{ + // + string result = NULL; + + // + string strValue = ToString(value); + if (!IsValid(strValue)) + { + return result; + } + + // + result = + // + (IsValid(mToken) + ? mToken + : "") + + // + startString + + strValue + + endString + // + ; + + // + return result; +} + +// +// Periods / Cycles ... + +// +// Converts an String to TimeFrame ... +ENUM_TIMEFRAMES ToPeriod(string value) +{ + // + if (StringLen(value) == 0) + { + return _Period; + } + + // + StringTrimLeft(value); + StringTrimRight(value); + + // + ENUM_TIMEFRAMES result = _Period; + + // + if (value == "M1") + { + result = PERIOD_M1; + } + else if (value == "M2") + { + result = PERIOD_M2; + } + else if (value == "M3") + { + result = PERIOD_M3; + } + else if (value == "M4") + { + result = PERIOD_M4; + } + else if (value == "M5") + { + result = PERIOD_M5; + } + else if (value == "M6") + { + result = PERIOD_M6; + } + else if (value == "M10") + { + result = PERIOD_M10; + } + else if (value == "M12") + { + result = PERIOD_M12; + } + else if (value == "M15") + { + result = PERIOD_M15; + } + else if (value == "M20") + { + result = PERIOD_M20; + } + else if (value == "M30") + { + result = PERIOD_M30; + } + else if (value == "H1") + { + result = PERIOD_H1; + } + else if (value == "H2") + { + result = PERIOD_H2; + } + else if (value == "H3") + { + result = PERIOD_H3; + } + else if (value == "H4") + { + result = PERIOD_H4; + } + else if (value == "H6") + { + result = PERIOD_H6; + } + else if (value == "H8") + { + result = PERIOD_H8; + } + else if (value == "H12") + { + result = PERIOD_H12; + } + else if (value == "D1") + { + result = PERIOD_D1; + } + else if (value == "W1") + { + result = PERIOD_W1; + } + else if (value == "MN1") + { + result = PERIOD_MN1; + } + + // + return result; +} + +// +// Converts Period to String ... +string ToString(ENUM_TIMEFRAMES mPeriod) +{ + // + string result = ""; + + // + string mPStr = EnumToString(mPeriod); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[1]; + + // + return result; +} + +// +// Retrieve All Available Period as an Array ...s +int GetAllAvailablePeriods( + ENUM_TIMEFRAMES &result[] // Holds Result ... +) +{ + // + Clean(result); + + // + Add( + PERIOD_M1, + result + // + ); + + // + Add( + PERIOD_M2, + result + // + ); + + // + Add( + PERIOD_M3, + result + // + ); + + // + Add( + PERIOD_M4, + result + // + ); + + // + Add( + PERIOD_M5, + result + // + ); + + // + Add( + PERIOD_M6, + result + // + ); + + // + Add( + PERIOD_M10, + result + // + ); + + // + Add( + PERIOD_M12, + result + // + ); + + // + Add( + PERIOD_M15, + result + // + ); + + // + Add( + PERIOD_M20, + result + // + ); + + // + Add( + PERIOD_M30, + result + // + ); + + // + Add( + PERIOD_H1, + result + // + ); + + // + Add( + PERIOD_H2, + result + // + ); + + // + Add( + PERIOD_H3, + result + // + ); + + // + Add( + PERIOD_H4, + result + // + ); + + // + Add( + PERIOD_H6, + result + // + ); + + // + Add( + PERIOD_H8, + result + // + ); + + // + Add( + PERIOD_H12, + result + // + ); + + // + Add( + PERIOD_D1, + result + // + ); + + // + Add( + PERIOD_W1, + result + // + ); + + // + Add( + PERIOD_MN1, + result + // + ); + + // + int mResult = ArraySize(result); + + // + return mResult; +} + +// +// Get Specific Time Frame Start Candle Time ... +datetime GetPeriodStartTime( + string mSymbol = NULL, // Specified Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... + datetime mTime = NULL // Specified Bar Time of Host Period ... +) +{ + // + // Normalize Arg ... + mTime = NormalizeTime(mTime); + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false + // + ); + + // + datetime result = GetBarTime( + mSymbol, + mPeriod, + barIndex + // + ); + + // + return result; +} + +// +// Converts an String to it's related Market Cycle ... +ENUM_X_MARKET_CYCLES ToCycle(string value) +{ + // + ENUM_X_MARKET_CYCLES result = X_MARKET_CYCLE_UNKNOWN; + + // + ENUM_X_MARKET_CYCLES cycles[]; + int count = GetAllMarketCycles(cycles); + for (int i = 0; i < count; i++) + { + // + ENUM_X_MARKET_CYCLES iCycle = cycles[i]; + string iStr = ToString(iCycle); + + // + if (value == iStr) + { + // + result = iCycle; + break; + } + } + + // + return result; +} + +// +// Converts a Cycle to it's String Representation ... +string ToString(ENUM_X_MARKET_CYCLES cycle) +{ + // + string result = ""; + + // + string mPStr = EnumToString(cycle); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[3]; + + // + return result; +} + +// +// Retrieve all Available Cycles ... +int GetAllMarketCycles(ENUM_X_MARKET_CYCLES &result[]) +{ + // + int mResult = 0; + + // + Clean(result); + + // + ENUM_X_MARKET_CYCLES tmp[] = { + X_MARKET_CYCLE_UNKNOWN, + X_MARKET_CYCLE_SHORT, + X_MARKET_CYCLE_MEDIUM, + X_MARKET_CYCLE_LONG, + X_MARKET_CYCLE_HIND}; + + // + Copy( + tmp, + result); + + // + Clean(tmp); + + // + mResult = ArraySize(result); + + // + return mResult; +} + +// +// Retrieve Nearest Period base on Given Period ... +ENUM_TIMEFRAMES GetNearestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + result = PERIOD_M4; + break; + + // + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_M6; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_M15; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_M30; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H4; + break; + + // + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_H12; + break; + + // + case PERIOD_H12: + result = PERIOD_D1; + break; + + // + case PERIOD_D1: + result = PERIOD_W1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Retrieve Mediest Period base on Given Period ... +ENUM_TIMEFRAMES GetMediestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + result = PERIOD_M15; + break; + + // + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_M30; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_H1; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_H2; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H8; + break; + + // + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_D1; + break; + + // + case PERIOD_H12: + result = PERIOD_W1; + break; + + // + case PERIOD_D1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Retrieve Longest Period base on Given Period ... +ENUM_TIMEFRAMES GetLongestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + result = PERIOD_M30; + break; + + // + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_H1; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_H2; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_H4; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H12; + break; + + // + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_W1; + break; + + // + case PERIOD_H12: + result = PERIOD_MN1; + break; + + // + case PERIOD_D1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Retrieve Hindmost Period base on Given Period ... +ENUM_TIMEFRAMES GetHindMostPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + result = PERIOD_H1; + break; + + // + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_H2; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_H4; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_H8; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_D1; + break; + + // + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_MN1; + break; + + // + case PERIOD_H12: + result = PERIOD_MN1; + break; + + // + case PERIOD_D1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Retrieve Specified Cycles Period related to Host Period ... +ENUM_TIMEFRAMES GetCyclePeriod( + ENUM_X_MARKET_CYCLES mCycle = NULL, // Specified Cycle + ENUM_TIMEFRAMES mPeriod = NULL // Host Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + mPeriod = NormalizePeriod(mPeriod); + mCycle = NormalizeCycle(mCycle); + + // + switch (mCycle) + { + // + // Short ... + case X_MARKET_CYCLE_SHORT: + result = GetNearestPeriod(mPeriod); + break; + + // + // Medium ... + case X_MARKET_CYCLE_MEDIUM: + result = GetMediestPeriod(mPeriod); + break; + + // + // Long ... + case X_MARKET_CYCLE_LONG: + result = GetLongestPeriod(mPeriod); + break; + + // + // Hind ... + case X_MARKET_CYCLE_HIND: + result = GetHindMostPeriod(mPeriod); + break; + } + + // + return result; +} \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.draw.lib.ex5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.draw.lib.ex5 new file mode 100644 index 0000000..663a701 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.draw.lib.ex5 differ diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.draw.lib.mq5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.draw.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.draw.lib.mq5 rename to MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.draw.lib.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.http.lib.ex5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.http.lib.ex5 new file mode 100644 index 0000000..60ca77d Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.http.lib.ex5 differ diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.http.lib.mq5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.http.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.http.lib.mq5 rename to MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.http.lib.mq5 diff --git a/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.log.lib.ex5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.log.lib.ex5 new file mode 100644 index 0000000..60429e2 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.log.lib.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.log.lib.mq5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.log.lib.mq5 new file mode 100644 index 0000000..ad34125 --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.log.lib.mq5 @@ -0,0 +1,1084 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Logger Library +// --------------------------------------- +// Name: XLogger +// Description: provides Logging abilities ... +// +// +// 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 + +// +// START Inputs ... +// +// input group "Logging"; +// input bool enableLogging = true; // Enable Logging +bool enableLogging = true; // Enable Logging +// +// END Inputs ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// +string logTag = "X-Logger"; // LogTag +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// +// +// Logging a Message ... +void LogMessage(string message) +{ + // + if (!enableLogging) + { + return; + } + + // + Print(logTag, " > ", message); +} +void LogMessage(string tag, string message) +{ + // + if (!enableLogging) + { + return; + } + + // + Print(tag, " > ", message); +} + +// +void LogEmptyLine() +{ + LogMessage(" "); +} + +// +void LogError( + int error = -1 // Specific Error +) { + // + if (error <= -1) { + error = GetLastError(); + } + + // + string errorMsg = GetErrorDescription(error); + + // + LogMessage("Error: " + errorMsg); +} + +// +// Logging an Array ... +void LogArray(int &array[]) +{ + // + if (!enableLogging) + { + return; + } + + // + Print(logTag, ">"); + ArrayPrint(array); +} +void LogArray(double &array[]) +{ + // + if (!enableLogging) + { + return; + } + + // + Print(logTag, ">"); + ArrayPrint(array); +} +void LogArray(string &array[]) +{ + // + if (!enableLogging) + { + return; + } + + // + Print(logTag, ">"); + ArrayPrint(array); +} +// +// END Provided Functions ... +// + + +// +// Error Descriptions Functions ... +// + +// +// Retrieve Specified Error Code Description ... +string GetErrorDescription(int err_code) +{ + // + string result = ""; + + // + switch (err_code) + { + // + //--- Constant Description + + // + case ERR_SUCCESS: + result = "The operation completed successfully"; + break; + + // + case ERR_INTERNAL_ERROR: + result = "Unexpected internal error"; + break; + + // + case ERR_WRONG_INTERNAL_PARAMETER: + result = "Wrong parameter in the inner call of the client terminal function"; + break; + + // + case ERR_INVALID_PARAMETER: + result = "Wrong parameter when calling the system function"; + break; + + // + case ERR_NOT_ENOUGH_MEMORY: + result = "Not enough memory to perform the system function"; + break; + + // + case ERR_STRUCT_WITHOBJECTS_ORCLASS: + result = "The structure contains objects of strings and/or dynamic arrays and/or structure of such objects and/or classes"; + break; + + // + case ERR_INVALID_ARRAY: + result = "Array of a wrong type, wrong size, or a damaged object of a dynamic array"; + break; + + // + case ERR_ARRAY_RESIZE_ERROR: + result = "Not enough memory for the relocation of an array, or an attempt to change the size of a static array"; + break; + + // + case ERR_STRING_RESIZE_ERROR: + result = "Not enough memory for the relocation of string"; + break; + + // + case ERR_NOTINITIALIZED_STRING: + result = "Not initialized string"; + break; + + // + case ERR_INVALID_DATETIME: + result = "Invalid date and/or time"; + break; + + // + case ERR_ARRAY_BAD_SIZE: + result = "Requested array size exceeds 2 GB"; + break; + + // + case ERR_INVALID_POINTER: + result = "Wrong pointer"; + break; + + // + case ERR_INVALID_POINTER_TYPE: + result = "Wrong type of pointer"; + break; + + // + case ERR_FUNCTION_NOT_ALLOWED: + result = "System function is not allowed to call"; + break; + + // + //--- Charts + + // + case ERR_CHART_WRONG_ID: + result = "Wrong chart ID"; + break; + + // + case ERR_CHART_NO_REPLY: + result = "Chart does not respond"; + break; + + // + case ERR_CHART_NOT_FOUND: + result = "Chart not found"; + break; + + // + case ERR_CHART_NO_EXPERT: + result = "No Expert Advisor in the chart that could handle the event"; + break; + + // + case ERR_CHART_CANNOT_OPEN: + result = "Chart opening error"; + break; + + // + case ERR_CHART_CANNOT_CHANGE: + result = "Failed to change chart symbol and period"; + break; + + // + case ERR_CHART_CANNOT_CREATE_TIMER: + result = "Failed to create timer"; + break; + + // + case ERR_CHART_WRONG_PROPERTY: + result = "Wrong chart property ID"; + break; + + // + case ERR_CHART_SCREENSHOT_FAILED: + result = "Error creating screenshots"; + break; + + // + case ERR_CHART_NAVIGATE_FAILED: + result = "Error navigating through chart"; + break; + + // + case ERR_CHART_TEMPLATE_FAILED: + result = "Error applying template"; + break; + + // + case ERR_CHART_WINDOW_NOT_FOUND: + result = "Subwindow containing the indicator was not found"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_ADD: + result = "Error adding an indicator to chart"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_DEL: + result = "Error deleting an indicator from the chart"; + break; + + // + case ERR_CHART_INDICATOR_NOT_FOUND: + result = "Indicator not found on the specified chart"; + break; + + // + //--- Graphical Objects + case ERR_OBJECT_ERROR: + result = "Error working with a graphical object"; + break; + + // + case ERR_OBJECT_NOT_FOUND: + result = "Graphical object was not found"; + break; + + // + case ERR_OBJECT_WRONG_PROPERTY: + result = "Wrong ID of a graphical object property"; + break; + + // + case ERR_OBJECT_GETDATE_FAILED: + result = "Unable to get date corresponding to the value"; + break; + + // + case ERR_OBJECT_GETVALUE_FAILED: + result = "Unable to get value corresponding to the date"; + break; + + // + //--- MarketInfo + + // + case ERR_MARKET_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_MARKET_NOT_SELECTED: + result = "Symbol is not selected in MarketWatch"; + break; + + // + case ERR_MARKET_WRONG_PROPERTY: + result = "Wrong identifier of a symbol property"; + break; + + // + case ERR_MARKET_LASTTIME_UNKNOWN: + result = "Time of the last tick is not known (no ticks)"; + break; + + // + case ERR_MARKET_SELECT_ERROR: + result = "Error adding or deleting a symbol in MarketWatch"; + break; + + // + //--- History Access + + // + case ERR_HISTORY_NOT_FOUND: + result = "Requested history not found"; + break; + + // + case ERR_HISTORY_WRONG_PROPERTY: + result = "Wrong ID of the history property"; + break; + + // + //--- Global_Variables + + // + case ERR_GLOBALVARIABLE_NOT_FOUND: + result = "Global variable of the client terminal is not found"; + break; + + // + case ERR_GLOBALVARIABLE_EXISTS: + result = "Global variable of the client terminal with the same name already exists"; + break; + + // + case ERR_MAIL_SEND_FAILED: + result = "Email sending failed"; + break; + + // + case ERR_PLAY_SOUND_FAILED: + result = "Sound playing failed"; + break; + + // + case ERR_MQL5_WRONG_PROPERTY: + result = "Wrong identifier of the program property"; + break; + + // + case ERR_TERMINAL_WRONG_PROPERTY: + result = "Wrong identifier of the terminal property"; + break; + + // + case ERR_FTP_SEND_FAILED: + result = "File sending via ftp failed"; + break; + + // + case ERR_NOTIFICATION_SEND_FAILED: + result = "Error in sending notification"; + break; + + // + //--- Custom Indicator Buffers + + // + case ERR_BUFFERS_NO_MEMORY: + result = "Not enough memory for the distribution of indicator buffers"; + break; + + // + case ERR_BUFFERS_WRONG_INDEX: + result = "Wrong indicator buffer index"; + break; + + // + //--- Custom Indicator Properties + + // + case ERR_CUSTOM_WRONG_PROPERTY: + result = "Wrong ID of the custom indicator property"; + break; + + // + //--- Account + + // + case ERR_ACCOUNT_WRONG_PROPERTY: + result = "Wrong account property ID"; + break; + + // + case ERR_TRADE_WRONG_PROPERTY: + result = "Wrong trade property ID"; + break; + + // + case ERR_TRADE_DISABLED: + result = "Trading by Expert Advisors prohibited"; + break; + + // + case ERR_TRADE_POSITION_NOT_FOUND: + result = "Position not found"; + break; + + // + case ERR_TRADE_ORDER_NOT_FOUND: + result = "Order not found"; + break; + + // + case ERR_TRADE_DEAL_NOT_FOUND: + result = "Deal not found"; + break; + + // + case ERR_TRADE_SEND_FAILED: + result = "Trade request sending failed"; + break; + + // + //--- Indicators + + // + case ERR_INDICATOR_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_INDICATOR_CANNOT_CREATE: + result = "Indicator cannot be created"; + break; + + // + case ERR_INDICATOR_NO_MEMORY: + result = "Not enough memory to add the indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_APPLY: + result = "The indicator cannot be applied to another indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_ADD: + result = "Error applying an indicator to chart"; + break; + + // + case ERR_INDICATOR_DATA_NOT_FOUND: + result = "Requested data not found"; + break; + + // + case ERR_INDICATOR_WRONG_HANDLE: + result = "Wrong indicator handle"; + break; + + // + case ERR_INDICATOR_WRONG_PARAMETERS: + result = "Wrong number of parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_PARAMETERS_MISSING: + result = "No parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_CUSTOM_NAME: + result = "The first parameter in the array must be the name of the custom indicator"; + break; + + // + case ERR_INDICATOR_PARAMETER_TYPE: + result = "Invalid parameter type in the array when creating an indicator"; + break; + + // + case ERR_INDICATOR_WRONG_INDEX: + result = "Wrong index of the requested indicator buffer"; + break; + + // + //--- Depth of Market + + // + case ERR_BOOKS_CANNOT_ADD: + result = "Depth Of Market can not be added"; + break; + + // + case ERR_BOOKS_CANNOT_DELETE: + result = "Depth Of Market can not be removed"; + break; + + // + case ERR_BOOKS_CANNOT_GET: + result = "The data from Depth Of Market can not be obtained"; + break; + + // + case ERR_BOOKS_CANNOT_SUBSCRIBE: + result = "Error in subscribing to receive new data from Depth Of Market"; + break; + + // + //--- File Operations + + // + case ERR_TOO_MANY_FILES: + result = "More than 64 files cannot be opened at the same time"; + break; + + // + case ERR_WRONG_FILENAME: + result = "Invalid file name"; + break; + + // + case ERR_TOO_LONG_FILENAME: + result = "Too long file name"; + break; + + // + case ERR_CANNOT_OPEN_FILE: + result = "File opening error"; + break; + + // + case ERR_FILE_CACHEBUFFER_ERROR: + result = "Not enough memory for cache to read"; + break; + + // + case ERR_CANNOT_DELETE_FILE: + result = "File deleting error"; + break; + + // + case ERR_INVALID_FILEHANDLE: + result = "A file with this handle was closed, or was not opening at all"; + break; + + // + case ERR_WRONG_FILEHANDLE: + result = "Wrong file handle"; + break; + + // + case ERR_FILE_NOTTOWRITE: + result = "The file must be opened for writing"; + break; + + // + case ERR_FILE_NOTTOREAD: + result = "The file must be opened for reading"; + break; + + // + case ERR_FILE_NOTBIN: + result = "The file must be opened as a binary one"; + break; + + // + case ERR_FILE_NOTTXT: + result = "The file must be opened as a text"; + break; + + // + case ERR_FILE_NOTTXTORCSV: + result = "The file must be opened as a text or CSV"; + break; + + // + case ERR_FILE_NOTCSV: + result = "The file must be opened as CSV"; + break; + + // + case ERR_FILE_READERROR: + result = "File reading error"; + break; + + // + case ERR_FILE_BINSTRINGSIZE: + result = "String size must be specified, because the file is opened as binary"; + break; + + // + case ERR_INCOMPATIBLE_FILE: + result = "A text file must be for string arrays, for other arrays - binary"; + break; + + // + case ERR_FILE_IS_DIRECTORY: + result = "This is not a file, this is a directory"; + break; + + // + case ERR_FILE_NOT_EXIST: + result = "File does not exist"; + break; + + // + case ERR_FILE_CANNOT_REWRITE: + result = "File can not be rewritten"; + break; + + // + case ERR_WRONG_DIRECTORYNAME: + result = "Wrong directory name"; + break; + + // + case ERR_DIRECTORY_NOT_EXIST: + result = "Directory does not exist"; + break; + + // + case ERR_FILE_ISNOT_DIRECTORY: + result = "This is a file, not a directory"; + break; + + // + case ERR_CANNOT_DELETE_DIRECTORY: + result = "The directory cannot be removed"; + break; + + // + case ERR_CANNOT_CLEAN_DIRECTORY: + result = "Failed to clear the directory (probably one or more files are blocked and removal operation failed)"; + break; + + // + case ERR_FILE_WRITEERROR: + result = "Failed to write a resource to a file"; + break; + + // + //--- String Casting + + // + case ERR_NO_STRING_DATE: + result = "No date in the string"; + break; + + // + case ERR_WRONG_STRING_DATE: + result = "Wrong date in the string"; + break; + + // + case ERR_WRONG_STRING_TIME: + result = "Wrong time in the string"; + break; + + // + case ERR_STRING_TIME_ERROR: + result = "Error converting string to date"; + break; + + // + case ERR_STRING_OUT_OF_MEMORY: + result = "Not enough memory for the string"; + break; + + // + case ERR_STRING_SMALL_LEN: + result = "The string length is less than expected"; + break; + + // + case ERR_STRING_TOO_BIGNUMBER: + result = "Too large number, more than ULONG_MAX"; + break; + + // + case ERR_WRONG_FORMATSTRING: + result = "Invalid format string"; + break; + + // + case ERR_TOO_MANY_FORMATTERS: + result = "Amount of format specifiers more than the parameters"; + break; + + // + case ERR_TOO_MANY_PARAMETERS: + result = "Amount of parameters more than the format specifiers"; + break; + + // + case ERR_WRONG_STRING_PARAMETER: + result = "Damaged parameter of string type"; + break; + + // + case ERR_STRINGPOS_OUTOFRANGE: + result = "Position outside the string"; + break; + + // + case ERR_STRING_ZEROADDED: + result = "0 added to the string end, a useless operation"; + break; + + // + case ERR_STRING_UNKNOWNTYPE: + result = "Unknown data type when converting to a string"; + break; + + // + case ERR_WRONG_STRING_OBJECT: + result = "Damaged string object"; + break; + + // + //--- Operations with Arrays + + // + case ERR_INCOMPATIBLE_ARRAYS: + result = "Copying incompatible arrays. String array can be copied only to a string array, and a numeric array - in numeric array only"; + break; + + // + case ERR_SMALL_ASSERIES_ARRAY: + result = "The receiving array is declared as AS_SERIES, and it is of insufficient size"; + break; + + // + case ERR_SMALL_ARRAY: + result = "Too small array, the starting position is outside the array"; + break; + + // + case ERR_ZEROSIZE_ARRAY: + result = "An array of zero length"; + break; + + // + case ERR_NUMBER_ARRAYS_ONLY: + result = "Must be a numeric array"; + break; + + // + case ERR_ONEDIM_ARRAYS_ONLY: + result = "Must be a one-dimensional array"; + break; + + // + case ERR_SERIES_ARRAY: + result = "Timeseries cannot be used"; + break; + + // + case ERR_DOUBLE_ARRAY_ONLY: + result = "Must be an array of type double"; + break; + + // + case ERR_FLOAT_ARRAY_ONLY: + result = "Must be an array of type float"; + break; + + // + case ERR_LONG_ARRAY_ONLY: + result = "Must be an array of type long"; + break; + + // + case ERR_INT_ARRAY_ONLY: + result = "Must be an array of type int"; + break; + + // + case ERR_SHORT_ARRAY_ONLY: + result = "Must be an array of type short"; + break; + + // + case ERR_CHAR_ARRAY_ONLY: + result = "Must be an array of type char"; + break; + + // + //--- Operations with OpenCL + + // + case ERR_OPENCL_NOT_SUPPORTED: + result = "OpenCL functions are not supported on this computer"; + break; + + // + case ERR_OPENCL_INTERNAL: + result = "Internal error occurred when running OpenCL"; + break; + + // + case ERR_OPENCL_INVALID_HANDLE: + result = "Invalid OpenCL handle"; + break; + + // + case ERR_OPENCL_CONTEXT_CREATE: + result = "Error creating the OpenCL context"; + break; + + // + case ERR_OPENCL_QUEUE_CREATE: + result = "Failed to create a run queue in OpenCL"; + break; + + // + case ERR_OPENCL_PROGRAM_CREATE: + result = "Error occurred when compiling an OpenCL program"; + break; + + // + case ERR_OPENCL_TOO_LONG_KERNEL_NAME: + result = "Too long kernel name (OpenCL kernel)"; + break; + + // + case ERR_OPENCL_KERNEL_CREATE: + result = "Error creating an OpenCL kernel"; + break; + + // + case ERR_OPENCL_SET_KERNEL_PARAMETER: + result = "Error occurred when setting parameters for the OpenCL kernel"; + break; + + // + case ERR_OPENCL_EXECUTE: + result = "OpenCL program runtime error"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_SIZE: + result = "Invalid size of the OpenCL buffer"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_OFFSET: + result = "Invalid offset in the OpenCL buffer"; + break; + + // + case ERR_OPENCL_BUFFER_CREATE: + result = "Failed to create and OpenCL buffer"; + break; + + // + //--- User-Defined Errors + default: + result = "UNKNOWN Erro ..."; + break; + } + + // + return result; +} + +// +// Retrieve Specified Error Code Description ... +string GetTradeServerReturnCodeDescription(int return_code) +{ + // + string result = ""; + + // + switch (return_code) + { + // + case TRADE_RETCODE_REQUOTE: + result = "Requote"; + break; + + // + case TRADE_RETCODE_REJECT: + result = "Request rejected"; + break; + + // + case TRADE_RETCODE_CANCEL: + result = "Request canceled by trader"; + break; + + // + case TRADE_RETCODE_PLACED: + result = "Order placed"; + break; + + // + case TRADE_RETCODE_DONE: + result = "Request completed"; + break; + + // + case TRADE_RETCODE_DONE_PARTIAL: + result = "Only part of the request was completed"; + break; + + // + case TRADE_RETCODE_ERROR: + result = "Request processing error"; + break; + + // + case TRADE_RETCODE_TIMEOUT: + result = "Request canceled by timeout"; + break; + + // + case TRADE_RETCODE_INVALID: + result = "Invalid request"; + break; + + // + case TRADE_RETCODE_INVALID_VOLUME: + result = "Invalid volume in the request"; + break; + + // + case TRADE_RETCODE_INVALID_PRICE: + result = "Invalid price in the request"; + break; + + // + case TRADE_RETCODE_INVALID_STOPS: + result = "Invalid stops in the request"; + break; + + // + case TRADE_RETCODE_TRADE_DISABLED: + result = "Trade is disabled"; + break; + + // + case TRADE_RETCODE_MARKET_CLOSED: + result = "Market is closed"; + break; + + // + case TRADE_RETCODE_NO_MONEY: + result = "There is not enough money to complete the request"; + break; + + // + case TRADE_RETCODE_PRICE_CHANGED: + result = "Prices changed"; + break; + + // + case TRADE_RETCODE_PRICE_OFF: + result = "There are no quotes to process the request"; + break; + + // + case TRADE_RETCODE_INVALID_EXPIRATION: + result = "Invalid order expiration date in the request"; + break; + + // + case TRADE_RETCODE_ORDER_CHANGED: + result = "Order state changed"; + break; + + // + case TRADE_RETCODE_TOO_MANY_REQUESTS: + result = "Too frequent requests"; + break; + + // + case TRADE_RETCODE_NO_CHANGES: + result = "No changes in request"; + break; + + // + case TRADE_RETCODE_SERVER_DISABLES_AT: + result = "Autotrading disabled by server"; + break; + + // + case TRADE_RETCODE_CLIENT_DISABLES_AT: + result = "Autotrading disabled by client terminal"; + break; + + // + case TRADE_RETCODE_LOCKED: + result = "Request locked for processing"; + break; + + // + case TRADE_RETCODE_FROZEN: + result = "Order or position frozen"; + break; + + // + case TRADE_RETCODE_INVALID_FILL: + result = "Invalid order filling type"; + break; + + // + case TRADE_RETCODE_CONNECTION: + result = "No connection with the trade server"; + break; + + // + case TRADE_RETCODE_ONLY_REAL: + result = "Operation is allowed only for live accounts"; + break; + + // + case TRADE_RETCODE_LIMIT_ORDERS: + result = "The number of pending orders has reached the limit"; + break; + + // + case TRADE_RETCODE_LIMIT_VOLUME: + result = "The volume of orders and positions for the symbol has reached the limit"; + break; + + // + default: + result = "Invalid return code of the trade server"; + break; + } + + // + return result; +} diff --git a/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.models.lib.ex5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.models.lib.ex5 new file mode 100644 index 0000000..cc0ed41 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.models.lib.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.seriallizer.lib.ex5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.seriallizer.lib.ex5 new file mode 100644 index 0000000..f3f3686 Binary files /dev/null and b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.seriallizer.lib.ex5 differ diff --git a/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.xtrade.lib.mq5 b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.xtrade.lib.mq5 new file mode 100644 index 0000000..c52370b --- /dev/null +++ b/MQLTestWorkspace/BKPS/14030228/Libraries/x-saherelm.xtrade.lib.mq5 @@ -0,0 +1,3018 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XTradeLib +// Description: All models related to Trade ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xdata-collector.mq5" + +// +// Definitions ... + +// +// a List of Used Tokens ... + +// +// Common ... +string XIDToken = "ID"; +string XModeToken = "MD"; +string XTypeToken = "TY"; +string XPeriodToken = "PR"; +string XProviderToken = "PRV"; + +// +string XTPToken = "TP"; +string XSLToken = "SL"; +string XTimeToken = "TM"; +string XEntryToken = "EN"; +string XVolumeToken = "VL"; +string XSymbolToken = "SMBL"; + +// +string XSupportToken = "SP"; +string XEQMSupportToken = "EQM"; + +// +// Available Order Modes ... +enum ENUM_X_ORDER_MODES +{ + X_ORDER_MODE_NOTHING, // Nothing + X_ORDER_MODE_MARKET, // Market Order + X_ORDER_MODE_STOP, // Pending Stop Order + X_ORDER_MODE_LIMIT, // Pending Limit Order + X_ORDER_MODE_STOP_LIMIT, // Pending Stop Limit Order +}; + +// +// Select Positions Type ... +enum ENUM_X_POSITION_SELECT_METHODS +{ + X_POSITION_SELECT_NONE, // None + X_POSITION_SELECT_MAX, // Max + X_POSITION_SELECT_MIN, // Min + X_POSITION_SELECT_BOTH, // Min and Max + X_POSITION_SELECT_ALL, // All +}; + +// +// Signal Execution Result ... +// note that some of them must be handles in +// EA's ... +enum ENUM_X_SIGNAL_EXECUTION_RESULT +{ + // + X_SIGNAL_EXECUTION_UNKNOWN, // Unknown + X_SIGNAL_EXECUTION_SUCCEED, // Succed + X_SIGNAL_EXECUTION_FAILED_NO_EQUITY, // No Equity for Trade + X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR, // Price Error + X_SIGNAL_EXECUTION_FAILED_MAX_REACHED, // Max Allowed Positions Reached + X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS, // Invalid Params +}; + +// +// Structs ... + +// +// Model a Signal ... +struct XSignal +{ + // + // Props ... + + // + ulong positionId; // if Executed this filled ... + double entry; // Exntry or Execution Price ... + double volume; // Position Volume ... + + // + datetime time; // Issue Time ... + + // + double tps[]; // a Collection of TP(s) ... + double sls[]; // a Collection of SL(s) ... + + // + string symbol; // Trading Symbol ... + string provider; // Signaller ... + string comment; // Comment ... + + // + ENUM_TIMEFRAMES period; // Trading TimeFrame ... + ENUM_POSITION_TYPE type; // Long (Buy) or Short (Sell) ... + ENUM_X_ORDER_MODES mode; // Execution Mode ... + + // + XSignal supports[]; // a Collecion of Support Signals ... + XOHCLSupRes supportResistances; // Support and Resistances ... + + // + // Constructor ... + XSignal() + { + Clean(); + } + + // + bool Prepare( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_POSITION_TYPE mType, // Long (Buy) or Short (Sell) + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + bool result = false; + + // + result = + // + IsValid(mMode) && + IsValid(mSymbol) && + IsValid(mPeriod) && + NotEmpty(mEntry) && + NotEmpty(mVolume) && + IsValid(mProvider) + // + ; + if (!result) + { + return result; + } + + // + type = mType; + mode = mMode; + symbol = mSymbol; + period = mPeriod; + provider = mProvider; + + // + // Normalization Values ... + sl = NormalizePrice(sl, mSymbol); + tp = NormalizePrice(tp, mSymbol); + mEntry = NormalizePrice(mEntry, mSymbol); + mVolume = NormalizeVolume(mVolume, mSymbol); + + // + entry = mEntry; + volume = mVolume; + + // + Add( + sl, + sls + // + ); + + // + Add( + tp, + tps + // + ); + + // + time = TimeCurrent(); + + // + result = IsValid(); + + // + return result; + } + + // + bool PrepareLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_BUY, + mMode, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + bool PrepareShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_SELL, + mMode, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + // Market Mode ... + + // + bool PrepareMarketLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_BUY, + X_ORDER_MODE_MARKET, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + bool PrepareMarketShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_SELL, + X_ORDER_MODE_MARKET, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + // Stop Mode ... + + // + bool PrepareStopLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_BUY, + X_ORDER_MODE_STOP, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + bool PrepareStopShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_SELL, + X_ORDER_MODE_STOP, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + // Limit Mode ... + + // + bool PrepareLimitLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_BUY, + X_ORDER_MODE_LIMIT, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + bool PrepareLimitShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_SELL, + X_ORDER_MODE_LIMIT, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + entry = 0; + volume = 0; + positionId = 0; + + // + time = NULL; + type = NULL; + mode = NULL; + symbol = NULL; + period = NULL; + comment = NULL; + provider = NULL; + + // + Clean(tps); + Clean(sls); + Clean(supports); + supportResistances.Clean(); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(period) && + IsValid(symbol) && + NotEmpty(volume) && + NotEmpty(entry) && + (ArraySize(tps) > 0 || + ArraySize(sls) > 0) + // + ; + + // + return result; + } + + // + // Check Signal Executed or not ... + bool IsExecuted() + { + // + bool result = false; + + // + result = + // + IsValid() && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Generate Comment for Signal ... + string GenerateComment() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + if (IsValid(provider)) + { + // + // Generate Provider Tag ... + result += GenerateProviderTag(provider); + } + + // + if (IsValid(period)) + { + // + // Generate Period Tag ... + result += GeneratePeriodTag(period); + } + + // + return result; + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XSignal &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + mode == value.mode && + entry == value.entry && + volume == value.volume && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId && + ArraySize(sls) == ArraySize(value.sls) && + ArraySize(tps) == ArraySize(value.tps) + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XSignal &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_POSITION_TYPE mType = NULL, // Long (Buy), Short (Sell) + ENUM_X_ORDER_MODES mMode = NULL // Execution Mode + ) + { + // + bool result = false; + + // + result = + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // Mode Filter ... + IsModeFilterPassed( + mMode, + this + // + ) + // + ; + + // + return result; + } + + // + string GetToken() + { + // + string mType = GetTypeName(this); + + // + string result = mType; + + // + string parts[]; + int partsCount = SplitContent( + parts, + result, + " " + // + ); + if (partsCount <= 0) + { + // + result = mType; + return result; + } + + // + bool hasLastPart = GetLastItem( + result, + parts + // + ); + if (!hasLastPart) + { + // + result = mType; + return result; + } + + // + return result; + } + + // + // To String Representation ... + string ToString() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + // For Modeling a Signal we Only Used: + // - Period; + // - Provider; + // - Type; + // - Mode; + // - Symbol; + // - PositionID; + // - Entry; + // - Volume; + // - TPS; + // - SLS; + // - Issue Time; + + // + int iPeriodInt = (int)period; + + // + string periodStr = Surround(XPeriodToken, iPeriodInt); + string providerStr = Surround(XProviderToken, provider); + string typeStr = Surround(XTypeToken, type); + string modeStr = Surround(XModeToken, mode); + string SymbolStr = Surround(XSymbolToken, symbol); + string positionIdStr = Surround(XIDToken, positionId); + string entryStr = Surround(XEntryToken, entry); + string volumeStr = Surround(XVolumeToken, volume); + string timeStr = Surround(XTimeToken, time); + + // + // TP ... + string tpsContentStr = ToString(tps); + string tpsStr = Surround(XTPToken, tpsContentStr); + + // + // SL ... + string slsContentStr = ToString(sls); + string slsStr = Surround(XSLToken, slsContentStr); + + // + result = + // + GetToken() + + "[" + + // + periodStr + + providerStr + + typeStr + + modeStr + + SymbolStr + + positionIdStr + + entryStr + + volumeStr + + tpsStr + + slsStr + + timeStr + + // + "]" + // + ; + + // + return result; + } + + // + // Parse String Model and Fill Available + // Items ... + bool Parse(string value) + { + // + bool result = false; + + // + Clean(); + + // + if (!IsValid(value)) + { + return false; + } + + // + // For Modeling a Signal we Only Used: + // - Period; + // - Provider; + // - Type; + // - Mode; + // - Symbol; + // - PositionID; + // - Entry; + // - Volume; + // - TPS; + // - SLS; + // - Issue Time; + + // + entry = ParseDoubleSurrounded(value, XEntryToken); + volume = ParseDoubleSurrounded(value, XVolumeToken); + positionId = ParseLongSurrounded(value, XIDToken); + + // + time = ParseTimeSurrounded(value, XTimeToken); + symbol = ParseStringSurrounded(value, XSymbolToken); + provider = ParseStringSurrounded(value, XProviderToken); + type = ((ENUM_POSITION_TYPE)ParseIntSurrounded(value, XTypeToken)); + mode = ((ENUM_X_ORDER_MODES)ParseIntSurrounded(value, XModeToken)); + period = ((ENUM_TIMEFRAMES)ParseIntSurrounded(value, XPeriodToken)); + + // + // TPS ... + ParseDoubleArraySurrounded( + tps, + value, + XTPToken + // + ); + + // + // SLS ... + ParseDoubleArraySurrounded( + sls, + value, + XSLToken + // + ); + + // + // Validate ... + result = IsValid(); + ; + + // + return result; + } +}; + +// +// Model an Open Position ... +struct XPosition +{ + // + // Props ... + + // + // Magic Number ... + ulong magic; + + // + // Ticket ID ... + ulong ticket; + + // + // Tradinng Symbol ... + string symbol; + + // + // Trading Period ... + ENUM_TIMEFRAMES period; + + // + // Position Type ... + ENUM_POSITION_TYPE type; + + // + // Take Profit ... + double tp; + + // + // Stop Loss ... + double sl; + + // + // Position Current Profit ... + double profit; + + // + // Position Open Price ... + double entry; + + // + // Current Symbol Price ... + double price; + + // + // Position Swap ... + double swap; + + // + // Position Commission ... + double commission; + + // + // Volume ... + double volume; + + // + // Position Open Time ... + datetime openAt; + + // + // Sifnal Provider ... + string provider; + + // + // Position Comment ... + string comment; + + // + // Constructor ... + XPosition() + { + Clean(); + } + + // + // Initializers ... + + bool ByIndex(int index) + { + // + bool result = false; + + // + static CPositionInfo mPositionInfo; + + // + result = mPositionInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + ulong mTicket = mPositionInfo.Ticket(); + + // + result = ByTicket(mTicket); + + // + return result; + } + + bool ByTicket(ulong mTicket) + { + // + bool result = false; + + // + static CPositionInfo mPositionInfo; + + // + result = mPositionInfo.SelectByTicket(mTicket); + if (!result) + { + return result; + } + + // + swap = mPositionInfo.Swap(); + magic = mPositionInfo.Magic(); + openAt = mPositionInfo.Time(); + sl = mPositionInfo.StopLoss(); + ticket = mPositionInfo.Ticket(); + symbol = mPositionInfo.Symbol(); + tp = mPositionInfo.TakeProfit(); + profit = mPositionInfo.Profit(); + volume = mPositionInfo.Volume(); + comment = mPositionInfo.Comment(); + entry = mPositionInfo.PriceOpen(); + type = mPositionInfo.PositionType(); + price = mPositionInfo.PriceCurrent(); + commission = mPositionInfo.Commission(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + magic = 0; + ticket = 0; + tp = 0; + sl = 0; + swap = 0; + entry = 0; + price = 0; + profit = 0; + volume = 0; + openAt = 0; + commission = 0; + + // + type = NULL; + period = NULL; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XPosition &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + magic == value.magic && + entry == value.entry && + ticket == value.ticket && + volume == value.volume && + symbol == value.symbol && + provider == value.provider + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XPosition &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_POSITION_TYPE mType = NULL, // Long (Buy), Short (Sell) + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model an Order ... +struct XOrder +{ + // + // Time of order placement ... + datetime setupAt; + + // + // Time of order expiration ... + datetime expiredAt; + + // + // Time of order execution or cancellation ... + datetime executedAt; + + // + // Order type ... + ENUM_ORDER_TYPE type; + + // + // Order state ... + ENUM_ORDER_STATE state; + + // + // Type of execution by remainder ... + ENUM_ORDER_TYPE_FILLING filling; + + // + // Order lifetime ... + ENUM_ORDER_TYPE_TIME lifetime; + + // + // Order ticket ... + ulong ticket; + + // + // Magic Number ... + long magic; + + // + // Position id, that is placed on order, + // when it is executed. Each executed order invokes a + // deal, that opens new or changes existing + // position. Id of that position is placed on + // executed order in this moment. + long positionId; + + // + // Initial volume on order placement ... + double initialVolume; + + // + // Unfilled volume ... + double currentVolume; + + // + // Price, specified in the order ... + double openPrice; + + // + // Current price by order symbol ... + double currentPrice; + + // + // Price of placing Limit order when StopLimit order is triggered ... + double stopLimitPrice; + + // + // Take Profit level ... + double tp; + + // + // Stop Loss level ... + double sl; + + // + // Trading Symbol ... + string symbol; + + // + // Signal Provider ... + string provider; + + // + // Order Comment ... + string comment; + + // + ENUM_TIMEFRAMES period; + + // + // Constructor ... + XOrder() + { + Clean(); + } + + // + // Initializers ... + bool ByIndex( + int index // Fill By Index ... + ) + { + // + bool result = false; + + // + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + static COrderInfo mOrderInfo; + + // + result = mOrderInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + // Reading Order Info ... + magic = mOrderInfo.Magic(); + sl = mOrderInfo.StopLoss(); + tp = mOrderInfo.TakeProfit(); + ticket = mOrderInfo.Ticket(); + openPrice = mOrderInfo.PriceOpen(); + positionId = mOrderInfo.PositionId(); + currentPrice = mOrderInfo.PriceCurrent(); + initialVolume = mOrderInfo.VolumeInitial(); + currentVolume = mOrderInfo.VolumeCurrent(); + stopLimitPrice = mOrderInfo.PriceStopLimit(); + + // + symbol = mOrderInfo.Symbol(); + comment = mOrderInfo.Comment(); + + // + state = mOrderInfo.State(); + type = mOrderInfo.OrderType(); + lifetime = mOrderInfo.TypeTime(); + filling = mOrderInfo.TypeFilling(); + + // + setupAt = mOrderInfo.TimeSetup(); + executedAt = mOrderInfo.TimeDone(); + expiredAt = mOrderInfo.TimeExpiration(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Retrieve Specific History Order ... + bool HistoryByIndex( + int index // Fill By Index ... + ) + { + // + bool result = false; + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + static CHistoryOrderInfo mOrderInfo; + + // + result = mOrderInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + // Reading Order Info ... + magic = mOrderInfo.Magic(); + sl = mOrderInfo.StopLoss(); + tp = mOrderInfo.TakeProfit(); + ticket = mOrderInfo.Ticket(); + openPrice = mOrderInfo.PriceOpen(); + positionId = mOrderInfo.PositionId(); + currentPrice = mOrderInfo.PriceCurrent(); + initialVolume = mOrderInfo.VolumeInitial(); + currentVolume = mOrderInfo.VolumeCurrent(); + stopLimitPrice = mOrderInfo.PriceStopLimit(); + + // + symbol = mOrderInfo.Symbol(); + comment = mOrderInfo.Comment(); + + // + state = mOrderInfo.State(); + type = mOrderInfo.OrderType(); + lifetime = mOrderInfo.TypeTime(); + filling = mOrderInfo.TypeFilling(); + + // + setupAt = mOrderInfo.TimeSetup(); + executedAt = mOrderInfo.TimeDone(); + expiredAt = mOrderInfo.TimeExpiration(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + tp = 0; + sl = 0; + magic = 0; + ticket = 0; + positionId = 0; + openPrice = 0; + currentPrice = 0; + initialVolume = 0; + currentVolume = 0; + stopLimitPrice = 0; + + // + setupAt = NULL; + expiredAt = NULL; + executedAt = NULL; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + type = NULL; + state = NULL; + period = NULL; + filling = NULL; + lifetime = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XOrder &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + state == value.state && + magic == value.magic && + ticket == value.ticket && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XOrder &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_ORDER_TYPE mType = NULL, // Long (Buy), Short (Sell) + ENUM_ORDER_STATE mState = NULL, // Order State + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // State Filter ... + IsStateFilterPassed( + mState, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model a Deal ... +struct XDeal +{ + // + // the ID of the Expert Advisor, that executed the deal ... + ulong magic; + + // + // the ID of position, in which the deal was involved ... + ulong positionId; + + // + // Ticket ... + ulong ticket; + + // + // the name of the deal symbol ... + string symbol; + + // + // order by which the deal is executed ... + ulong order; + + // + // the time of deal execution ... + datetime time; + + // + // Deal price ... + double price; + + // + // the financial result of the deal (in deposit currency) ... + double profit; + + // + // the amount of swap when position is closed ... + double swap; + + // + // the amount of commission of the deal ... + double commission; + + // + // the volume of deal ... + double volume; + + // + // the deal comment ... + string comment; + + // + string provider; + + // + ENUM_TIMEFRAMES period; + + // + // the deal type ... + // ------------------------------------------------------------------ + // DEAL_TYPE_BUY => Buy ... + // DEAL_TYPE_SELL => Sell ... + // DEAL_TYPE_BUY_CANCELED => Canceled buy deal ... + // There can be a situation when a previously executed buy deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ... + // + // DEAL_TYPE_SELL_CANCELED => Canceled sell deal ... + // There can be a situation when a previously executed sell deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation + // + // DEAL_TYPE_BALANCE => Balance ... + // DEAL_TYPE_CREDIT => Credit ... + // DEAL_TYPE_CHARGE => Additional charge ... + // DEAL_TYPE_CORRECTION => Correction ... + // DEAL_TAX => Tax charges ... + // DEAL_TYPE_BONUS => Bonus ... + // DEAL_TYPE_INTEREST => Interest rate ... + // DEAL_DIVIDEND => Dividend operations... + // DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ... + // DEAL_TYPE_COMMISSION => Additional commission ... + // DEAL_TYPE_COMMISSION_DAILY => Daily commission ... + // DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ... + // DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ... + // DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission + ENUM_DEAL_TYPE type; + + // + // the deal direction ... + // ---------------------------------- + // DEAL_ENTRY_IN => Entry in ... + // DEAL_ENTRY_OUT => Entry out ... + // DEAL_ENTRY_INOUT => Reverse ... + // DEAL_ENTRY_OUT_BY => Close a position by an opposite one ... + ENUM_DEAL_ENTRY entry; + + // + // deal reson ... + // --------------------- + // DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ... + // DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ... + // DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ... + // DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ... + // DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ... + // DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ... + // DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ... + // DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ... + // DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ... + // DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ... + ENUM_DEAL_REASON reason; + + // + // Constructor ... + XDeal() + { + Clean(); + } + + // + // Initializers ... + bool ByIndex( + int index // Deal Index + ) + { + // + bool result = false; + + // + int dealsCount = HistoryDealsTotal(); + result = dealsCount > 0; + if (!result) + { + return result; + } + + // + static CDealInfo mDealInfo; + + // + result = mDealInfo.SelectByIndex(index); + if (!result) + { + // + return result; + } + + // + // Reading Order Info ... + swap = mDealInfo.Swap(); + magic = mDealInfo.Magic(); + order = mDealInfo.Order(); + ticket = mDealInfo.Ticket(); + time = mDealInfo.Time(); + price = mDealInfo.Price(); + symbol = mDealInfo.Symbol(); + profit = mDealInfo.Profit(); + volume = mDealInfo.Volume(); + comment = mDealInfo.Comment(); + positionId = mDealInfo.PositionId(); + entry = mDealInfo.Entry(); + commission = mDealInfo.Commission(); + type = mDealInfo.DealType(); + reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( + ticket, + DEAL_REASON); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + magic = 0; + positionId = 0; + ticket = 0; + order = 0; + time = 0; + price = 0; + profit = 0; + swap = 0; + commission = 0; + volume = 0; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + type = NULL; + entry = NULL; + period = NULL; + reason = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XDeal &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + magic == value.magic && + entry == value.entry && + reason == value.reason && + ticket == value.ticket && + volume == value.volume && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XDeal &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_DEAL_TYPE mType = NULL, // Deal Type + ENUM_DEAL_ENTRY mEntry = NULL, // Deal Entry + ENUM_DEAL_REASON mReason = NULL, // Deal Reason + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // Entry Filter ... + IsEntryFilterPassed( + mEntry, + this + // + ) + // + && + // + // Reason Filter ... + IsReasonFilterPassed( + mReason, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model OnTrade Event Handler Result on XCTrade Class ... +struct XOnTradeHandlerState +{ + // + bool hasNewDeal; + int newDeals; + + // + bool hasNewOrder; + int newOrders; + + // + bool hasNewPosition; + int newPositions; + + // + bool hasNewHistoryOrder; + int newHistoryOrders; + + // + // Constructor ... + XOnTradeHandlerState() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + hasNewDeal = false; + hasNewOrder = false; + hasNewPosition = false; + hasNewHistoryOrder = false; + + // + newDeals = 0; + newOrders = 0; + newPositions = 0; + newHistoryOrders = 0; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ( + // + hasNewDeal + ? newDeals > 0 + : true + // + ) + // + && + // + ( + // + hasNewOrder + ? newOrders > 0 + : true + // + ) + // + && + // + ( + // + hasNewPosition + ? newPositions > 0 + : true + // + ) + // + && + // + ( + // + hasNewHistoryOrder + ? newHistoryOrders > 0 + : true + // + ) + // + ; + + // + return result; + } +}; + +// +// Model a Position with all of it's Supports ... +struct XPositionPack +{ + // + ulong ticket; // Main Position's Ticket + + // + XPosition position; // Main Position (if Exists) + + // + int supportOrdersCount; // Supported Orders (Untriggered) + int supportPositionsCount; // Supported Positions + + // + XOrder supportOrders[]; // Supported Orders (Untriggered) + XPosition supportPositions[]; // Supported Positions + + // + // Constructor ... + XPositionPack() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + ticket = 0; + + // + position.Clean(); + + // + supportOrdersCount = 0; + supportPositionsCount = 0; + + // + Clean(supportOrders); + Clean(supportPositions); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + NotEmpty(ticket) && + ( + // + supportOrdersCount > 0 + ? ArraySize(supportOrders) == supportOrdersCount + : true + // + ) + // + && + // + ( + // + supportPositionsCount > 0 + ? ArraySize(supportPositions) == supportPositionsCount + : true + // + ) + // + ; + + // + return result; + } +}; + +// +// TypeDefs ... + +// +typedef void (*TOnDealsChanged)(int count); + +// +typedef void (*TOnOrdersChanged)(int count); + +// +typedef void (*TOnPositionsChanged)(int count); + +// +typedef void (*TOnStopLoss)(const XDeal &deal); +typedef void (*TOnTakeProfit)(const XDeal &deal); + +// +typedef void (*TOnTradeStateChanged)(const XOnTradeHandlerState &state); + +// +// Classes ... + +// +// Create a Signal Specfic Data Collector ... +class XSCSignalCollector +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructor ... + void XSCSignalCollector() + { + // + XSCDataCollector mBase; + mBase.Clear(); + } + + // + // Deconstructor ... + + // + // Tools ... + + // + // Inheritanced Functions ... + + // + // Cleaning Store ... + void Clear() + { + // + XSCDataCollector mBase; + + // + mBase.Clear(); + } + + // + // Collect All Store ... + int Collect(XSignal &result[]) + { + // + int mResult = 0; + + // + XSCDataCollector mBase; + + // + mResult = mBase.Collect(result); + + // + return mResult; + } + + // + // Add Item To Store ... + bool Add(XSignal &item) + { + // + bool result = false; + + // + XSCDataCollector mBase; + + // + result = mBase.Add(item); + + // + return result; + } + + // + // Add Item(s) To Store ... + int Add(XSignal &items[]) + { + // + int result = 0; + + // + XSCDataCollector mBase; + + // + result = mBase.Add(items); + + // + return result; + } + + // + // Remove an Item from Store ... + bool Remove(XSignal &item) + { + // + bool result = false; + + // + XSCDataCollector mBase; + + // + result = mBase.Remove(item); + + // + return result; + } + + // + // Custom Functions ... + + // + int CollectSignals( + XSignal &result[], // Hold Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Timeframe + ENUM_POSITION_TYPE type = NULL, // Long (Buy), Short (Sell) + ENUM_X_ORDER_MODES mode = NULL // Execution Mode + ) + { + // + int mResult = 0; + + // // + // XSignal signals[]; + // int signalsCount = Collect(signals); + // if (signalsCount <= 0) + // { + // return mResult; + // } + + // // + // mResult = ArraySize(result); + + // // + // // Now we Have to Apply Filters ... + // for (int i = 0; i < signalsCount; i++) + // { + // // + // XSignal iSignal = signals[i]; + + // // // + // // bool isFiltersPassed = + // // iSignal.IsFilteresPassed( + // // symbol, + // // provider, + // // period, + // // type, + // // mode + // // // + // // ); + // // if (!isFiltersPassed) + // // { + // // continue; + // // } + + // // // + // // AddRef( + // // iPosition, + // // result + // // // + // // ); + // } + + // + return mResult; + } + + // + // Protected ... +protected: + // + // Tools ... + + // + // Private ... +private: + // + // Props ... + + // + // Tools ... +}; + +// +// Tools ... + +// +bool IsValid(ENUM_X_ORDER_MODES value) +{ + return value != X_ORDER_MODE_NOTHING; +} + +// +// Ages ... + +// +// Retrieve a Position Age ... +int GetAge( + XPosition &position, // Selected Position ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + position.symbol, + period, + position.openAt); + + // + return result; +} + +// +// Retrieve an Order Age ... +int GetAge( + XOrder &order, // Selected Order ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + order.symbol, + period, + order.setupAt); + + // + return result; +} + +// +// Retrieve a Deal Age ... +int GetAge( + XDeal &deal, // Selected Deal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + deal.symbol, + period, + deal.time); + + // + return result; +} + +// +// Get Oldest Deal ... +int GetOldest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Deal ... +int GetYoungest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldest Order ... +int GetOldest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Order ... +int GetYoungest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldes Position ... +int GetOldest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Position ... +int GetYoungest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Check Filters ... + +// +// Magic Filter ... +template +bool IsMagicFilterPassed( + ulong magic, + bool filterByMagic, + T &item + // +) +{ + // + return !filterByMagic + ? true + : !NotEmpty(magic) + ? false + : magic == item.magic; +} + +// +// Symbol Filter ... +template +bool IsSymbolFilterPassed( + string symbol, + T &item + // +) +{ + // + return !IsValid(symbol) + ? true + : symbol == item.symbol; +} + +// +// Provider Filter ... +template +bool IsProviderFilterPassed( + string provider, + T &item + // +) +{ + // + return !IsValid(provider) + ? true + : provider == item.provider; +} + +// +// Period Filter ... +template +bool IsPeriodFilterPassed( + ENUM_TIMEFRAMES period, + T &item + // +) +{ + // + return !IsValid(period) + ? true + : period == item.period; +} + +// +// Type Filter ... +template +bool IsTypeFilterPassed( + ENUM_POSITION_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} +template +bool IsTypeFilterPassed( + ENUM_ORDER_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} +template +bool IsTypeFilterPassed( + ENUM_DEAL_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} + +// +// Mode Filter ... +template +bool IsModeFilterPassed( + ENUM_X_ORDER_MODES mode, + T &item + // +) +{ + // + return mode == NULL + ? true + : mode == item.mode; +} + +// +// Entry Filter ... +template +bool IsEntryFilterPassed( + ENUM_DEAL_ENTRY entry, + T &item + // +) +{ + // + return entry == NULL + ? true + : entry == item.entry; +} + +// +// Reason Filter ... +template +bool IsReasonFilterPassed( + ENUM_DEAL_REASON reason, + T &item + // +) +{ + // + return reason == NULL + ? true + : reason == item.reason; +} + +// +// State Filter ... +template +bool IsStateFilterPassed( + ENUM_ORDER_STATE state, + T &item + // +) +{ + // + return state == NULL + ? true + : state == item.state; +} + +// + +// +// Find Specific Item Index inside a Collection ... +template +int FindIndex( + T &item, // Item to Find + const T &items[] // Items for Search +) +{ + // + int result = -1; + + // + // Check Item Validation ... + if (!item.IsValid()) + { + return result; + } + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < itemsCount; i++) + { + // + T iItem = items[i]; + + // + // Validate Item ... + if (!iItem.IsValid()) + { + continue; + } + + // + bool isSame = item.IsSameAs(iItem); + if (isSame && result <= -1) + { + // + result = i; + break; + } + } + + // + return result; +} + +// +// Tagging ... + +// +// Generate Specified Tag for Using in Comments ... +string GeneratePeriodTag(ENUM_TIMEFRAMES period) +{ + // + string strPeriod = ToString(period); + return Surround( + XPeriodToken, + strPeriod + // + ); +} + +// +// Extract Period from a Tagged string ... +ENUM_TIMEFRAMES ExtractPeriod(string value) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + string pStr = ParseStringSurrounded( + value, + XPeriodToken + // + ); + if (!IsValid(pStr)) + { + return result; + } + + // + result = ToPeriod(pStr); + + // + return result; +} + +// Generate Specified Tag for Using in Comments ... +string GenerateProviderTag(string provider) +{ + // + return Surround( + XProviderToken, + provider + // + ); +} + +// +// Extract Provider from a Tagged string ... +string ExtractProvider(string value) +{ + // + return ParseStringSurrounded( + value, + XProviderToken + // + ); +} + +// +// Generate Support Comment Tag ... +string GenerateSupportTag(ulong ticket) +{ + // + return Surround( + XSupportToken, + ticket + // + ); +} + +// +// Extract Support Positions from a Tagged string ... +ulong ExtractSupportedTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XSupportToken + // + ); +} + +// +// Generate EQM Support Comment Tag ... +string GenerateEQMSupportTag(ulong ticket) +{ + // + return Surround( + XEQMSupportToken, + ticket + // + ); +} + +// +// Extract EQM Support Positions from a Tagged string ... +ulong ExtractEQMSupportedTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XEQMSupportToken + // + ); +} + +// diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.http.class.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.http.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.http.class.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.http.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.http.class.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.http.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.http.class.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.http.class.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.x121.provider.class.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.x121.provider.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.x121.provider.class.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.x121.provider.class.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.x121.xea.class.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.x121.xea.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.x121.xea.class.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.x121.xea.class.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.x121.xea.class.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.x121.xea.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.x121.xea.class.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.x121.xea.class.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xaccount.class.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xaccount.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xaccount.class.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xaccount.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xaccount.class.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xaccount.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xaccount.class.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xaccount.class.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xea.class.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xea.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xea.class.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xea.class.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xea.class.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xea.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xea.class.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xea.class.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xhelper.class.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xhelper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xhelper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xhelper.class.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xhelper.class.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xhelper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xhelper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xhelper.class.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xnotifier.class.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xnotifier.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xnotifier.class.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xnotifier.class.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xprovider.class.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xprovider.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xprovider.class.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xprovider.class.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xprovider.class.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xprovider.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xprovider.class.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xprovider.class.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xtrade.class.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xtrade.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xtrade.class.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xtrade.class.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xtrade.class.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xtrade.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Classes/x-saherelm.xtrade.class.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Classes/x-saherelm.xtrade.class.mq5 diff --git a/MQLTestWorkspace/BKPS/X121/14030217/Documents/.gitkeep b/MQLTestWorkspace/BKPS/X121/14030217/Documents/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-color.tools.js b/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-color.tools.js new file mode 100644 index 0000000..c3ac5f9 --- /dev/null +++ b/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-color.tools.js @@ -0,0 +1,506 @@ +/** + * XColor Tools Module ... + * a module for handle colorify text contents in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Module Imports ... +const XValueTools = require("./x-value.tools"); +//#endregion + +// +//#region Constants ... +/** + * these are available style which can applied to an string ... + */ +const AVAILABLE_STYLES = { + // + Bold: "\x1b[1m", + Dim: "\x1b[2m", + Underlined: "\x1b[4m", + Blink: "\x1b[5m", + ReverseFandB: "\x1b[7m", + Hidden: "\x1b[8m", + // + // Commonly used for reset all Styles ... + Reset: "\x1b[0m" +}; + +/** + * these are available foreground colors which can applied to an string ... + */ +const AVAILABLE_FOREGROUND_COLORS = { + Default: "\x1b[39m", + Black: "\x1b[30m", + Red: "\x1b[31m", + Green: "\x1b[32m", + Yellow: "\x1b[33m", + Blue: "\x1b[34m", + Magenta: "\x1b[35m", + Cyan: "\x1b[36m", + LightGray: "\x1b[37m", + DarkGray: "\x1b[90m", + LightRed: "\x1b[91m", + LightGreen: "\x1b[92m", + LightYellow: "\x1b[93m", + LightBlue: "\x1b[94m", + LightMagenta: "\x1b[95m", + LightCyan: "\x1b[96m", + White: "\x1b[97m", +}; + +/** + * these are available background colors which can applied to an string ... + */ +const AVAILABLE_BACKGROUND_COLORS = { + Default: "\x1b[49m", + Black: "\x1b[40m", + Red: "\x1b[41m", + Green: "\x1b[42m", + Yellow: "\x1b[43m", + Blue: "\x1b[44m", + Magenta: "\x1b[45m", + Cyan: "\x1b[46m", + LightGray: "\x1b[47m", + DarkGray: "\x1b[100m", + LightRed: "\x1b[101m", + LightGreen: "\x1b[102m", + LightYellow: "\x1b[103m", + LightBlue: "\x1b[104m", + LightMagenta: "\x1b[105m", + LightCyan: "\x1b[106m", + White: "\x1b[107m", +}; + +/** + * these are available style names, which exports from module and + * users can use them ... + */ +const STYLE_NAMES = { + Bold: "Bold", + Dim: "Dim", + Underlined: "Underlined", + Blink: "Blink", + ReverseFandB: "ReverseFandB", + Hidden: "Hidden", + Reset: "Reset", +}; + +/** + * these are available color names, which exports from module and + * users can use them ... + */ +const COLOR_NAMES = { + Default: "Default", + Black: "Black", + Red: "Red", + Green: "Green", + Yellow: "Yellow", + Blue: "Blue", + Magenta: "Magenta", + Cyan: "Cyan", + LightGray: "LightGray", + DarkGray: "DarkGray", + LightRed: "LightRed", + LightGreen: "LightGreen", + LightYellow: "LightYellow", + LightBlue: "LightBlue", + LightMagenta: "LightMagenta", + LightCyan: "LightCyan", + White: "White", +}; +//#endregion + +// +//#region Actions ... +/** + * apply specified style and color on a content ... + * + * @param {string} content specified content for styling ... + * @param {string} color specific color name for using to styling ... + * @param {string} style soecufic style name to use ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} styled content ... + */ +function apply( + content, + color, + style, + toForeground = true, + toBackground = false +) { + // + let result = content; + + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}${result}${AVAILABLE_STYLES.Reset}`; + } + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}${result}${AVAILABLE_STYLES.Reset}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}${result}${AVAILABLE_STYLES.Reset}`; + } + +} + +/** + * apply specific style on a content ... + * + * @param {string} content specific content which going to styled ... + * @param {string} style a member of STYLE_NAMES which specified that which style going to applied to content ... + * @returns {string} styled content ... + */ +function applyStyle(content, style) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eStyle = AVAILABLE_STYLES[style]; + if (eStyle === undefined) { + return content; + } + + // + return `${eStyle}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * apply specific foreground color on a content ... + * + * @param {string} content specific content which going to colorified ... + * @param {string} color a member of COLOR_NAMES which specified that which color going to applied to content ... + * @returns {string} colorified content ... + */ +function applyForegroundColor(content, color) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eColor = AVAILABLE_FOREGROUND_COLORS[color]; + if (eColor === undefined) { + return content; + } + + // + return `${eColor}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * apply specific background color on a content ... + * + * @param {string} content specific content which going to colorified ... + * @param {string} color a member of COLOR_NAMES which specified that which color going to applied to content ... + * @returns {string} colorified content ... + */ +function applyBackgroundColor(content, color) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eColor = AVAILABLE_BACKGROUND_COLORS[color]; + if (eColor === undefined) { + return content; + } + + // + return `${eColor}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * generate style and color applier expression ... + * + * @param {string} color specific color name for using to styling ... + * @param {string} style soecufic style name to use ... + * @param {boolean} reset close applier string by reset styles ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} style and color applier string ... + */ +function getApplier( + style = "", + color = "", + reset = false, + toForeground = true, + toBackground = false +) { + // + let result = ""; + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}`; + } + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * generate style applier expression ... + * + * @param {string} style soecufic style name to use ... + * @param {boolean} reset close applier string by reset styles ... + * @returns {string} style applier string ... + */ +function getStyleApplier( + style = "", + reset = false +) { + // + let result = ""; + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * generate color applier expression ... + * + * @param {string} color specific color name for using to styling ... + * @param {boolean} reset close applier string by reset styles ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} color applier string ... + */ +function getColorApplier( + color = "", + reset = false, + toForeground = true, + toBackground = false +) { + // + let result = ""; + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * colorified specific content ... + * + * @param {string} content specified content for styling ... + * @param {string} color specific color name for using to styling ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} + */ +function colorifyContent( + content = "", + color = "", + toForeground = true, + toBackground = false +) { + // + let result = content; + + // + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Finde Colors ... + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}${result}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}${result}`; + } + + // + if ( + result.length > 0 + && ( + XValueTools.isValidArg(eFColor) || + XValueTools.isValidArg(eBColor) + ) + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * apply style on specific content ... + * + * @param {string} content specified content for styling ... + * @param {string} style soecufic style name to use ... + * @returns {string} + */ +function stylifiyContent( + content = "", + style = "", +) { + // + let result = content; + + // + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}${result}`; + } + + // + if ( + result.length > 0 + && XValueTools.isValidArg(eStyle) + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + STYLE_NAMES, + COLOR_NAMES, + // + apply, + applyStyle, + getApplier, + getColorApplier, + getStyleApplier, + colorifyContent, + stylifiyContent, + applyForegroundColor, + applyBackgroundColor, +} +//#endregion \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-file.tools.js b/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-file.tools.js new file mode 100644 index 0000000..a1642a4 --- /dev/null +++ b/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-file.tools.js @@ -0,0 +1,830 @@ +/** + * XFile Tools Module ... + * a module for handle all file/folder manipulating task in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Module Imports ... +const fs = require('fs'); +const os = require('os'); +const Path = require('path'); +const http = require('http'); +const https = require('https'); +const XValueTools = require('./x-value.tools'); +//#endregion + +// +//#region Constants ... +/** + * current os path separators ... + */ +const PathSeparator = Path.sep; + +/** + * current directory ... + */ +const CurrentDir = __dirname; +//#endregion + +// +//#region Actions ... +// +//#region Global ... +/** + * retrieve a path status ... + * + * @param {string} path a path value to check ... + * @returns an stat object ... + */ +function getStatus(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return undefined; + } + + // + return fs.statSync(path); +} + +/** + * retrieve user's Home path ... + * + * @returns {string} a path ... + */ +function getHomePath() { + return os.homedir(); +} +//#endregion + +// +//#region Path ... +/** + * retrieve the base name of specific address path ... + * + * @param {string} path address of file or folder ... + * @returns string ... + */ +function basename(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return ''; + } + + // + const result = Path.basename(path); + return result; +} + +/** + * join several path segments together ... + * + * @param {...string} path path params ... + * @returns a joined paths ... + */ +function joinPath(...path) { + return Path.join(...path); +} + +/** + * resolve a relative path to absolute ... + * + * @param {string[]} path a path value to check ... + * @returns {string} + */ +function resolvePath(...path) { + return Path.resolve(...path); +} +//#endregion + +// +//#region File ... +/** + * determines a path destination is a file or not ... + * + * @param {string} path a path value to check ... + * @returns a boolean value ... + */ +function isFileExists(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return false; + } + + // + try { + const stat = getStatus(path); + if (!stat) { + return false; + } + + // + return stat.isFile(); + } catch { + return false; + } +} + +/** + * remove a file ... + * + * @param {string} path a file path ... + * @returns {Promise} action done or not ... + */ +function removeFile(path = '') { + return new Promise((resolve) => { + // + if (!isFileExists(path)) { + resolve(false); + } + + // + fs.unlink(path, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * copy a file to destination path ... + * + * @param {string} source source file path ... + * @param {string} dest dest folder path ... + * @returns {Promise} action done or not ... + */ +function copyFile( + source = '', + dest = '' +) { + return new Promise((resolve) => { + // + if ( + !isFileExists(source) || + !isDirectoryExists(dest) + ) { + resolve(false); + return; + } + + // + const destFilePath = Path.join(dest, Path.basename(source)); + fs.copyFile(source, destFilePath, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * reading specified file content ... + * + * @param {string} path a file path ... + * @returns {Promise} file content ... + */ +function readFile(path = '') { + return new Promise((resolve) => { + // + if (!isFileExists(path)) { + resolve(''); + return; + } + + // + fs.readFile(path, 'utf8', (err, content) => { + // + if (err) { + resolve(undefined); + return; + } + + // + resolve(content); + }); + }); +} + +/** + * write content to a file ... + * + * @param {string} path a file path ... + * @param {string} content the content which going to write to the file ... + * @param {bool} overwrite determines file overwrite if exists ... + * @returns {Promise} action done or not ... + */ +function writeFile( + path = '', + content = '', + overwrite = true +) { + return new Promise((resolve) => { + // + if (isFileExists(path) && !overwrite) { + // + resolve(false); + return; + } + + // + // Normalize Content ... + content = XValueTools.isValidArg(content) ? + content : + ''; + + // + fs.writeFile(path, content, (err) => { + // + if (err) { + // + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * create a file ... + * + * @param {string} path file path ... + * @param {string} fileName file name ... + * @returns {Promise} action done or not ... + */ +function createFile( + path = '', + fileName = '' +) { + return new Promise((resolve) => { + // + const filePath = Path.join(path, fileName); + if ( + isFileExists(filePath) || + !XValueTools.isValidArg(path) || + !XValueTools.isValidArg(fileName) + ) { + // + resolve(false); + return; + } + + // + fs.writeFile(filePath, '', (err) => { + // + if (err) { + // + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * remove a file name extension ... + * + * @param {string} name + * @returns {string} name without extension ... + */ +function removeFileExtension(name = '') { + return name.substring(0, name.lastIndexOf('.')) || name; +} + +/** + * retrieve a file extension ... + * + * @param {string} path a path which locate a file ... + * @returns {string} + */ +function getFileExtension(path = '') { + // + let result = ""; + + // + // Validate Arg ... + if ( + !XValueTools.isValidArg(path) + || !isFileExists(path) + ) { + return result; + } + + // + // Retrieve just file name ... + const fileName = basename(path); + result = fileName.replace( + removeFileExtension(fileName), + "" + ); + + // + return result; +} + +/** + * retrieve all files list recursively from specific path ... + * + * @param {string} path a source folder path ... + * @param {string[]} extensions which file extensions need to be listed, live empty for all files ... + * @returns {Promise} + */ +async function getRecursiveFilesList( + path = "", + extensions = [] +) { + // + let result = []; + + // + // Validate Args ... + if ( + !XValueTools.isValidArg(path) + || !isDirectoryExists(path) + ) { + return result; + } + + // + const contents = await getDirectoryContents(path); + for(const item of contents) { + // + const itemPath = joinPath( + path, + item + ); + + // + const isItemFile = isFileExists(itemPath); + if (isItemFile) { + // + const itemFileExtension = getFileExtension(itemPath); + const isFileInSupportedExtensions = + extensions === undefined || extensions.length === 0 + ? true + : extensions.includes(itemFileExtension) + ; + if (isFileInSupportedExtensions) { + result.push(itemPath); + } + } else if (isDirectoryExists(itemPath)) { + // + const itemPathFiles = await getRecursiveFilesList(itemPath, extensions); + result.push(...itemPathFiles); + } + } + + // + return result; +} +//#endregion + +// +//#region Directory ... +/** + * create a directory ... + * + * @param {string} path destination path including dir name ... + * @param {boolean} recursive create directories recursively ... + * @returns action done or not ... + */ +function createDirectory( + path = '', + recursive = true +) { + // + let result = false; + + // + if ( + isDirectoryExists(path) || + !XValueTools.isValidArg(path) + ) { + return false; + } + + // + try { + // + fs.mkdirSync(path, { recursive: recursive }); + result = true; + return result; + } catch { + return false; + } +} + +/** + * remove a directory ... + * + * @param {string} path destination path including dir name ... + * @param {boolean} recursive removes directories recursively ... + * @returns {Promise} action done or not ... + */ +function removeDirectory( + path = '', + recursive = false +) { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve(false); + return; + } + + // + fs.rm(path, { + recursive + }, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * determines a path destination is a directory or not ... + * + * @param {string} path a folder path ... + * @returns represent destnation path is Directory or not ... + */ +function isDirectoryExists(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return false; + } + + // + try { + // + const isExists = fs.existsSync(path); + if (!isExists) { + return false; + } + + // + const stat = getStatus(path); + if (!stat) { + return false; + } + + // + const result = stat.isDirectory(); + return result; + } catch { + return false; + } +} + +/** + * retrieve a directory content ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder files ... + */ +function getDirectoryContents(path = '') { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + resolve(content); + }); + }); +} + +/** + * retrieve a directory files ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder files ... + */ +function getDirectoryFiles( + path = '', + containsHiddenFiles = false +) { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + if (!containsHiddenFiles) { + content = content.filter(c => !c.startsWith('.')); + } + + // + const result = []; + content + .forEach(c => { + // + const cPath = Path.join(path, c); + if (isFileExists(cPath)) { + result.push(c); + } + }); + + // + resolve(result); + }); + }); +} + +/** + * retrieve a directory folders ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder names ... + */ +function getDirectoryFolders(path = '') { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + const result = []; + content.forEach(c => { + // + const cPath = Path.join(path, c); + if (isDirectoryExists(cPath)) { + result.push(c); + } + }); + + // + resolve(result); + }); + }); +} + +/** + * copy a folder with all of it's content to dest ... + * + * @param {string} source source folder path ... + * @param {string} dest dest folder path ... + * @returns {Promise} action done or not ... + */ +async function copyFolder( + source = '', + dest = '' +) { + // + if ( + !isDirectoryExists(source) || + !XValueTools.isValidArg(dest) || + !XValueTools.isValidArg(source) + ) { + return false; + } + + // + const folderName = Path.basename(source); + const destPath = Path.join(dest, folderName); + + // + // Create Dest Path folder if not exists ... + if (!isDirectoryExists(destPath)) { + // + let result = createDirectory(destPath, true); + if (!result) { + return false; + } + } + + // + // Files ... + const files = await getDirectoryFiles(source); + if (files && files.constructor === Array && files.length > 0) { + // + const filesPromises = files.map(file => copyFile(Path.join(source, file), destPath)); + const filesResult = (await Promise.all(filesPromises)).every(r => !!r); + if (!filesResult) { + return false; + } + } + + // + // Folders ... + const folders = await getDirectoryFolders(source); + if (folders && folders.constructor === Array && folders.length > 0) { + // + const folderPromises = folders.map(folder => copyFolder(Path.join(source, folder), destPath)); + const filesResult = (await Promise.all(folderPromises)).every(r => !!r); + if (!filesResult) { + return false; + } + } + + // + return true; +} +//#endregion + +// +//#region Downloader ... +/** + * download a file from specific url and store it ... + * + * @param {string} filepath the file name and path which required to put download file on it ... + * @param {string} url the web url for downloading ... + */ +function download(filepath, url) { + // + // Validate Args ... + if ( + !XValueTools.isValidArg(url) + || !XValueTools.isValidURL(url) + || !XValueTools.isValidArg(filepath) + ) { + return; + } + + // + var file = fs.createWriteStream(filepath); + + // + if (url.startsWith('https:')) { + https.get(url, function (response) { + response.pipe(file); + }); + } else if (url.startsWith('http:')) { + http.get(url, function (response) { + response.pipe(file); + }); + } +} +//#endregion + +// +//#region JSON ... +/** + * read and parse a JSON content from a file ... + * + * @param {string} path source file path ... + * @returns {any} + */ +function readJSON(path = "") { + // + // Validate Args ... + if (!isFileExists(path)) { + return undefined; + } + + // + let result = undefined; + try { + result = require(path); + } catch { + result = undefined; + } + + // + return result; +} + +/** + * write a JSON Object content into a file ... + * + * @param {string} path dest file path ... + * @param {any} content an object which required to write to file ... + * @returns {Promise} + */ +async function writeJSON( + path = "", + content = undefined +) { + // + let result = false; + + // + // Validate Args ... + if (!XValueTools.isValidArg(path)) { + return result; + } + + // + // Normallize Content ... + if (content === undefined) { + content = {}; + } + + // + const contentString = XValueTools.beautifyJSON(content); + + // + result = await writeFile( + path, + contentString, + true + ); + + // + return result; +} +//#endregion +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + CurrentDir, + PathSeparator, + + // + getStatus, + getHomePath, + + // + basename, + joinPath, + resolvePath, + + // + download, + + // + readJSON, + writeJSON, + + // + copyFile, + readFile, + writeFile, + createFile, + removeFile, + isFileExists, + getFileExtension, + removeFileExtension, + getRecursiveFilesList, + + // + copyFolder, + createDirectory, + removeDirectory, + createDirectory, + removeDirectory, + isDirectoryExists, + isDirectoryExists, + getDirectoryFiles, + getDirectoryFolders, + getDirectoryContents, +} +//#endregion \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-shell.tools.js b/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-shell.tools.js new file mode 100644 index 0000000..0ee13de --- /dev/null +++ b/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-shell.tools.js @@ -0,0 +1,219 @@ +/** + * XShell Tools Module ... + * a module for handling shell actions and retrieve OS Info in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Imports ... +const os = require('os'); +const process = require('process'); +const { exec } = require("child_process"); +const XFileTools = require('./x-file.tools'); +//#endregion + +// +//#region Constants ... +// +const OS = { + Aix: 'aix', + Darwin: 'darwin', + FreeBSD: 'freebsd', + Linux: 'linux', + OpenBSD: 'openbsd', + SnOS: 'sunos', + Windows: 'win32' +}; + +// +const isWindows = process.platform === OS.Windows; +//#endregion + +// +//#region Actions ... +// +//#region Pure shell commands ... +/** + * execute a command using NodeJS on shell ... + * + * @param {string} cmd command to execute ... + * @param {string} cwd working directory ... + * + * @returns Promise instance ... + */ +function execute(cmd, cwd) { + return new Promise((resolve, reject) => { + // + if (!cmd || cmd.toString().length === 0 || (cwd && !XFileTools.isDirectoryExists(cwd))) { + reject('invalid args ...'); + return; + } + + // + exec(cmd, { cwd }, (err, result, stdError) => { + // + if (err) { + reject(err); + return; + } + + // + if (stdError) { + // + // reject(stdError); + // return; + } + + // + resolve(result); + }); + }); +}; + +/** + * determines a command exists on host or not ... + * + * @param {string} name specific command name ... + * + * @returns boolean Promise ... + */ +function checkCommandExists(name) { + return new Promise(resolve => { + // + if (!name) { + resolve(false); + return; + } + + // + const cmd = isWindows ? `${name} >nul 2>&1` : `type ${name} >/dev/null 2>&1`; + execute(cmd).then(result => { + resolve(true); + }) + .catch(err => { + resolve(false); + }); + }); +} +//#endregion + +// +//#region required commands state ... +/** + * check al required commands exists or not ... + * + * @returns + */ +async function isRequiredCommandsExists() { + // + let result = false; + + // + // const isTarExists = await isTarCommandExists(); + // const isCatExists = await isCatCommandExists(); + // const isGrepExists = await isGrepCommandExists(); + // const isSedExists = await isSedCommandExists(); + const isNpmExists = await isNpmCommandExists(); + const isNgExists = await isNgCommandExists(); + const isIonicExists = await isIonicCommandExists(); + const isCordovaExists = await isCordovaCommandExists(); + + // + result = isNpmExists + && isNgExists + && isIonicExists + && isCordovaExists + ; + + // + return result; +} + +/** + * retrieve required commands state object ... + * + * @returns + */ +async function getRequiredCommandsStates() { + // + const result = {}; + + // + // const isTarExists = await isTarCommandExists(); + // const isCatExists = await isCatCommandExists(); + // const isGrepExists = await isGrepCommandExists(); + // const isSedExists = await isSedCommandExists(); + const isNpmExists = await isNpmCommandExists(); + const isNgExists = await isNgCommandExists(); + const isIonicExists = await isIonicCommandExists(); + const isCordovaExists = await isCordovaCommandExists(); + + // + result['npm'] = isNpmExists; + result['ng'] = isNgExists; + result['ionic'] = isIonicExists; + result['cordova'] = isCordovaExists; + + // + return result; +} +//#endregion + +// +//#region Commonly used Command Checkers ... +/** + * determines npm command exists or not ... + * + * @returns + */ +function isNpmCommandExists() { + return checkCommandExists('npm'); +} + +/** + * determines ng command exists or not ... + * + * @returns + */ +function isNgCommandExists() { + return checkCommandExists('ng'); +} + +/** + * determines ionic command exists or not ... + * + * @returns + */ +function isIonicCommandExists() { + return checkCommandExists('ionic'); +} + +/** + * determines cordova command exists or not ... + * + * @returns + */ +function isCordovaCommandExists() { + return checkCommandExists('cordova'); +} +//#endregion +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + execute, + checkCommandExists, + isRequiredCommandsExists, + getRequiredCommandsStates, + + // + isNgCommandExists, + isIonicCommandExists, + isCordovaCommandExists, +} +//#endregion \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-type-detector.tools.js b/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-type-detector.tools.js new file mode 100644 index 0000000..86ed3d8 --- /dev/null +++ b/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-type-detector.tools.js @@ -0,0 +1,268 @@ +/** + * DataType Tools Module ... + * a module for manipulate and detect supported data types in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Constants ... +/** + * all supported data types ... + */ +const DataTypes = { + Null: 'null', + Date: 'date', + Array: 'array', + Object: 'object', + String: 'string', + Number: 'number', + Unknown: 'unknown', + Boolean: 'boolean', + Function: 'function', + Undefined: 'undefined', +}; +//#endregion + +// +//#region Actions ... +/** + * detect type of a content ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getType(value) { + // + const type = typeof value; + + // + let result = DataTypes.Unknown; + let dateIdentifier = '[object Date]'; + let constructor = value && value.constructor ? + value.constructor.toString() : + ''; + + // + switch (type) { + // + case 'undefined': + result = DataTypes.Undefined; + break; + + // + case 'boolean': + result = DataTypes.Boolean; + break; + + // + case 'string': + result = DataTypes.String; + break; + + // + case 'number': + result = DataTypes.Number; + break; + + // + case 'function': + result = DataTypes.Function; + break; + + // + case 'object': + // + // Null ... + if (value === null) { + result = DataTypes.Null; + } else + // + // Array ... + if (Array.isArray(value)) { + result = DataTypes.Array; + } else + // + // Data ... + if ( + value instanceof Date || + isFunction(value.getMonth) || + constructor.includes(dateIdentifier) || + Object.prototype.toString.call(value) === dateIdentifier + ) { + result = DataTypes.Date; + } else + // + // Object ... + { + result = DataTypes.Object; + } + break; + + // + default: + result = DataTypes.Unknown; + break; + } + + // + return result; +} + +/** + * retrieve an object constructor ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getConstructor(value) { + // + const result = value && value.constructor ? + value.constructor.toString() : + ''; + + // + return result; +} + +/** + * retrieve an object prototype ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getPrototype(value) { + // + const result = value ? + Object.prototype.toString.call(value) : + ''; + + // + return result; +} + +/** + * check an object is null or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNull(value) { + return getType(value) === DataTypes.Null; +} + +/** + * check an object is undefined or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isUndefined(value) { + return getType(value) === DataTypes.Undefined; +} + +/** + * check an object is null or undefined or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNullOrUndefined(value) { + return isNull(value) || isUndefined(value); +} + +/** + * check an object is a date or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isDate(value) { + return getType(value) === DataTypes.Date; +} + +/** + * check an object is number or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNumber(value) { + return getType(value) === DataTypes.Number; +} + +/** + * check an object is string or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isString(value) { + return getType(value) === DataTypes.String; +} + +/** + * check an object is boolean or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isBoolean(value) { + return getType(value) === DataTypes.Boolean; +} + +/** + * check an object is an Array or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isArray(value) { + return getType(value) === DataTypes.Array; +} + +/** + * check an object is and Object or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isObject(value) { + return getType(value) === DataTypes.Object; +} + +/** + * check an object is a Function or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isFunction(value) { + return getType(value) === DataTypes.Function; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + DataTypes, + + // + getType, + getConstructor, + getPrototype, + isNull, + isUndefined, + isNullOrUndefined, + isDate, + isNumber, + isString, + isBoolean, + isArray, + isObject, + isFunction, +} +//#endregion \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-value.tools.js b/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-value.tools.js new file mode 100644 index 0000000..81cfcc4 --- /dev/null +++ b/MQLTestWorkspace/BKPS/X121/14030217/Documents/JsModules/x-value.tools.js @@ -0,0 +1,1528 @@ +/** + * Value Tools Module ... + * a module for Validate args and values ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Imports ... +const XTypeTools = require('./x-type-detector.tools'); +//#endregion + +// +//#region Actions ... +/** +* validate a value as an argument ... +* +* @param {string} value the value which going to validate ... +* @returns +*/ +function isValidArg(value) { + // + let result = false; + + // + result = value && + value.length > 0; + + // + return result; +} + +/** + * validate a collection of valuea as an arguments ... + * + * @param {string|string[]} values the value collection which going to checked ... + * @returns + */ +function isValidArgs(values) { + // + // Normalize Values ... + const normalValues = toNormalArray(values); + if (!hasChildArray(normalValues)) { + return false; + } + + // + let result = normalValues.every(nv => isValidArg(nv)); + return result; +} + +/** + * converts content to an array object ... + * + * @param {string|string[]} content the content which required to normalized ... + * @returns {string[]} array object ... + */ +function toNormalArray(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + const result = Array.isArray(content) ? + [...content] : + content.includes(',') && + content !== ',' ? + [...content.split(',')] : + [content]; + + // + return result; +} + +/** + * determines value is array and has atleast one child ... + * + * @param {any} value the value which going to checked ... + * @returns {boolean} result of checking ... + */ +function hasChildArray(value) { + // + let result = false; + result = value && + Array.isArray(value) && + value.length > 0; + + // + return result; +} + +/** + * check an string is ends with specified symbol ... + * + * @param {string} symbol specified search symbol ... + * @param {string} value specified search content ... + * @param {boolean} ignoreCase specified search case sensitive or not ... + * @returns + */ +function endsWidth( + symbol = '', + value = '', + ignoreCase = true +) { + // + if (!isValidArg(value)) { + return false; + } + + // + if (!isValidArg(symbol)) { + return true; + } + + // + // TODO: uncomment it if necessary ... + // symbol = symbol.trim(); + + // + let result = false; + const subtractedContent = value.substring(value.length - symbol.length); + result = !!ignoreCase ? + subtractedContent + .toLowerCase() === symbol + .toLowerCase() : + subtractedContent === symbol; + + // + return result; +} + +/** + * surround specified content by provided symbol ... + * + * @param {string} symbol surround string ... + * @param {string} content used content to surrounded by symbol ... + * @returns surrounded content ... + */ +function surroundBy( + symbol = '', + content = '' +) { + // + // Validate Args ... + if (!isValidArg(content)) { + content = ''; + } + + // + if (!isValidArg(symbol)) { + symbol = ''; + } + + // + if (isSurrounded(symbol, content)) { + return content; + } + + // + const result = `${symbol}${content}${symbol}`; + return result; +} + +/** + * convert a parsed sign to clear string ... + * + * @param {string} value a parsed content ... + * @returns clear parsed signs ... + */ +function toStringExpression(value) { + // + let result = ''; + result = value; + + // + if ( + !value || + !isValidArg(value) || + !isSurroundedString(value) + ) { + return result; + } + + // + const startSymbol = value.charAt(0); + const endSymbol = value.charAt(value.length - 1); + + // + if (startSymbol !== endSymbol) { + return result; + } + + // + if ( + startSymbol === "\"" || + startSymbol === "\'" + ) { + result = clearSurround(startSymbol, value); + } + + // + return result; +} + + + +/** + * find and cleare proposed candidates from specified content ... + * + * @param {string|string[]} candidates the proposed string(s) whic going to cleared from content ... + * @param {string} content the destination content which used to find and replace candidates on it ... + * @returns cleared content ... + */ +function clearContent( + candidates, + content +) { + // + // Validate Args ... + if ( + !candidates || + !isValidArg(content) + ) { + return ''; + } + + // + // Normalize candidates ... + const normalCandidates = toNormalArray(candidates) + .filter(c => isValidArg(c)); + if (!hasChildArray(normalCandidates)) { + return content; + } + + // + // define regexp for content ... + const regExpExpression = normalCandidates.join('|'); + const regExp = new RegExp( + regExpExpression, + 'gi' + ); + + // + let result = ''; + result = content.replace(regExp, ''); + + // + return result; +} + +/** + * clear surrounded symbol from content ... + * + * @param {string} symbol specified search symbol ... + * @param {string} content specified content to clear ... + * @returns + */ +function clearSurround( + symbol = '', + content = '' +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + (isValidArg(symbol) && + symbol.length >= content.length - 1) + ) { + return ''; + } + + // + // Validate Surround ... + if (!isSurrounded(symbol, content)) { + return content; + } + + // + if (!isValidArg(symbol)) { + return content; + } + + // + let result = content.substring(symbol.length, content.length - symbol.length); + return result; +} + +/** + * clear object sign ... + * + * @param {string} content + * @returns cleared content ... + */ +function clearObjectSurround(content = '') { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isSurroundedObject(content) + ) { + return content; + } + + // + const endIndex = content.length - ( + endsWidth('}', content) ? + 1 : + endsWidth('},', content) || + endsWidth('};', content) || + endsWidth('}\n', content) ? + 2 : + 0 + ); + + // + const result = content.substring(1, endIndex); + return result; +} + +/** + * clear array sign ... + * + * @param {string} content + * @returns cleared content ... + */ +function clearArraySurround(content = '') { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isSurroundedArray(content) + ) { + return content; + } + + // + const endIndex = content.length - ( + endsWidth(']', content) ? + 1 : + endsWidth('],', content) || + endsWidth('];', content) || + endsWidth(']\n', content) ? + 2 : + 0 + ); + + // + const result = content.substring(1, endIndex); + return result; +} + +/** + * slice a content to individual parts ... + * + * @param {number|number[]} indexes which indexes used to slice ... + * @param {strng} content the content which going to sliced ... + * @returns sliced parts of content ... + */ +function sliceContent(indexes, content) { + // + // Validate Args ... + if ( + !isValidArg(indexes) || + !isValidArg(content) + ) { + return []; + } + + // + // Normalize indexes ... + const normalIndexes = toNormalArray(indexes) + .filter(index => index > -1 && index < content.length); + if (!hasChildArray(normalIndexes)) { + return []; + } + + // + let result = ['']; + result.pop(); + + // + let lastIndex = 0; + for (const index of normalIndexes) { + // + const part = content.substring(lastIndex, index); + if (isValidArg(part)) { + result.push(part.trim()); + } + + // + lastIndex = index + 1; + } + + // + // check remained parts ... + if (lastIndex < content.length) { + // + const part = content.substring(lastIndex); + if (isValidArg(part)) { + result.push(part.trim()); + } + } + + // + return result; +} + + + +/** + * check an string is starts and ends with specified symbol ... + * + * @param {string} symbol specified search symbol ... + * @param {string} content specified search content ... + * @param {boolean} ignoreCase specified search case sensitive or not ... + * @returns + */ +function isSurrounded( + symbol = '', + content = '', + ignoreCase = true +) { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + if (!isValidArg(symbol)) { + return true; + } + + // + symbol = symbol.trim(); + + // + let result = false; + result = (!!ignoreCase ? + content + .toLowerCase() + .startsWith(symbol.toLowerCase()) : + content.startsWith(symbol) + ) && + endsWidth(symbol, content, ignoreCase); + + // + return result; +} + +/** + * determines a content is an string surrounded value or not ... + * + * @param {string} content a content which going to check ... + * @returns + */ +function isSurroundedString(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = ( + content.startsWith('\'') && + ( + endsWidth('\'', content) || + endsWidth('\',', content) || + endsWidth('\';', content) || + endsWidth('\'\n', content) + ) || + content.startsWith('\"') && + ( + endsWidth('\"', content) || + endsWidth('\",', content) || + endsWidth('\";', content) || + endsWidth('\"\n', content) + ) || + content.startsWith('`') && + ( + endsWidth('\`', content) || + endsWidth('\`,', content) || + endsWidth('\`;', content) || + endsWidth('\`\n', content) + ) + ); + return result; +} + +/** + * check a content is an array content or not ... + * + * @param {string} content + * @returns + */ +function isSurroundedArray(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = content.startsWith('[') && + ( + endsWidth(']', content) || + endsWidth('],', content) || + endsWidth('];', content) || + endsWidth(']\n', content) + ); + return result; +} + +/** + * check a content is an object content or not ... + * + * @param {string} content + * @returns + */ +function isSurroundedObject(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = content.startsWith('{') && + ( + endsWidth('}', content) || + endsWidth('},', content) || + endsWidth('};', content) || + endsWidth('}\n', content) + ); + return result; +} + +/** + * check an index model is contains inside anothers or not ... + * + * @param {{ start: number, end: number}} source the source index model to check ... + * @param {...{ start: number, end: number}} dest the collection of index models which going to check ... + * @returns + */ +function isIndexInside(source, ...dest) { + // + let result = false; + + // + // Validate Args ... + if (!source || !dest) { + return result; + } + + // + // Check idx is standard ... + if ( + !source || + !source.end || + !source.start || + source.start > source.end + ) { + return false; + } + + // + // Check types of destinations ... + for (let index of dest) { + // + // Check idx is standard ... + if ( + !index || + !index.end || + !index.start || + index.start > index.end + ) { + return false; + } + } + + // + if (dest.includes(source)) { + dest = dest.filter(d => d !== source); + } + + // + const insideContentIndex = dest.find(dIndex => { + // + const result = source.start >= dIndex.start && + source.start <= dIndex.end && + source.end >= dIndex.start && + source.end <= dIndex.end; + return result; + }); + + // + result = insideContentIndex; + return result; +} + +/** + * check a number exists in + * @param {number} idx the number which going to check ... + * @param {{ start: number, end: number}} index the index model + * @returns + */ +function isInsideIndex(idx = -1, index) { + // + let result = false; + + // + // Validate Args ... + if ( + !index || + !index.hasOwnProperty('end') || + !index.hasOwnProperty('start') + ) { + return result; + } + + // + result = idx > index.start && idx < index.end; + return result; +} + +/** + * determines an object is key/value and type ... + * + * @param {any} content the object which we are going to check ... + * @returns + */ +function isKeyValueType(content) { + // + const result = content && + content.hasOwnProperty('key') && + content.hasOwnProperty('type') && + content.hasOwnProperty('value'); + + // + return result; +} + + + +/** + * find all indexes of token(s) in content ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns {number[]} all occured indexes ... + */ +function findAllIndexes( + tokens, + content +) { + // + // Validate Args ... + if ( + !isValidArg(tokens) || + !isValidArg(content) + ) { + return []; + } + + // + // normalize tokens ... + const normalTokens = toNormalArray(tokens); + if (!hasChildArray(normalTokens)) { + return []; + } + + // + // Parse contents ... + let match; + const result = []; + const regExp = new RegExp( + normalTokens.join('|'), + 'g' + ); + while ((match = regExp.exec(content)) !== null) { + result.push(match.index); + } + if (!hasChildArray(result)) { + return []; + } + + // + return result; +} + +/** + * find nearest symbol in a content from specified index ... + * + * @param {string|string[]} candidates specifies which symbols to find ... + * @param {string} content te content for seasrch ... + * @param {number} startFromIndex the index of start position ... + * @returns + */ +function findNearest( + candidates, + content = '', + startFromIndex = 0 +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(candidates) || + !isValidArg(content.trim()) + ) { + return ''; + } + + // + // Normalize Content ... + content = content.trim(); + + // + // Normalize Starts From ... + startFromIndex = startFromIndex < 0 || startFromIndex > content.length - 1 ? 0 : startFromIndex; + + // + // Normalize Symbols ... + const normalCandidates = toNormalArray(candidates); + if (!hasChildArray(normalCandidates)) { + return ''; + } + + // + let nearestIndex = findNearestIndex( + normalCandidates, + content, + startFromIndex + ); + if (nearestIndex < 0) { + return ''; + } + + // + let result = content.substring( + nearestIndex, + nearestIndex + Math.max(...normalCandidates.map(nc => nc.length)) + ).trim(); + return result; +} + +/** + * search candidates in content and find nearest one and return it ... + * + * @param {string|string[]} candidates which candidates required to check ... + * @param {string} content the content which required to search candidates ... + * @param {number} startFromIndex the proposed index to start searching content from on ... + * @returns + */ +function findNearestIndex( + candidates = [''], + content = '', + startFromIndex = 0, + ignoreClosedItems = false +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(candidates) + ) { + return -1; + } + + // + // Mormalize startFromIndex value ... + startFromIndex = startFromIndex < 0 ? + 0 : + startFromIndex > content.length - 1 ? + content.length - 1 : + startFromIndex; + + // + // Normalize candidates ... + let normalCandidates = toNormalArray(candidates); + + // + if (!!ignoreClosedItems) { + normalCandidates = normalCandidates + .map(c => content.indexOf( + c, + startFromIndex + ) + ).map(c => +c) + .filter(c => +c > -1); + } else { + normalCandidates = findAllIndexesOutOfCloseds(normalCandidates, content) + .filter(c => c >= startFromIndex); + } + if (!hasChildArray(normalCandidates)) { + return -1; + } + + // + let result = -1; + result = Math.min(...normalCandidates); + + // + return result; +} + +/** + * find close index of specific sign in destination content ... + * + * @param {string} openSymbol open of area sign ... + * @param {string} closeSymbol close of area sign ... + * @param {string} content the destination content for parsing ... + * @param {number} startsFrom an start index of content for start parsing ... + * @returns + */ +function findCloseIndex( + openSymbol = '', + closeSymbol = '', + content = '', + startsFrom = -1 +) { + // + // Validate Args ... + if ( + startsFrom < 0 || + !isValidArg(content) || + !isValidArg(openSymbol) || + !isValidArg(closeSymbol) || + openSymbol === closeSymbol || + !content.includes(openSymbol) || + !content.includes(closeSymbol) || + startsFrom > content.length - 1 + ) { + return -1; + } + + // + let result = -1; + + // + let index = startsFrom; + const openSignStack = []; + while (index < content.length) { + // + const openCandidate = content.substring(index, index + openSymbol.length); + const closeCandidate = content.substring(index, index + closeSymbol.length); + + // + if (openCandidate === openSymbol) { + openSignStack.push(index); + } else if (closeCandidate === closeSymbol) { + // + if (openSignStack.length > 0) { + openSignStack.pop(); + } + + // + if (openSignStack.length === 0) { + result = index; + break; + } + } + + // + index++; + } + + // + return result; +} + +/** + * find closed contents of specific sign in destination content ... + * + * @param {string} openSymbol open of area sign ... + * @param {string} closeSymbol close of area sign ... + * @param {string} content the destination content for parsing ... + * @param {number} startsFrom an start index of content for start parsing ... + * @returns + */ +function findClosedContent( + openSymbol = '', + closeSymbol = '', + content = '', + startsFrom = 0, +) { + // + let result = [{ + start: -1, + end: -1, + content: '' + }]; + result.pop(); + + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(openSymbol) || + !isValidArg(closeSymbol) || + !content.includes(openSymbol) || + !content.includes(closeSymbol) || + openSymbol.length >= content.length || + closeSymbol.length >= content.length + ) { + return result; + } + + // + // Normalize Start From ... + startsFrom = startsFrom < 0 || startsFrom >= content.length ? 0 : startsFrom; + + // + let canContinue = true; + while (!!canContinue) { + // + let openSymbolIndex = content.indexOf(openSymbol, startsFrom); + if (openSymbolIndex < 0) { + // + canContinue = false; + continue; + } + + // + let closeSymbolIndex = findCloseIndex( + openSymbol, + closeSymbol, + content, + openSymbolIndex + ); + if (closeSymbolIndex < 0) { + // + canContinue = false; + continue; + } + if (content.charAt(closeSymbolIndex) !== closeSymbol) { + closeSymbolIndex++; + } + + // + // Prevent ${} string interpolations ... + if ( + openSymbol === '{' && + openSymbolIndex - 1 >= 0 + ) { + // + const prevChar = content.charAt(openSymbolIndex - 1); + if (prevChar === '$') { + continue; + } + } + + // + const item = content + .substring(openSymbolIndex, closeSymbolIndex + 1) + .trim(); + startsFrom = closeSymbolIndex + 1; + result.push({ + start: openSymbolIndex, + end: closeSymbolIndex, + content: item + }); + } + + // + if (!hasChildArray(result)) { + return result; + } + + // + return result; +} + +/** + * extract a collection of closed contents exists in a content ... + * + * @param symbols a collection of open and close contents ... + * @param {string} content a content for searching inside it ... + * @returns a collection of closed content ... + */ +function findClosedContents( + symbols = [ + { + openSymbol: '', + closeSymbol: '' + } + ], + content = '' +) { + // + let result = [{ + start: -1, + end: -1, + content: '' + }]; + result.pop(); + + // + if ( + !isValidArg(content) || + !hasChildArray(symbols) + ) { + return []; + } + + // + symbols.forEach(symbol => { + // + const closedContent = findClosedContent( + symbol.openSymbol, + symbol.closeSymbol, + content + ); + + // + if (hasChildArray(closedContent)) { + result.push( + ...closedContent + ); + } + }); + + // + return result; +} + +/** + * find all string content closed items ... + * + * @param {string} content a content which going to search ... + * @returns a collection of index descriptors ... + */ +function findClosedStrings(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // there are 3 types of strings ... + // ' " and ` + + // + const token1 = '\''; + const token1Stack = [0]; + token1Stack.pop(); + + // + const token2 = '"'; + const token2Stack = [0]; + token2Stack.pop(); + + // + const token3 = '`'; + const token3Stack = [0]; + token3Stack.pop(); + + // + const result = [ + { + start: -1, + end: -1, + content: '' + } + ]; + result.pop(); + + // + for (let i = 0; i < content.length; i++) { + // + const currentChart = content.charAt(i); + + // + //#region Token 1 ... + if (currentChart === token1) { + // + if (!hasChildArray(token1Stack)) { + token1Stack.push(i); + } else { + // + const start = token1Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + + // + //#region Token 2 ... + if (currentChart === token2) { + // + if (!hasChildArray(token2Stack)) { + token2Stack.push(i); + } else { + // + const start = token2Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + + // + //#region Token 3 ... + if (currentChart === token3) { + // + if (!hasChildArray(token3Stack)) { + token3Stack.push(i); + } else { + // + const start = token3Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + } + + // + return result; +} + +/** + * find container indexes from within indexes ... + * + * @param {...{start: number, end: number}} index the collection of indexes to find beiggers inside ... + * @returns + */ +function findContainerIndexes(...index) { + // + let result = [ + { + start: -1, + end: -1, + content: '' + } + ]; + result.pop(); + + // + let concatedIndexes = []; + for (let idx of index) { + // + // Index Childs ... + for (let iix of idx) { + // + // Check idx is standard ... + if ( + !iix || + !iix.end || + !iix.start || + iix.start > iix.end + ) { + continue; + } + + // + // Check index inside another index ... + concatedIndexes.push(iix); + } + } + + // + if (!hasChildArray(concatedIndexes)) { + return result; + } + + // + for (let ccIdx of concatedIndexes) { + // + const isInside = isIndexInside(ccIdx, ...concatedIndexes); + if (isInside) { + continue; + } + + // + if (hasChildArray(result)) { + // + const isInsideResult = isIndexInside(ccIdx, ...result); + if (isInsideResult) { + continue; + } + } + + // + result.push(ccIdx); + } + + // + return result; +} + +/** + * find all tokens indexes inside a content which they are not inside closed items ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns + */ +function findAllIndexesOutOfCloseds1( + tokens, + content, +) { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // Extract token Indexes ... + const tokensIndexes = findAllIndexes(tokens, content); + if (!hasChildArray(tokensIndexes)) { + return []; + } + + // + // Extract Closed Objects Indexes ... + const closedArrays = findClosedContent('[', ']', content); + const closedObjects = findClosedContent('{', '}', content); + const closedStrings = findClosedStrings(content); + if ( + !hasChildArray(closedObjects) && + !hasChildArray(closedArrays) && + !hasChildArray(closedStrings) + ) { + return tokensIndexes; + } + + // + // find bigger sloded ... + let containerClosedItems = findContainerIndexes( + closedArrays, + closedObjects, + closedStrings + ).filter(i => !isSurroundedString(i.content)); + + // + let result = [-1]; + result.pop(); + + // + for (let tIdx of tokensIndexes) { + // + let canAdd = true; + for (let ccIndex of containerClosedItems) { + // + canAdd = isInsideIndex(tIdx, ccIndex); + if (canAdd) { + break; + } + } + + // + if (!canAdd) { + result.push(tIdx); + } + } + + // + return result; +} + +/** + * find all tokens indexes inside a content which they are not inside closed items ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns + */ +function findAllIndexesOutOfCloseds( + tokens, + content, +) { + // + // Define Result ... + let result = [-1]; + result.pop(); + + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // Normalize Tokens ... + const normalizeTokens = toNormalArray(tokens); + if (!hasChildArray(normalizeTokens)) { + return result; + } + + // + // Extract Closed Objects Indexes ... + let openSymbols = [ + '{', + '[', + '\'', + '"', + '`' + ]; + let closeSymbols = [ + '}', + ']', + '\'', + '"', + '`' + ]; + let openStack = []; + let lastOpenSymbol = ''; + let lastClosedIndex = -1; + for (let i = 0; i < content.length; i++) { + // + const prevChar = content.charAt(i - 1) || ''; + const char = content.charAt(i); + const nextChar = content.charAt(i + 1) || ''; + + // + const isToken = normalizeTokens.includes(char); + const isOpenSymbol = openSymbols.includes(char); + const isCloseSymbol = closeSymbols.includes(char); + + // + if (isOpenSymbol && lastOpenSymbol !== char) { + openStack.push(i); + lastOpenSymbol = char === '\'' || char === '"' || char === '`' ? char : lastOpenSymbol; + } else if (isCloseSymbol) { + // + lastOpenSymbol = char === '\'' || char === '"' || char === '`' ? '' : lastOpenSymbol; + let lastPop = openStack.pop(); + if (openStack.length === 0) { + lastClosedIndex = lastPop; + } + } else if (isToken) { + if ( + i > lastClosedIndex && + openStack.length === 0 + ) { + result.push(i); + } + } + } + + // + return result; +} +//#endregion + +// +//#region Validator Actions ... +/** + * check specified value is Valid URL Address or not ... + * + * @param {string} value specified string which required to check + * @returns {boolean} + */ +function isValidURL(value = "") { + // + if (!isValidArg(value)) { + return false; + } + + const pattern = new RegExp( + '^([a-zA-Z]+:\\/\\/)?' + // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR IP (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string + '(\\#[-a-z\\d_]*)?$', // fragment locator + 'i' + ); + + // + const result = pattern.test(value); + return result; +} + +/** + * check specified value is Valid URL Address or not ... + * + * @param {string} value specified string which required to check + */ +function isValidEmail(value = "") { + // + if (!isValidArg(value)) { + return false; + } + + // + const pattern = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/gim; + + // + const result = pattern.test(value); + return result; +} +//#endregion + +// +//#region Normallizers ... +/** + * normallize an string ... + * + * @param {string} value specified value ... + * @returns {string} + */ +function toNormalString(value = "") { + // + if (!XTypeTools.isString(value)) { + value = ""; + } + + // + const result = value + .trim() + .toLowerCase(); + + // + return result; +} +//#endregion + +// +//#region Beautifiers ... +/** + * converts an object to string based on json and beautify result ... + * + * @param {any} object + * @returns {string} + */ +function beautifyJSON(object = undefined) { + // + // TODO: Complete this ... + let result = ""; + + // + // validate object ... + if (object === undefined) { + return result; + } + + // + // Convert result ... + result = JSON.stringify( + object, + null, + 4 + ); + + // + return result; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + endsWidth, + surroundBy, + isValidArg, + isValidArgs, + toNormalArray, + hasChildArray, + toStringExpression, + + // + sliceContent, + clearContent, + clearSurround, + clearArraySurround, + clearObjectSurround, + + // + isSurrounded, + isIndexInside, + isInsideIndex, + isKeyValueType, + isSurroundedArray, + isSurroundedString, + isSurroundedObject, + + // + findNearest, + findAllIndexes, + findCloseIndex, + findNearestIndex, + findClosedContent, + findClosedStrings, + findClosedContents, + findAllIndexesOutOfCloseds, + + // + // Validator Actions ... + isValidURL, + isValidEmail, + + // + // Normallizers ... + toNormalString, + + // + beautifyJSON, +} +//#endregion \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/X121/14030217/Documents/Temp/multi.asset.configs.yml b/MQLTestWorkspace/BKPS/X121/14030217/Documents/Temp/multi.asset.configs.yml new file mode 100644 index 0000000..79e0ba7 --- /dev/null +++ b/MQLTestWorkspace/BKPS/X121/14030217/Documents/Temp/multi.asset.configs.yml @@ -0,0 +1 @@ +EURUSDb,GBPUSDb,USDJPYb,USDCHFb,XAUUSDb|M5,M15|0.01|X786|true \ No newline at end of file diff --git a/MQLTestWorkspace/X121/14030217/Experts/x-saherelm.xea.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Experts/x-saherelm.xea.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Experts/x-saherelm.xea.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Experts/x-saherelm.xea.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Experts/x-saherelm.xea.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Experts/x-saherelm.xea.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Experts/x-saherelm.xea.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Experts/x-saherelm.xea.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Helpers/x-saherelm.x121.xman.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Helpers/x-saherelm.x121.xman.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Helpers/x-saherelm.x121.xman.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Helpers/x-saherelm.x121.xman.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Helpers/x-saherelm.x121.xman.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Helpers/x-saherelm.x121.xman.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Helpers/x-saherelm.x121.xman.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Helpers/x-saherelm.x121.xman.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Indicators/x-saherelm.x121.xman.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Indicators/x-saherelm.x121.xman.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Indicators/x-saherelm.x121.xman.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Indicators/x-saherelm.x121.xman.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Indicators/x-saherelm.x121.xman.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Indicators/x-saherelm.x121.xman.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Indicators/x-saherelm.x121.xman.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Indicators/x-saherelm.x121.xman.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.alert.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.alert.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.alert.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.alert.lib.ex5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.alert.lib.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.alert.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.alert.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.alert.lib.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.common.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.common.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.common.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.common.lib.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.common.lib.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.common.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.common.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.common.lib.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.draw.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.draw.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.draw.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.draw.lib.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.draw.lib.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.draw.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.draw.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.draw.lib.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.http.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.http.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.http.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.http.lib.ex5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.http.lib.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.http.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.http.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.http.lib.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.log.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.log.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.log.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.log.lib.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.log.lib.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.log.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.log.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.log.lib.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.models.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.models.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.models.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.models.lib.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.models.lib.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.models.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.models.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.models.lib.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.seriallizer.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.seriallizer.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.seriallizer.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.seriallizer.lib.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.seriallizer.lib.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.seriallizer.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.seriallizer.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.seriallizer.lib.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.x121.condition.parser.lib.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.x121.condition.parser.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.x121.condition.parser.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.x121.condition.parser.lib.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.x121.draw.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.x121.draw.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.x121.draw.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.x121.draw.lib.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.x121.draw.lib.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.x121.draw.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.x121.draw.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.x121.draw.lib.mq5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.x121.signaller.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.x121.signaller.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.x121.signaller.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.x121.signaller.lib.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.x121.support.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.x121.support.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.x121.support.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.x121.support.lib.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.xman.parser.lib.ex5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.xman.parser.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.xman.parser.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.xman.parser.lib.ex5 diff --git a/MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.xman.parser.lib.mq5 b/MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.xman.parser.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/14030217/Libraries/x-saherelm.xman.parser.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/14030217/Libraries/x-saherelm.xman.parser.lib.mq5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.http.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.http.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.http.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.http.class.ex5 diff --git a/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.http.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.http.class.mq5 new file mode 100644 index 0000000..e28342d --- /dev/null +++ b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.http.class.mq5 @@ -0,0 +1,385 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCHttp +// Description: provides all HTTP 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 + +// +// START Definitions ... +// + +// +enum X_HTTP_METHOD +{ + X_HTTP_GET, + X_HTTP_POST +}; + +// +// Convert enum to String ... +string ToString(X_HTTP_METHOD method) +{ + // + string result = ""; + + // + switch (method) + { + // + case X_HTTP_GET: + result = "GET"; + break; + + // + case X_HTTP_POST: + result = "POST"; + break; + } + + // + return result; +} + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Class for Manage Account ... +class XSCHttp +{ + // + // Public ... +public: + // + // Constructor ... + void XSCHttp() + { + XSCHttp("", 10000); + } + void XSCHttp( + string path, // Base Folder to Store Data + int timeout // base timeout for Requests + ) + { + // + Path(path); + Timeout(timeout); + } + + // + // Deconstructor ... + void ~XSCHttp() + { + } + + // + // START Getter(s)/Setter(s) ... + // + + // + // Path ... + void Path(string value) + { + mPath = value; + } + + string Path() + { + return mPath; + } + + // + // Timeout ... + void Timeout(int value) + { + mTimeout = value; + } + + // + int Timeout() + { + return mTimeout; + } + + // + // Error ... + int Error() + { + return mError; + } + + // + // Response ... + string Response() + { + return mResponse; + } + + // + // END Getter(s)/Setter(s) ... + // + + // + // START Provided Functions ... + // + + // + // Send Global Request ... + int SendRequest( + X_HTTP_METHOD method, // Httm Request Method + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = -1; + + // + string strMethod = ToString(method); + if (StringLen(strMethod) == 0) + { + return result; + } + + // + // Reset State ... + ResetState(); + + // + result = WebRequest( + strMethod, + url, + headers, + timeout, + payload, + response, + responseHeaders); + + // + if (result < 0) + { + mError = GetLastError(); + } + else + { + mResponse = CharArrayToString(response); + } + + // + return result; + } + + // + // Get Request ... + int GetRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = SendRequest( + X_HTTP_GET, + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + return result; + } + + // + // Post Request ... + int PostRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = SendRequest( + X_HTTP_POST, + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + return result; + } + + // + // Handle Download Specific URL Content to Specific Path and File Name ... + bool Download( + string url, // the URL address which going to download + string fileName // Specify Destination file name to Store Response + ) + { + // + bool result = false; + + // + string filePath = GetFilePath(fileName); + string cookie = NULL; + string referer = NULL; + int timeout = Timeout(); + + // + char payload[]; + string headers; + char response[]; + string responseHeaders; + + // + // Send Request ... + int requestResult = GetRequest( + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + // Define File Handler ... + int mFileHandler = FileOpen( + filePath, + FILE_WRITE | FILE_BIN); + if (mFileHandler == INVALID_HANDLE) + { + // + mError = GetLastError(); + return result; + } + + // + // Write Response to File ... + uint writed = FileWriteArray( + mFileHandler, + response, + 0, + ArraySize(response)); + FileFlush(mFileHandler); + FileClose(mFileHandler); + + // + result = writed > 0; + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... +protected: + // + // Destintion Folder Path ... + string mPath; + + // + // WEB Request Timeout Value ... + int mTimeout; + + // + // WEB Request's Response ... + string mResponse; + + // + // Error Value ... + int mError; + + // + // Private ... +private: + // + // Reset Errors State ... + void ResetState() + { + // + // Reset Errors ... + mError = -1; + mResponse = ""; + ResetLastError(); + } + + // + // Generate Full File Path ... + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + Path() + "\\" + fileName + // + ; + + // + return result; + } +}; + +// +// START Usefull Functions ... +// + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.x121.provider.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.x121.provider.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.x121.provider.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.x121.provider.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.x121.provider.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.x121.provider.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.x121.provider.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.x121.provider.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.x121.xea.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.x121.xea.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.x121.xea.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.x121.xea.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.x121.xea.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.x121.xea.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.x121.xea.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.x121.xea.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xaccount.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xaccount.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xaccount.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xaccount.class.ex5 diff --git a/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xaccount.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xaccount.class.mq5 new file mode 100644 index 0000000..4425f0b --- /dev/null +++ b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xaccount.class.mq5 @@ -0,0 +1,398 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCAccount +// Description: provides all Account 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 + +// +// START Definitions ... +// + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Class for Manage Account ... +class XSCAccount +{ + // + // Public ... +public: + // + // Constructor ... + void XSCAccount() + { + // + mAccountInfo = new CAccountInfo(); + } + + // + // Deconstructor ... + void ~XSCAccount() + { + } + + // + // START Provided Functions ... + // + + // + // User Account ... + long GetUserAccount() + { + return mAccountInfo.Login(); + } + + // + // Account Leverage ... + long GetLeverage() + { + return mAccountInfo.Leverage(); + } + + // + // Get Trade Expert State ... + bool CanExpertTrade() + { + return mAccountInfo.TradeExpert(); + } + + // + // User Account Trade Mopde (ENUM_ACCOUNT_TRADE_MODE) ... + // -------------------------- + // ACCOUNT_TRADE_MODE_DEMO + // ACCOUNT_TRADE_MODE_CONTEST + // ACCOUNT_TRADE_MODE_REAL + ENUM_ACCOUNT_TRADE_MODE GetTradeMode() + { + return mAccountInfo.TradeMode(); + } + + // + // Get Account Balance ... + double GetBalance() + { + return mAccountInfo.Balance(); + } + + // + // Get the amount of give Credit ... + double GetCredit() + { + return mAccountInfo.Credit(); + } + + // + // Get the amount of current Profit on account ... + double GetProfit() + { + return mAccountInfo.Profit(); + } + + // + // Get the amount of current Equity on account ... + double GetEquity() + { + return mAccountInfo.Equity(); + } + + // + // Get the amount of reserved Margin ... + double GetMargin() + { + return mAccountInfo.Margin(); + } + + // + // Get the amount of free Margin ... + double GetFreeMargin() + { + return mAccountInfo.FreeMargin(); + } + + // + // Get the Level of Margin ... + double GetMarginLevel() + { + return mAccountInfo.MarginLevel(); + } + + // + // Get the Level Of Margin for a Deposit ... + double GetMarginCall() + { + return mAccountInfo.MarginCall(); + } + + // + // Get the Level of Margin for Stop out ... + double GetMarginStopOut() + { + return mAccountInfo.MarginStopOut(); + } + + // + // Get the Client Name ... + string GetName() + { + return mAccountInfo.Name(); + } + + // + // Get the Trade Server Name ... + string GetServerName() + { + return mAccountInfo.Server(); + } + + // + // Get deposit Currency Name ... + string GetCurrency() + { + return mAccountInfo.Currency(); + } + + // + // Get the Company Name that serves an Account ... + string GetCompany() + { + return mAccountInfo.Company(); + } + + // + // Calculate Profits for the current account based on passed parameters ... + double CalculateTradeProfit( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry, // open price + double exit // close price + ) + { + // + double result = mAccountInfo.OrderProfitCheck( + symbol, + type, + volume, + entry, + exit); + + // + return result; + } + + // + // Calculate amount of margin which required for trade operation ... + double CalculateMarging( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry // open price + ) + { + // + double result = mAccountInfo.MarginCheck( + symbol, + type, + volume, + entry); + + // + return result; + } + + // + // Calculate amount of free margin left after trade operation ... + double CalculateFreeMarging( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry // open price + ) + { + // + double result = mAccountInfo.FreeMarginCheck( + symbol, + type, + volume, + entry); + + // + return result; + } + + // + // Calculate the Maximum possible volume of trade operation ... + double CalculateMaxVolume( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double entry, // open price + double percent = 100 // percent of available margin + ) + { + // + double result = mAccountInfo.MaxLotCheck( + symbol, + type, + entry, + percent); + + // + return result; + } + + // + // Calculate Point Value for Given Symbol based on Account ... + double GetPointValue( + string symbol // trading symbol + ) + { + // + double result = 0; + + // + double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); + double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); + double point = SymbolInfoDouble(symbol, SYMBOL_POINT); + + // + double ticksPerPoint = tickSize / point; + + // + result = tickValue / ticksPerPoint; + + // + return result; + } + + // + // Calculate Risk Amount based on account Currency by Providing: + // Points and Volume ... + double CalculateRiskAmount( + string symbol, // trading symbol + double points, // amount of Risk Points + double volume // position Volume + ) + { + // + double result = 0; + + // + double pointValue = GetPointValue(symbol); + + // + result = pointValue * volume * points; + + // + return result; + } + + // + // Calculate Risk Points based on account Currency by Providing: + // Volume and Amount ... + double CalculateRiskPoints( + string symbol, // trading symbol + double volume, // position Volume + double amount // amount of Risk based on Account Currency + ) + { + // + double result = 0; + + // + double pointValue = GetPointValue(symbol); + + // + result = amount / (pointValue * volume); + + // + return result; + } + + // + // Calculate Volume based on account Currency by Providing: + // Amount and Risk Points ... + double CalculateVolume( + string symbol, // trading symbol + double amount, // amount of Risk based on Account Currency + double points // amount of Risk Points + ) + { + // + double result = 0; + + // + points = + points <= 0 + ? 10 + : points; + + // + double pointValue = GetPointValue(symbol); + + // + result = amount / (pointValue * points); + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Account Info ... + CAccountInfo mAccountInfo; +}; + +// +// START Usefull Functions ... +// + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xea.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xea.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xea.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xea.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xea.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xea.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xea.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xea.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xhelper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xhelper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xhelper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xhelper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xhelper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xhelper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xhelper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xhelper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xnotifier.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xnotifier.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xnotifier.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xnotifier.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xprovider.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xprovider.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xprovider.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xprovider.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xprovider.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xprovider.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xprovider.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xprovider.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xtrade.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xtrade.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xtrade.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xtrade.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xtrade.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xtrade.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Classes/x-saherelm.xtrade.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Classes/x-saherelm.xtrade.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Experts/x-saherelm.xea.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Experts/x-saherelm.xea.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Experts/x-saherelm.xea.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Experts/x-saherelm.xea.ex5 diff --git a/MQLTestWorkspace/X121/Old/Experts/x-saherelm.xea.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Experts/x-saherelm.xea.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Experts/x-saherelm.xea.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Experts/x-saherelm.xea.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xama.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xama.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xama.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xama.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xama.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xama.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xama.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xama.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xcc.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xcc.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xcc.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xcc.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xcc.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xcc.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xcc.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xcc.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xche.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xche.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xche.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xche.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xche.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xche.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xche.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xche.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xct.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xct.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xct.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xct.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xct.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xct.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xct.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xct.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xdema.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xdema.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xdema.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xdema.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xdema.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xdema.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xdema.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xdema.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xfbb.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xfbb.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xfbb.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xfbb.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xfbb.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xfbb.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xfbb.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xfbb.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xhk.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xhk.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xhk.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xhk.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xhk.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xhk.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xhk.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xhk.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xhull.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xhull.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xhull.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xhull.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xhull.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xhull.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xhull.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xhull.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xich.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xich.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xich.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xich.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xich.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xich.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xich.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xich.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xman.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xman.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xman.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xman.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xman.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xman.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xman.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xman.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xmrb.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xmrb.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xmrb.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xmrb.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xmrb.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xmrb.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xmrb.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xmrb.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xosc.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xosc.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xosc.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xosc.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xosc.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xosc.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xosc.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xosc.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xpv.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xpv.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xpv.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xpv.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xpv.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xpv.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xpv.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xpv.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xsslc.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xsslc.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xsslc.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xsslc.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xsslc.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xsslc.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xsslc.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xsslc.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xstr.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xstr.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xstr.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xstr.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xstr.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xstr.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xstr.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xstr.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xtm.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xtm.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xtm.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xtm.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xtm.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xtm.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xtm.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xtm.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xtrnd.helper.class.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xtrnd.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xtrnd.helper.class.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xtrnd.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xtrnd.helper.class.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xtrnd.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xtrnd.helper.class.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Helpers/x-saherelm.x121.xtrnd.helper.class.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/Market/WH Fair Value Gap MT5.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/Market/WH Fair Value Gap MT5.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/Market/WH Fair Value Gap MT5.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/Market/WH Fair Value Gap MT5.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xama.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xama.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xama.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xama.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xama.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xama.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xama.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xama.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xcc.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xcc.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xcc.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xcc.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xcc.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xcc.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xcc.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xcc.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xche.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xche.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xche.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xche.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xche.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xche.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xche.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xche.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xcpv.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xcpv.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xcpv.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xcpv.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xct.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xct.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xct.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xct.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xct.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xct.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xct.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xct.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xdema.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xdema.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xdema.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xdema.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xdema.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xdema.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xdema.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xdema.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xfbb.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xfbb.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xfbb.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xfbb.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xfbb.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xfbb.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xfbb.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xfbb.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xhk.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xhk.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xhk.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xhk.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xhk.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xhk.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xhk.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xhk.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xhull.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xhull.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xhull.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xhull.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xhull.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xhull.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xhull.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xhull.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xich.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xich.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xich.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xich.ex5 diff --git a/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xich.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xich.mq5 new file mode 100644 index 0000000..724aff6 --- /dev/null +++ b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xich.mq5 @@ -0,0 +1,836 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121_XICH +// Description: Ichimoku Kinko Hyo ... +// +// +// 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_XICH Indicator" +#property strict + +// +// START Constants ... +// + +// +// Indicator Short Name ... +#define ShortName "X121_XICH" + +// +// Ichimoku Golden Numbers ... +enum ENUM_X_ICHIMOKU_GOLDEN_NUMBERS +{ + X_ICH_BASE = 9, + X_ICH_GOLDEN = 17, + X_ICH_CYCLE = 26, + X_ICH_PERIOD = 35, + X_ICH_STAR = 45, + X_ICH_MED = 52, + X_ICH_LONG = 63, + X_ICH_FULL = 72 +}; + +// +// Ichimoku Lines Calculator Mode ... +enum ENUM_X_ICHIMOKU_CALCULATION_MODE +{ + // + X_XICH_HH_LL_MODE = 1, // Highest High and Lowest Low + X_XICH_HO_LC_MODE = 2, // Highest Open and Lowest Close +}; + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +// ICHIMOKU Kinko Hyo ... + +// +// TENKANSEN ... +input group "Tenkan Sen"; +input int tenkanSenLength = 9; // Length +input ENUM_X_ICHIMOKU_CALCULATION_MODE tenkanSenMode = X_XICH_HH_LL_MODE; // Calculation Mode + +// +// KIJUNSEN ... +input group "Kijun Sen"; +input int kijunSenLength = 26; // Length +input ENUM_X_ICHIMOKU_CALCULATION_MODE kijunSenMode = X_XICH_HH_LL_MODE; // Calculation Mode + +// +// SENKOUSPANB ... +input group "Senkou Span B"; +input int senkouSpanBLength = 52; // Length +input ENUM_X_ICHIMOKU_CALCULATION_MODE senkouSpanBMode = X_XICH_HH_LL_MODE; // Calculation Mode + +// +// CHIKOUSPAN ... +input group "Chikou Span"; +input ENUM_APPLIED_PRICE chikuoSpanAppliedTo = PRICE_CLOSE; // Price Type + +// +input group "Presentation"; +input bool showTenkanSen = true; // Show Tenkan Sen +input bool showKijunSen = true; // Show Kijun Sen +input bool showKijunSenPlus = false; // Show Kijun Sen + +input bool showKijunSenNegative = false; // Show Kijun Sen - +input bool showChikouSpan = true; // Show Chikou Span +input bool showSenkouSpanA = true; // Show Senkou Span A +input bool showSenkouSpanB = true; // Show Senkou Span B +input bool showKumo = true; // Show Kumo +input bool shiftKumo = true; // Shift Kumo to Future + +// +// END Inputs ... +// + +// +// START Includes and Imports ... +// + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Includes and Imports ... +// + +// +// START Buffers ... +// +#property indicator_chart_window + +// +#property indicator_buffers 15 +#property indicator_plots 8 + +// +// PLOTTED Buffers ... + +// +// ICHIMOKU ... + +// +// TENKANSEN ... + +// +#define tenkanSenBufferIndex 0 +double tenkanSenBuffer[]; + +// +#property indicator_label1 "X121_XICH TK" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrBrown +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +// +// KIJUNSEN ... + +// +#define kijunSenBufferIndex 1 +double kijunSenBuffer[]; + +// +#property indicator_label2 "X121_XICH KJ" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrDodgerBlue +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +// +#define kijunSenPlusBufferIndex 2 +double kijunSenPlusBuffer[]; + +// +#property indicator_label3 "X121_XICH KJ+" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrMediumTurquoise +#property indicator_style3 STYLE_DOT +#property indicator_width3 1 + +// +#define kijunSenNegativeBufferIndex 3 +double kijunSenNegativeBuffer[]; + +// +#property indicator_label4 "X121_XICH KJ-" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrDarkSeaGreen +#property indicator_style4 STYLE_DOT +#property indicator_width4 1 + +// +// CHIKOUSPAN ... + +// +#define chikouSpanBufferIndex 4 +double chikouSpanBuffer[]; + +// +#property indicator_label5 "X121_XICH CS" +#property indicator_type5 DRAW_LINE +#property indicator_color5 clrDarkGreen +#property indicator_style5 STYLE_SOLID +#property indicator_width5 1 + +// +#define senkouABufferIndex 5 +double senkouABuffer[]; + +// +#property indicator_label6 "X121_XICH SSA" +#property indicator_type6 DRAW_LINE +#property indicator_color6 clrLightGray +#property indicator_style6 STYLE_DASHDOTDOT +#property indicator_width6 1 + +// +#define senkouBBufferIndex 6 +double senkouBBuffer[]; + +// +#property indicator_label7 "X121_XICH SSB" +#property indicator_type7 DRAW_LINE +#property indicator_color7 clrLightGray +#property indicator_style7 STYLE_DASHDOTDOT +#property indicator_width7 1 + +// +// KUMO ... + +// +// SENKOUSPANA ... + +// +#define senkouSpanABufferIndex 7 +double senkouSpanABuffer[]; + +// +// SENKOUSPANB ... + +// +#define senkouSpanBBufferIndex 8 +double senkouSpanBBuffer[]; + +// +// KUMOCLOUD ... + +// +#define kumoBufferIndex 7 + +// +#property indicator_label8 "X121_XICH Kumo" +#property indicator_type8 DRAW_FILLING +#property indicator_color8 clrAqua, clrMagenta +#property indicator_style8 STYLE_SOLID +#property indicator_width8 1 + +// +// DATA Buffers ... + +// +#define dTenkanBufferIndex 9 +double dTenkanBuffer[]; + +// +#define dKijunBufferIndex 10 +double dKijunBuffer[]; + +// +#define dChikouBufferIndex 11 +double dChikouBuffer[]; + +// +#define dSSABufferIndex 12 +double dSSABuffer[]; + +// +#define dSSBBufferIndex 13 +double dSSBBuffer[]; + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; +int mHandler; + +// +ENUM_SERIESMODE mTenkanSenTopMode = NULL; +ENUM_SERIESMODE mTenkanSenBottomMode = NULL; + +// +ENUM_SERIESMODE mKijunSenTopMode = NULL; +ENUM_SERIESMODE mKijunSenBottomMode = NULL; + +// +ENUM_SERIESMODE mSenkouSpanBTopMode = NULL; +ENUM_SERIESMODE mSenkouSpanBBottomMode = NULL; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + 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(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Init Handler ... + mHandler = iIchimoku( + _Symbol, + _Period, + tenkanSenLength, + kijunSenLength, + senkouSpanBLength); + if (mHandler == INVALID_HANDLE) + { + return INIT_FAILED; + } + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 + + // + IndicatorRelease(mHandler); +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + 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); + + // + // this counts Available Bars ... + int limit; + + // + // Check Calculated Bars ... + int ichCalculatedBars = BarsCalculated(mHandler); + if (ichCalculatedBars < maxLength) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + int copiedTenkans = CopyBuffer(mHandler, TENKANSEN_LINE, 0, limit, dTenkanBuffer); + int copiedKijuns = CopyBuffer(mHandler, KIJUNSEN_LINE, 0, limit, dKijunBuffer); + int copiedChikous = CopyBuffer(mHandler, CHIKOUSPAN_LINE, 0, limit, dChikouBuffer); + int copiedSSAs = CopyBuffer(mHandler, SENKOUSPANA_LINE, 0, limit, dSSABuffer); + int copiedSSBs = CopyBuffer(mHandler, SENKOUSPANB_LINE, 0, limit, dSSBBuffer); + if ( + copiedSSAs < 0 || + copiedSSBs < 0 || + copiedKijuns < 0 || + copiedTenkans < 0 || + copiedChikous < 0) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + CalculateBuffers(i); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = + // + (tenkanSenLength > 2 && + kijunSenLength > tenkanSenLength && + senkouSpanBLength > kijunSenLength) + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // Ichimoku ... + result = MathMax(result, tenkanSenLength); + result = MathMax(result, kijunSenLength); + result = MathMax(result, senkouSpanBLength); + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // ICHIMOKU ... + + // + // TENKANSEN ... + + // + ENUM_DRAW_TYPE tenkanSenDrawType = showTenkanSen ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(tenkanSenBuffer, true); + SetIndexBuffer(tenkanSenBufferIndex, tenkanSenBuffer, INDICATOR_DATA); + PlotIndexSetInteger(tenkanSenBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(tenkanSenBufferIndex, PLOT_SHOW_DATA, showTenkanSen); + PlotIndexSetInteger(tenkanSenBufferIndex, PLOT_DRAW_TYPE, tenkanSenDrawType); + + // + // KIJUNSEN ... + + // + ENUM_DRAW_TYPE kijunSenDrawType = showKijunSen ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(kijunSenBuffer, true); + SetIndexBuffer(kijunSenBufferIndex, kijunSenBuffer, INDICATOR_DATA); + PlotIndexSetInteger(kijunSenBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(kijunSenBufferIndex, PLOT_SHOW_DATA, showKijunSen); + PlotIndexSetInteger(kijunSenBufferIndex, PLOT_DRAW_TYPE, kijunSenDrawType); + + // + // KIJUNSEN Plus ... + + // + ENUM_DRAW_TYPE kijunSenPlusDrawType = showKijunSenPlus ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(kijunSenPlusBuffer, true); + SetIndexBuffer(kijunSenPlusBufferIndex, kijunSenPlusBuffer, INDICATOR_DATA); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_SHIFT, kijunSenLength); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_DRAW_TYPE, kijunSenPlusDrawType); + + // + // KIJUNSEN Negative ... + + // + ENUM_DRAW_TYPE kijunSenNegativeDrawType = showKijunSenNegative ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(kijunSenNegativeBuffer, true); + SetIndexBuffer(kijunSenNegativeBufferIndex, kijunSenNegativeBuffer, INDICATOR_DATA); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_SHIFT, -kijunSenLength); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_DRAW_TYPE, kijunSenNegativeDrawType); + + // + // CHIKOUSPAN ... + + // + ENUM_DRAW_TYPE chikouSpanDrawType = showChikouSpan ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(chikouSpanBuffer, true); + SetIndexBuffer(chikouSpanBufferIndex, chikouSpanBuffer, INDICATOR_DATA); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_SHIFT, -kijunSenLength); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_SHOW_DATA, showChikouSpan); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_DRAW_TYPE, chikouSpanDrawType); + + // + // SENKOUSPAN A and B ... + int shiftSize = shiftKumo ? kijunSenLength : 0; + + // + // SENKOUSPANA ... + ENUM_DRAW_TYPE senkouSpanADrawType = showSenkouSpanA ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(senkouABuffer, true); + SetIndexBuffer(senkouABufferIndex, senkouABuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouABufferIndex, PLOT_SHIFT, shiftSize); + PlotIndexSetInteger(senkouABufferIndex, PLOT_SHOW_DATA, showSenkouSpanA); + PlotIndexSetInteger(senkouABufferIndex, PLOT_DRAW_TYPE, senkouSpanADrawType); + + // + // SENKOUSPANB ... + ENUM_DRAW_TYPE senkouSpanBDrawType = showSenkouSpanB ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(senkouBBuffer, true); + SetIndexBuffer(senkouBBufferIndex, senkouBBuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouBBufferIndex, PLOT_SHIFT, shiftSize); + PlotIndexSetInteger(senkouBBufferIndex, PLOT_SHOW_DATA, showSenkouSpanB); + PlotIndexSetInteger(senkouBBufferIndex, PLOT_DRAW_TYPE, senkouSpanBDrawType); + + // + // KUMO ... + + // + // SENKOUSPANA ... + ArraySetAsSeries(senkouSpanABuffer, true); + SetIndexBuffer(senkouSpanABufferIndex, senkouSpanABuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouSpanABufferIndex, PLOT_DRAW_BEGIN, maxLength); + + // + // SENKOUSPANB ... + ArraySetAsSeries(senkouSpanBBuffer, true); + SetIndexBuffer(senkouSpanBBufferIndex, senkouSpanBBuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouSpanBBufferIndex, PLOT_DRAW_BEGIN, maxLength); + + // + // KUMO ... + + // + ENUM_DRAW_TYPE kumoDrawType = showKumo ? DRAW_FILLING : DRAW_NONE; + + // + PlotIndexSetInteger(kumoBufferIndex, PLOT_SHIFT, shiftSize); + PlotIndexSetInteger(kumoBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(kumoBufferIndex, PLOT_DRAW_TYPE, kumoDrawType); + + // + // DATA Buffers ... + + // + // D Tenkan ... + ArraySetAsSeries(dTenkanBuffer, true); + SetIndexBuffer(dTenkanBufferIndex, dTenkanBuffer, INDICATOR_CALCULATIONS); + + // + // D Kijun ... + ArraySetAsSeries(dKijunBuffer, true); + SetIndexBuffer(dKijunBufferIndex, dKijunBuffer, INDICATOR_CALCULATIONS); + + // + // D Chikou ... + ArraySetAsSeries(dChikouBuffer, true); + SetIndexBuffer(dChikouBufferIndex, dChikouBuffer, INDICATOR_CALCULATIONS); + + // + // D SSA ... + ArraySetAsSeries(dSSABuffer, true); + SetIndexBuffer(dSSABufferIndex, dSSABuffer, INDICATOR_CALCULATIONS); + + // + // D SSB ... + ArraySetAsSeries(dSSBBuffer, true); + SetIndexBuffer(dSSBBufferIndex, dSSBBuffer, INDICATOR_CALCULATIONS); +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index // Selected Bar Index +) +{ + // + // ICHIMOKU ... + + // + double topValue; + double bottomValue; + + // + // TENKANSEN ... + + // + // Extract Tenkan Sen Top/Bottom Calculation Mode based on User Input ... + if (mTenkanSenTopMode == NULL || mTenkanSenBottomMode == NULL) + { + // + switch (tenkanSenMode) + { + // + case X_XICH_HH_LL_MODE: + // + mTenkanSenTopMode = MODE_HIGH; + mTenkanSenBottomMode = MODE_LOW; + break; + + // + case X_XICH_HO_LC_MODE: + // + mTenkanSenTopMode = MODE_OPEN; + mTenkanSenBottomMode = MODE_CLOSE; + break; + } + } + + // + // Calculate Top ... + topValue = GetHighestHigh( + _Symbol, + _Period, + mTenkanSenTopMode, + tenkanSenLength, + bar_index); + + // + // Calculate Bottom ... + bottomValue = GetLowestLow( + _Symbol, + _Period, + mTenkanSenBottomMode, + tenkanSenLength, + bar_index); + + // + double tenkanSenValue = (topValue + bottomValue) / 2; + tenkanSenBuffer[bar_index] = tenkanSenValue; + + // + // KIJUNSEN ... + + // + // Extract Kijun Sen Top/Bottom Calculation Mode based on User Input ... + if (mKijunSenTopMode == NULL || mKijunSenBottomMode == NULL) + { + // + switch (kijunSenMode) + { + // + case X_XICH_HH_LL_MODE: + // + mKijunSenTopMode = MODE_HIGH; + mKijunSenBottomMode = MODE_LOW; + break; + + // + case X_XICH_HO_LC_MODE: + // + mKijunSenTopMode = MODE_OPEN; + mKijunSenBottomMode = MODE_CLOSE; + break; + } + } + + // + // Calculate Top ... + topValue = GetHighestHigh( + _Symbol, + _Period, + mKijunSenTopMode, + kijunSenLength, + bar_index); + + // + // Calculate Bottom ... + bottomValue = GetLowestLow( + _Symbol, + _Period, + mKijunSenBottomMode, + kijunSenLength, + bar_index); + + // + double kijunSenValue = (topValue + bottomValue) / 2; + kijunSenBuffer[bar_index] = kijunSenValue; + + // + kijunSenPlusBuffer[bar_index] = kijunSenValue; + kijunSenNegativeBuffer[bar_index] = kijunSenValue; + + // + // CHIKOUSPAN ... + double chikouSpanValue = GetAppliedPrice( + bar_index, + chikuoSpanAppliedTo); + chikouSpanBuffer[bar_index] = chikouSpanValue; + + // + // KUMO ... + + // + // SENKOUSPANA ... + double senkouSpanAValue = (tenkanSenValue + kijunSenValue) / 2; + senkouABuffer[bar_index] = senkouSpanAValue; + senkouSpanABuffer[bar_index] = senkouSpanAValue; + + // + // SENKOUSPANB ... + + // + // Extract Senkou Span B Top/Bottom Calculation Mode based on User Input ... + if (mSenkouSpanBTopMode == NULL || mSenkouSpanBBottomMode == NULL) + { + // + switch (senkouSpanBMode) + { + // + case X_XICH_HH_LL_MODE: + // + mSenkouSpanBTopMode = MODE_HIGH; + mSenkouSpanBBottomMode = MODE_LOW; + break; + + // + case X_XICH_HO_LC_MODE: + // + mSenkouSpanBTopMode = MODE_OPEN; + mSenkouSpanBBottomMode = MODE_CLOSE; + break; + } + } + + // + // Calculate Top ... + topValue = GetHighestHigh( + _Symbol, + _Period, + mSenkouSpanBTopMode, + senkouSpanBLength, + bar_index); + + // + // Calculate Bottom ... + bottomValue = GetLowestLow( + _Symbol, + _Period, + mSenkouSpanBBottomMode, + senkouSpanBLength, + bar_index); + + // + double senkouSpanBValue = (topValue + bottomValue) / 2; + senkouBBuffer[bar_index] = senkouSpanBValue; + senkouSpanBBuffer[bar_index] = senkouSpanBValue; +} + +// +// END Functions ... +// diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xman.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xman.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xman.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xman.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xman.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xman.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xman.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xman.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xmrb.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xmrb.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xmrb.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xmrb.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xmrb.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xmrb.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xmrb.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xmrb.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xosc.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xosc.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xosc.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xosc.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xosc.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xosc.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xosc.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xosc.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xpv.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xpv.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xpv.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xpv.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xpv.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xpv.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xpv.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xpv.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xsslc.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xsslc.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xsslc.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xsslc.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xsslc.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xsslc.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xsslc.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xsslc.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xstr.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xstr.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xstr.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xstr.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xstr.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xstr.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xstr.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xstr.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xtm.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xtm.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xtm.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xtm.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xtm.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xtm.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xtm.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xtm.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xtrnd.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xtrnd.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xtrnd.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xtrnd.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xtrnd.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xtrnd.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xtrnd.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.x121.xtrnd.mq5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.xchnl.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.xchnl.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.xchnl.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.xchnl.ex5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.xchnl.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.xchnl.mq5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.xchnl.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Indicators/x-saherelm.xchnl.mq5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.alert.lib.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.alert.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.alert.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.alert.lib.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.alert.lib.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.alert.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.alert.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.alert.lib.mq5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.common.lib.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.common.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.common.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.common.lib.ex5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.common.lib.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.common.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.common.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.common.lib.mq5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.draw.lib.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.draw.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.draw.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.draw.lib.ex5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.draw.lib.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.draw.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.draw.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.draw.lib.mq5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.http.lib.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.http.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.http.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.http.lib.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.http.lib.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.http.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.http.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.http.lib.mq5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.log.lib.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.log.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.log.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.log.lib.ex5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.log.lib.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.log.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.log.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.log.lib.mq5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.models.lib.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.models.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.models.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.models.lib.ex5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.models.lib.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.models.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.models.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.models.lib.mq5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.seriallizer.lib.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.seriallizer.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.seriallizer.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.seriallizer.lib.ex5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.seriallizer.lib.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.seriallizer.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.seriallizer.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.seriallizer.lib.mq5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.draw.lib.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.draw.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.draw.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.draw.lib.ex5 diff --git a/MQLTestWorkspace/Libraries/x-saherelm.x121.draw.lib.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.draw.lib.mq5 similarity index 100% rename from MQLTestWorkspace/Libraries/x-saherelm.x121.draw.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.draw.lib.mq5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.signaller.lib.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.signaller.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.signaller.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.signaller.lib.ex5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.signaller.lib.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.signaller.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.signaller.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.signaller.lib.mq5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.support.lib.ex5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.support.lib.ex5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.support.lib.ex5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.support.lib.ex5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.support.lib.mq5 b/MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.support.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.support.lib.mq5 rename to MQLTestWorkspace/BKPS/X121/Old/Libraries/x-saherelm.x121.support.lib.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Experts/x-donchain.ea.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-donchain.ea.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Experts/x-donchain.ea.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-donchain.ea.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Experts/x-rsima.ea.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-rsima.ea.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Experts/x-rsima.ea.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-rsima.ea.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Experts/x-saherelm.xbe.ea.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-saherelm.xbe.ea.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Experts/x-saherelm.xbe.ea.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-saherelm.xbe.ea.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Experts/x-saherelm.xbe.ea.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-saherelm.xbe.ea.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Experts/x-saherelm.xbe.ea.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-saherelm.xbe.ea.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Experts/x-saherelm.xea.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-saherelm.xea.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Experts/x-saherelm.xea.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-saherelm.xea.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Experts/x-saherelm.xea.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-saherelm.xea.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Experts/x-saherelm.xea.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Experts/x-saherelm.xea.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Helpers/x-saherelm.x121.xman.helper.class.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Helpers/x-saherelm.x121.xman.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Helpers/x-saherelm.x121.xman.helper.class.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Helpers/x-saherelm.x121.xman.helper.class.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Helpers/x-saherelm.x121.xman.helper.class.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Helpers/x-saherelm.x121.xman.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Helpers/x-saherelm.x121.xman.helper.class.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Helpers/x-saherelm.x121.xman.helper.class.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xche.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xche.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xche.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xche.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xche.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xche.mq5 new file mode 100644 index 0000000..59e850f --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xche.mq5 @@ -0,0 +1,631 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121_XCHE +// Description: Chandelier Exit 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 X121_XCHE Indicator" +#property strict + +// +// START Constants ... +// + +// +#define ShortName "X121_XCHE" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input group "Market"; +input int length = 35; // Length +input int loopback = 26; // Loopback +input double multiplier1 = 3.0; // 1st Multiplier +input double multiplier2 = 3.5; // 2nd Multiplier + +// +input group "Calculation"; +input ENUM_APPLIED_PRICE upAppliedTo = PRICE_HIGH; // Up Zone Applied to +input ENUM_APPLIED_PRICE downAppliedTo = PRICE_LOW; // Down Zone Applied to + +// +input group "Presentation"; +input bool showLongExit1Line = true; // Show 1st Long Exit +input bool showShortExit1Line = true; // Show 1st Short Exit +input bool showLongExit2Line = true; // Show 2st Long Exit +input bool showShortExit2Line = true; // Show 2st Short Exit + +// +// END Inputs ... +// + +// +// START Includes and Imports ... +// + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Includes and Imports ... +// + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 8 +#property indicator_plots 8 + +// +// Long Exit 1 ... +#define longExit1BufferIndex 0 +double longExit1Buffer[]; + +// +#property indicator_label1 "X121_XCHE LE 1" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrLime +#property indicator_style1 STYLE_DOT + +// +// Short Exit 1 ... +#define shortExit1BufferIndex 1 +double shortExit1Buffer[]; + +// +#property indicator_label2 "X121_XCHE SE 1" +#property indicator_type2 DRAW_LINE +#property indicator_style2 STYLE_DOT +#property indicator_color2 clrRed + +// +// Long Exit 2 ... +#define longExit2BufferIndex 2 +double longExit2Buffer[]; + +// +#property indicator_label3 "X121_XCHE LE 2" +#property indicator_type3 DRAW_LINE +#property indicator_style2 STYLE_DOT +#property indicator_color3 clrAqua + +// +// Short Exit 2 ... +#define shortExit2BufferIndex 3 +double shortExit2Buffer[]; + +// +#property indicator_label4 "X121_XCHE SE 2" +#property indicator_type4 DRAW_LINE +#property indicator_style2 STYLE_DOT +#property indicator_color4 clrMagenta + +// +// START Arrows ... + +// +// Long Exit 1 Start ... +#define longExit1StartBufferIndex 4 +double longExit1StartBuffer[]; + +// +#property indicator_label5 "X121_XCHE LES 1" +#property indicator_type5 DRAW_ARROW +#property indicator_color5 clrLime + +// +// Short Exit 1 Start ... +#define shortExit1StartBufferIndex 5 +double shortExit1StartBuffer[]; + +// +#property indicator_label6 "X121_XCHE SES 1" +#property indicator_type6 DRAW_ARROW +#property indicator_color6 clrRed + +// +// Long Exit 2 Start ... +#define longExit2StartBufferIndex 6 +double longExit2StartBuffer[]; + +// +#property indicator_label7 "X121_XCHE LES 2" +#property indicator_type7 DRAW_ARROW +#property indicator_color7 clrAqua + +// +// Short Exit 2 Start ... +#define shortExit2StartBufferIndex 7 +double shortExit2StartBuffer[]; + +// +#property indicator_label8 "X121_XCHE SES 2" +#property indicator_type8 DRAW_ARROW +#property indicator_color8 clrMagenta + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +// Working Array ... +double work[][6]; +#define hi1Idx 0 +#define lo1Idx 1 +#define hi2Idx 2 +#define lo2Idx 3 +#define trend1Idx 4 +#define trend2Idx 5 + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + 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(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 mPeriod 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 +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + const int &spread[]) +{ + // + if (Bars(_Symbol, _Period) < rates_total) + { + return (prev_calculated); + } + + // + if (ArrayRange(work, 0) != rates_total) + { + ArrayResize(work, rates_total); + } + + // + // this counts Available Bars ... + int limit; + + // + limit = prev_calculated - 1; + if (limit < 0) + { + limit = 0; + } + + // + // Main Loop ... + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + low, + close); + } + + // + return rates_total; +} +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = true; + + // + result = + length >= 9 && + loopback >= 0; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(length, loopback); + + // + return result; +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + uint arrowCode = 159; + + // + // LEVEL 1 ... + + // + // Long Exit 1 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE longExit1DrawType = showLongExit1Line ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE longExit1StartDrawType = showLongExit1Line ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(longExit1BufferIndex, longExit1Buffer, INDICATOR_DATA); + PlotIndexSetInteger(longExit1BufferIndex, PLOT_SHOW_DATA, showLongExit1Line); + PlotIndexSetInteger(longExit1BufferIndex, PLOT_DRAW_TYPE, longExit1DrawType); + + // + // Start Buffer ... + SetIndexBuffer(longExit1StartBufferIndex, longExit1StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(longExit1StartBufferIndex, PLOT_ARROW, arrowCode); + PlotIndexSetInteger(longExit1StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(longExit1StartBufferIndex, PLOT_DRAW_TYPE, longExit1StartDrawType); + + // + // Short Exit 1 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE shortExit1DrawType = showShortExit1Line ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE shortExit1StartDrawType = showShortExit1Line ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(shortExit1BufferIndex, shortExit1Buffer, INDICATOR_DATA); + PlotIndexSetInteger(shortExit1BufferIndex, PLOT_SHOW_DATA, showShortExit1Line); + PlotIndexSetInteger(shortExit1BufferIndex, PLOT_DRAW_TYPE, shortExit1DrawType); + + // + // Start Buffer ... + SetIndexBuffer(shortExit1StartBufferIndex, shortExit1StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(shortExit1StartBufferIndex, PLOT_ARROW, arrowCode); + PlotIndexSetInteger(shortExit1StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(shortExit1StartBufferIndex, PLOT_DRAW_TYPE, shortExit1StartDrawType); + + // + // LEVEL 2 ... + + // + // Long Exit 2 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE longExit2DrawType = showLongExit2Line ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE longExit2StartDrawType = showLongExit2Line ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(longExit2BufferIndex, longExit2Buffer, INDICATOR_DATA); + PlotIndexSetInteger(longExit2BufferIndex, PLOT_SHOW_DATA, showLongExit2Line); + PlotIndexSetInteger(longExit2BufferIndex, PLOT_DRAW_TYPE, longExit2DrawType); + + // + // Start Buffer ... + SetIndexBuffer(longExit2StartBufferIndex, longExit2StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(longExit2StartBufferIndex, PLOT_ARROW, arrowCode); + PlotIndexSetInteger(longExit2StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(longExit2StartBufferIndex, PLOT_DRAW_TYPE, longExit2StartDrawType); + + // + // Short Exit 2 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE shortExit2DrawType = showShortExit2Line ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE shortExit2StartDrawType = showShortExit2Line ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(shortExit2BufferIndex, shortExit2Buffer, INDICATOR_DATA); + PlotIndexSetInteger(shortExit2BufferIndex, PLOT_SHOW_DATA, showShortExit2Line); + PlotIndexSetInteger(shortExit2BufferIndex, PLOT_DRAW_TYPE, shortExit2DrawType); + + // + // Start Buffer ... + SetIndexBuffer(shortExit2StartBufferIndex, shortExit2StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(shortExit2StartBufferIndex, PLOT_ARROW, arrowCode); + PlotIndexSetInteger(shortExit2StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(shortExit2StartBufferIndex, PLOT_DRAW_TYPE, shortExit2StartDrawType); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index, // Selected Bar Index + int prevCalculated, // Previous Calculated + int ratesTotal, // Total Rates + const double &open[], // Rates Open ... + const double &high[], // Rates High ... + const double &low[], // Rates Low ... + const double &close[] // Rates Close ... +) +{ + // + // Cleanup Buffers ... + longExit1Buffer[bar_index] = longExit1StartBuffer[bar_index] = shortExit1Buffer[bar_index] = shortExit1StartBuffer[bar_index] = EMPTY_VALUE; + longExit2Buffer[bar_index] = longExit2StartBuffer[bar_index] = shortExit2Buffer[bar_index] = shortExit2StartBuffer[bar_index] = EMPTY_VALUE; + + // + int start = MathMax(bar_index - loopback, 0); + + // + // Calculate ATR Value ... + double atrValue = 0; + for (int k = 1; k <= length && (bar_index - k - 1) >= 0; k++) + { + // + atrValue += MathMax(high[bar_index - k], close[MathMax(bar_index - k - 1, 0)]) - + MathMin(low[bar_index - k], close[MathMax(bar_index - k - 1, 0)]); + } + atrValue /= (double)length; + + // + // Retrieve Highest High and Lowest Lows ... + double loopbackMax = high[ArrayMaximum(high, start, loopback)]; + double loopbackMin = low[ArrayMinimum(low, start, loopback)]; + + // + // Fill Multi Dimesional Working Array ... + work[bar_index][hi1Idx] = loopbackMax - multiplier1 * atrValue; + work[bar_index][lo1Idx] = loopbackMin + multiplier1 * atrValue; + work[bar_index][hi2Idx] = loopbackMax - multiplier2 * atrValue; + work[bar_index][lo2Idx] = loopbackMin + multiplier2 * atrValue; + work[bar_index][trend1Idx] = (bar_index > 0) ? work[bar_index - 1][trend1Idx] : 0; + work[bar_index][trend2Idx] = (bar_index > 0) ? work[bar_index - 1][trend2Idx] : 0; + + // + if (bar_index > 0) + { + // + // Calculate Trends ... + if (close[bar_index] > work[bar_index - 1][lo1Idx]) + { + work[bar_index][trend1Idx] = 1; + } + + // + if (close[bar_index] < work[bar_index - 1][hi1Idx]) + { + work[bar_index][trend1Idx] = -1; + } + + // + if (close[bar_index] > work[bar_index - 1][lo2Idx]) + { + work[bar_index][trend2Idx] = 1; + } + + // + if (close[bar_index] < work[bar_index - 1][hi2Idx]) + { + work[bar_index][trend2Idx] = -1; + } + + // + // Calculate Exit Values ... + + // + // Exit 1 ... + + // + // Long ... + if (multiplier1 > 0 && work[bar_index][trend1Idx] == 1) + { + // + if (work[bar_index][hi1Idx] < work[bar_index - 1][hi1Idx]) + { + work[bar_index][hi1Idx] = work[bar_index - 1][hi1Idx]; + } + + // + longExit1Buffer[bar_index] = work[bar_index][hi1Idx]; + + // + if (longExit1Buffer[bar_index - 1] == EMPTY_VALUE) + { + longExit1StartBuffer[bar_index] = longExit1Buffer[bar_index]; + } + } + + // + // Short ... + if (multiplier1 > 0 && work[bar_index][trend1Idx] == -1) + { + // + if (work[bar_index][lo1Idx] > work[bar_index - 1][lo1Idx]) + { + work[bar_index][lo1Idx] = work[bar_index - 1][lo1Idx]; + } + + // + shortExit1Buffer[bar_index] = work[bar_index][lo1Idx]; + + // + if (shortExit1Buffer[bar_index - 1] == EMPTY_VALUE) + { + shortExit1StartBuffer[bar_index] = shortExit1Buffer[bar_index]; + } + } + + // + // Exit 2 ... + + // + // Long ... + if (multiplier2 > 0 && work[bar_index][trend2Idx] == 1) + { + if (work[bar_index][hi2Idx] < work[bar_index - 1][hi2Idx]) + { + work[bar_index][hi2Idx] = work[bar_index - 1][hi2Idx]; + } + + // + longExit2Buffer[bar_index] = work[bar_index][hi2Idx]; + + // + if (longExit2Buffer[bar_index - 1] == EMPTY_VALUE) + { + longExit2StartBuffer[bar_index] = longExit2Buffer[bar_index]; + } + } + + // + // Short ... + if (multiplier2 > 0 && work[bar_index][trend2Idx] == -1) + { + // + if (work[bar_index][lo2Idx] > work[bar_index - 1][lo2Idx]) + { + work[bar_index][lo2Idx] = work[bar_index - 1][lo2Idx]; + } + + // + shortExit2Buffer[bar_index] = work[bar_index][lo2Idx]; + + // + if (shortExit2Buffer[bar_index - 1] == EMPTY_VALUE) + { + shortExit2StartBuffer[bar_index] = shortExit2Buffer[bar_index]; + } + } + } +} + +// +// END Functions ... +// diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xdema.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xdema.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xdema.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xdema.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xdema.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xdema.mq5 new file mode 100644 index 0000000..186778e --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xdema.mq5 @@ -0,0 +1,348 @@ +////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121_XDEMA +// Description: Super Trend 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 X121_XAMA Indicator" +#property strict + +// +// START Constants ... +// + +#define ShortName "X121_XDEMA" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +// Market ... +input group "Market"; +input int length = 200; // Length +input int shift = 0; // Shift + +// +// Presentation ... +input group "Presentation"; +input bool showDema = true; // Show Dema +input bool showEMA = false; // Show EMA +input bool showEMAOfEMA = false; // Show EMA of EMA + +// +// END Inputs ... +// + +// +// Includes Common Library ... +#include +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 6 +#property indicator_plots 6 + +// +#define demaBufferIndex 0 +double demaBuffer[]; + +// +#define demaColorBufferIndex 1 +double demaColorBuffer[]; + +// +#property indicator_label1 "X121_XDEMA DEMA" +#property indicator_type1 DRAW_COLOR_LINE +#property indicator_color1 clrDodgerBlue, CLR_NONE +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +// +#define emaBufferIndex 2 +double emaBuffer[]; + +// +#define emaColorBufferIndex 3 +double emaColorBuffer[]; + +// +#property indicator_label2 "X121_XDEMA EMA" +#property indicator_type2 DRAW_COLOR_LINE +#property indicator_color2 clrBlue, CLR_NONE +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +// +#define emaOfEMABufferIndex 4 +double emaOfEMABuffer[]; + +// +#define emaOfEMAColorBufferIndex 5 +double emaOfEMAColorBuffer[]; + +// +#property indicator_label3 "X121_XDEMA EMA of EMA" +#property indicator_type3 DRAW_COLOR_LINE +#property indicator_color3 clrOrange, CLR_NONE +#property indicator_style3 STYLE_DOT +#property indicator_width3 1 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + 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(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 +} + +// +// Do Calculations ... +int OnCalculate(const int rates_total, + const int prev_calculated, + const int begin, + const double &price[]) +{ + // + ArraySetAsSeries(price, true); + + // + // check for data ... + if (rates_total < 2 * length - 2) + { + return 0; + } + + // + int limit; + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // calculate EMA ... + ExponentialMAOnBuffer(rates_total, prev_calculated, 0, length, price, emaBuffer); + + // + // calculate EMA on EMA array ... + ExponentialMAOnBuffer(rates_total, prev_calculated, length - 1, length, emaBuffer, emaOfEMABuffer); + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + // calculate DEMA ... + demaBuffer[i] = 2 * emaBuffer[i] - emaOfEMABuffer[i]; + + // + double showColorIDX = 0; + double hideColorIDX = 1; + + // + demaColorBuffer[i] = hideColorIDX; + emaColorBuffer[i] = hideColorIDX; + emaOfEMAColorBuffer[i] = hideColorIDX; + + // + if (showDema) + { + demaColorBuffer[i] = showColorIDX; + } + + // + if (showEMA) + { + emaColorBuffer[i] = showColorIDX; + } + + // + if (showEMAOfEMA) + { + emaOfEMAColorBuffer[i] = showColorIDX; + } + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = + // + (length > 2 && + shift >= 0) + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // Peaks and Vales ... + result = length; + + // + return result; +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // DEMA ... + + // + // Buffer ... + ArraySetAsSeries(demaBuffer, true); + SetIndexBuffer(demaBufferIndex, demaBuffer, INDICATOR_DATA); + PlotIndexSetInteger(demaBufferIndex, PLOT_SHOW_DATA, showDema); + + // + // Color Buffer ... + ArraySetAsSeries(demaColorBuffer, true); + SetIndexBuffer(demaColorBufferIndex, demaColorBuffer, INDICATOR_COLOR_INDEX); + + // + // EMA ... + + // + // Buffer ... + ArraySetAsSeries(emaBuffer, true); + SetIndexBuffer(emaBufferIndex, emaBuffer, INDICATOR_DATA); + PlotIndexSetInteger(emaBufferIndex, PLOT_SHOW_DATA, showEMA); + + // + // Color Buffer ... + ArraySetAsSeries(emaColorBuffer, true); + SetIndexBuffer(emaColorBufferIndex, emaColorBuffer, INDICATOR_COLOR_INDEX); + + // + // EMA of EMA ... + + // + // Buffer ... + ArraySetAsSeries(emaOfEMABuffer, true); + SetIndexBuffer(emaOfEMABufferIndex, emaOfEMABuffer, INDICATOR_DATA); + PlotIndexSetInteger(emaOfEMABufferIndex, PLOT_SHOW_DATA, showEMAOfEMA); + + // + // Color Buffer ... + ArraySetAsSeries(emaOfEMAColorBuffer, true); + SetIndexBuffer(emaOfEMAColorBufferIndex, emaOfEMAColorBuffer, INDICATOR_COLOR_INDEX); +} + +// +// END Functions ... +// diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xdsr.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xdsr.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xdsr.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xdsr.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xdsr.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xdsr.mq5 new file mode 100644 index 0000000..dbae73a --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xdsr.mq5 @@ -0,0 +1,964 @@ +/////////////////////////////////////////////////////// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------- +// Name: XDSR +// Description: Dynamic Support and Resistances ... +// +// 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 XDSR Indicator" +#property strict + +// +#define ShortName "XDSR" + +// +// Includes ... +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// INPUT ... + +// +// Maarket ... +input group "Cycles"; + +// +// Short ... +input group "Short"; +input ENUM_X_PERIOD_METHOD scMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES scPeriod = PERIOD_H4; // Period + +// +// Medium ... +input group "Medium"; +input ENUM_X_PERIOD_METHOD mcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES mcPeriod = PERIOD_H12; // Mid Period + +// +// Long ... +input group "Long"; +input ENUM_X_PERIOD_METHOD lcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES lcPeriod = PERIOD_D1; // Long Period + +// +// Hind ... +input group "Hind"; +input ENUM_X_PERIOD_METHOD hcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES hcPeriod = PERIOD_W1; // Hind Period + +// +// BUFFERS ... + +// +#property indicator_chart_window + +// +#property indicator_buffers 24 +#property indicator_plots 24 + +// +// Short ... + +// +// Open ... + +// +#define scOpenBufferIndex 0 +#define scOpenBufferPlotIndex 0 +double scOpenBuffer[]; + +// +#define scOpenColorBufferIndex 1 +double scOpenColorBuffer[]; + +// +#property indicator_label1 "X121_XDSR SC O" +#property indicator_type1 DRAW_COLOR_LINE +#property indicator_color1 clrGreen, clrRed +#property indicator_width1 1 + +// +// High ... +#define scHighBufferIndex 2 +#define scHighBufferPlotIndex 1 +double scHighBuffer[]; + +// +#property indicator_label2 "X121_XDSR SC H" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrAqua +#property indicator_width2 1 + +// +// Close ... + +// +#define scCloseBufferIndex 3 +#define scCloseBufferPlotIndex 2 +double scCloseBuffer[]; + +// +#define scCloseColorBufferIndex 4 +double scCloseColorBuffer[]; + +// +#property indicator_label3 "X121_XDSR SC C" +#property indicator_type3 DRAW_COLOR_LINE +#property indicator_color3 clrGreen, clrRed +#property indicator_width3 1 + +// +// Low ... +#define scLowBufferIndex 5 +#define scLowBufferPlotIndex 3 +double scLowBuffer[]; + +// +#property indicator_label4 "X121_XDSR SC L" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrMagenta +#property indicator_width4 1 + +// +// Medium ... + +// +// Open ... + +// +#define mcOpenBufferIndex 6 +#define mcOpenBufferPlotIndex 4 +double mcOpenBuffer[]; + +// +#define mcOpenColorBufferIndex 7 +double mcOpenColorBuffer[]; + +// +#property indicator_label5 "X121_XDSR MC O" +#property indicator_type5 DRAW_COLOR_LINE +#property indicator_color5 clrGreen, clrRed +#property indicator_width5 1 + +// +// High ... +#define mcHighBufferIndex 8 +#define mcHighBufferPlotIndex 5 +double mcHighBuffer[]; + +// +#property indicator_label6 "X121_XDSR MC H" +#property indicator_type6 DRAW_LINE +#property indicator_color6 clrAqua +#property indicator_width6 1 + +// +// Close ... + +// +#define mcCloseBufferIndex 9 +#define mcCloseBufferPlotIndex 6 +double mcCloseBuffer[]; + +// +#define mcCloseColorBufferIndex 10 +double mcCloseColorBuffer[]; + +// +#property indicator_label7 "X121_XDSR MC C" +#property indicator_type7 DRAW_COLOR_LINE +#property indicator_color7 clrGreen, clrRed +#property indicator_width7 1 + +// +// Low ... +#define mcLowBufferIndex 11 +#define mcLowBufferPlotIndex 7 +double mcLowBuffer[]; + +// +#property indicator_label8 "X121_XDSR MC L" +#property indicator_type8 DRAW_LINE +#property indicator_color8 clrMagenta +#property indicator_width8 1 + +// +// Long ... + +// +// Open ... + +// +#define lcOpenBufferIndex 12 +#define lcOpenBufferPlotIndex 8 +double lcOpenBuffer[]; + +// +#define lcOpenColorBufferIndex 13 +double lcOpenColorBuffer[]; + +// +#property indicator_label9 "X121_XDSR LC O" +#property indicator_type9 DRAW_COLOR_LINE +#property indicator_color9 clrGreen, clrRed +#property indicator_width9 1 + +// +// High ... +#define lcHighBufferIndex 14 +#define lcHighBufferPlotIndex 9 +double lcHighBuffer[]; + +// +#property indicator_label10 "X121_XDSR LC H" +#property indicator_type10 DRAW_LINE +#property indicator_color10 clrAqua +#property indicator_width10 1 + +// +// Close ... + +// +#define lcCloseBufferIndex 15 +#define lcCloseBufferPlotIndex 10 +double lcCloseBuffer[]; + +// +#define lcCloseColorBufferIndex 16 +double lcCloseColorBuffer[]; + +// +#property indicator_label11 "X121_XDSR LC C" +#property indicator_type11 DRAW_COLOR_LINE +#property indicator_color11 clrGreen, clrRed +#property indicator_width11 1 + +// +// Low ... +#define lcLowBufferIndex 17 +#define lcLowBufferPlotIndex 11 +double lcLowBuffer[]; + +// +#property indicator_label12 "X121_XDSR LC L" +#property indicator_type12 DRAW_LINE +#property indicator_color12 clrMagenta +#property indicator_width12 1 + +// +// Hind ... + +// +// Open ... + +// +#define hcOpenBufferIndex 18 +#define hcOpenBufferPlotIndex 12 +double hcOpenBuffer[]; + +// +#define hcOpenColorBufferIndex 19 +double hcOpenColorBuffer[]; + +// +#property indicator_label13 "X121_XDSR HC O" +#property indicator_type13 DRAW_COLOR_LINE +#property indicator_color13 clrGreen, clrRed +#property indicator_width13 1 + +// +// High ... +#define hcHighBufferIndex 20 +#define hcHighBufferPlotIndex 13 +double hcHighBuffer[]; + +// +#property indicator_label14 "X121_XDSR HC H" +#property indicator_type14 DRAW_LINE +#property indicator_color14 clrAqua +#property indicator_width14 1 + +// +// Close ... + +// +#define hcCloseBufferIndex 21 +#define hcCloseBufferPlotIndex 14 +double hcCloseBuffer[]; + +// +#define hcCloseColorBufferIndex 22 +double hcCloseColorBuffer[]; + +// +#property indicator_label15 "X121_XDSR HC C" +#property indicator_type15 DRAW_COLOR_LINE +#property indicator_color15 clrGreen, clrRed +#property indicator_width15 1 + +// +// Low ... +#define hcLowBufferIndex 23 +#define hcLowBufferPlotIndex 15 +double hcLowBuffer[]; + +// +#property indicator_label16 "X121_XDSR HC L" +#property indicator_type16 DRAW_LINE +#property indicator_color16 clrMagenta +#property indicator_width16 1 + +// +// VARIABLES ... + +// +// Cycles Definitions ... +XMarketCycle sc; +XMarketCycle mc; +XMarketCycle lc; +XMarketCycle hc; + +// +// EVENT Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Initial Market Cycles ... + if (!InitMarketCycles()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + 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); + + // + // this counts Available Bars ... + int limit; + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total - 1 + : (rates_total - prev_calculated); + + // + // Main Loop ... + for (int i = limit; i >= 0 && !IsStopped(); i--) + { + // + // Calculate Buffers ... + CalculateBuffer(i); + } + + // + return rates_total; +} + +// +// CUSTOM Functions ... + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + // Short ... + IsValidCycle( + scMode, + scPeriod) + // + && + // + // Medium ... + IsValidCycle( + mcMode, + mcPeriod) + // + && + // + // Long ... + IsValidCycle( + lcMode, + lcPeriod) + // + && + // + // Hind ... + IsValidCycle( + hcMode, + hcPeriod) + // + ; + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // Short ... + + // + // High ... + + // + ArraySetAsSeries(scHighBuffer, true); + SetIndexBuffer(scHighBufferIndex, scHighBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(scHighBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(scHighBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(scHighBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Low ... + + // + ArraySetAsSeries(scLowBuffer, true); + SetIndexBuffer(scLowBufferIndex, scLowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(scLowBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(scLowBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(scLowBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Open ... + + // + ArraySetAsSeries(scOpenBuffer, true); + SetIndexBuffer(scOpenBufferIndex, scOpenBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(scOpenBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(scOpenBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(scOpenBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + ArraySetAsSeries(scOpenColorBuffer, true); + SetIndexBuffer(scOpenColorBufferIndex, scOpenColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Close ... + + ArraySetAsSeries(scCloseBuffer, true); + SetIndexBuffer(scCloseBufferIndex, scCloseBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(scCloseBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(scCloseBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(scCloseBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + ArraySetAsSeries(scCloseColorBuffer, true); + SetIndexBuffer(scCloseColorBufferIndex, scCloseColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Medium ... + + // + // High ... + + // + ArraySetAsSeries(mcHighBuffer, true); + SetIndexBuffer(mcHighBufferIndex, mcHighBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(mcHighBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(mcHighBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(mcHighBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Low ... + + // + ArraySetAsSeries(mcLowBuffer, true); + SetIndexBuffer(mcLowBufferIndex, mcLowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(mcLowBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(mcLowBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(mcLowBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Open ... + + // + ArraySetAsSeries(mcOpenBuffer, true); + SetIndexBuffer(mcOpenBufferIndex, mcOpenBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(mcOpenBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(mcOpenBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(mcOpenBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + ArraySetAsSeries(mcOpenColorBuffer, true); + SetIndexBuffer(mcOpenColorBufferIndex, mcOpenColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Close ... + + ArraySetAsSeries(mcCloseBuffer, true); + SetIndexBuffer(mcCloseBufferIndex, mcCloseBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(mcCloseBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(mcCloseBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(mcCloseBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + ArraySetAsSeries(mcCloseColorBuffer, true); + SetIndexBuffer(mcCloseColorBufferIndex, mcCloseColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Long ... + + // + // High ... + + // + ArraySetAsSeries(lcHighBuffer, true); + SetIndexBuffer(lcHighBufferIndex, lcHighBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(lcHighBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(lcHighBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(lcHighBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Low ... + + // + ArraySetAsSeries(lcLowBuffer, true); + SetIndexBuffer(lcLowBufferIndex, lcLowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(lcLowBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(lcLowBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(lcLowBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Open ... + + // + ArraySetAsSeries(lcOpenBuffer, true); + SetIndexBuffer(lcOpenBufferIndex, lcOpenBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(lcOpenBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(lcOpenBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(lcOpenBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + ArraySetAsSeries(lcOpenColorBuffer, true); + SetIndexBuffer(lcOpenColorBufferIndex, lcOpenColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Close ... + + ArraySetAsSeries(lcCloseBuffer, true); + SetIndexBuffer(lcCloseBufferIndex, lcCloseBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(lcCloseBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(lcCloseBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(lcCloseBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + ArraySetAsSeries(lcCloseColorBuffer, true); + SetIndexBuffer(lcCloseColorBufferIndex, lcCloseColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Hind ... + + // + // High ... + + // + ArraySetAsSeries(hcHighBuffer, true); + SetIndexBuffer(hcHighBufferIndex, hcHighBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(hcHighBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(hcHighBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(hcHighBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Low ... + + // + ArraySetAsSeries(hcLowBuffer, true); + SetIndexBuffer(hcLowBufferIndex, hcLowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(hcLowBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(hcLowBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(hcLowBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Open ... + + // + ArraySetAsSeries(hcOpenBuffer, true); + SetIndexBuffer(hcOpenBufferIndex, hcOpenBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(hcOpenBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(hcOpenBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(hcOpenBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + ArraySetAsSeries(hcOpenColorBuffer, true); + SetIndexBuffer(hcOpenColorBufferIndex, hcOpenColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Close ... + + ArraySetAsSeries(hcCloseBuffer, true); + SetIndexBuffer(hcCloseBufferIndex, hcCloseBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(hcCloseBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(hcCloseBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(hcCloseBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + ArraySetAsSeries(hcCloseColorBuffer, true); + SetIndexBuffer(hcCloseColorBufferIndex, hcCloseColorBuffer, INDICATOR_COLOR_INDEX); +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +void CalculateBuffer(const int barIndex) +{ + // + // First Update Market Cycles ... + UpdateMarketCycles(barIndex); + + // + double bullishColorIDX = 0; + double bearishColorIDX = 1; + + // + // Short ... + int scBarIndex = sc.GetBarIndex(barIndex); + XOHCL scBar1 = sc.GetBar(scBarIndex + 1); + + // + bool isSCBar1Bullish = scBar1.open < scBar1.close; + + // + scOpenBuffer[barIndex] = scBar1.open; + scHighBuffer[barIndex] = scBar1.high; + scCloseBuffer[barIndex] = scBar1.close; + scLowBuffer[barIndex] = scBar1.low; + + // + scOpenColorBuffer[barIndex] = + isSCBar1Bullish + ? bullishColorIDX + : bearishColorIDX; + + // + scCloseColorBuffer[barIndex] = + isSCBar1Bullish + ? bullishColorIDX + : bearishColorIDX; + + // + // Medium ... + int mcBarIndex = mc.GetBarIndex(barIndex); + XOHCL mcBar1 = mc.GetBar(mcBarIndex + 1); + + // + bool isMCBar1Bullish = mcBar1.open < mcBar1.close; + + // + mcOpenBuffer[barIndex] = mcBar1.open; + mcHighBuffer[barIndex] = mcBar1.high; + mcCloseBuffer[barIndex] = mcBar1.close; + mcLowBuffer[barIndex] = mcBar1.low; + + // + mcOpenColorBuffer[barIndex] = + isMCBar1Bullish + ? bullishColorIDX + : bearishColorIDX; + + // + mcCloseColorBuffer[barIndex] = + isMCBar1Bullish + ? bullishColorIDX + : bearishColorIDX; + + // + // Long ... + int lcBarIndex = lc.GetBarIndex(barIndex); + XOHCL lcBar1 = lc.GetBar(lcBarIndex + 1); + + // + bool isLCBar1Bullish = lcBar1.open < lcBar1.close; + + // + lcOpenBuffer[barIndex] = lcBar1.open; + lcHighBuffer[barIndex] = lcBar1.high; + lcCloseBuffer[barIndex] = lcBar1.close; + lcLowBuffer[barIndex] = lcBar1.low; + + // + lcOpenColorBuffer[barIndex] = + isLCBar1Bullish + ? bullishColorIDX + : bearishColorIDX; + + // + lcCloseColorBuffer[barIndex] = + isLCBar1Bullish + ? bullishColorIDX + : bearishColorIDX; + + // + // Hind ... + int hcBarIndex = hc.GetBarIndex(barIndex); + XOHCL hcBar1 = hc.GetBar(hcBarIndex + 1); + + // + bool isHCBar1Bullish = hcBar1.open < hcBar1.close; + + // + hcOpenBuffer[barIndex] = hcBar1.open; + hcHighBuffer[barIndex] = hcBar1.high; + hcCloseBuffer[barIndex] = hcBar1.close; + hcLowBuffer[barIndex] = hcBar1.low; + + // + hcOpenColorBuffer[barIndex] = + isHCBar1Bullish + ? bullishColorIDX + : bearishColorIDX; + + // + hcCloseColorBuffer[barIndex] = + isHCBar1Bullish + ? bullishColorIDX + : bearishColorIDX; +} + +// +// TOOLS ... + +// +// Initial Market Cycles ... +bool InitMarketCycles() +{ + // + bool result = false; + + // + // Short ... + sc.method = scMode; + sc.period = scPeriod; + result = sc.Init( + _Symbol, + _Period, + X_MARKET_CYCLE_SHORT); + if (!result) + { + return result; + } + + // + // Medium ... + mc.method = mcMode; + mc.period = mcPeriod; + result = mc.Init( + _Symbol, + _Period, + X_MARKET_CYCLE_MEDIUM); + if (!result) + { + return result; + } + + // + // Long ... + lc.method = lcMode; + lc.period = lcPeriod; + result = lc.Init( + _Symbol, + _Period, + X_MARKET_CYCLE_LONG); + if (!result) + { + return result; + } + + // + // Hind ... + hc.method = hcMode; + hc.period = hcPeriod; + result = hc.Init( + _Symbol, + _Period, + X_MARKET_CYCLE_HIND); + if (!result) + { + return result; + } + + // + return result; +} + +// +// Update Market Cycles ... +bool UpdateMarketCycles(int barIndex) +{ + // + bool result = false; + + // + // Short ... + result = sc.Update(barIndex); + if (!result) + { + return result; + } + + // + // Medium ... + result = mc.Update(barIndex); + if (!result) + { + return result; + } + + // + // Long ... + result = lc.Update(barIndex); + if (!result) + { + return result; + } + + // + // Hind ... + result = hc.Update(barIndex); + if (!result) + { + return result; + } + + // + return result; +} diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xich.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xich.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xich.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xich.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xich.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xich.mq5 new file mode 100644 index 0000000..724aff6 --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xich.mq5 @@ -0,0 +1,836 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121_XICH +// Description: Ichimoku Kinko Hyo ... +// +// +// 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_XICH Indicator" +#property strict + +// +// START Constants ... +// + +// +// Indicator Short Name ... +#define ShortName "X121_XICH" + +// +// Ichimoku Golden Numbers ... +enum ENUM_X_ICHIMOKU_GOLDEN_NUMBERS +{ + X_ICH_BASE = 9, + X_ICH_GOLDEN = 17, + X_ICH_CYCLE = 26, + X_ICH_PERIOD = 35, + X_ICH_STAR = 45, + X_ICH_MED = 52, + X_ICH_LONG = 63, + X_ICH_FULL = 72 +}; + +// +// Ichimoku Lines Calculator Mode ... +enum ENUM_X_ICHIMOKU_CALCULATION_MODE +{ + // + X_XICH_HH_LL_MODE = 1, // Highest High and Lowest Low + X_XICH_HO_LC_MODE = 2, // Highest Open and Lowest Close +}; + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +// ICHIMOKU Kinko Hyo ... + +// +// TENKANSEN ... +input group "Tenkan Sen"; +input int tenkanSenLength = 9; // Length +input ENUM_X_ICHIMOKU_CALCULATION_MODE tenkanSenMode = X_XICH_HH_LL_MODE; // Calculation Mode + +// +// KIJUNSEN ... +input group "Kijun Sen"; +input int kijunSenLength = 26; // Length +input ENUM_X_ICHIMOKU_CALCULATION_MODE kijunSenMode = X_XICH_HH_LL_MODE; // Calculation Mode + +// +// SENKOUSPANB ... +input group "Senkou Span B"; +input int senkouSpanBLength = 52; // Length +input ENUM_X_ICHIMOKU_CALCULATION_MODE senkouSpanBMode = X_XICH_HH_LL_MODE; // Calculation Mode + +// +// CHIKOUSPAN ... +input group "Chikou Span"; +input ENUM_APPLIED_PRICE chikuoSpanAppliedTo = PRICE_CLOSE; // Price Type + +// +input group "Presentation"; +input bool showTenkanSen = true; // Show Tenkan Sen +input bool showKijunSen = true; // Show Kijun Sen +input bool showKijunSenPlus = false; // Show Kijun Sen + +input bool showKijunSenNegative = false; // Show Kijun Sen - +input bool showChikouSpan = true; // Show Chikou Span +input bool showSenkouSpanA = true; // Show Senkou Span A +input bool showSenkouSpanB = true; // Show Senkou Span B +input bool showKumo = true; // Show Kumo +input bool shiftKumo = true; // Shift Kumo to Future + +// +// END Inputs ... +// + +// +// START Includes and Imports ... +// + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Includes and Imports ... +// + +// +// START Buffers ... +// +#property indicator_chart_window + +// +#property indicator_buffers 15 +#property indicator_plots 8 + +// +// PLOTTED Buffers ... + +// +// ICHIMOKU ... + +// +// TENKANSEN ... + +// +#define tenkanSenBufferIndex 0 +double tenkanSenBuffer[]; + +// +#property indicator_label1 "X121_XICH TK" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrBrown +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +// +// KIJUNSEN ... + +// +#define kijunSenBufferIndex 1 +double kijunSenBuffer[]; + +// +#property indicator_label2 "X121_XICH KJ" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrDodgerBlue +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +// +#define kijunSenPlusBufferIndex 2 +double kijunSenPlusBuffer[]; + +// +#property indicator_label3 "X121_XICH KJ+" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrMediumTurquoise +#property indicator_style3 STYLE_DOT +#property indicator_width3 1 + +// +#define kijunSenNegativeBufferIndex 3 +double kijunSenNegativeBuffer[]; + +// +#property indicator_label4 "X121_XICH KJ-" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrDarkSeaGreen +#property indicator_style4 STYLE_DOT +#property indicator_width4 1 + +// +// CHIKOUSPAN ... + +// +#define chikouSpanBufferIndex 4 +double chikouSpanBuffer[]; + +// +#property indicator_label5 "X121_XICH CS" +#property indicator_type5 DRAW_LINE +#property indicator_color5 clrDarkGreen +#property indicator_style5 STYLE_SOLID +#property indicator_width5 1 + +// +#define senkouABufferIndex 5 +double senkouABuffer[]; + +// +#property indicator_label6 "X121_XICH SSA" +#property indicator_type6 DRAW_LINE +#property indicator_color6 clrLightGray +#property indicator_style6 STYLE_DASHDOTDOT +#property indicator_width6 1 + +// +#define senkouBBufferIndex 6 +double senkouBBuffer[]; + +// +#property indicator_label7 "X121_XICH SSB" +#property indicator_type7 DRAW_LINE +#property indicator_color7 clrLightGray +#property indicator_style7 STYLE_DASHDOTDOT +#property indicator_width7 1 + +// +// KUMO ... + +// +// SENKOUSPANA ... + +// +#define senkouSpanABufferIndex 7 +double senkouSpanABuffer[]; + +// +// SENKOUSPANB ... + +// +#define senkouSpanBBufferIndex 8 +double senkouSpanBBuffer[]; + +// +// KUMOCLOUD ... + +// +#define kumoBufferIndex 7 + +// +#property indicator_label8 "X121_XICH Kumo" +#property indicator_type8 DRAW_FILLING +#property indicator_color8 clrAqua, clrMagenta +#property indicator_style8 STYLE_SOLID +#property indicator_width8 1 + +// +// DATA Buffers ... + +// +#define dTenkanBufferIndex 9 +double dTenkanBuffer[]; + +// +#define dKijunBufferIndex 10 +double dKijunBuffer[]; + +// +#define dChikouBufferIndex 11 +double dChikouBuffer[]; + +// +#define dSSABufferIndex 12 +double dSSABuffer[]; + +// +#define dSSBBufferIndex 13 +double dSSBBuffer[]; + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; +int mHandler; + +// +ENUM_SERIESMODE mTenkanSenTopMode = NULL; +ENUM_SERIESMODE mTenkanSenBottomMode = NULL; + +// +ENUM_SERIESMODE mKijunSenTopMode = NULL; +ENUM_SERIESMODE mKijunSenBottomMode = NULL; + +// +ENUM_SERIESMODE mSenkouSpanBTopMode = NULL; +ENUM_SERIESMODE mSenkouSpanBBottomMode = NULL; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + 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(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Init Handler ... + mHandler = iIchimoku( + _Symbol, + _Period, + tenkanSenLength, + kijunSenLength, + senkouSpanBLength); + if (mHandler == INVALID_HANDLE) + { + return INIT_FAILED; + } + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 + + // + IndicatorRelease(mHandler); +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + 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); + + // + // this counts Available Bars ... + int limit; + + // + // Check Calculated Bars ... + int ichCalculatedBars = BarsCalculated(mHandler); + if (ichCalculatedBars < maxLength) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + int copiedTenkans = CopyBuffer(mHandler, TENKANSEN_LINE, 0, limit, dTenkanBuffer); + int copiedKijuns = CopyBuffer(mHandler, KIJUNSEN_LINE, 0, limit, dKijunBuffer); + int copiedChikous = CopyBuffer(mHandler, CHIKOUSPAN_LINE, 0, limit, dChikouBuffer); + int copiedSSAs = CopyBuffer(mHandler, SENKOUSPANA_LINE, 0, limit, dSSABuffer); + int copiedSSBs = CopyBuffer(mHandler, SENKOUSPANB_LINE, 0, limit, dSSBBuffer); + if ( + copiedSSAs < 0 || + copiedSSBs < 0 || + copiedKijuns < 0 || + copiedTenkans < 0 || + copiedChikous < 0) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + CalculateBuffers(i); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = + // + (tenkanSenLength > 2 && + kijunSenLength > tenkanSenLength && + senkouSpanBLength > kijunSenLength) + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // Ichimoku ... + result = MathMax(result, tenkanSenLength); + result = MathMax(result, kijunSenLength); + result = MathMax(result, senkouSpanBLength); + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // ICHIMOKU ... + + // + // TENKANSEN ... + + // + ENUM_DRAW_TYPE tenkanSenDrawType = showTenkanSen ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(tenkanSenBuffer, true); + SetIndexBuffer(tenkanSenBufferIndex, tenkanSenBuffer, INDICATOR_DATA); + PlotIndexSetInteger(tenkanSenBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(tenkanSenBufferIndex, PLOT_SHOW_DATA, showTenkanSen); + PlotIndexSetInteger(tenkanSenBufferIndex, PLOT_DRAW_TYPE, tenkanSenDrawType); + + // + // KIJUNSEN ... + + // + ENUM_DRAW_TYPE kijunSenDrawType = showKijunSen ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(kijunSenBuffer, true); + SetIndexBuffer(kijunSenBufferIndex, kijunSenBuffer, INDICATOR_DATA); + PlotIndexSetInteger(kijunSenBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(kijunSenBufferIndex, PLOT_SHOW_DATA, showKijunSen); + PlotIndexSetInteger(kijunSenBufferIndex, PLOT_DRAW_TYPE, kijunSenDrawType); + + // + // KIJUNSEN Plus ... + + // + ENUM_DRAW_TYPE kijunSenPlusDrawType = showKijunSenPlus ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(kijunSenPlusBuffer, true); + SetIndexBuffer(kijunSenPlusBufferIndex, kijunSenPlusBuffer, INDICATOR_DATA); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_SHIFT, kijunSenLength); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_DRAW_TYPE, kijunSenPlusDrawType); + + // + // KIJUNSEN Negative ... + + // + ENUM_DRAW_TYPE kijunSenNegativeDrawType = showKijunSenNegative ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(kijunSenNegativeBuffer, true); + SetIndexBuffer(kijunSenNegativeBufferIndex, kijunSenNegativeBuffer, INDICATOR_DATA); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_SHIFT, -kijunSenLength); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_DRAW_TYPE, kijunSenNegativeDrawType); + + // + // CHIKOUSPAN ... + + // + ENUM_DRAW_TYPE chikouSpanDrawType = showChikouSpan ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(chikouSpanBuffer, true); + SetIndexBuffer(chikouSpanBufferIndex, chikouSpanBuffer, INDICATOR_DATA); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_SHIFT, -kijunSenLength); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_SHOW_DATA, showChikouSpan); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_DRAW_TYPE, chikouSpanDrawType); + + // + // SENKOUSPAN A and B ... + int shiftSize = shiftKumo ? kijunSenLength : 0; + + // + // SENKOUSPANA ... + ENUM_DRAW_TYPE senkouSpanADrawType = showSenkouSpanA ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(senkouABuffer, true); + SetIndexBuffer(senkouABufferIndex, senkouABuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouABufferIndex, PLOT_SHIFT, shiftSize); + PlotIndexSetInteger(senkouABufferIndex, PLOT_SHOW_DATA, showSenkouSpanA); + PlotIndexSetInteger(senkouABufferIndex, PLOT_DRAW_TYPE, senkouSpanADrawType); + + // + // SENKOUSPANB ... + ENUM_DRAW_TYPE senkouSpanBDrawType = showSenkouSpanB ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(senkouBBuffer, true); + SetIndexBuffer(senkouBBufferIndex, senkouBBuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouBBufferIndex, PLOT_SHIFT, shiftSize); + PlotIndexSetInteger(senkouBBufferIndex, PLOT_SHOW_DATA, showSenkouSpanB); + PlotIndexSetInteger(senkouBBufferIndex, PLOT_DRAW_TYPE, senkouSpanBDrawType); + + // + // KUMO ... + + // + // SENKOUSPANA ... + ArraySetAsSeries(senkouSpanABuffer, true); + SetIndexBuffer(senkouSpanABufferIndex, senkouSpanABuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouSpanABufferIndex, PLOT_DRAW_BEGIN, maxLength); + + // + // SENKOUSPANB ... + ArraySetAsSeries(senkouSpanBBuffer, true); + SetIndexBuffer(senkouSpanBBufferIndex, senkouSpanBBuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouSpanBBufferIndex, PLOT_DRAW_BEGIN, maxLength); + + // + // KUMO ... + + // + ENUM_DRAW_TYPE kumoDrawType = showKumo ? DRAW_FILLING : DRAW_NONE; + + // + PlotIndexSetInteger(kumoBufferIndex, PLOT_SHIFT, shiftSize); + PlotIndexSetInteger(kumoBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(kumoBufferIndex, PLOT_DRAW_TYPE, kumoDrawType); + + // + // DATA Buffers ... + + // + // D Tenkan ... + ArraySetAsSeries(dTenkanBuffer, true); + SetIndexBuffer(dTenkanBufferIndex, dTenkanBuffer, INDICATOR_CALCULATIONS); + + // + // D Kijun ... + ArraySetAsSeries(dKijunBuffer, true); + SetIndexBuffer(dKijunBufferIndex, dKijunBuffer, INDICATOR_CALCULATIONS); + + // + // D Chikou ... + ArraySetAsSeries(dChikouBuffer, true); + SetIndexBuffer(dChikouBufferIndex, dChikouBuffer, INDICATOR_CALCULATIONS); + + // + // D SSA ... + ArraySetAsSeries(dSSABuffer, true); + SetIndexBuffer(dSSABufferIndex, dSSABuffer, INDICATOR_CALCULATIONS); + + // + // D SSB ... + ArraySetAsSeries(dSSBBuffer, true); + SetIndexBuffer(dSSBBufferIndex, dSSBBuffer, INDICATOR_CALCULATIONS); +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index // Selected Bar Index +) +{ + // + // ICHIMOKU ... + + // + double topValue; + double bottomValue; + + // + // TENKANSEN ... + + // + // Extract Tenkan Sen Top/Bottom Calculation Mode based on User Input ... + if (mTenkanSenTopMode == NULL || mTenkanSenBottomMode == NULL) + { + // + switch (tenkanSenMode) + { + // + case X_XICH_HH_LL_MODE: + // + mTenkanSenTopMode = MODE_HIGH; + mTenkanSenBottomMode = MODE_LOW; + break; + + // + case X_XICH_HO_LC_MODE: + // + mTenkanSenTopMode = MODE_OPEN; + mTenkanSenBottomMode = MODE_CLOSE; + break; + } + } + + // + // Calculate Top ... + topValue = GetHighestHigh( + _Symbol, + _Period, + mTenkanSenTopMode, + tenkanSenLength, + bar_index); + + // + // Calculate Bottom ... + bottomValue = GetLowestLow( + _Symbol, + _Period, + mTenkanSenBottomMode, + tenkanSenLength, + bar_index); + + // + double tenkanSenValue = (topValue + bottomValue) / 2; + tenkanSenBuffer[bar_index] = tenkanSenValue; + + // + // KIJUNSEN ... + + // + // Extract Kijun Sen Top/Bottom Calculation Mode based on User Input ... + if (mKijunSenTopMode == NULL || mKijunSenBottomMode == NULL) + { + // + switch (kijunSenMode) + { + // + case X_XICH_HH_LL_MODE: + // + mKijunSenTopMode = MODE_HIGH; + mKijunSenBottomMode = MODE_LOW; + break; + + // + case X_XICH_HO_LC_MODE: + // + mKijunSenTopMode = MODE_OPEN; + mKijunSenBottomMode = MODE_CLOSE; + break; + } + } + + // + // Calculate Top ... + topValue = GetHighestHigh( + _Symbol, + _Period, + mKijunSenTopMode, + kijunSenLength, + bar_index); + + // + // Calculate Bottom ... + bottomValue = GetLowestLow( + _Symbol, + _Period, + mKijunSenBottomMode, + kijunSenLength, + bar_index); + + // + double kijunSenValue = (topValue + bottomValue) / 2; + kijunSenBuffer[bar_index] = kijunSenValue; + + // + kijunSenPlusBuffer[bar_index] = kijunSenValue; + kijunSenNegativeBuffer[bar_index] = kijunSenValue; + + // + // CHIKOUSPAN ... + double chikouSpanValue = GetAppliedPrice( + bar_index, + chikuoSpanAppliedTo); + chikouSpanBuffer[bar_index] = chikouSpanValue; + + // + // KUMO ... + + // + // SENKOUSPANA ... + double senkouSpanAValue = (tenkanSenValue + kijunSenValue) / 2; + senkouABuffer[bar_index] = senkouSpanAValue; + senkouSpanABuffer[bar_index] = senkouSpanAValue; + + // + // SENKOUSPANB ... + + // + // Extract Senkou Span B Top/Bottom Calculation Mode based on User Input ... + if (mSenkouSpanBTopMode == NULL || mSenkouSpanBBottomMode == NULL) + { + // + switch (senkouSpanBMode) + { + // + case X_XICH_HH_LL_MODE: + // + mSenkouSpanBTopMode = MODE_HIGH; + mSenkouSpanBBottomMode = MODE_LOW; + break; + + // + case X_XICH_HO_LC_MODE: + // + mSenkouSpanBTopMode = MODE_OPEN; + mSenkouSpanBBottomMode = MODE_CLOSE; + break; + } + } + + // + // Calculate Top ... + topValue = GetHighestHigh( + _Symbol, + _Period, + mSenkouSpanBTopMode, + senkouSpanBLength, + bar_index); + + // + // Calculate Bottom ... + bottomValue = GetLowestLow( + _Symbol, + _Period, + mSenkouSpanBBottomMode, + senkouSpanBLength, + bar_index); + + // + double senkouSpanBValue = (topValue + bottomValue) / 2; + senkouBBuffer[bar_index] = senkouSpanBValue; + senkouSpanBBuffer[bar_index] = senkouSpanBValue; +} + +// +// END Functions ... +// diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xman.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xman.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xman.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xman.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xman.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xman.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xman.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xman.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xosc.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xosc.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xosc.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xosc.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xosc.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xosc.mq5 new file mode 100644 index 0000000..0f0f9ef --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xosc.mq5 @@ -0,0 +1,721 @@ +////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121_XOSC +// Description: provides some oscillator values +// as empty 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 X121_XAMA Indicator" +#property strict + +// +// START Constants ... +// + +#define ShortName "X121_XOSC" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +// ATR ... +input group "ATR"; +input int atrLength = 14; // Length + +// +// RVI ... +// The buffer numbers are the following: 0 - MAIN_LINE, 1 - SIGNAL_LINE. +input group "RVI"; +input int rviLength = 10; // Length + +// +// BULLPOWER ... +input group "Bulls Power"; +input int bullpLength = 13; // Length + +// +// BEARPOWER ... +input group "Bears Power"; +input int bearpLength = 13; // Length + +// +// VOLUME ... +input group "Volumes"; +input ENUM_APPLIED_VOLUME volumeAppliedTo = VOLUME_TICK; // Applied To + +// +// RSI ... +input group "RSI"; +input int rsiLength = 14; // Length +input ENUM_APPLIED_PRICE rsiAppliedTo = PRICE_CLOSE; // Applied To + +// +// CCI ... +input group "CCI"; +input int cciLength = 14; // Length +input ENUM_APPLIED_PRICE cciAppliedTo = PRICE_TYPICAL; // Applied To + +// +// STDDEV ... +input group "Standard Deviation"; +input int stddevLength = 20; // Length +input int stddevShift = 0; // Shift +input ENUM_MA_METHOD stddevMethod = MODE_SMA; // Mode +input ENUM_APPLIED_PRICE stddevAppliedTo = PRICE_CLOSE; // AppliedTo + +// +// MOMENTUM ... +input group "Momentum"; +input int momentumLength = 14; // Length +input ENUM_APPLIED_PRICE momentumAppliedTo = PRICE_CLOSE; // Applied To + +// +// SAR ... +input group "SAR"; +input double sarStep = 0.02; // Step +input double sarMaximum = 0.2; // Maximum + +// +// MACD ... +// The buffer numbers are the following: 0 - MAIN_LINE, 1 - SIGNAL_LINE. +input group "MACD"; +input int macdFastLength = 12; // Fast Length +input int macdSlowLength = 26; // Slow Length +input int macdSignaLength = 9; // Signal Length +input ENUM_APPLIED_PRICE macdAppliedTo = PRICE_CLOSE; // Applied To + +// +// STOCHASTIC ... +// The buffer numbers: 0 - MAIN_LINE, 1 - SIGNAL_LINE. +input group "Stochastic"; +input int stochKLength = 5; // K Length +input int stochDLength = 3; // D Length +input int stochSlowing = 3; // Slowing +input ENUM_MA_METHOD stochMaMethod = MODE_SMA; // Ma Method +input ENUM_STO_PRICE stochMode = STO_LOWHIGH; // Calculation Mode + +// +// END Inputs ... +// + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 15 +#property indicator_plots 0 + +// +// ATR ... +#define atrBufferIndex 0 +double atrBuffer[]; + +// +// RVI ... +#define rviMainBufferIndex 1 +#define rviSignalBufferIndex 2 +double rviMainBuffer[]; +double rviSignalBuffer[]; + +// +// BULLPOWER ... +#define bullPBufferIndex 3 +double bullPBuffer[]; + +// +// BEARPOWER ... +#define bearPBufferIndex 4 +double bearPBuffer[]; + +// +// VOLUME ... +#define volumeBufferIndex 5 +double volumeBuffer[]; + +// +// RSI ... +#define rsiBufferIndex 6 +double rsiBuffer[]; + +// +// CCI ... +#define cciBufferIndex 7 +double cciBuffer[]; + +// +// MOMENTUM ... +#define momentumBufferIndex 8 +double momentumBuffer[]; + +// +// SAR ... +#define sarBufferIndex 9 +double sarBuffer[]; + +// +// MACD ... +#define macdMainBufferIndex 10 +#define macdSignalBufferIndex 11 +double macdMainBuffer[]; +double macdSignalBuffer[]; + +// +// STOCHASTIC ... +#define stochMainBufferIndex 12 +#define stochSignalBufferIndex 13 +double stochMainBuffer[]; +double stochSignalBuffer[]; + +// +// STANDARDDEVIATION ... +#define stddevBufferIndex 14 +double stddevBuffer[]; + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +int atrHandler = INVALID_HANDLE; +int rviHandler = INVALID_HANDLE; +int bullPHandler = INVALID_HANDLE; +int bearPHandler = INVALID_HANDLE; +int volumeHandler = INVALID_HANDLE; +int rsiHandler = INVALID_HANDLE; +int cciHandler = INVALID_HANDLE; +int momentumHandler = INVALID_HANDLE; +int sarHandler = INVALID_HANDLE; +int macdHandler = INVALID_HANDLE; +int stochHandler = INVALID_HANDLE; +int stddevHandler = INVALID_HANDLE; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + 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(); + + // + // Initializing Handlers ... + + // + // ATR ... + atrHandler = iATR( + _Symbol, + _Period, + atrLength); + + // + // RVI ... + rviHandler = iRVI( + _Symbol, + _Period, + rviLength); + + // + // BULLSPOWER ... + bullPHandler = iBullsPower( + _Symbol, + _Period, + bullpLength); + + // + // BEARSPOWER ... + bearPHandler = iBearsPower( + _Symbol, + _Period, + bullpLength); + + // + // VOLUMES ... + volumeHandler = iVolumes( + _Symbol, + _Period, + volumeAppliedTo); + + // + // RSI ... + rsiHandler = iRSI( + _Symbol, + _Period, + rsiLength, + rsiAppliedTo); + + // + // CCI ... + cciHandler = iCCI( + _Symbol, + _Period, + cciLength, + cciAppliedTo); + + // + // MOMENTUM ... + momentumHandler = iMomentum( + _Symbol, + _Period, + momentumLength, + momentumAppliedTo); + + // + // SAR ... + sarHandler = iSAR( + _Symbol, + _Period, + sarStep, + sarMaximum); + + // + // MACD ... + macdHandler = iMACD( + _Symbol, + _Period, + macdFastLength, + macdSlowLength, + macdSignaLength, + macdAppliedTo); + + // + // STOCHASTIC ... + stochHandler = iStochastic( + _Symbol, + _Period, + stochKLength, + stochDLength, + stochSlowing, + stochMaMethod, + stochMode); + + // + // STANDARDDEVIATION ... + stddevHandler = iStdDev( + _Symbol, + _Period, + stddevLength, + stddevShift, + stddevMethod, + stddevAppliedTo); + + // + bool isAllHandlersInit = + // + atrHandler != INVALID_HANDLE && + rviHandler != INVALID_HANDLE && + bullPHandler != INVALID_HANDLE && + bearPHandler != INVALID_HANDLE && + volumeHandler != INVALID_HANDLE && + rsiHandler != INVALID_HANDLE && + cciHandler != INVALID_HANDLE && + momentumHandler != INVALID_HANDLE && + sarHandler != INVALID_HANDLE && + macdHandler != INVALID_HANDLE && + stochHandler != INVALID_HANDLE && + stddevHandler != INVALID_HANDLE + // + ; + if (!isAllHandlersInit) + { + return INIT_FAILED; + } + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 + + // + // Here we can handle De Initialization Reasons ... + IndicatorRelease(atrHandler); + IndicatorRelease(rviHandler); + IndicatorRelease(bullPHandler); + IndicatorRelease(bearPHandler); + IndicatorRelease(volumeHandler); + IndicatorRelease(rsiHandler); + IndicatorRelease(cciHandler); + IndicatorRelease(momentumHandler); + IndicatorRelease(sarHandler); + IndicatorRelease(macdHandler); + IndicatorRelease(stochHandler); + IndicatorRelease(stddevHandler); +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + 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); + + // + // this counts Available Bars ... + int limit; + + // + // Check Calculated Bars ... + int atrCalculatedBars = BarsCalculated(atrHandler); + int rviCalculatedBars = BarsCalculated(rviHandler); + int bullPCalculatedBars = BarsCalculated(bullPHandler); + int bearPCalculatedBars = BarsCalculated(bearPHandler); + int volumeCalculatedBars = BarsCalculated(volumeHandler); + int rsiCalculatedBars = BarsCalculated(rsiHandler); + int cciCalculatedBars = BarsCalculated(cciHandler); + int momentumCalculatedBars = BarsCalculated(momentumHandler); + int sarCalculatedBars = BarsCalculated(sarHandler); + int macdCalculatedBars = BarsCalculated(macdHandler); + int stochCalculatedBars = BarsCalculated(stochHandler); + int stddevCalculatedBars = BarsCalculated(stddevHandler); + + // + bool isCalculatedBarsPassed = + // + atrCalculatedBars >= maxLength && + rviCalculatedBars >= maxLength && + bullPCalculatedBars >= maxLength && + bearPCalculatedBars >= maxLength && + volumeCalculatedBars >= maxLength && + rsiCalculatedBars >= maxLength && + cciCalculatedBars >= maxLength && + momentumCalculatedBars >= maxLength && + sarCalculatedBars >= maxLength && + macdCalculatedBars >= maxLength && + stochCalculatedBars >= maxLength && + stddevCalculatedBars >= maxLength + // + ; + if (!isCalculatedBarsPassed) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + int atrCopiedItems = CopyBuffer(atrHandler, 0, 0, limit, atrBuffer); + int rviMainCopiedItems = CopyBuffer(rviHandler, MAIN_LINE, 0, limit, rviMainBuffer); + int rviSignalCopiedItems = CopyBuffer(rviHandler, SIGNAL_LINE, 0, limit, rviSignalBuffer); + int bullPCopiedItems = CopyBuffer(bullPHandler, 0, 0, limit, bullPBuffer); + int bearPCopiedItems = CopyBuffer(bearPHandler, 0, 0, limit, bearPBuffer); + int volumeCopiedItems = CopyBuffer(volumeHandler, 0, 0, limit, volumeBuffer); + int rsiCopiedItems = CopyBuffer(rsiHandler, 0, 0, limit, rsiBuffer); + int cciCopiedItems = CopyBuffer(cciHandler, 0, 0, limit, cciBuffer); + int momentumCopiedItems = CopyBuffer(momentumHandler, 0, 0, limit, momentumBuffer); + int sarCopiedItems = CopyBuffer(sarHandler, 0, 0, limit, sarBuffer); + int macdMainCopiedItems = CopyBuffer(macdHandler, MAIN_LINE, 0, limit, macdMainBuffer); + int macdSignalCopiedItems = CopyBuffer(macdHandler, SIGNAL_LINE, 0, limit, macdSignalBuffer); + int stochMainCopiedItems = CopyBuffer(stochHandler, MAIN_LINE, 0, limit, stochMainBuffer); + int stocSignalhCopiedItems = CopyBuffer(stochHandler, SIGNAL_LINE, 0, limit, stochSignalBuffer); + int stddevCopiedItems = CopyBuffer(stddevHandler, 0, 0, limit, stddevBuffer); + + // + bool isCopiedBarsPassed = + // + atrCopiedItems > 0 && + rviMainCopiedItems > 0 && + rviSignalCopiedItems > 0 && + bullPCopiedItems > 0 && + bearPCopiedItems > 0 && + volumeCopiedItems > 0 && + rsiCopiedItems > 0 && + cciCopiedItems > 0 && + momentumCopiedItems > 0 && + sarCopiedItems > 0 && + macdMainCopiedItems > 0 && + macdSignalCopiedItems > 0 && + stochMainCopiedItems > 0 && + stocSignalhCopiedItems > 0 && + stddevCopiedItems > 0 + // + ; + if (!isCopiedBarsPassed) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + // Do Buffers Calculation ... + // HERE We Do Not anything ... + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + // Validate Args ... + result = + // + atrLength >= 2 && + rviLength >= 2 && + bullpLength >= 2 && + bearpLength >= 2 && + rsiLength >= 2 && + cciLength >= 2 && + momentumLength >= 2 && + sarStep > 0 && + sarStep < sarMaximum && + macdFastLength >= 2 && + macdSlowLength > macdFastLength && + macdSignaLength >= 2 && + stochKLength >= 2 && + stochDLength >= 2 && + stochSlowing >= 2 && + stddevLength >= 2 && + stddevShift >= 0 + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(atrLength, rviLength); + result = MathMax(result, bullpLength); + result = MathMax(result, bearpLength); + result = MathMax(result, rsiLength); + result = MathMax(result, cciLength); + result = MathMax(result, momentumLength); + result = MathMax(result, macdFastLength); + result = MathMax(result, macdSlowLength); + result = MathMax(result, macdSignaLength); + result = MathMax(result, stochKLength); + result = MathMax(result, stochDLength); + result = MathMax(result, stochSlowing); + result = MathMax(result, stddevLength); + + // + return result; +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // DATA Buffers ... + + // + // ATR ... + ArraySetAsSeries(atrBuffer, true); + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + // RVI ... + + // + // Main ... + ArraySetAsSeries(rviMainBuffer, true); + SetIndexBuffer(rviMainBufferIndex, rviMainBuffer, INDICATOR_CALCULATIONS); + + // + // Signal ... + ArraySetAsSeries(rviSignalBuffer, true); + SetIndexBuffer(rviSignalBufferIndex, rviSignalBuffer, INDICATOR_CALCULATIONS); + + // + // BULLPOWER ... + ArraySetAsSeries(bullPBuffer, true); + SetIndexBuffer(bullPBufferIndex, bullPBuffer, INDICATOR_CALCULATIONS); + + // + // BEARPOWER ... + ArraySetAsSeries(bearPBuffer, true); + SetIndexBuffer(bearPBufferIndex, bearPBuffer, INDICATOR_CALCULATIONS); + + // + // VOLUME ... + ArraySetAsSeries(volumeBuffer, true); + SetIndexBuffer(volumeBufferIndex, volumeBuffer, INDICATOR_CALCULATIONS); + + // + // RSI ... + ArraySetAsSeries(rsiBuffer, true); + SetIndexBuffer(rsiBufferIndex, rsiBuffer, INDICATOR_CALCULATIONS); + + // + // CCI ... + ArraySetAsSeries(cciBuffer, true); + SetIndexBuffer(cciBufferIndex, cciBuffer, INDICATOR_CALCULATIONS); + + // + // MOMENTUM ... + ArraySetAsSeries(momentumBuffer, true); + SetIndexBuffer(momentumBufferIndex, momentumBuffer, INDICATOR_CALCULATIONS); + + // + // SAR ... + ArraySetAsSeries(sarBuffer, true); + SetIndexBuffer(sarBufferIndex, sarBuffer, INDICATOR_CALCULATIONS); + + // + // STANDARDDEVIATION ... + ArraySetAsSeries(stddevBuffer, true); + SetIndexBuffer(stddevBufferIndex, stddevBuffer, INDICATOR_CALCULATIONS); + + // + // MACD ... + + // + // Main ... + ArraySetAsSeries(macdMainBuffer, true); + SetIndexBuffer(macdMainBufferIndex, macdMainBuffer, INDICATOR_CALCULATIONS); + + // + // Signal ... + ArraySetAsSeries(macdSignalBuffer, true); + SetIndexBuffer(macdSignalBufferIndex, macdSignalBuffer, INDICATOR_CALCULATIONS); +} + +// +// END Functions ... +// diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xstr.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xstr.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xstr.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xstr.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xstr.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xstr.mq5 new file mode 100644 index 0000000..bca9597 --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xstr.mq5 @@ -0,0 +1,580 @@ +////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121_XSTR +// Description: Super Trend 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 X121_XAMA Indicator" +#property strict + +// +// START Constants ... +// + +#define ShortName "X121_XSTR" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +// Market ... +input group "ATR"; +input int atrLength = 14; // Length +input double atrMultiplier = 3.0; // Multiplier +input ENUM_APPLIED_PRICE atrAppliedTo = PRICE_MEDIAN; // Applied To + +// +// Presentation ... +input group "Presentation"; +input bool showTrends = true; // Show Trends +input bool fillTrends = true; // Fill Trends + +// +// END Inputs ... +// + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 9 +#property indicator_plots 2 + +// +#define fillUpBufferIndex 0 +double fillUpBuffer[]; + +#define fillDownBufferIndex 1 +double fillDownBuffer[]; + +// +#define fillingPlotBufferIndex 0 + +// +#property indicator_label1 "X121_XSTR Filling" +#property indicator_type1 DRAW_FILLING +#property indicator_color1 clrBisque, clrPaleGreen + +// +#define mainBufferIndex 2 +#define mainPlotBufferIndex 1 +double mainBuffer[]; + +// +#define mainColorBufferIndex 3 +double mainColorBuffer[]; + +// +#property indicator_label2 "X121_XSTR" +#property indicator_type2 DRAW_COLOR_LINE +#property indicator_color2 CLR_NONE, clrGreen, clrDarkRed +#property indicator_style2 STYLE_DOT + +// +// DATA Buffers ... + +// +#define atrBufferIndex 4 +double atrBuffer[]; + +// +#define trendBufferIndex 5 +double trendBuffer[]; + +// +#define upBufferIndex 6 +double upBuffer[]; + +// +#define downBufferIndex 7 +double downBuffer[]; + +// +#define priceBufferIndex 8 +double priceBuffer[]; + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +int atrHandler = INVALID_HANDLE; + +// +int changeOfTrend; +int startBearishTrend; +int startBullishTrend; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + 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(); + + // + atrHandler = iATR( + _Symbol, + _Period, + atrLength); + if (atrHandler == INVALID_HANDLE) + { + return INIT_FAILED; + } + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 + + // + // Here we can handle De Initialization Reasons ... + IndicatorRelease(atrHandler); +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + const int &spread[]) +{ + // + int numOfRequiredAtrs; + if (prev_calculated > rates_total || prev_calculated < 0) + { + numOfRequiredAtrs = rates_total; + } + else + { + // + numOfRequiredAtrs = rates_total - prev_calculated; + if (prev_calculated > 0) + { + numOfRequiredAtrs++; + } + } + + // + // Checking for stop ... + if (IsStopped()) + { + return 0; + } + + // + // Check Number of items Copy or not ... + int copiedATRs = CopyBuffer(atrHandler, 0, 0, numOfRequiredAtrs, atrBuffer); + if (copiedATRs <= 0) + { + return 0; + } + + // + int limit; + + // + // checking for the limit start of calculation of an indicator ... + if (prev_calculated > rates_total || prev_calculated <= 0) + { + // + // starting index for calculation of all bars ... + limit = maxLength; + } + else + { + // + // starting number for calculation of new bars + limit = prev_calculated - 1; + } + + // + // Main Loop ... + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + // + // Calculated Price ... + double price = getPrice( + atrAppliedTo, + open, + high, + low, + close, + i); + // price = (high[i] + low[i]) / 2; + priceBuffer[i] = price; + + // + double atr = atrBuffer[i]; + + // + // Up ... + upBuffer[i] = price + (atrMultiplier * atr); + + // + // Down ... + downBuffer[i] = price - (atrMultiplier * atr); + + // + if (close[i] > upBuffer[i - 1]) + { + // + trendBuffer[i] = 1; + if (trendBuffer[i - 1] == -1) + { + changeOfTrend = 1; + } + } + else if (close[i] < downBuffer[i - 1]) + { + // + trendBuffer[i] = -1; + if (trendBuffer[i - 1] == 1) + { + changeOfTrend = 1; + } + } + else if (trendBuffer[i - 1] == 1) + { + // + trendBuffer[i] = 1; + changeOfTrend = 0; + } + else if (trendBuffer[i - 1] == -1) + { + // + trendBuffer[i] = -1; + changeOfTrend = 0; + } + + // + // Down Trend Starting ... + if (trendBuffer[i] < 0 && trendBuffer[i - 1] > 0) + { + startBearishTrend = 1; + } + else + { + startBearishTrend = 0; + } + + // + // Up Trend Starting ... + if (trendBuffer[i] > 0 && trendBuffer[i - 1] < 0) + { + startBullishTrend = 1; + } + else + { + startBullishTrend = 0; + } + + // + if (trendBuffer[i] > 0 && downBuffer[i] < downBuffer[i - 1]) + { + downBuffer[i] = downBuffer[i - 1]; + } + + // + if (trendBuffer[i] < 0 && upBuffer[i] > upBuffer[i - 1]) + { + upBuffer[i] = upBuffer[i - 1]; + } + + // + if (startBearishTrend == 1) + { + upBuffer[i] = priceBuffer[i] + (atrMultiplier * atr); + } + + // + if (startBullishTrend == 1) + { + downBuffer[i] = priceBuffer[i] - (atrMultiplier * atr); + } + + // + // Draw the indicator ... + + // + double colorIDX = 0; + mainColorBuffer[i] = colorIDX; + + // + if (trendBuffer[i] == 1) + { + // + mainBuffer[i] = downBuffer[i]; + if (changeOfTrend == 1) + { + mainBuffer[i - 1] = mainBuffer[i - 2]; + changeOfTrend = 0; + } + + // + colorIDX = 1; + } + else if (trendBuffer[i] == -1) + { + // + mainBuffer[i] = upBuffer[i]; + if (changeOfTrend == 1) + { + // + mainBuffer[i - 1] = mainBuffer[i - 2]; + changeOfTrend = 0; + } + + // + colorIDX = 2; + } + + // + if (showTrends) + { + mainColorBuffer[i] = colorIDX; + } + + // + // Filling ... + if (fillTrends) + { + // + fillUpBuffer[i] = mainBuffer[i]; + fillDownBuffer[i] = close[i]; + } + else + { + // + fillUpBuffer[i] = EMPTY_VALUE; + fillDownBuffer[i] = EMPTY_VALUE; + } + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + // Validate Args ... + result = + // + atrLength >= 2 + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = atrLength; + + // + return result; +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // PLOT Buffers ... + + // + // FILLINGS ... + SetIndexBuffer(fillUpBufferIndex, fillUpBuffer, INDICATOR_DATA); + SetIndexBuffer(fillDownBufferIndex, fillDownBuffer, INDICATOR_DATA); + PlotIndexSetInteger(fillingPlotBufferIndex, PLOT_SHOW_DATA, false); + + // + // MAIN ... + SetIndexBuffer(mainBufferIndex, mainBuffer, INDICATOR_DATA); + PlotIndexSetInteger(mainPlotBufferIndex, PLOT_SHOW_DATA, showTrends); + SetIndexBuffer(mainColorBufferIndex, mainColorBuffer, INDICATOR_COLOR_INDEX); + + // + // DATA Buffers ... + + // + // ATR ... + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + // TREND ... + SetIndexBuffer(trendBufferIndex, trendBuffer, INDICATOR_CALCULATIONS); + + // + // UP ... + SetIndexBuffer(upBufferIndex, upBuffer, INDICATOR_CALCULATIONS); + + // + // DOWN ... + SetIndexBuffer(downBufferIndex, downBuffer, INDICATOR_CALCULATIONS); + + // + // PRICE ... + SetIndexBuffer(priceBufferIndex, priceBuffer, INDICATOR_CALCULATIONS); +} + +// +// END Functions ... +// + +// +// TEMPLATE Function ... + +template +double getPrice(ENUM_APPLIED_PRICE tprice, T &open[], T &high[], T &low[], T &close[], int i) +{ + switch (tprice) + { + case PRICE_CLOSE: + return (close[i]); + case PRICE_OPEN: + return (open[i]); + case PRICE_HIGH: + return (high[i]); + case PRICE_LOW: + return (low[i]); + case PRICE_MEDIAN: + return ((high[i] + low[i]) / 2.0); + case PRICE_TYPICAL: + return ((high[i] + low[i] + close[i]) / 3.0); + case PRICE_WEIGHTED: + return ((high[i] + low[i] + close[i] + close[i]) / 4.0); + } + return (0); +} diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xzg.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xzg.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.x121.xzg.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xzg.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xzg.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xzg.mq5 new file mode 100644 index 0000000..d7cde07 --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.x121.xzg.mq5 @@ -0,0 +1,757 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121_XZG +// Description: Zogzag Implementation ... +// +// +// 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_XZG Indicator" +#property strict + +// +#define ShortName "X121_XZG" + +// +// DEFINITIONS ... +enum ENUM_X_ZG_SEARCH_MODE +{ + X_ZG_SEARCH_EXTREMUM = 0, // searching for the first extremum + X_ZG_SEARCH_PEAK = 1, // searching for the next ZigZag peak + X_ZG_SEARCH_VALE = -1 // searching for the next ZigZag vale +}; + +// +// How to Calculate Up and Down Price ... +enum ENUM_X_ZG_PRICE_MODE +{ + // + X_ZG_PRICE_HIGH_LOW_MODE = 1, + X_ZG_PRICE_OPEN_CLOSE_MODE = 2, +}; + +// +// INPUT ... + +// +input int depth = 12; // Depth +input int deviation = 5; // Deviation +input int backStep = 3; // Back Step +input ENUM_X_ZG_PRICE_MODE mode = X_ZG_PRICE_HIGH_LOW_MODE; // Mode + +// +// BUFFERS ... + +// +#property indicator_chart_window + +// +#property indicator_buffers 5 +#property indicator_plots 3 + +// +// ZigZag ... + +// +#define mainBufferIndex 0 +#define mainBufferPlotIndex 0 +double mainBuffer[]; + +// +#property indicator_label1 "X121_XZG Main" +#property indicator_type1 DRAW_SECTION +#property indicator_color1 clrYellow +#property indicator_width1 2 + +// +// Highs ... + +// +// ZigZag Pointer or Line Indicator ... +#define arrowBufferIndex 1 +#define arrowBufferPlotIndex 1 +double arrowBuffer[]; + +// +#define arrowColorBufferIndex 2 +double arrowColorBuffer[]; + +// +#property indicator_label2 "X121_XZG PV" +#property indicator_type2 DRAW_COLOR_ARROW +#property indicator_color2 clrAqua, clrMagenta +#property indicator_width2 1 + +// +#define highsBufferIndex 3 +double highsBuffer[]; + +// +// Lows ... + +// +#define lowsBufferIndex 4 +double lowsBuffer[]; + +// +// VARIABLES ... + +// +int mRecalc = 3; // Number of last extremes for recalculation + +// +// EVENT Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // logTag = ShortName; + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + const int &spread[] // +) +{ + // + double mZGHigh[]; + double mZGLow[]; + if (mode == X_ZG_PRICE_OPEN_CLOSE_MODE) + { + // + ArrayCopy( + mZGHigh, + open + // + ); + + // + ArrayCopy( + mZGLow, + close + // + ); + } + else + { + // + ArrayCopy( + mZGHigh, + high + // + ); + + // + ArrayCopy( + mZGLow, + low + // + ); + } + + // + int zigZagResult = CalcukateZigZag( + prev_calculated, + rates_total, + mZGHigh, + mZGLow + // + ); + + // + if (zigZagResult != rates_total) + { + return zigZagResult; + } + + // + return rates_total; +} + +// +// CUSTOM Functions ... + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + depth > 0 && + deviation > 0 && + backStep > 0 + // + ; + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // Main ... + + // + SetIndexBuffer(mainBufferIndex, mainBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(mainBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(mainBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(mainBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Arrow ... + + // + SetIndexBuffer(arrowBufferIndex, arrowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_ARROW, 159); + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_ARROW_SHIFT, 0); + PlotIndexSetDouble(arrowBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Arrow Color ... + SetIndexBuffer(arrowColorBufferIndex, arrowColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Highs ... + SetIndexBuffer(highsBufferIndex, highsBuffer, INDICATOR_CALCULATIONS); + + // + // Lows ... + SetIndexBuffer(lowsBufferIndex, lowsBuffer, INDICATOR_CALCULATIONS); +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Calculating Zig Zag ... +int CalcukateZigZag( + const int prev_calculated, + const int rates_total, + double &high[], + double &low[] + // +) +{ + // + if (rates_total < 100) + { + return 0; + } + + // + // Define Variables ... + int i = 0; + + // + int start = 0; + int extreme_counter = 0; + int extreme_search = X_ZG_SEARCH_EXTREMUM; + int shift = 0; + int back = 0; + int last_high_pos = 0; + int last_low_pos = 0; + + // + double val = 0; + double res = 0; + double curlow = 0; + double curhigh = 0; + double last_high = 0; + double last_low = 0; + + // + double colorIDX = 0; + double lastZigZagValue = 0; + + // + // Initializing ... + if (prev_calculated == 0) + { + // + ArrayInitialize(mainBuffer, 0); + ArrayInitialize(highsBuffer, 0); + ArrayInitialize(lowsBuffer, 0); + + // + start = depth; + } + + // + // Already Calculated Before ... + if (prev_calculated > 0) + { + // + i = rates_total - 1; + + // + // Searching for the third X_ZG_SEARCH_EXTREMUM from the last UnComplete Bar ... + while (extreme_counter < mRecalc && i > rates_total - 100) + { + // + res = mainBuffer[i]; + if (res != 0) + { + extreme_counter++; + } + + // + i--; + } + + // + i++; + start = i; + + // + // What type of X_ZG_SEARCH_EXTREMUM we Search for ... + if (lowsBuffer[i] != 0) + { + // + curlow = lowsBuffer[i]; + extreme_search = X_ZG_SEARCH_PEAK; + } + else + { + // + curhigh = highsBuffer[i]; + extreme_search = X_ZG_SEARCH_VALE; + } + + // + // Clear Values ... + for (i = start + 1; i < rates_total && !IsStopped(); i++) + { + // + mainBuffer[i] = 0; + lowsBuffer[i] = 0; + highsBuffer[i] = 0; + } + } + + // + // Search for High and Low Extremes ... + for (shift = start; shift < rates_total && !IsStopped(); shift++) + { + // + // Low ... + val = low[Lowest(low, depth, shift)]; + if (val == last_low) + { + val = 0; + } + else + { + // + last_low = val; + + // + if ((low[shift] - val) > deviation * _Point) + { + val = 0; + } + else + { + // + for (back = 1; back <= backStep; back++) + { + // + res = lowsBuffer[shift - back]; + if ((res != 0) && (res > val)) + { + lowsBuffer[shift - back] = 0; + } + } + } + } + + // + if (low[shift] == val) + { + lowsBuffer[shift] = val; + } + else + { + lowsBuffer[shift] = 0; + } + + // + // High ... + val = high[Highest(high, depth, shift)]; + if (val == last_high) + { + val = 0; + } + else + { + // + last_high = val; + + // + if ((val - high[shift]) > deviation * _Point) + { + val = 0; + } + else + { + // + for (back = 1; back <= backStep; back++) + { + // + res = highsBuffer[shift - back]; + if ((res != 0) && (res < val)) + { + highsBuffer[shift - back] = 0; + } + } + } + } + + // + if (high[shift] == val) + { + highsBuffer[shift] = val; + } + else + { + highsBuffer[shift] = 0; + } + } + + // + // Set Last Value ... + if (extreme_search == 0) // Undefined Values ... + { + // + last_low = 0; + last_high = 0; + } + else + { + // + last_low = curlow; + last_high = curhigh; + } + + // + // Final Selection of Extreme Points for ZigZag ... + for (shift = start; shift < rates_total && !IsStopped(); shift++) + { + // + res = 0; + + // + switch (extreme_search) + { + // + case X_ZG_SEARCH_EXTREMUM: + // + if (last_low == 0 && last_high == 0) + { + // + if (highsBuffer[shift] != 0) + { + // + last_high_pos = shift; + last_high = high[shift]; + + // + extreme_search = X_ZG_SEARCH_VALE; + + // + mainBuffer[shift] = last_high; + + // + res = 1; + } + + // + if (lowsBuffer[shift] != 0) + { + // + last_low_pos = shift; + last_low = low[shift]; + + // + extreme_search = X_ZG_SEARCH_PEAK; + + // + mainBuffer[shift] = last_low; + + // + res = 1; + } + } + break; + + // + case X_ZG_SEARCH_PEAK: + // + if (lowsBuffer[shift] != 0 && lowsBuffer[shift] < last_low && highsBuffer[shift] == 0) + { + // + mainBuffer[last_low_pos] = 0; + + // + last_low_pos = shift; + last_low = lowsBuffer[shift]; + + // + mainBuffer[shift] = last_low; + + // + res = 1; + } + + // + if (highsBuffer[shift] != 0 && lowsBuffer[shift] == 0) + { + // + last_high_pos = shift; + last_high = highsBuffer[shift]; + + // + mainBuffer[shift] = last_high; + + // + extreme_search = X_ZG_SEARCH_VALE; + + // + res = 1; + } + break; + + // + case X_ZG_SEARCH_VALE: + // + if (highsBuffer[shift] != 0 && highsBuffer[shift] > last_high && lowsBuffer[shift] == 0) + { + // + mainBuffer[last_high_pos] = 0; + + // + last_high_pos = shift; + last_high = highsBuffer[shift]; + + // + mainBuffer[shift] = last_high; + } + + // + if (lowsBuffer[shift] != 0 && highsBuffer[shift] == 0) + { + // + last_low_pos = shift; + last_low = lowsBuffer[shift]; + + // + mainBuffer[shift] = last_low; + + // + extreme_search = X_ZG_SEARCH_PEAK; + } + break; + } + + // + double iZigZagForColor = lastZigZagValue; + double iZigZag = mainBuffer[shift]; + if (iZigZag == 0 && lastZigZagValue != 0) + { + arrowBuffer[shift] = lastZigZagValue; + } + else if (iZigZag != 0) + { + // + lastZigZagValue = iZigZag; + arrowBuffer[shift] = lastZigZagValue; + } + + // + colorIDX = + lastZigZagValue > iZigZagForColor + ? 0 + : lastZigZagValue < iZigZagForColor + ? 1 + : colorIDX; + arrowColorBuffer[shift] = colorIDX; + } + + // + return rates_total; +} + +// +// TOOLS ... + +// +// Search for the index of the highest bar ... +int Highest( + const double &mArray[], + const int mDepth, + const int mStart // +) +{ + // + int result = 0; + + // + if (mStart < 0) + { + return result; + } + + // + double max = mArray[mStart]; + result = mStart; + + // + // Start searching ... + for (int i = mStart - 1; i > mStart - mDepth && i >= 0; i--) + { + // + if (mArray[i] > max) + { + // + result = i; + max = mArray[i]; + } + } + + // + // Return index of the highest bar + return result; +} + +// +// Search for the index of the lowest bar ... +int Lowest( + const double &mArray[], + const int mDepth, + const int mStart // +) +{ + // + int result = 0; + + // + if (mStart < 0) + { + return result; + } + + // + double min = mArray[mStart]; + result = mStart; + + // + // Start searching ... + for (int i = mStart - 1; i > mStart - mDepth && i >= 0; i--) + { + // + if (mArray[i] < min) + { + // + result = i; + min = mArray[i]; + } + } + + // + // Return index of the lowest bar + return result; +} diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.xchnl.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.xchnl.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.xchnl.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.xchnl.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.xchnl.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.xchnl.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.xchnl.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.xchnl.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.xdon.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.xdon.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.xdon.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.xdon.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.xdon.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.xdon.mq5 new file mode 100644 index 0000000..e479e65 --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Indicators/x-saherelm.xdon.mq5 @@ -0,0 +1,365 @@ +/////////////////////////////////////////////////////// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------- +// Name: XDON +// Description: DONCHAIN Channel ... +// +// 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 XDON Indicator" +#property strict + +// +#define ShortName "XDON" + +// +// INPUT ... + +// +input int length = 52; // Market Length +input double offset = 0; // Offset + +// +// BUFFERS ... + +// +#property indicator_chart_window + +// +#property indicator_buffers 8 +#property indicator_plots 8 + +// +#define upperOBufferIndex 0 +double upperOBuffer[]; + +// +#property indicator_label1 "XDON OU" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrCornflowerBlue +#property indicator_width1 2 + +// +#define lowerOBufferIndex 1 +double lowerOBuffer[]; + +// +#property indicator_label2 "XDON OL" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrCornflowerBlue +#property indicator_width2 2 + +// +#define upperCBufferIndex 2 +double upperCBuffer[]; + +// +#property indicator_label3 "XDON CU" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrCoral +#property indicator_width3 2 + +// +#define lowerCBufferIndex 3 +double lowerCBuffer[]; + +// +#property indicator_label4 "XDON CL" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrCoral +#property indicator_width4 2 + +// +#define upperHBufferIndex 4 +double upperHBuffer[]; + +// +#property indicator_label5 "XDON HU" +#property indicator_type5 DRAW_LINE +#property indicator_color5 clrAquamarine +#property indicator_width5 2 + +// +#define lowerHBufferIndex 5 +double lowerHBuffer[]; + +// +#property indicator_label6 "XDON HL" +#property indicator_type6 DRAW_LINE +#property indicator_color6 clrAquamarine +#property indicator_width6 2 + +// +#define upperLBufferIndex 6 +double upperLBuffer[]; + +// +#property indicator_label7 "XDON LU" +#property indicator_type7 DRAW_LINE +#property indicator_color7 clrDarkOrchid +#property indicator_width7 2 + +// +#define lowerLBufferIndex 7 +double lowerLBuffer[]; + +// +#property indicator_label8 "XDON LL" +#property indicator_type8 DRAW_LINE +#property indicator_color8 clrDarkOrchid +#property indicator_width8 2 + +// +// EVENT Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + const int &spread[]) +{ + // + if (rates_total < length - 1) + { + return prev_calculated; + } + + // + int start = prev_calculated == 0 + ? length + : prev_calculated - 1; + + // + // Main Loop ... + for (int barIndex = start; barIndex < rates_total; barIndex++) + { + // + // OPEN ... + + // + double upperOValue = open[ArrayMaximum(open, barIndex - length + 1, length)]; + double lowerOValue = open[ArrayMinimum(open, barIndex - length + 1, length)]; + + // + double oDelta = MathAbs(upperOValue - lowerOValue); + double oOffsetValue = oDelta * (offset) * 0.01; + + // + upperOBuffer[barIndex] = upperOValue - oOffsetValue; + lowerOBuffer[barIndex] = lowerOValue + oOffsetValue; + + // + // CLOSE ... + + // + double upperCValue = close[ArrayMaximum(close, barIndex - length + 1, length)]; + double lowerCValue = close[ArrayMinimum(close, barIndex - length + 1, length)]; + + // + double cDelta = MathAbs(upperCValue - lowerCValue); + double cOffsetValue = cDelta * (offset) * 0.01; + + // + upperCBuffer[barIndex] = upperCValue - cOffsetValue; + lowerCBuffer[barIndex] = lowerCValue + cOffsetValue; + + // + // HIGH ... + + // + double upperHValue = high[ArrayMaximum(high, barIndex - length + 1, length)]; + double lowerHValue = high[ArrayMinimum(high, barIndex - length + 1, length)]; + + // + double hDelta = MathAbs(upperHValue - lowerHValue); + double hOffsetValue = hDelta * (offset) * 0.01; + + // + upperHBuffer[barIndex] = upperHValue - hOffsetValue; + lowerHBuffer[barIndex] = lowerHValue + hOffsetValue; + + // + // LOW ... + + // + double upperLValue = low[ArrayMaximum(low, barIndex - length + 1, length)]; + double lowerLValue = low[ArrayMinimum(low, barIndex - length + 1, length)]; + + // + double lDelta = MathAbs(upperLValue - lowerLValue); + double lOffsetValue = lDelta * (offset) * 0.01; + + // + upperLBuffer[barIndex] = upperLValue - lOffsetValue; + lowerLBuffer[barIndex] = lowerLValue + lOffsetValue; + } + + // + return rates_total; +} + +// +// CUSTOM Functions ... + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + result = length >= 7; + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // Open ... + + // + // UPPER ... + SetIndexBuffer(upperOBufferIndex, upperOBuffer, INDICATOR_DATA); + PlotIndexSetInteger(upperOBufferIndex, PLOT_SHOW_DATA, true); + PlotIndexSetDouble(upperOBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + + // + // LOWER ... + SetIndexBuffer(lowerOBufferIndex, lowerOBuffer, INDICATOR_DATA); + PlotIndexSetInteger(lowerOBufferIndex, PLOT_SHOW_DATA, true); + PlotIndexSetDouble(lowerOBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + + // + // Close ... + + // + // UPPER ... + SetIndexBuffer(upperCBufferIndex, upperCBuffer, INDICATOR_DATA); + PlotIndexSetInteger(upperCBufferIndex, PLOT_SHOW_DATA, true); + PlotIndexSetDouble(upperCBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + + // + // LOWER ... + SetIndexBuffer(lowerCBufferIndex, lowerCBuffer, INDICATOR_DATA); + PlotIndexSetInteger(lowerCBufferIndex, PLOT_SHOW_DATA, true); + PlotIndexSetDouble(lowerCBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + + // + // High ... + + // + // UPPER ... + SetIndexBuffer(upperHBufferIndex, upperHBuffer, INDICATOR_DATA); + PlotIndexSetInteger(upperHBufferIndex, PLOT_SHOW_DATA, true); + PlotIndexSetDouble(upperHBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + + // + // LOWER ... + SetIndexBuffer(lowerHBufferIndex, lowerHBuffer, INDICATOR_DATA); + PlotIndexSetInteger(lowerHBufferIndex, PLOT_SHOW_DATA, true); + PlotIndexSetDouble(lowerHBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + + // + // Low ... + + // + // UPPER ... + SetIndexBuffer(upperLBufferIndex, upperLBuffer, INDICATOR_DATA); + PlotIndexSetInteger(upperLBufferIndex, PLOT_SHOW_DATA, true); + PlotIndexSetDouble(upperLBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + + // + // LOWER ... + SetIndexBuffer(lowerLBufferIndex, lowerLBuffer, INDICATOR_DATA); + PlotIndexSetInteger(lowerLBufferIndex, PLOT_SHOW_DATA, true); + PlotIndexSetDouble(lowerLBufferIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.alert.lib.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.alert.lib.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.alert.lib.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.alert.lib.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.alert.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.alert.lib.mq5 new file mode 100644 index 0000000..429d830 --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.alert.lib.mq5 @@ -0,0 +1,187 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Alert Library +// -------------------------------------- +// Name: XAlert +// Description: provides Alerts abilities ... +// +// +// 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 + +// +// START Inputs ... +// +input group "Alerts"; +input bool enableAlerts = true; // Enable Alerts +input bool logAlerts = true; // Log Alerts +input bool terminalAlerts = false; // Terminal Alerts +input bool mailAlerts = false; // Mail Alerts +input bool pushAlerts = false; // Push Alerts +// +// END Inputs ... +// + +// +#include "x-saherelm.log.lib.mq5" + +// +// START Global Definitions: Variables, Properties and etc ... +// +string alertPrefix = "X-Alert"; +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// +// +// Initial Library if required ... +bool OnInInitAlertLibrary() +{ + return false; +} + +// +// DeInitial Library if required ... +void OnDeinitAlertLibrary() +{ +} + +// +// Attach Alert Prefix to Message ... +string PrepareAlertMessage(string message) +{ + // + StringReplace(message, "\n", " | "); + + // + StringConcatenate(message, alertPrefix, " > ", message); + + // + return message; +} + +// +// Logging an Alert ... +void LogAlert(string message) +{ + // + // Validate Args ... + if (!enableAlerts || !logAlerts) + { + return; + } + + // + LogMessage(alertPrefix, message); +} + +// +// Terminal Alert ... +void TerminalAlert(string message) +{ + // + // Validate Args ... + if (!enableAlerts || !terminalAlerts) + { + return; + } + + // + // Prepare Message ... + message = PrepareAlertMessage(message); + + // Send Terminal Alert ... + Alert(message); +} + +// +// Mail Alert ... +void MailAlert(string message) +{ + // + // Validate Args ... + if (!enableAlerts || !mailAlerts) + { + return; + } + + // + // Send Mail Alert ... + SendMail(alertPrefix, message); +} + +// +// Send Push Notification ... +void PushAlert(string message) +{ + // + // Validate Args ... + if (!enableAlerts || !pushAlerts) + { + return; + } + + // + // Prepare Message ... + message = PrepareAlertMessage(message); + + // + // Send Push Notification Alert ... + SendNotification(message); +} + +// +// Alert Sending ... +void SendAlert(string message) +{ + // + // Validate Args ... + if (!enableAlerts) + { + return; + } + + // + // Log ... + if (logAlerts) + { + LogAlert(message); + } + + // + // Terminal ... + if (terminalAlerts) + { + TerminalAlert(message); + } + + // + // Mail ... + if (mailAlerts) + { + MailAlert(message); + } + + // + // Push ... + if (pushAlerts) + { + PushAlert(message); + } +} +// +// END Provided Functions ... +// diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.common.lib.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.common.lib.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.common.lib.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.common.lib.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.common.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.common.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.common.lib.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.common.lib.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.draw.lib.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.draw.lib.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.draw.lib.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.draw.lib.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.draw.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.draw.lib.mq5 new file mode 100644 index 0000000..b714aba --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.draw.lib.mq5 @@ -0,0 +1,3608 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Draw Library +// -------------------------------------- +// Name: XDraw +// Description: provides Draw abilities ... +// +// +// 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 + +// +// START Inputs ... +// +// +// END Inputs ... +// + +// +// Include Logger Library ... +#include "x-saherelm.log.lib.mq5" +#include "x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xmd5.class.mq5" + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +string drawPrefix = "X-OBJ"; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// + +// +// DeInitial Library if required ... +void OnDeinitDrawLibrary() +{ + RemoveDraws(); +} + +// +// remove drawn objects ... +void RemoveDraws( + string tag = NULL, + long chartId = -1, + int subWindow = -1) +{ + // + // Normalize Args ... + // + if (tag == NULL) + { + tag = drawPrefix; + } + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + if (StringFind(on, tag) >= 0) + { + ObjectDelete(chartId, on); + } + } + + // + // Redraw Chart ... + ChartRedraw(); +} + +// +bool RemoveDraw( + string name, + long chartId = -1, + int subWindow = -1) +{ + // + bool result = false; + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + string objName = ""; + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + if (StringFind(on, name) >= 0) + { + // + objName = on; + break; + } + } + + // + if (StringLen(objName) > 0) + { + result = ObjectDelete(chartId, objName); + } + + // + return result; +} + +// +// Deselect All Draws ... +void DeselectAllDraws() +{ + // + int objs = ObjectsTotal(ChartID(), 0); + for (int o = 0; o < objs; o++) + { + ObjectSetInteger(ChartID(), ObjectName(ChartID(), o, 0), OBJPROP_SELECTED, false); + } + + // + ChartRedraw(); +} + +// +// Check Object Exists ... +bool IsDrawExists( + string name, + long chartId = -1, + int subWindow = -1) +{ + // + bool result = false; + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + result = StringFind(on, name) >= 0; + if (result) + { + break; + } + } + + // + return result; +} + +// +// END Provided Functions ... +// + +// +// START Regular Draws ... +// + +// +// START Arrow Functions ... +// + +// +// Draw an Arrow Object on Chart ... +bool DrawArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow", // arrow name + const int subWindow = 0, // subwindow index + datetime time = 0, // anchor point time + double price = 0, // anchor point price + const uchar arrowCode = 252, // arrow code + const ENUM_ARROW_ANCHOR anchor = ANCHOR_BOTTOM, // anchor point position + const color clr = clrAqua, // arrow color + const ENUM_LINE_STYLE style = STYLE_SOLID, // border line style + const int width = 3, // arrow size + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // Order Object ... +) +{ + // + // set anchor point coordinates if they are not set ... + ChangeArrowEmptyPoint(time, price); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create an arrow ... + if (!ObjectCreate(chartID, objName, OBJ_ARROW, subWindow, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to create an arrow! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set the arrow code ... + ObjectSetInteger(chartID, objName, OBJPROP_ARROWCODE, arrowCode); + + // + // set anchor type ... + ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + // set the arrow color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set the border line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set the arrow's size ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the arrow by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is false by default, if you want making it possible to highlight and move the object + // change it to true ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move the anchor point of Arrow ... +bool MoveArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // reset the error value + ResetLastError(); + + // + // move the anchor point ... + if (!ObjectMove(chartID, name, 0, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to move the anchor point! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete an arrow ... +bool DeleteArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow" // arrow name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete an arrow ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete an arrow! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Change the arrow code ... +bool ArrowCodeChange( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + const uchar code = 252 // arrow code +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // change the arrow code ... + if (!ObjectSetInteger(chartID, name, OBJPROP_ARROWCODE, code)) + { + // + string message = + __FUNCTION__ + + ": failed to change the arrow code! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Change anchor type ... +bool ArrowAnchorChange( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + const ENUM_ARROW_ANCHOR anchor = ANCHOR_TOP // anchor type +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // change anchor type ... + if (!ObjectSetInteger(chartID, name, OBJPROP_ANCHOR, anchor)) + { + // + string message = + __FUNCTION__ + + ": failed to change anchor type! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Check anchor point values and set default values +// for empty ones ... +void ChangeArrowEmptyPoint( + datetime &time, + double &price) +{ + // + // if the point's time is not set, it will be on the current bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // if the point's price is not set, it will have Bid value ... + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } +} + +// +// END Arrow Functions ... +// + +// +// START Horizontal Line Functions ... +// + +// +// Create, Draw the horizontal line ... +bool DrawHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine", // line name + const int subWindow = 0, // subwindow index + double price = 0, // line price + const color clr = clrRed, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // if the price is not set, set it at the current Bid price level ... + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a horizontal line ... + if (!ObjectCreate(chartID, objName, OBJ_HLINE, subWindow, 0, price)) + { + // + string message = + __FUNCTION__ + + ": failed to create a horizontal line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move horizontal line ... +bool MoveHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine", // line name + double price = 0 // line price +) +{ + // + // if the line price is not set, move it to the current Bid price level ... + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // reset the error value ... + ResetLastError(); + + // + // move a horizontal line ... + if (!ObjectMove(chartID, name, 0, 0, price)) + { + // + string message = + __FUNCTION__ + + ": failed to move the horizontal line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete a horizontal line ... +bool DeleteHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine" // line name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete a horizontal line ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete a horizontal line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// END Horizontal Line Functions ... +// + +// +// START Vertical Line Functions ... +// + +// +// Create the vertical line ... +bool DrawVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine", // line name + const int subWindow = 0, // subwindow index + datetime time = 0, // line time + const color clr = clrRed, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // if the line time is not set, draw it via the last bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // reset the error value + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a vertical line ... + if (!ObjectCreate(chartID, objName, OBJ_VLINE, subWindow, time, 0)) + { + // + string message = + __FUNCTION__ + + ": failed to create a vertical line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move the vertical line ... +bool MoveVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine", // line name + datetime time = 0 // line time +) +{ + // + // if line time is not set, move the line to the last bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // reset the error value ... + ResetLastError(); + + // + // move the vertical line ... + if (!ObjectMove(chartID, name, 0, time, 0)) + { + // + string message = + __FUNCTION__ + + ": failed to move the vertical line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete the vertical line ... +bool DeleteVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine" // line name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete the vertical line ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete the vertical line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// END Vertical Line Functions ... +// + +// +// START Rectangle Functions ... +// + +// +// Create rectangle by the given coordinates ... +bool DrawRectangle( + const long chartID = 0, // chart's ID + const string name = "Rectangle", // rectangle name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrRed, // rectangle color + const ENUM_LINE_STYLE style = STYLE_SOLID, // style of rectangle lines + const int width = 1, // width of rectangle lines + const bool fill = false, // filling rectangle with color + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Set anchor points' coordinates if they are not set ... + ChangeRectangleEmptyPoints(time1, price1, time2, price2); + + // + // Create a rectangle by the given coordinates ... + result = ObjectCreate(chartID, name, OBJ_RECTANGLE, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // Set rectangle color ... + ObjectSetInteger(chartID, name, OBJPROP_COLOR, clr); + + // + // Set the style of rectangle lines + ObjectSetInteger(chartID, name, OBJPROP_STYLE, style); + + // + // Set width of the rectangle lines ... + ObjectSetInteger(chartID, name, OBJPROP_WIDTH, width); + + // + // Enable (true) or disable (false) the mode of filling the rectangle ... + ObjectSetInteger(chartID, name, OBJPROP_FILL, fill); + + // + // Display in the foreground (false) or background (true) ... + ObjectSetInteger(chartID, name, OBJPROP_BACK, back); + + // + // Enable (true) or disable (false) the mode of highlighting the rectangle for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object + ObjectSetInteger(chartID, name, OBJPROP_SELECTABLE, selection); + + // + ObjectSetInteger(chartID, name, OBJPROP_SELECTED, selection); + + // + // Hide (true) or display (false) graphical object name in the object list ... + ObjectSetInteger(chartID, name, OBJPROP_HIDDEN, hidden); + + // + // Set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, name, OBJPROP_ZORDER, zOrder); + + // + // Successful execution + return result; +} + +// +// Move the rectangle anchor point ...s +bool RectanglePointChange( + const long chartID = 0, // chart's ID + const string name = "Rectangle", // rectangle name + const int pointIndex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // Move the anchor point ... + result = ObjectMove(chartID, name, pointIndex, time, price); + if (!result) + { + return result; + } + + // + // Successful execution + return result; +} + +// +// Delete the rectangle ... +bool DeleteRectangle( + const long chartID = 0, // chart's ID + const string name = "Rectangle" // rectangle name +) +{ + // + bool result = false; + + // + result = ObjectDelete(chartID, name); + + // + return result; +} + +// +// Check the values of rectangle's anchor points and set default +// values for empty ones +void ChangeRectangleEmptyPoints( + datetime &time1, double &price1, + datetime &time2, double &price2) +{ + // + // if the first point's time is not set, it will be on the current bar ... + if (!time1) + { + time1 = TimeCurrent(); + } + + // + // if the first point's price is not set, it will have Bid value ... + if (!price1) + { + price1 = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // if the second point's time is not set, it is located 9 bars left from the second one ... + if (!time2) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time1, 10, temp); + + // + // set the second point 9 bars left from the first one ... + time2 = temp[0]; + } + + // + // if the second point's price is not set, move it 300 points lower than the first one ... + if (!price2) + { + price2 = price1 - 300 * SymbolInfoDouble(Symbol(), SYMBOL_POINT); + } +} + +// +// END Rectangle Functions ... +// + +// +// START RectangleLabel Functions ... +// + +// +// Create Rectangle Label Object ... +bool DrawRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int subWindow = 0, // subwindow index + const int x = 0, // X coordinate + const int y = 0, // Y coordinate + const int width = 50, // width + const int height = 18, // height + const color bgColor = clrWhiteSmoke, // background color + const ENUM_BORDER_TYPE border = BORDER_SUNKEN, // border type + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring + const color clr = clrRed, // flat border color (Flat) + const ENUM_LINE_STYLE style = STYLE_SOLID, // flat border style + const int lineWidth = 1, // flat border width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // + // create a rectangle label + if (!ObjectCreate(chartID, objName, OBJ_RECTANGLE_LABEL, subWindow, 0, 0)) + { + // + string message = + __FUNCTION__ + + ": failed to create a rectangle label! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set label coordinates ... + ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + // set label size ... + ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + // set background color ... + ObjectSetInteger(chartID, objName, OBJPROP_BGCOLOR, bgColor); + + // + // set border type ... + ObjectSetInteger(chartID, objName, OBJPROP_BORDER_TYPE, border); + + // + // set the chart's corner, relative to which point coordinates are defined ... + ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + // set flat border color (in Flat mode) ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set flat border line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set flat border width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, lineWidth); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the label by mouse ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move Rectangle Label .. +bool MoveRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int x = 0, // X coordinate + const int y = 0 // Y coordinate +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // move the rectangle label ... + if (!ObjectSetInteger(chartID, name, OBJPROP_XDISTANCE, x)) + { + // + string message = + __FUNCTION__ + + ": failed to move X coordinate of the label! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + if (!ObjectSetInteger(chartID, name, OBJPROP_YDISTANCE, y)) + { + // + string message = + __FUNCTION__ + + ": failed to move Y coordinate of the label! Error code = " + + (string)GetLastError(); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete the rectangle label ... +bool DeleteRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel" // label name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete the label ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete a rectangle label! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Change Rectangle Label Size ... +bool ChangeSizeRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int width = 50, // label width + const int height = 18 // label height +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // change label size ... + if (!ObjectSetInteger(chartID, name, OBJPROP_XSIZE, width)) + { + // + string message = + __FUNCTION__ + + ": failed to change the label's width! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + if (!ObjectSetInteger(chartID, name, OBJPROP_YSIZE, height)) + { + // + string message = + __FUNCTION__ + + ": failed to change the label's height! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Change rectangle label border type ... +bool RectLabelChangeBorderType( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const ENUM_BORDER_TYPE border = BORDER_SUNKEN // border type +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // change border type ... + if (!ObjectSetInteger(chartID, name, OBJPROP_BORDER_TYPE, border)) + { + // + string message = + __FUNCTION__ + + ": failed to change the border type! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// END RectangleLabel Functions ... +// + +// +// START TrendLine Funcions ... +// + +// +// Create a trend line by the given coordinates ... +bool DrawTrendLine( + const long chartID = 0, // chart's ID + const string name = "TrendLine", // line name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrYellow, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool rayRight = false, // line's continuation to the right + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // set anchor points' coordinates if they are not set ... + ChangeTrendLineEmptyPoints( + time1, + price1, + time2, + price2); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a trend line by the given coordinates ... + if (!ObjectCreate(chartID, objName, OBJ_TREND, subWindow, time1, price1, time2, price2)) + { + // + string message = + __FUNCTION__ + + ": failed to create a trend line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the line's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move trend line anchor point ... | +bool ChangeTrendLinePoint( + const long chartID = 0, // chart's ID + const string name = "TrendLine", // line name + const int pointindex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // reset the error value ... + ResetLastError(); + + // + // move trend line's anchor point ... + if (!ObjectMove(chartID, name, pointindex, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to move the anchor point! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// The function deletes the trend line from the chart ... +bool DeleteTrendLine( + const long chartID = 0, // chart's ID + const string name = "TrendLine" // line name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete a trend line ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete a trend line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Check the values of trend line's anchor points and set default ... +// values for empty ones ... +void ChangeTrendLineEmptyPoints( + datetime &time1, + double &price1, + datetime &time2, + double &price2) +{ + // + // if the first point's time is not set, it will be on the current bar ... + if (!time1) + { + time1 = TimeCurrent(); + } + + // + // if the first point's price is not set, it will have Bid value ... + if (!price1) + { + price1 = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // if the second point's time is not set, it is located 9 bars left from the second one ... + if (!time2) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time1, 10, temp); + + // + // set the second point 9 bars left from the first one ... + time2 = temp[0]; + } + + // + // if the second point's price is not set, it is equal to the first point's one ... + if (!price2) + { + price2 = price1; + } +} + +// +// END TrendLine Functions ... +// + +// +// START Text Functions ... +// + +// +// Create and Draw a Text Object ... +bool DrawText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + const int subWindow = 0, // subwindow index + datetime time = 0, // anchor point time + double price = 0, // anchor point price + const string text = "Text", // the text itself + const string font = "Arial", // font + const int fontSize = 10, // font size + const color clr = clrRed, // color + const double angle = 0.0, // text slope + const ENUM_ANCHOR_POINT anchor = ANCHOR_CENTER, // anchor type + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // set anchor point coordinates if they are not set ... + ChangeTextEmptyPoint(time, price); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // + // create Text object + if (!ObjectCreate(chartID, objName, OBJ_TEXT, subWindow, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to create \"Text\" object! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set the text ... + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set text font ... + ObjectSetString(chartID, objName, OBJPROP_FONT, font); + + // + // set font size ... + ObjectSetInteger(chartID, objName, OBJPROP_FONTSIZE, fontSize); + + // + // set the slope angle of the text ... + ObjectSetDouble(chartID, objName, OBJPROP_ANGLE, angle); + + // + // set anchor type ... + ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the object by mouse ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move the anchor point ... +bool MoveText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + // + // if point position is not set, move it to the current bar having Bid price + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // reset the error value ... + ResetLastError(); + + // + // move the anchor point .. + if (!ObjectMove(chartID, name, 0, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to move the anchor point! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Change the object text ... +bool ChangeText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + const string text = "Text" // text +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // change object text ... + if (!ObjectSetString(chartID, name, OBJPROP_TEXT, text)) + { + // + string message = + __FUNCTION__ + + ": failed to change the text! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete Text object ... +bool DeleteText( + const long chartID = 0, // chart's ID + const string name = "Text" // object name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete the object ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete \"Text\" object! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution + return true; +} + +// +// Check anchor point values and set default values +// for empty ones ... +void ChangeTextEmptyPoint( + datetime &time, + double &price) +{ + // + // if the point's time is not set, it will be on the current bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // if the point's price is not set, it will have Bid value ... + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } +} + +// +// END Text Functions ... +// + +// +// START Fibonacchi Functions ... +// + +// +// Create Fibonacci Retracement by the given coordinates ... +bool DrawFibonacci( + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrRed, // object color + const ENUM_LINE_STYLE style = STYLE_SOLID, // object line style + const int width = 1, // object line width + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool rayRight = false, // object's continuation to the right + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // set anchor points' coordinates if they are not set ... + ChangeFibonacciEmptyPoints(time1, price1, time2, price2); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create Fibonacci Retracement by the given coordinates ... + if (!ObjectCreate(chartID, objName, OBJ_FIBO, subWindow, time1, price1, time2, price2)) + { + // + string message = + __FUNCTION__ + + ": failed to create \"Fibonacci Retracement\"! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of highlighting the channel for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the object's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Create Fibonacci Retracement by the given coordinates ... +bool DrawCustomFibonacci( + // + int levels, // number of level lines + double &values[], // values of level lines + color &colors[], // color of level lines + ENUM_LINE_STYLE &styles[], // style of level lines + int &widths[], // width of level lines + string &descriptions[], // level Descriptions + // + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrAqua, // object color + const ENUM_LINE_STYLE style = STYLE_DOT, // object line style + const int width = 1, // object line width + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool rayRight = false, // object's continuation to the right + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // set anchor points' coordinates if they are not set ... + ChangeFibonacciEmptyPoints(time1, price1, time2, price2); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create Fibonacci Retracement by the given coordinates ... + if (!ObjectCreate(chartID, name, OBJ_FIBO, subWindow, time1, price1, time2, price2)) + { + // + string message = + __FUNCTION__ + + ": failed to create \"Fibonacci Retracement\"! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of highlighting the channel for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the object's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // Change Levels Of Fibonacci ... + bool result = FibonacciLevelsSet( + levels, + values, + colors, + styles, + widths, + descriptions, + chartID, + objName); + + // + // successful execution ... + return result; +} + +// +// Set number of levels and their parameters ... +bool FibonacciLevelsSet( + int levels, // number of level lines + double &values[], // values of level lines + color &colors[], // color of level lines + ENUM_LINE_STYLE &styles[], // style of level lines + int &widths[], // width of level lines + string &descriptions[], // level Descriptions + const long chartID = 0, // chart's ID + const string name = "Fibonacci" // object name +) +{ + // + // check array sizes ... + if ( + levels != ArraySize(colors) || + levels != ArraySize(styles) || + levels != ArraySize(widths) || + levels != ArraySize(widths)) + { + // + string message = + __FUNCTION__ + + ": array length does not correspond to the number of levels, error!"; + + // + LogMessage(message); + + // + return false; + } + + // + // set the number of levels ... + ObjectSetInteger(chartID, name, OBJPROP_LEVELS, levels); + + // + // set the properties of levels in the loop ... + for (int i = 0; i < levels; i++) + { + // + // level value ... + ObjectSetDouble(chartID, name, OBJPROP_LEVELVALUE, i, values[i]); + + // + // level color ... + ObjectSetInteger(chartID, name, OBJPROP_LEVELCOLOR, i, colors[i]); + + // + // level style ... + ObjectSetInteger(chartID, name, OBJPROP_LEVELSTYLE, i, styles[i]); + + // + // level width ... + ObjectSetInteger(chartID, name, OBJPROP_LEVELWIDTH, i, widths[i]); + + // + // level description ... + // ObjectSetString(chartID, name, OBJPROP_LEVELTEXT, i, DoubleToString(100 * values[i], 1)); + ObjectSetString(chartID, name, OBJPROP_LEVELTEXT, i, descriptions[i]); + } + + // + // successful execution ... + return true; +} + +// +// Move Fibonacci Retracement anchor point ... +bool FibonacciPointChange( + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int pointIndex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // reset the error value ... + ResetLastError(); + + // + // move the anchor point ... + if (!ObjectMove(chartID, name, pointIndex, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to move the anchor point! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete Fibonacci Retracement ... +bool DeleteFibonachi( + const long chartID = 0, // chart's ID + const string name = "Fibonacci" // object name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete the object ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete \"Fibonacci Retracement\"! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Check the values of Fibonacci Retracement anchor points and set +// default values for empty ones ... +void ChangeFibonacciEmptyPoints( + datetime &time1, + double &price1, + datetime &time2, + double &price2) +{ + // + // if the second point's time is not set, it will be on the current bar ... + if (!time2) + { + time2 = TimeCurrent(); + } + + // + // if the second point's price is not set, it will have Bid value ... + if (!price2) + { + price2 = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // if the first point's time is not set, it is located 9 bars left from the second one ... + if (!time1) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time2, 10, temp); + + // + // set the first point 9 bars left from the second one ... + time1 = temp[0]; + } + + // + // if the first point's price is not set, move it 200 points below the second one ... + if (!price1) + { + price1 = price2 - 200 * SymbolInfoDouble(_Symbol, SYMBOL_POINT); + } +} + +// +// END Fibonacci Functions ... +// + +// +// START Event Functions ... +// + +// +// Create an Event ... +bool EventCreate( + const long chartID = 0, // chart's ID + const string name = "Event", // object name + const int subWindow = 0, // subwindow index + const string text = "Content", // event text + datetime time = 0, // anchor point time + const color clr = clrRed, // color + const int width = 1, // point width when highlighted + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + if (!time) + { + time = TimeCurrent(); + } + + // + ResetLastError(); + + // + if (!ObjectCreate(chartID, name, OBJ_EVENT, subWindow, time, 0)) + { + // + string message = + __FUNCTION__ + + ": failed to create \"Event\" object! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set event text + ObjectSetString(chartID, name, OBJPROP_TEXT, text); + + // + // set color + ObjectSetInteger(chartID, name, OBJPROP_COLOR, clr); + + // + // set anchor point width if the object is highlighted + ObjectSetInteger(chartID, name, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true + ObjectSetInteger(chartID, name, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving event by mouse + ObjectSetInteger(chartID, name, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, name, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list + ObjectSetInteger(chartID, name, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, name, OBJPROP_ZORDER, zOrder); + + // + // successful execution + return true; +} + +// +// Change Event object text +bool EventTextChange( + const long chartID = 0, // chart's ID + const string name = "Event", // event name + const string text = "Content" // text +) +{ + // + // reset the error value + ResetLastError(); + + // + // change object text + if (!ObjectSetString(chartID, name, OBJPROP_TEXT, text)) + { + // + string message = + __FUNCTION__ + + ": failed to change the text! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution + return true; +} + +// +// Move Event object +bool EventMove( + const long chartID = 0, // chart's ID + const string name = "Event", // event name + datetime time = 0 // time +) +{ + // + // if time is not set, move event to the last bar + if (!time) + { + time = TimeCurrent(); + } + + // + // reset the error value + ResetLastError(); + + // + // move the object + if (!ObjectMove(chartID, name, 0, time, 0)) + { + // + string message = + __FUNCTION__ + + ": failed to move \"Event\" object! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution + return true; +} + +// +// Delete Event object +bool EventDelete( + const long chartID = 0, // chart's ID + const string name = "Event" // event name +) +{ + // + // reset the error value + ResetLastError(); + + // + // delete the object + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete \"Event\" object! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution + return true; +} + +// +// END Event Functions ... +// + +// +// START Button Functions ... +// + +// +// Create the button ... +bool ButtonCreate( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int subWindow = 0, // subwindow index + const int x = 0, // X coordinate + const int y = 0, // Y coordinate + const int width = 50, // button width + const int height = 15, // button height + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring + const string text = "Button", // text + const string font = "Arial", // font + const int fontSize = 8, // font size + const color clr = clrBlack, // text color + const color bgColor = clrLightGray, // background color + const color borderColor = clrNONE, // border color + const bool state = false, // pressed/released + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // create the button + result = ObjectCreate(chartID, name, OBJ_BUTTON, subWindow, 0, 0); + if (!result) + { + return result; + } + + // + // set button coordinates + ObjectSetInteger(chartID, name, OBJPROP_XDISTANCE, x); + ObjectSetInteger(chartID, name, OBJPROP_YDISTANCE, y); + + // + // set button size + ObjectSetInteger(chartID, name, OBJPROP_XSIZE, width); + ObjectSetInteger(chartID, name, OBJPROP_YSIZE, height); + + // + // set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(chartID, name, OBJPROP_CORNER, corner); + + // + // set the text + ObjectSetString(chartID, name, OBJPROP_TEXT, text); + + // + // set text font + ObjectSetString(chartID, name, OBJPROP_FONT, font); + + // + // set font size + ObjectSetInteger(chartID, name, OBJPROP_FONTSIZE, fontSize); + + // + // set text color + ObjectSetInteger(chartID, name, OBJPROP_COLOR, clr); + + // + // set background color + ObjectSetInteger(chartID, name, OBJPROP_BGCOLOR, bgColor); + + // + // set border color + ObjectSetInteger(chartID, name, OBJPROP_BORDER_COLOR, borderColor); + + // + // display in the foreground false or background true + ObjectSetInteger(chartID, name, OBJPROP_BACK, back); + + // + // set button state + ObjectSetInteger(chartID, name, OBJPROP_STATE, state); + + // + // enable true or disable false the mode of moving the button by mouse + ObjectSetInteger(chartID, name, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, name, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list + ObjectSetInteger(chartID, name, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, name, OBJPROP_ZORDER, zOrder); + + // + return result; +} + +// +// Move the button ... +bool ButtonMove( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int x = 0, // X coordinate + const int y = 0 // Y coordinate +) +{ + // + bool result = false; + + // + // move the button + + // + result = ObjectSetInteger(chartID, name, OBJPROP_XDISTANCE, x); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, name, OBJPROP_YDISTANCE, y); + + // + return result; +} + +// +// Change button size ... +bool ButtonChangeSize( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int width = 50, // button width + const int height = 18 // button height +) +{ + // + bool result = false; + + // + // change the button size + + // + result = ObjectSetInteger(chartID, name, OBJPROP_XSIZE, width); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, name, OBJPROP_YSIZE, height); + + // + return result; +} + +// +// Change corner of the chart for binding the button ... +bool ButtonChangeCorner( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER // chart corner for anchoring +) +{ + // + bool result = false; + + // + // change anchor corner + + // + result = ObjectSetInteger(chartID, name, OBJPROP_CORNER, corner); + + // + return result; +} + +// +// Change button text ... +bool ButtonTextChange( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const string text = "Text" // text +) +{ + // + bool result = false; + + // + // change object text + result = ObjectSetString(chartID, name, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Delete the button ... +bool ButtonDelete( + const long chartID = 0, // chart's ID + const string name = "Button" // button name +) +{ + // + bool result = false; + + // + // delete the button + result = ObjectDelete(chartID, name); + + // + return result; +} + +// +// END Button Functions ... +// + +// +// END Regular Draws ... +// + +// +// START Chart Style Drawers ... +// + +// +// Apply Styles On Chart ... +void ApplyChartStyle( + long mChartId = -1, // chart's ID + ENUM_CHART_MODE mMode = CHART_CANDLES, // chart's mMode + bool mShowBidLine = true, // show bid line + bool mShowAskLine = true, // show ask line + bool mShowGrid = false, // show grids on chart + bool mShowVolumes = false, // show volumes + bool mShowTradeLevels = true, // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) + bool mAutoScroll = true, // chart autoscroll + bool mQuickNavigation = true, // chart quick navigation state + color mForeGroundColor = clrWhite, // chart's foreground color + color mBackGroundColor = clrBlack, // chart's background color + color mUpColor = clrGreen, // Up Color + color mDownColor = clrRed, // Down Color + color mBullishColor = clrGreen, // Bullish color + color mBearishColor = clrRed, // Bearish color + color mGridColor = clrGray, // grid color + color mBidLineColor = clrGray, // bid line color + color mAskLineColor = clrRed, // ask line color + color mLineColor = clrLime, // line mMode and doji candlestick color + color mStopColor = clrGold, // Color of stop order levels (Stop Loss and Take Profit) + color mVolumesColor = clrGreen // volumes color +) +{ + // + // Validate Args ... + if (mChartId == -1) + { + mChartId = 0; + } + + // + ChartSetInteger(mChartId, CHART_MODE, mMode); + ChartSetInteger(mChartId, CHART_SHOW_BID_LINE, mShowBidLine); + ChartSetInteger(mChartId, CHART_SHOW_ASK_LINE, mShowAskLine); + ChartSetInteger(mChartId, CHART_SHOW_GRID, mShowGrid); + ChartSetInteger(mChartId, CHART_SHOW_VOLUMES, mShowVolumes); + ChartSetInteger(mChartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels); + ChartSetInteger(mChartId, CHART_AUTOSCROLL, mAutoScroll); + ChartSetInteger(mChartId, CHART_QUICK_NAVIGATION, mQuickNavigation); + ChartSetInteger(mChartId, CHART_COLOR_FOREGROUND, mForeGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_BACKGROUND, mBackGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_UP, mUpColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_DOWN, mDownColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BULL, mBullishColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BEAR, mBearishColor); + ChartSetInteger(mChartId, CHART_COLOR_GRID, mGridColor); + ChartSetInteger(mChartId, CHART_COLOR_BID, mBidLineColor); + ChartSetInteger(mChartId, CHART_COLOR_ASK, mAskLineColor); + ChartSetInteger(mChartId, CHART_COLOR_STOP_LEVEL, mStopColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_LINE, mLineColor); + ChartSetInteger(mChartId, CHART_COLOR_VOLUME, mVolumesColor); +} + +// +// Retrieve Chart Size in Pixel ... +struct XSize +{ + long width; + long height; + + // + int x; + int y; + int w; + int h; + + // + int wStep; + int hStep; +}; + +// +// Retrieve Chart Size ... +bool GetChartSize( + XSize &result, // Holds Result ... + long chartID = 0 // Specified Chart ID ... +) +{ + // + bool mResult = false; + + // + mResult = ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0, result.width); + if (!mResult) + { + return mResult; + } + + // + mResult = ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0, result.height); + + // + return mResult; +} + +// +// END Chart Style Drawers ... +// + +// +// START Custom Drawings ... +// + +// +// Define a Draw Specifications ... +struct XDrawSpecifications +{ + // + // Props ... + + // + bool draw; // Draw or Not ... + + // + int width; // Draw Witdth ... + color clr; // Draw Color ... + ENUM_LINE_STYLE style; // Draw Style ... + + // + bool back; // in the background + bool fill; // fill object if supported + bool selection; // highlight to move + bool rayRight; // line's continuation to the right + bool hidden; // hidden in the object list + long zOrder; // priority for mouse click + + // + string label; // Label ... + color labelColor; // Label Color ... + double labelAngel; // Label Angle ... + string labelFont; // Label Font ... + int labelFontSize; // Label Font Size ... + ENUM_ANCHOR_POINT labelAnchor; // Label Anchor Point ... + + // + // Constructor ... + XDrawSpecifications() + { + Clean(); + } + + // + // Operator ... + void operator=(const XDrawSpecifications &value) + { + // + clr = value.clr; + draw = value.draw; + width = value.width; + style = value.style; + + // + back = value.back; + hidden = value.hidden; + zOrder = value.zOrder; + rayRight = value.rayRight; + selection = value.selection; + + // + fill = value.fill; + + // + label = value.label; + labelColor = value.labelColor; + labelAngel = value.labelAngel; + labelFont = value.labelFont; + labelFontSize = value.labelFontSize; + labelAnchor = value.labelAnchor; + } + + // + // Functions ... + + // + void Clean() + { + // + draw = false; + width = 1; + clr = CLR_NONE; + style = STYLE_SOLID; + + // + back = false; + hidden = false; + rayRight = false; + selection = false; + fill = false; + + // + zOrder = 0; + + // + label = ""; + labelColor = CLR_NONE; + labelAngel = 0; + labelFont = "Arial"; + labelFontSize = 20; + labelAnchor = ANCHOR_LEFT_UPPER; + } + + // + void Label( + string mLabel = "", // Label ... + color mLabelColor = CLR_NONE, // Label Color ... + string mLabelFont = "Arial", // Label Font ... + int mLabelFontSize = 20, // Label Font Size ... + ENUM_ANCHOR_POINT mLabelAnchor = ANCHOR_LEFT_UPPER, // Label Anchor Point ... + double mLabelAngel = 0 // Label Angle ... + ) + { + // + label = mLabel; + labelFont = mLabelFont; + labelColor = mLabelColor; + labelAngel = mLabelAngel; + labelAnchor = mLabelAnchor; + labelFontSize = mLabelFontSize; + } +}; + +// +// Candle Draw Specifications ... +struct XOHCLDrawSpecification +{ + // + // Props ... + XDrawSpecifications openStyle; + XDrawSpecifications highStyle; + XDrawSpecifications closeStyle; + XDrawSpecifications lowStyle; + + // + // Constructors ... + XOHCLDrawSpecification() + { + Clean(); + } + + // + // Operators ... + void operator=(const XOHCLDrawSpecification &value) + { + // + lowStyle = value.lowStyle; + openStyle = value.openStyle; + highStyle = value.highStyle; + closeStyle = value.closeStyle; + } + + // + // Functions ... + + // + void Clean() + { + // + lowStyle.Clean(); + openStyle.Clean(); + highStyle.Clean(); + closeStyle.Clean(); + } + + // + void Default() + { + // + // Open ... + openStyle.width = 1; + openStyle.draw = true; + openStyle.clr = clrLime; + openStyle.style = STYLE_SOLID; + openStyle.Label( + "O", + openStyle.clr); + + // + // High ... + highStyle.width = 1; + highStyle.draw = true; + highStyle.clr = clrAqua; + highStyle.style = STYLE_SOLID; + highStyle.Label( + "H", + highStyle.clr); + + // + // Close ... + closeStyle.width = 1; + closeStyle.draw = true; + closeStyle.clr = clrRed; + closeStyle.style = STYLE_SOLID; + closeStyle.Label( + "C", + closeStyle.clr); + + // + // Low ... + lowStyle.width = 1; + lowStyle.draw = true; + lowStyle.clr = clrMagenta; + lowStyle.style = STYLE_SOLID; + lowStyle.Label( + "L", + lowStyle.clr); + } + + // + void Width(int value) + { + // + lowStyle.width = value; + openStyle.width = value; + highStyle.width = value; + closeStyle.width = value; + } + + // + void Style(ENUM_LINE_STYLE value) + { + // + lowStyle.style = value; + openStyle.style = value; + highStyle.style = value; + closeStyle.style = value; + } + + // + void Color(color value) + { + // + lowStyle.clr = value; + openStyle.clr = value; + highStyle.clr = value; + closeStyle.clr = value; + } + + // + void RayRight(bool value) + { + // + lowStyle.rayRight = value; + openStyle.rayRight = value; + highStyle.rayRight = value; + closeStyle.rayRight = value; + } + + // + void Draw(bool value) + { + // + lowStyle.draw = value; + openStyle.draw = value; + highStyle.draw = value; + closeStyle.draw = value; + } + + // + void Back(bool value) + { + // + lowStyle.back = value; + openStyle.back = value; + highStyle.back = value; + closeStyle.back = value; + } + + // + void Fill(bool value) + { + // + lowStyle.fill = value; + openStyle.fill = value; + highStyle.fill = value; + closeStyle.fill = value; + } + + // + void Label(string value) + { + // + lowStyle.Label(value); + openStyle.Label(value); + highStyle.Label(value); + closeStyle.Label(value); + } + + // + void SetLabelPrefix(string value) + { + // + lowStyle.label = value + " " + lowStyle.label; + openStyle.label = value + " " + openStyle.label; + highStyle.label = value + " " + highStyle.label; + closeStyle.label = value + " " + closeStyle.label; + } +}; + +// +bool RemoveCandle( + XOHCL &c, + long chartId = 0, + int subWindow = 0 // +) +{ + // + bool result = false; + + // + string cTag = GenerateTag(c); + + // + result = IsDrawExists( + cTag, + chartId, + subWindow); + if (!result) + { + return result; + } + + // + RemoveDraws( + cTag, + chartId, + subWindow); + + // + return result; +} + +// +// XOHCL ... +void DrawCandleAsLine( + long chartId, // Chart ID ... + int subWindow, // SubWindow ... + XOHCL &c, // the Candle Which required to Draw ... + const datetime time, // Candle Time ... + XOHCLDrawSpecification &config, // Draw Specifications ... + string tag = "", // Draw Tag ... + bool update = true, // Update Draw if Exists ... + bool drawMidLine = true // Draw Open Close Middle Line ... +) +{ + // + datetime cTime = TimeCurrent(); + XDrawSpecifications specs; + + // + string baseTag = tag + GenerateTag(c); + + // + // Open ... + specs = config.openStyle; + if (specs.draw) + { + // + double value = c.open; + string valueTag = "|O|"; + + // + string mTag = baseTag + valueTag + ToString(value); + string mLblTag = baseTag + valueTag + "_lbl"; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + mTag, + chartId, + subWindow // + ); + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteText( + chartId, + mLblTag // + ); + + // + DeleteTrendLine( + chartId, + mTag // + ); + } + + // + if (canDraw) + { + // + // Draw Label ... + if (StringLen(specs.label) > 0) + { + DrawText( + chartId, + mLblTag, + subWindow, + cTime, + value, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw ... + DrawTrendLine( + chartId, + mTag, + subWindow, + time, + value, + cTime, + value, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); + } + } + + // + // High ... + specs = config.highStyle; + if (specs.draw) + { + // + double value = c.high; + string valueTag = "|H|"; + + // + string mTag = baseTag + valueTag + ToString(value); + string mLblTag = baseTag + valueTag + "_lbl"; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + mTag, + chartId, + subWindow // + ); + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteText( + chartId, + mLblTag // + ); + + // + DeleteTrendLine( + chartId, + mTag // + ); + } + + // + if (canDraw) + { + // + // Draw Label ... + if (StringLen(specs.label) > 0) + { + DrawText( + chartId, + mLblTag, + subWindow, + cTime, + value, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw ... + DrawTrendLine( + chartId, + mTag, + subWindow, + time, + value, + cTime, + value, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); + } + } + + // + // Close ... + specs = config.closeStyle; + if (specs.draw) + { + // + double value = c.close; + string valueTag = "|C|"; + + // + string mTag = baseTag + valueTag + ToString(value); + string mLblTag = baseTag + valueTag + "_lbl"; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + mTag, + chartId, + subWindow // + ); + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteText( + chartId, + mLblTag // + ); + + // + DeleteTrendLine( + chartId, + mTag); + } + + // + if (canDraw) + { + // + // Draw Label ... + if (StringLen(specs.label) > 0) + { + DrawText( + chartId, + mLblTag, + subWindow, + cTime, + value, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw ... + DrawTrendLine( + chartId, + mTag, + subWindow, + time, + value, + cTime, + value, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); + } + } + + // + // Low ... + specs = config.lowStyle; + if (specs.draw) + { + // + double value = c.low; + string valueTag = "|L|"; + + // + string mTag = baseTag + valueTag + ToString(value); + string mLblTag = baseTag + valueTag + "_lbl"; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + mTag, + chartId, + subWindow // + ); + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteText( + chartId, + mLblTag // + ); + + // + DeleteTrendLine( + chartId, + mTag); + } + + // + if (canDraw) + { + // + // Draw Label ... + if (StringLen(specs.label) > 0) + { + DrawText( + chartId, + mLblTag, + subWindow, + cTime, + value, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw ... + DrawTrendLine( + chartId, + mTag, + subWindow, + time, + value, + cTime, + value, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); + } + } +} + +// +void DrawCandleAsBox( + long chartId, // Chart ID ... + int subWindow, // SubWindow ... + XOHCL &c, // the Candle Which required to Draw ... + const datetime time, // Candle Time ... + XOHCLDrawSpecification &config, // Draw Specifications ... + string tag = "", // Draw Tag ... + bool drawBody = true, // Draw Body ... + bool drawShadows = true, // Draw Shadows ... + bool update = true // Update Draw if Exists ... +) +{ + // + datetime cTime = TimeCurrent(); + + // + // First Check all Styles Must Be Draw true ... + bool canDraw = + // + config.openStyle.draw && + config.highStyle.draw && + config.closeStyle.draw && + config.lowStyle.draw + // + ; + + // + if (!canDraw) + { + return; + } + + // + // Next we have to determine Candle is Bullish or Bearish ... + // + bool isBullish = + c.open < c.close; + + // + bool isBearish = + c.open > c.close; + + // + XDrawSpecifications bodySpec; + if (isBullish) + { + bodySpec = config.openStyle; + } + else if (isBearish) + { + bodySpec = config.closeStyle; + } + else + { + // + bodySpec.clr = clrGray; + } + + // + // Now We have to Draw 3 Rectangle ... + // 1- Up Shadow + // 2- Candle Body + // 3- Down Shadow + + // + double upPrice = MathMax(c.open, c.close); + double downPrice = MathMin(c.open, c.close); + double upShadowSize = c.high - upPrice; + double downShadowSize = downPrice - c.low; + + // + string mTag = GenerateTag(c); + + // + // Draw Up Shadow ... + if (drawShadows) + { + // + string upShadowTag = mTag + "|US|"; + + XDrawSpecifications spec = config.highStyle; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + upShadowTag, + chartId, + subWindow // + ); + + // + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteRectangle( + chartId, + upShadowTag // + ); + } + + // + if (canDraw) + { + // + // New ... + DrawRectangle( + chartId, + upShadowTag, + subWindow, + time, + c.high, + cTime, + upPrice, + spec.clr, + spec.style, + spec.width, + spec.fill, + spec.back, + spec.selection, + spec.hidden, + spec.zOrder // + ); + } + } + + // + // Draw Body ... + if (drawBody) + { + // + string bodyTag = mTag + "|BDY|"; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + bodyTag, + chartId, + subWindow // + ); + + // + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteRectangle( + chartId, + bodyTag // + ); + } + + // + if (canDraw) + { + // + // New ... + DrawRectangle( + chartId, + bodyTag, + subWindow, + time, + upPrice, + cTime, + downPrice, + bodySpec.clr, + bodySpec.style, + bodySpec.width, + bodySpec.fill, + bodySpec.back, + bodySpec.selection, + bodySpec.hidden, + bodySpec.zOrder // + ); + } + } + + // + // Draw Down Shadow ... + if (drawShadows) + { + // + string downShadowTag = mTag + "|DS|"; + + XDrawSpecifications spec = config.lowStyle; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + downShadowTag, + chartId, + subWindow // + ); + + // + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteRectangle( + chartId, + downShadowTag // + ); + } + + // + if (canDraw) + { + // + // New ... + DrawRectangle( + chartId, + downShadowTag, + subWindow, + time, + downPrice, + cTime, + downPrice + downShadowSize, + spec.clr, + spec.style, + spec.width, + spec.fill, + spec.back, + spec.selection, + spec.hidden, + spec.zOrder // + ); + } + } +} + +// +// END Custom Drawings ... +// diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.http.lib.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.http.lib.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.http.lib.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.http.lib.ex5 diff --git a/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.http.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.http.lib.mq5 new file mode 100644 index 0000000..97f7ac0 --- /dev/null +++ b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.http.lib.mq5 @@ -0,0 +1,177 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Http Library +// ------------------------------------------ +// Name: XHttp +// Description: provide http communication +// abilities ... +// +// +// 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 + +// +// START Model Definition ... +// +enum X_HTTP_METHOD +{ + X_HTTP_GET, + X_HTTP_POST +}; +// +// END Model Definition ... +// + +// +// START Inputs ... +// +// +// END Inputs ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// +// +// Initial Library if required ... +bool OnInInitHttpLibrary() +{ + return false; +} + +// +// DeInitial Library if required ... +void OnDeinitHttpLibrary() +{ +} + +// +// Convert enum to String ... +string ToString(X_HTTP_METHOD method) +{ + // + string result = ""; + + // + switch (method) + { + // + case X_HTTP_GET: + result = "GET"; + break; + + // + case X_HTTP_POST: + result = "POST"; + break; + } + + // + return result; +} + +// +// Send Global Request ... +int SendRequest( + X_HTTP_METHOD method, // Httm Request Method + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 +) +{ + // + int result = -1; + + // + string strMethod = ToString(method); + if (StringLen(strMethod) == 0) { + return result; + } + + // + result = WebRequest( + strMethod, + url, + headers, + timeout, + payload, + response, + responseHeaders + ); + + // + return result; +} + +// +// Get Request ... +int GetRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 +) { + // + int result = SendRequest( + X_HTTP_GET, + url, + headers, + payload, + response, + responseHeaders, + timeout + ); + + // + return result; +} + +// +// Post Request ... +int PostRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 +) { + // + int result = SendRequest( + X_HTTP_POST, + url, + headers, + payload, + response, + responseHeaders, + timeout + ); + + // + return result; +} +// +// END Provided Functions ... +// diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.log.lib.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.log.lib.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.log.lib.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.log.lib.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.log.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.log.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.log.lib.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.log.lib.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.models.lib.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.models.lib.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.models.lib.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.models.lib.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.models.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.models.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.models.lib.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.models.lib.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.seriallizer.lib.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.seriallizer.lib.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.seriallizer.lib.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.seriallizer.lib.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.seriallizer.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.seriallizer.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.seriallizer.lib.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.seriallizer.lib.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.condition.parser.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.condition.parser.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.condition.parser.lib.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.condition.parser.lib.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.draw.lib.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.draw.lib.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.draw.lib.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.draw.lib.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.draw.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.draw.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.draw.lib.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.draw.lib.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.x786.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.x786.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.x786.lib.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.x786.lib.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.x92.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.x92.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.x92.lib.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.x92.lib.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.xtest.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.xtest.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.x121.xtest.lib.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.x121.xtest.lib.mq5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.xman.parser.lib.ex5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.xman.parser.lib.ex5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.xman.parser.lib.ex5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.xman.parser.lib.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.xman.parser.lib.mq5 b/MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.xman.parser.lib.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Libraries/x-saherelm.xman.parser.lib.mq5 rename to MQLTestWorkspace/BKPS/XBEEA/14030224/Libraries/x-saherelm.xman.parser.lib.mq5 diff --git a/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.http.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.http.class.mq5 new file mode 100644 index 0000000..e28342d --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.http.class.mq5 @@ -0,0 +1,385 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCHttp +// Description: provides all HTTP 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 + +// +// START Definitions ... +// + +// +enum X_HTTP_METHOD +{ + X_HTTP_GET, + X_HTTP_POST +}; + +// +// Convert enum to String ... +string ToString(X_HTTP_METHOD method) +{ + // + string result = ""; + + // + switch (method) + { + // + case X_HTTP_GET: + result = "GET"; + break; + + // + case X_HTTP_POST: + result = "POST"; + break; + } + + // + return result; +} + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Class for Manage Account ... +class XSCHttp +{ + // + // Public ... +public: + // + // Constructor ... + void XSCHttp() + { + XSCHttp("", 10000); + } + void XSCHttp( + string path, // Base Folder to Store Data + int timeout // base timeout for Requests + ) + { + // + Path(path); + Timeout(timeout); + } + + // + // Deconstructor ... + void ~XSCHttp() + { + } + + // + // START Getter(s)/Setter(s) ... + // + + // + // Path ... + void Path(string value) + { + mPath = value; + } + + string Path() + { + return mPath; + } + + // + // Timeout ... + void Timeout(int value) + { + mTimeout = value; + } + + // + int Timeout() + { + return mTimeout; + } + + // + // Error ... + int Error() + { + return mError; + } + + // + // Response ... + string Response() + { + return mResponse; + } + + // + // END Getter(s)/Setter(s) ... + // + + // + // START Provided Functions ... + // + + // + // Send Global Request ... + int SendRequest( + X_HTTP_METHOD method, // Httm Request Method + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = -1; + + // + string strMethod = ToString(method); + if (StringLen(strMethod) == 0) + { + return result; + } + + // + // Reset State ... + ResetState(); + + // + result = WebRequest( + strMethod, + url, + headers, + timeout, + payload, + response, + responseHeaders); + + // + if (result < 0) + { + mError = GetLastError(); + } + else + { + mResponse = CharArrayToString(response); + } + + // + return result; + } + + // + // Get Request ... + int GetRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = SendRequest( + X_HTTP_GET, + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + return result; + } + + // + // Post Request ... + int PostRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = SendRequest( + X_HTTP_POST, + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + return result; + } + + // + // Handle Download Specific URL Content to Specific Path and File Name ... + bool Download( + string url, // the URL address which going to download + string fileName // Specify Destination file name to Store Response + ) + { + // + bool result = false; + + // + string filePath = GetFilePath(fileName); + string cookie = NULL; + string referer = NULL; + int timeout = Timeout(); + + // + char payload[]; + string headers; + char response[]; + string responseHeaders; + + // + // Send Request ... + int requestResult = GetRequest( + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + // Define File Handler ... + int mFileHandler = FileOpen( + filePath, + FILE_WRITE | FILE_BIN); + if (mFileHandler == INVALID_HANDLE) + { + // + mError = GetLastError(); + return result; + } + + // + // Write Response to File ... + uint writed = FileWriteArray( + mFileHandler, + response, + 0, + ArraySize(response)); + FileFlush(mFileHandler); + FileClose(mFileHandler); + + // + result = writed > 0; + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... +protected: + // + // Destintion Folder Path ... + string mPath; + + // + // WEB Request Timeout Value ... + int mTimeout; + + // + // WEB Request's Response ... + string mResponse; + + // + // Error Value ... + int mError; + + // + // Private ... +private: + // + // Reset Errors State ... + void ResetState() + { + // + // Reset Errors ... + mError = -1; + mResponse = ""; + ResetLastError(); + } + + // + // Generate Full File Path ... + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + Path() + "\\" + fileName + // + ; + + // + return result; + } +}; + +// +// START Usefull Functions ... +// + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.x121.provider.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.x121.provider.class.ex5 new file mode 100644 index 0000000..86ed200 Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.x121.provider.class.ex5 differ diff --git a/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.x121.provider.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.x121.provider.class.mq5 new file mode 100644 index 0000000..4a423b0 --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.x121.provider.class.mq5 @@ -0,0 +1,1788 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCX121Provider +// Description: X121 Signal Provider ... +// +// +// 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 + +// +// START Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Classes/x-saherelm.xprovider.class.mq5" +#include "../Helpers/x-saherelm.x121.xct.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xcc.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xhk.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xtm.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xpv.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xama.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xmrb.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xche.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xich.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xtrnd.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xsslc.helper.class.mq5" +#include "../Helpers/x-saherelm.x121.xhull.helper.class.mq5" + +// +// Seriallizer Library ... +#include "../Libraries/x-saherelm.seriallizer.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// Here we Have to Define an Input Structure Model +// for Provider Class to Handle Helpers Definitions ... +struct X121ProviderInputs +{ + // + // XCT ... + // Candle Timer ... + XCTInputs xctConfig; + + // + // XCC ... + // Candle Styling ... + XCCInputs xccConfig; + + // + // XHK ... + // HikenAshi Candle Representing ... + XHKInputs xhkConfig; + + // + // XTM ... + // Trend Magic ... + XTMInputs xtmConfig; + + // + // XPV ... + // Peaks And Vales ... + XPVInputs xpvConfig; + + // + // XAMA ... + // Adaptive Moving Average ... + XAMAInputs xamaConfig; + + // + // XMRB ... + // Moving Average Ribbon ... + XMRBInputs xmrbConfig; + + // + // XCHE ... + // Chandelier Exit Points ... + XCHEInputs xcheConfig; + + // + // XICH ... + // Ichimopku Kinko Hyo ... + XICHInputs xichConfig; + + // + // XTRND ... + // Trend Detector ... + XTRNDInputs xtrndConfig; + + // + // XSSLC ... + // SSL Channel ... + XSSLCInputs xsslcConfig; + + // + // XHULL ... + // Hull Trend Detection Channel ... + XHULLInputs xhullConfig; +}; + +// +// Model Market Sense based On Current Captured conditions ... +struct X121MarketConditions +{ + // + // Commonly Used Info ... + + // + // Symbol ... + string symbol; + + // + // Period ... + ENUM_TIMEFRAMES period; + + // + // Bar Time ... + datetime barTime; + + // + XCandleRemains barRemains; + + // + // Bar Index ... + int barIndex; + + // + // Check Current Market Condition has Signal or not ... + bool hasSignal; + + // + // If has any Signal, Models it's related info here ... + XSignal signal; + + // + // Support and Resistances ... + // if provides Signal ... + XOHCLSupRes supportResistances; + + // + // Change Price Steps ... + double momentumStep; + + // + // INDICATORS Market Sense ... + + // + // XCT ... + // there is not any Info provided here ... + + // + // XCC ... + // there is not any Info provided here ... + + // + // XHK ... + XHKInfo xhkInfo; + + // + // XTM ... + XTMInfo xtmInfo; + + // + // XPV ... + XPVInfo xpvInfo; + + // + // XAMA ... + XAMAInfo xamaInfo; + + // + // XMRB ... + XMRBInfo xmrbInfo; + + // + // XCHE ... + XCHEInfo xcheInfo; + + // + // XICH ... + XICHInfo xichInfo; + + // + // XTRND ... + XTRNDInfo xtrndInfo; + + // + // XSSLC ... + XSSLCInfo xsslcInfo; + + // + // XHULL ... + XHULLInfo xhullInfo; +}; + +// +// Notified a Signal was Appears ... +typedef void (*TOnSignalConditions)( + X121MarketConditions &info); + +// +// All Available Signal Types ... +enum ENUM_X121_SIGNAL_PROVIDERS +{ + NONE, // NONE ... + XPVF, // Peakse and Vales Using Fibo ... + XCHNL, // SSL Channel and MRB Signals ... + XTRND, // Trend Base ... +}; + +// +// END Definitions ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Base Class for All of our EA's ... +class XSCX121Provider : public XSCEABaseProvider +{ + // + // Public ... +public: + // + // Props ... + X121ProviderInputs providedConfig; + X121ProviderInputs currentConfig; + X121ProviderInputs cleanConfig; + + // + // Indicator Helper Classes Instance ... + + // + // XCT ... + XSCXCTHelper *mXCTHelper; + + // + // XCC ... + XSCXCCHelper *mXCCHelper; + + // + // XHK ... + XSCXHKHelper *mXHKHelper; + + // + // XTM ... + XSCXTMHelper *mXTMHelper; + + // + // XPV ... + XSCXPVHelper *mXPVHelper; + + // + // XAMA ... + XSCXAMAHelper *mXAMAHelper; + + // + // XMRB ... + XSCXMRBHelper *mXMRBHelper; + + // + // XCHE ... + XSCXCHEHelper *mXCHEHelper; + + // + // XICH ... + XSCXICHHelper *mXICHHelper; + + // + // XTRND ... + XSCXTRNDHelper *mXTRNDHelper; + + // + // XSSLC ... + XSCXSSLCHelper *mXSSLCHelper; + + // + // XHULL ... + XSCXHULLHelper *mXHULLHelper; + + // + // Hull Pivot Points ... + double upZonePivots[]; + double downZonePivots[]; + + // + // Peaks and Vales Verifications Number ... + double peaksPivots[]; + double valesPivots[]; + + // + double ichPivots[]; + + // + double fiboPivots[]; + + // + int pvConsequences; + + // + // Constructor ... + void XSCX121Provider( + string symbol, // Trading Symbol ... + ENUM_TIMEFRAMES period // Trading Time Frame ... + ) + { + // + mMinPivots = 100; + pvConsequences = 26; + mDisableXPVFShort = false; + mDisableXPVFLong = false; + + // + PrepareTag(); + } + + // + // Deconstructor ... + void ~XSCX121Provider() + { + // + IndicatorRelease(mCTimerHandler); + + // + // De construct Helpers ... + delete mXCTHelper; + delete mXCCHelper; + delete mXHKHelper; + delete mXTMHelper; + delete mXPVHelper; + delete mXAMAHelper; + delete mXMRBHelper; + delete mXCHEHelper; + delete mXICHHelper; + delete mXTRNDHelper; + delete mXSSLCHelper; + delete mXHULLHelper; + } + + // + int GetMinPivots() { + return mMinPivots; + } + + // + virtual void PrepareTag() + { + mTag = "X121Provider((" + mSymbol + ")(" + ToString(mPeriod) + ")"; + } + + // + virtual bool Init() + { + // + bool result = false; + + // + // Instantiate all Indicators Helper Classes ... + + // + // XCT ... + mXCTHelper = new XSCXCTHelper( + mSymbol, + mPeriod); + result = mXCTHelper.SetConfig(currentConfig.xctConfig); + if (!result) + { + return result; + } + + // + // XCC ... + mXCCHelper = new XSCXCCHelper( + mSymbol, + mPeriod); + result = mXCCHelper.SetConfig(currentConfig.xccConfig); + if (!result) + { + return result; + } + + // + // XHK ... + mXHKHelper = new XSCXHKHelper( + mSymbol, + mPeriod); + result = mXHKHelper.SetConfig(currentConfig.xhkConfig); + if (!result) + { + return result; + }; + + // + // XTM ... + mXTMHelper = new XSCXTMHelper( + mSymbol, + mPeriod); + result = mXTMHelper.SetConfig(currentConfig.xtmConfig); + if (!result) + { + return result; + }; + + // + // XPV ... + mXPVHelper = new XSCXPVHelper( + mSymbol, + mPeriod); + result = mXPVHelper.SetConfig(currentConfig.xpvConfig); + if (!result) + { + return result; + }; + + // + // XAMA ... + mXAMAHelper = new XSCXAMAHelper( + mSymbol, + mPeriod); + result = mXAMAHelper.SetConfig(currentConfig.xamaConfig); + if (!result) + { + return result; + }; + + // + // XMRB ... + mXMRBHelper = new XSCXMRBHelper( + mSymbol, + mPeriod); + result = mXMRBHelper.SetConfig(currentConfig.xmrbConfig); + if (!result) + { + return result; + }; + + // + // XCHE ... + mXCHEHelper = new XSCXCHEHelper( + mSymbol, + mPeriod); + result = mXCHEHelper.SetConfig(currentConfig.xcheConfig); + if (!result) + { + return result; + }; + + // + // XICH ... + mXICHHelper = new XSCXICHHelper( + mSymbol, + mPeriod); + result = mXICHHelper.SetConfig(currentConfig.xichConfig); + if (!result) + { + return result; + }; + + // + // XTRND ... + mXTRNDHelper = new XSCXTRNDHelper( + mSymbol, + mPeriod); + result = mXTRNDHelper.SetConfig(currentConfig.xtrndConfig); + if (!result) + { + return result; + }; + + // + // XSSLC ... + mXSSLCHelper = new XSCXSSLCHelper( + mSymbol, + mPeriod); + result = mXSSLCHelper.SetConfig(currentConfig.xsslcConfig); + if (!result) + { + return result; + }; + + // + // XHULL ... + mXHULLHelper = new XSCXHULLHelper( + mSymbol, + mPeriod); + result = mXHULLHelper.SetConfig(currentConfig.xhullConfig); + if (!result) + { + return result; + }; + + // + return result; + } + + // + virtual int GetMaxLength() + { + // + int result = -1; + + // + result = MathMax(result, mXCTHelper.GetMaxLength()); + result = MathMax(result, mXCCHelper.GetMaxLength()); + result = MathMax(result, mXHKHelper.GetMaxLength()); + result = MathMax(result, mXTMHelper.GetMaxLength()); + result = MathMax(result, mXPVHelper.GetMaxLength()); + result = MathMax(result, mXAMAHelper.GetMaxLength()); + result = MathMax(result, mXMRBHelper.GetMaxLength()); + result = MathMax(result, mXCHEHelper.GetMaxLength()); + result = MathMax(result, mXICHHelper.GetMaxLength()); + result = MathMax(result, mXTRNDHelper.GetMaxLength()); + result = MathMax(result, mXSSLCHelper.GetMaxLength()); + result = MathMax(result, mXHULLHelper.GetMaxLength()); + + // + return result; + } + + // + virtual int GetCalculatedBars() + { + // + int result = -1; + + // + int mXCTBars = mXCTHelper.GetCalculatedBars(); + int mXCCBars = mXCCHelper.GetCalculatedBars(); + int mXHKBars = mXHKHelper.GetCalculatedBars(); + int mXTMBars = mXTMHelper.GetCalculatedBars(); + int mXPVBars = mXPVHelper.GetCalculatedBars(); + int mXAMABars = mXAMAHelper.GetCalculatedBars(); + int mXMRBBars = mXMRBHelper.GetCalculatedBars(); + int mXCHEBars = mXCHEHelper.GetCalculatedBars(); + int mXICHBars = mXICHHelper.GetCalculatedBars(); + int mXTRNDBars = mXTRNDHelper.GetCalculatedBars(); + int mXSSLCBars = mXSSLCHelper.GetCalculatedBars(); + int mXHULLBars = mXHULLHelper.GetCalculatedBars(); + + // + int min = MathMin(mXCTBars, mXCCBars); + min = MathMin(min, mXHKBars); + min = MathMin(min, mXTMBars); + min = MathMin(min, mXPVBars); + min = MathMin(min, mXAMABars); + min = MathMin(min, mXMRBBars); + min = MathMin(min, mXCHEBars); + min = MathMin(min, mXICHBars); + min = MathMin(min, mXTRNDBars); + min = MathMin(min, mXSSLCBars); + min = MathMin(min, mXHULLBars); + + // + int max = MathMax(mXCTBars, mXCCBars); + max = MathMax(max, mXHKBars); + max = MathMax(max, mXTMBars); + max = MathMax(max, mXPVBars); + max = MathMax(max, mXAMABars); + max = MathMax(max, mXMRBBars); + max = MathMax(max, mXCHEBars); + max = MathMax(max, mXICHBars); + max = MathMax(max, mXTRNDBars); + max = MathMax(max, mXSSLCBars); + max = MathMax(max, mXHULLBars); + + // + result = min; + + // + return result; + } + + // + virtual void ProcessBuffers() + { + UpdatePivotPoints(); + } + + // + virtual bool ProcessTick(X121MarketConditions &conditions) + { + // + if (CanIgnoreTick()) { + return false; + } + + // + return ProcessSignals(conditions); + } + + // + X121ProviderInputs GetConfig() + { + // + X121ProviderInputs result; + + // + result = currentConfig; + + // + return result; + } + + // + bool SetConfig(X121ProviderInputs &config) + { + // + bool result = false; + + // + PrepareConfig(config); + + // + result = Init(); + + // + return result; + } + + // + bool ResetDefaultConfig() + { + // + bool result = SetConfig(providedConfig); + + // + return result; + } + + // + bool ShowCleanConfig() + { + // + currentConfig = cleanConfig; + + // + bool result = Init(); + + // + return result; + } + + // + bool ShowDefaultConfig() + { + // + currentConfig = providedConfig; + + // + bool result = Init(); + + // + return result; + } + + // + // Generate Market Sense ... + X121MarketConditions GetMarketConditions( + int barIndex // Specified Bar Index + ) + { + // + X121MarketConditions result; + + // + // Fill Common Data ... + result.symbol = mSymbol; + result.period = mPeriod; + result.barIndex = barIndex; + + // + datetime barTime = GetCandleTime( + mSymbol, + mPeriod, + barIndex); + result.barTime = barTime; + + // + int remainedCandle = barIndex > 0 + ? barIndex - 1 + : barIndex; + GetCandleRemainsTime( + result.barRemains, + mSymbol, + mPeriod, + remainedCandle); + + // + result.xhkInfo = mXHKHelper.GetInfo(barIndex); + result.xtmInfo = mXTMHelper.GetInfo(barIndex); + result.xpvInfo = mXPVHelper.GetInfo(barIndex); + result.xamaInfo = mXAMAHelper.GetInfo(barIndex); + result.xmrbInfo = mXMRBHelper.GetInfo(barIndex); + result.xcheInfo = mXCHEHelper.GetInfo(barIndex); + result.xichInfo = mXICHHelper.GetInfo(barIndex); + result.xtrndInfo = mXTRNDHelper.GetInfo(barIndex); + result.xsslcInfo = mXSSLCHelper.GetInfo(barIndex); + result.xhullInfo = mXHULLHelper.GetInfo(barIndex); + + // + return result; + } + + // + // TODO: Complete this ... + XOHCLSupRes GetSupportsAndResistances( + XSignal &signal, // Signal + int requirements = 10) + { + // + XOHCLSupRes result; + + // + int totalBars = Bars( + mSymbol, + mPeriod); + + // + int idx = 0; + + // + while ( + idx < totalBars - 17 || + ArraySize(result.sup) < requirements || + ArraySize(result.res) < requirements) + { + // + // Here we Try to Find Support and Resistances ... + + // + idx++; + } + + // + return result; + } + + // + bool GuardCheck(XGuard &guards[]) + { + // + bool result = false; + + // + Clean(guards); + + // + // Implement Guards Check ... + + // + return result; + } + + // + // Add Specific On SignalConditions Event Handler ... + int AddOnSignalConditionEventHandler(TOnSignalConditions handler) + { + // + ArrayResize( + mSignalConditionsEventHandlers, + ArraySize(mSignalConditionsEventHandlers) + 1); + + // + int result = ArraySize(mSignalConditionsEventHandlers) - 1; + mSignalConditionsEventHandlers[result] = handler; + + // + return result; + } + + // + // Remove All On Signal Event Handler ... + void ReoveOnSignalEventHandlers() + { + // + ArrayFree(mSignalConditionsEventHandlers); + } + + // + // Notify a Signal Found on all Event Listeners ... + void NotifyOnSignalConditionsEvent(X121MarketConditions &info) + { + // + int listenerCount = ArraySize(mSignalConditionsEventHandlers); + if (listenerCount <= 0) + { + return; + } + + // + // Loop Through Listeners ... + for (int i = 0; i < listenerCount; i++) + { + // + TOnSignalConditions listener = mSignalConditionsEventHandlers[i]; + + // + listener(info); + } + } + + // + void ProccessPivotPoints() + { + // + if (mStartPivotScan) + { + return; + } + + // + mStartPivotScan = true; + + // + int maxLength = GetMaxLength(); + int cBars = GetCalculatedBars(); + int scanSize = cBars - maxLength - 1; + for (int i = 1; i < scanSize; i++) + { + // + UpdatePivotPoints(i); + + // + int pivotsCount = CountPivots(); + if (pivotsCount >= mMinPivots) + { + break; + } + } + } + + // + int CountPivots() + { + // + int pivotSizes[]; + int upZoneCount = ArraySize(upZonePivots); + if (upZoneCount > 0) + { + // + Add( + upZoneCount, + pivotSizes); + } + + // + int downZoneCount = ArraySize(downZonePivots); + if (downZoneCount > 0) + { + // + Add( + downZoneCount, + pivotSizes); + } + + // + int peaksCount = ArraySize(peaksPivots); + if (peaksCount > 0) + { + // + Add( + peaksCount, + pivotSizes); + } + + // + int valesCount = ArraySize(valesPivots); + if (valesCount > 0) + { + // + Add( + valesCount, + pivotSizes); + } + + // + int fibsCount = ArraySize(fiboPivots); + if (fibsCount > 0) + { + // + Add( + fibsCount, + pivotSizes); + } + + // + int ichsCount = ArraySize(ichPivots); + if (ichsCount > 0) + { + // + Add( + ichsCount, + pivotSizes); + } + + // + int result = ArraySize(pivotSizes) > 0 + ? pivotSizes[ArrayMaximum(pivotSizes)] + : 0; + + // + return result; + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // CCandle Timer ... + int mCTimerHandler; + + // + // Signal Event Handlers ... + TOnSignalConditions mSignalConditionsEventHandlers[]; + + // + // Make Provided Config in Clean Style ... + void PrepareConfig(X121ProviderInputs &config) + { + // + cleanConfig = config; + + // + // XCT ... + // Candle Timing ... + cleanConfig.xctConfig.showCandleTime = false; + + // + // XCC ... + // Candle Styling ... + cleanConfig.xccConfig.showCandles = true; + + // + // XHK ... + // HikenAshi Candle Representing ... + cleanConfig.xhkConfig.drawCandles = false; + cleanConfig.xhkConfig.drawCandleLines = false; + + // + // XTM ... + // Trend Magic ... + cleanConfig.xtmConfig.showLine = false; + + // + // XPV ... + // Peaks And Vales ... + cleanConfig.xpvConfig.showPeaksAndVales = false; + cleanConfig.xpvConfig.showLevels = false; + cleanConfig.xpvConfig.showFibo1Levels = false; + cleanConfig.xpvConfig.showFibo2Levels = false; + cleanConfig.xpvConfig.showFibo3Levels = false; + + // + // XAMA ... + // Adaptive Moving Average ... + cleanConfig.xamaConfig.showLine = false; + + // + // XMRB ... + // Moving Average Ribbon ... + cleanConfig.xmrbConfig.showFastMa = false; + cleanConfig.xmrbConfig.showSlowMa = false; + cleanConfig.xmrbConfig.showRibbon = false; + + // + // XCHE ... + // Chandelier Exit Points ... + cleanConfig.xcheConfig.showLongExit1Line = false; + cleanConfig.xcheConfig.showShortExit1Line = false; + cleanConfig.xcheConfig.showLongExit2Line = false; + cleanConfig.xcheConfig.showShortExit2Line = false; + + // + // XICH ... + // Ichimopku Kinko Hyo ... + cleanConfig.xichConfig.showTenkanSen = false; + cleanConfig.xichConfig.showKijunSen = false; + cleanConfig.xichConfig.showKijunSenPlus = false; + cleanConfig.xichConfig.showKijunSenNegative = false; + cleanConfig.xichConfig.showChikouSpan = false; + cleanConfig.xichConfig.showSenkouSpanA = false; + cleanConfig.xichConfig.showSenkouSpanB = false; + cleanConfig.xichConfig.showKumo = false; + + // + // XTRND ... + // Trend Detector ... + cleanConfig.xtrndConfig.showConsolidations = false; + cleanConfig.xtrndConfig.showTrend = false; + cleanConfig.xtrndConfig.showL1Trend = false; + cleanConfig.xtrndConfig.showL2Trend = false; + cleanConfig.xtrndConfig.showL3Trend = false; + + // + // XSSLC ... + // SSL Channel ... + cleanConfig.xsslcConfig.showUp = false; + cleanConfig.xsslcConfig.showDown = false; + + // + // XHULL ... + // Hull Trend Detection Channel ... + cleanConfig.xhullConfig.showUpZone = false; + cleanConfig.xhullConfig.showDownZone = false; + + // + providedConfig = config; + currentConfig = config; + } + + // + int mMinPivots; + bool mStartPivotScan; + bool mDisableXPVFLong; + bool mDisableXPVFShort; + double mLastMomentumStep; + + // + // Find Required Pivots for Support and Resistance ... + void UpdatePivotPoints( + int barIndex = 1 // Specified Candle ... + ) + { + // + mXCTHelper.Calculate(barIndex); + mXCCHelper.Calculate(barIndex); + mXHKHelper.Calculate(barIndex); + mXTMHelper.Calculate(barIndex); + mXPVHelper.Calculate(barIndex); + mXAMAHelper.Calculate(barIndex); + mXMRBHelper.Calculate(barIndex); + mXCHEHelper.Calculate(barIndex); + mXICHHelper.Calculate(barIndex); + mXTRNDHelper.Calculate(barIndex); + mXSSLCHelper.Calculate(barIndex); + mXHULLHelper.Calculate(barIndex); + + // + // Detect Peask and Vales Pivots ... + + // + // Detect Hull Pivots ... + // find Hull Trend Changes ... + int idx = 1; + bool isHullUpChanged = + // + ( + // + (XHULL_ZONE_STATES)mXHULLHelper.upStateBuffer[idx] == XHULL_STATE_BULLISH && + (XHULL_ZONE_STATES)mXHULLHelper.upStateBuffer[idx + 1] != XHULL_STATE_BULLISH + // + ) + // + || + // + ( + // + (XHULL_ZONE_STATES)mXHULLHelper.upStateBuffer[idx] == XHULL_STATE_BEARISH && + (XHULL_ZONE_STATES)mXHULLHelper.upStateBuffer[idx + 1] != XHULL_STATE_BEARISH + // + ) + // + ; + + // + bool isHullDownChanged = + // + ( + // + (XHULL_ZONE_STATES)mXHULLHelper.downStateBuffer[idx] == XHULL_STATE_BULLISH && + (XHULL_ZONE_STATES)mXHULLHelper.downStateBuffer[idx + 1] != XHULL_STATE_BULLISH + // + ) + // + || + // + ( + // + (XHULL_ZONE_STATES)mXHULLHelper.downStateBuffer[idx] == XHULL_STATE_BEARISH && + (XHULL_ZONE_STATES)mXHULLHelper.downStateBuffer[idx + 1] != XHULL_STATE_BEARISH + // + ) + // + ; + + // + // Find Change State ... + if (isHullUpChanged || + isHullDownChanged) + { + // + AddIfNotExists( + mXHULLHelper.upBuffer[idx], + upZonePivots); + + // + AddIfNotExists( + mXHULLHelper.downBuffer[idx], + downZonePivots); + } + + // + // Find Momentom Step ... + if (isHullUpChanged && + isHullDownChanged) + { + // + mLastMomentumStep = MathAbs(mXHULLHelper.upBuffer[idx] - mXHULLHelper.downBuffer[idx]); + mLastMomentumStep = NormalizePrice( + mLastMomentumStep, + mSymbol); + } + + // + // Find Peaks and Vales ... + double selectedFib1 = mXPVHelper.fl1Buffer[idx]; + double selectedFib2 = mXPVHelper.fl2Buffer[idx]; + double selectedFib3 = mXPVHelper.fl3Buffer[idx]; + double selectedPeak = mXPVHelper.peaksBuffer[idx]; + double selectedVale = mXPVHelper.valesBuffer[idx]; + + // + double selectedTenkanSen = mXICHHelper.tenkanSenBuffer[idx]; + double selectedKijunSen = mXICHHelper.kijunSenBuffer[idx]; + + // + int fib1Verified = 0; + int fib2Verified = 0; + int fib3Verified = 0; + int peaksVerified = 0; + int valesVerified = 0; + int kijunSenVerified = 0; + int tenkanSenVerified = 0; + int senkouSpanAVerified = 0; + int senkouSpanBVerified = 0; + for (int i = barIndex + 1; i < pvConsequences + barIndex + 1; i++) + { + // + int idx = i - barIndex; + + // + // PEAKS and VALES ... + + // + if (selectedPeak == mXPVHelper.peaksBuffer[idx]) + { + peaksVerified++; + } + else + { + peaksVerified = 0; + } + + // + if (selectedVale == mXPVHelper.valesBuffer[idx]) + { + valesVerified++; + } + else + { + valesVerified = 0; + } + + // + if (selectedFib1 == mXPVHelper.fl1Buffer[idx]) + { + fib1Verified++; + } + else + { + fib1Verified = 0; + } + + // + if (selectedFib2 == mXPVHelper.fl2Buffer[idx]) + { + fib2Verified++; + } + else + { + fib2Verified = 0; + } + + // + if (selectedFib3 == mXPVHelper.fl3Buffer[idx]) + { + fib3Verified++; + } + else + { + fib3Verified = 0; + } + + // + // ICHIMOKU Kinko Hyo ... + + // + if (selectedTenkanSen == mXICHHelper.tenkanSenBuffer[idx]) + { + tenkanSenVerified++; + } + else + { + tenkanSenVerified = 0; + } + + // + if (selectedKijunSen == mXICHHelper.kijunSenBuffer[idx]) + { + kijunSenVerified++; + } + else + { + kijunSenVerified++; + } + } + + // + if (peaksVerified >= pvConsequences) + { + // + AddIfNotExists( + selectedPeak, + peaksPivots); + } + + // + if (valesVerified >= pvConsequences) + { + // + AddIfNotExists( + selectedVale, + valesPivots); + } + + // + if (fib1Verified >= pvConsequences) + { + // + AddIfNotExists( + selectedFib1, + fiboPivots); + } + + // + if (fib2Verified >= pvConsequences) + { + // + AddIfNotExists( + selectedFib2, + fiboPivots); + } + + // + if (fib3Verified >= pvConsequences) + { + // + AddIfNotExists( + selectedFib3, + fiboPivots); + } + + // + if (tenkanSenVerified >= pvConsequences) + { + // + AddIfNotExists( + selectedTenkanSen, + ichPivots); + } + + // + if (kijunSenVerified >= pvConsequences) + { + // + AddIfNotExists( + selectedKijunSen, + ichPivots); + } + + // // + // if (senkouSpanAVerified >= pvConsequences) + // { + // // + // AddIfNotExists( + // selectedSenkouSpanA, + // ichPivots); + // } + + // // + // if (senkouSpanBVerified >= pvConsequences) + // { + // // + // AddIfNotExists( + // selectedSenkouSpanB, + // ichPivots); + // } + } + + // + void FillPivotPoints( + double &result[]) + { + // + Clean(result); + + // + int pCount = CountPivots(); + if (pCount <= 0) + { + return; + } + + // + AddsIfNotExists( + upZonePivots, + result); + + // + AddsIfNotExists( + downZonePivots, + result); + + // + AddsIfNotExists( + peaksPivots, + result); + + // + AddsIfNotExists( + valesPivots, + result); + + // + AddsIfNotExists( + fiboPivots, + result); + + // + AddsIfNotExists( + ichPivots, + result); + } + + // + // Here we are Capture Conditions and Check Signals ... + // The Signals Must be Unique for each providers ... + bool ProcessSignals(X121MarketConditions &conditions) + { + // + X121MarketConditions mConditions = GetMarketConditions(1); + + // + // BUY ... + + // + Clean(mConditions.signal); + bool hasLongSignal = HasLongSignal(mConditions); + if (hasLongSignal) + { + // + NotifyOnSignalEvent( + mConditions.signal); + NotifyOnSignalConditionsEvent(mConditions); + mWaitUntilNewCandle = true; + + // + conditions = mConditions; + return true; + } + + // + // SELL ... + + // + Clean(mConditions.signal); + bool hasShortignal = HasShortSignal(mConditions); + if (hasShortignal) + { + // + NotifyOnSignalEvent( + mConditions.signal); + NotifyOnSignalConditionsEvent(mConditions); + mWaitUntilNewCandle = true; + + // + conditions = mConditions; + return true; + } + + // + return false; + } + + // + // Check has Long Signal on Each Strategies ... + bool HasLongSignal(X121MarketConditions &conditions) + { + // + bool result = false; + + // + double entry = GetEntry( + mSymbol, + POSITION_TYPE_BUY); + + // + XOHCL c1 = GetCandle( + mSymbol, + mPeriod, + 1); + + // + double pivots[]; + FillPivotPoints(pivots); + XOHCLSupRes supRes = ExtractSupportAndResistance( + 1, + pivots, + 15); + X121MarketConditions mConditions = GetMarketConditions(1); + + // + mXPVHelper.Calculate(1); + + // + Clean(mConditions.signal); + + // + // XPVF Signal Provider ... + bool xPVFSignal = false; + if (!mDisableXPVFLong) + { + // + xPVFSignal = + // + mConditions.xpvInfo.isNewPeak && + mXPVHelper.peaksBuffer[0] < mXPVHelper.peaksBuffer[1] && + mXPVHelper.valesBuffer[0] == mXPVHelper.valesBuffer[1] + // + ; + + // + if (xPVFSignal) + { + // + Add( + ToString(XPVF), + mConditions.signal.providers); + + // + mConditions.signal.r2r = 1.5; + mConditions.signal.riskAmount = 0.005; + mConditions.signal.mode = X_ORDER_MODE_MARKET; + mConditions.signal.entry = entry; + mConditions.signal.sl = 0; // mXCHEHelper.longExit2[1]; + mConditions.signal.tp = 0; + + // + // mConditions.signal.calculateTP = true; + // mConditions.signal.useRiskAmountAsVolume = false; + // mConditions.signal.useSupportAndResistance = true; + + // + // mDisableXPVFLong = true; + // mDisableXPVFShort = false; + } + } + + // + result = + // + xPVFSignal + // + ; + + // + if (result) + { + // + conditions = mConditions; + + // + conditions.supportResistances = supRes; + conditions.momentumStep = mLastMomentumStep; + + // + conditions.signal.symbol = mSymbol; + conditions.signal.period = mPeriod; + conditions.signal.type = POSITION_TYPE_BUY; + + // + conditions.hasSignal = true; + } + + // + return result; + } + + // + // Check has Short Signal on Each Strategies ... + bool HasShortSignal(X121MarketConditions &conditions) + { + // + bool result = false; + + // + double entry = GetEntry( + mSymbol, + POSITION_TYPE_SELL); + + // + XOHCL c1 = GetCandle( + mSymbol, + mPeriod, + 1); + + // + double pivots[]; + FillPivotPoints(pivots); + XOHCLSupRes supRes = ExtractSupportAndResistance( + 1, + pivots, + 15); + + // + X121MarketConditions mConditions = GetMarketConditions(1); + + // + mXPVHelper.Calculate(1); + + // + Clean(mConditions.signal); + + // + // XPVF Signal Provider ... + bool xPVFSignal = false; + if (!mDisableXPVFShort) + { + // + xPVFSignal = + // + mConditions.xpvInfo.isNewVale && + mXPVHelper.valesBuffer[0] > mXPVHelper.valesBuffer[1] && + mXPVHelper.peaksBuffer[0] == mXPVHelper.peaksBuffer[1] + // + ; + + // + if (xPVFSignal) + { + // + Add( + ToString(XPVF), + mConditions.signal.providers); + + // + mConditions.signal.r2r = 1.5; + mConditions.signal.riskAmount = 0.005; + mConditions.signal.mode = X_ORDER_MODE_STOP; + mConditions.signal.entry = entry; + mConditions.signal.sl = 0; + mConditions.signal.tp = mXPVHelper.valesBuffer[1]; + + // + mConditions.signal.calculateTP = true; + mConditions.signal.useRiskAmountAsVolume = false; + mConditions.signal.useSupportAndResistance = true; + + // + // mDisableXPVFShort = true; + // mDisableXPVFLong = false; + } + } + + // + result = + // + xPVFSignal + // + ; + + // + if (result) + { + // + conditions = mConditions; + + // + conditions.supportResistances = supRes; + conditions.momentumStep = mLastMomentumStep; + + // + conditions.signal.symbol = mSymbol; + conditions.signal.period = mPeriod; + conditions.signal.type = POSITION_TYPE_SELL; + + // + conditions.hasSignal = true; + } + + // + return result; + } +}; + +// +// START Definitions ... +// + +// +// Model Signal Providers Definitions ... +struct X121SignalProvider +{ + // + // Provider use Which Symbol ... + string symbol; + + // + // Provider use Which Time Frame ... + ENUM_TIMEFRAMES period; + + // + // Risk Amount Per Trades Related to Time Frames ... + // Percent of Available Balance ... + double riskAmount; + + // + // Desired Magic Number ... + ulong magicNumber; + + // + // Provider ... + XSCX121Provider *provider; +}; + +// +// END Definitions ... +// + +// +// START Usefull Functions ... +// + +// +// Add Specific Provider to List ... +void Add( + X121SignalProvider &item, // item want to add + X121SignalProvider &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} + +// +// Generate Identifier Tag ... +string GenerateTag(X121SignalProvider &descriptor) +{ + // + string result = ""; + + // + result = descriptor.symbol + "," + ToString(descriptor.period); + + // + return result; +} + +// +// Converts a Signal provider to String ... +string ToString(ENUM_X121_SIGNAL_PROVIDERS provider) +{ + return EnumToString(provider); +} + +// +// convert an String to Signal provider ... +ENUM_X121_SIGNAL_PROVIDERS ToProvider(string provider) +{ + // + ENUM_X121_SIGNAL_PROVIDERS result = NONE; + + // + if (ToString(NONE) == provider) + { + result = NONE; + } + else if (ToString(XPVF) == provider) + { + result = XPVF; + } + else if (ToString(XCHNL) == provider) + { + result = XCHNL; + } + else if (ToString(XTRND) == provider) + { + result = XTRND; + } + + // + return result; +} + +// +// Extract Provider Type from Signal Commnet ... +ENUM_X121_SIGNAL_PROVIDERS ExtractPositionProvider(XPosition &position) +{ + // + ENUM_X121_SIGNAL_PROVIDERS result = NONE; + + // + string providerStr = + ExtractString( + position.comment, + XProviderToken + "(", + ")"); + if (StringLen(providerStr) <= 0) + { + return result; + } + + // + result = ToProvider(providerStr); + + // + return result; +} + +// +// Generate Provider String for Using in Positions Comment ... +// NOTE: if there is more than One Provider, it takes first +// provider as main and the others used to increase volume ... +string GenerateProvidersString(XSignal &signal) +{ + // + string result = ""; + + // + int providersCount = ArraySize(signal.providers); + if (providersCount <= 0) + { + return result; + } + + // + result = XProviderToken + "(" + signal.providers[0] + ")"; + + // + return result; +} + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/Classes/x-saherelm.x121.xea.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.x121.xea.class.mq5 similarity index 100% rename from MQLTestWorkspace/Classes/x-saherelm.x121.xea.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.x121.xea.class.mq5 diff --git a/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xaccount.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xaccount.class.mq5 new file mode 100644 index 0000000..4425f0b --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xaccount.class.mq5 @@ -0,0 +1,398 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCAccount +// Description: provides all Account 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 + +// +// START Definitions ... +// + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Class for Manage Account ... +class XSCAccount +{ + // + // Public ... +public: + // + // Constructor ... + void XSCAccount() + { + // + mAccountInfo = new CAccountInfo(); + } + + // + // Deconstructor ... + void ~XSCAccount() + { + } + + // + // START Provided Functions ... + // + + // + // User Account ... + long GetUserAccount() + { + return mAccountInfo.Login(); + } + + // + // Account Leverage ... + long GetLeverage() + { + return mAccountInfo.Leverage(); + } + + // + // Get Trade Expert State ... + bool CanExpertTrade() + { + return mAccountInfo.TradeExpert(); + } + + // + // User Account Trade Mopde (ENUM_ACCOUNT_TRADE_MODE) ... + // -------------------------- + // ACCOUNT_TRADE_MODE_DEMO + // ACCOUNT_TRADE_MODE_CONTEST + // ACCOUNT_TRADE_MODE_REAL + ENUM_ACCOUNT_TRADE_MODE GetTradeMode() + { + return mAccountInfo.TradeMode(); + } + + // + // Get Account Balance ... + double GetBalance() + { + return mAccountInfo.Balance(); + } + + // + // Get the amount of give Credit ... + double GetCredit() + { + return mAccountInfo.Credit(); + } + + // + // Get the amount of current Profit on account ... + double GetProfit() + { + return mAccountInfo.Profit(); + } + + // + // Get the amount of current Equity on account ... + double GetEquity() + { + return mAccountInfo.Equity(); + } + + // + // Get the amount of reserved Margin ... + double GetMargin() + { + return mAccountInfo.Margin(); + } + + // + // Get the amount of free Margin ... + double GetFreeMargin() + { + return mAccountInfo.FreeMargin(); + } + + // + // Get the Level of Margin ... + double GetMarginLevel() + { + return mAccountInfo.MarginLevel(); + } + + // + // Get the Level Of Margin for a Deposit ... + double GetMarginCall() + { + return mAccountInfo.MarginCall(); + } + + // + // Get the Level of Margin for Stop out ... + double GetMarginStopOut() + { + return mAccountInfo.MarginStopOut(); + } + + // + // Get the Client Name ... + string GetName() + { + return mAccountInfo.Name(); + } + + // + // Get the Trade Server Name ... + string GetServerName() + { + return mAccountInfo.Server(); + } + + // + // Get deposit Currency Name ... + string GetCurrency() + { + return mAccountInfo.Currency(); + } + + // + // Get the Company Name that serves an Account ... + string GetCompany() + { + return mAccountInfo.Company(); + } + + // + // Calculate Profits for the current account based on passed parameters ... + double CalculateTradeProfit( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry, // open price + double exit // close price + ) + { + // + double result = mAccountInfo.OrderProfitCheck( + symbol, + type, + volume, + entry, + exit); + + // + return result; + } + + // + // Calculate amount of margin which required for trade operation ... + double CalculateMarging( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry // open price + ) + { + // + double result = mAccountInfo.MarginCheck( + symbol, + type, + volume, + entry); + + // + return result; + } + + // + // Calculate amount of free margin left after trade operation ... + double CalculateFreeMarging( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry // open price + ) + { + // + double result = mAccountInfo.FreeMarginCheck( + symbol, + type, + volume, + entry); + + // + return result; + } + + // + // Calculate the Maximum possible volume of trade operation ... + double CalculateMaxVolume( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double entry, // open price + double percent = 100 // percent of available margin + ) + { + // + double result = mAccountInfo.MaxLotCheck( + symbol, + type, + entry, + percent); + + // + return result; + } + + // + // Calculate Point Value for Given Symbol based on Account ... + double GetPointValue( + string symbol // trading symbol + ) + { + // + double result = 0; + + // + double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); + double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); + double point = SymbolInfoDouble(symbol, SYMBOL_POINT); + + // + double ticksPerPoint = tickSize / point; + + // + result = tickValue / ticksPerPoint; + + // + return result; + } + + // + // Calculate Risk Amount based on account Currency by Providing: + // Points and Volume ... + double CalculateRiskAmount( + string symbol, // trading symbol + double points, // amount of Risk Points + double volume // position Volume + ) + { + // + double result = 0; + + // + double pointValue = GetPointValue(symbol); + + // + result = pointValue * volume * points; + + // + return result; + } + + // + // Calculate Risk Points based on account Currency by Providing: + // Volume and Amount ... + double CalculateRiskPoints( + string symbol, // trading symbol + double volume, // position Volume + double amount // amount of Risk based on Account Currency + ) + { + // + double result = 0; + + // + double pointValue = GetPointValue(symbol); + + // + result = amount / (pointValue * volume); + + // + return result; + } + + // + // Calculate Volume based on account Currency by Providing: + // Amount and Risk Points ... + double CalculateVolume( + string symbol, // trading symbol + double amount, // amount of Risk based on Account Currency + double points // amount of Risk Points + ) + { + // + double result = 0; + + // + points = + points <= 0 + ? 10 + : points; + + // + double pointValue = GetPointValue(symbol); + + // + result = amount / (pointValue * points); + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Account Info ... + CAccountInfo mAccountInfo; +}; + +// +// START Usefull Functions ... +// + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/Classes/x-saherelm.xdatacollector.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xdatacollector.class.mq5 similarity index 100% rename from MQLTestWorkspace/Classes/x-saherelm.xdatacollector.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xdatacollector.class.mq5 diff --git a/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xea.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xea.class.ex5 new file mode 100644 index 0000000..a52c19f Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xea.class.ex5 differ diff --git a/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xea.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xea.class.mq5 new file mode 100644 index 0000000..92dbc7f --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xea.class.mq5 @@ -0,0 +1,814 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCBaseEA +// Description: provides all Base EA 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 + +// +// START Definitions ... +// + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Libraries/x-saherelm.alert.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" +#include "../Classes/x-saherelm.xaccount.class.mq5" +#include "../Classes/x-saherelm.xprovider.class.mq5" +#include "../Libraries/x-saherelm.seriallizer.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Class for Handle base requirements ... +// for indicators ... +class XSCBaseEA +{ + // + // Public ... +public: + // + // Props ... + XSCTrade *mTrader; + XSCAccount *mAccount; + + // + bool isNewHour; + bool isNewDay; + bool isNewWeek; + bool isNewMonth; + bool isNewCandle; + + // + bool isInTestMode; + + // + bool mWaitsUntilNewCandle; + + // + // Constructor ... + void XSCBaseEA( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Time Frame + ulong magic, // Magic Number + int slippage, // Slippgae + OnStopLoss onStopLossTriggered = NULL, // On StopLoass Triggered Event Handler + OnTakeProfit onTakeProfitTriggered = NULL, // On TakeProfit Triggered Event Handler + OnDealsChanged onDealsChangedHandler = NULL, // On Deals Changed Event Handler + OnOrdersChanged onOrdersChangedHandler = NULL, // On Orders Changed Event Handler + OnPositionsChanged onPositionsChangedHandler = NULL, // On Positions Changed Event Handler + OnTradeStateChanged onTradeStateChangedHandler = NULL // On Trade State Changed Event Handler + ) + { + // + mSymbol = symbol; + mPeriod = period; + + // + mMagic = magic; + mSlippage = slippage; + + // + mOnStopLossTriggered = onStopLossTriggered; + mOnTakeProfitTriggered = onTakeProfitTriggered; + mOnDealsChangedHandler = onDealsChangedHandler; + mOnOrdersChangedHandler = onOrdersChangedHandler; + mOnPositionsChangedHandler = onPositionsChangedHandler; + mOnTradeStateChangedHandler = onTradeStateChangedHandler; + + // + // Reset Timings ... + ResetTiming(); + + // + InitRequirements(); + } + + // + // Deconstructor ... + void ~XSCBaseEA() + { + // + delete mTrader; + delete mAccount; + } + + // + // START Properties ... + // + + // + // Symbol ... + string GetSymbol() + { + return mSymbol; + } + + // + // Period ... + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + // + // Tag ... + string GetTag() + { + return mTag; + } + + // + ulong GetMagic() + { + return mMagic; + } + + // + int GetSlippage() + { + return mSlippage; + } + + // + // END Properties ... + // + + // + // START Provided Functions ... + // + + // + // Prepare Tag ... + virtual void PrepareTag() + { + mTag = "XEA" + mSymbol + "," + ToString(mPeriod) + (string)mMagic; + } + + // + // Handle Chart Events ... + virtual void OnChartEvent( + const int id, // event ID + const long &lparam, // long type event parameter + const double &dparam, // double type event parameter + const string &sparam // string type event parameter + ) + { + } + + // + // Check any Registered Providers Signalling ... + virtual bool SignalCheck(XSignal &signals[]) { + return false; + } + + // + // Check for any Custom Guard Actions Guard Actions ... + virtual bool CheckGuard(XGuard &guards[]) { + return false; + } + + // + // NOTE: you have to call these Functions on Static Classes to Handle Works ... + + // + // Handle StopLoss Event ... + virtual void OnStopLossTriggered(const XDeal &deal) {} + + // + // Handle TakeProfit Event ... + virtual void OnTakeProfitTriggered(const XDeal &deal) {} + + // + // Handle Deals Changed Event ... + virtual void OnDealsChangedHandler(int count) {} + + // + // Handle Order Changed Event ... + virtual void OnOrdersChangedHandler(int count) {} + + // + // Handle Position Changed Event ... + virtual void OnPositionsChangedHandler(int count) {} + + // + // Handle Trade State Changed ... + virtual void OnTradeStateChangedHandler(const XOnTradeHandlerState &state) {} + + // + // Implemented Actions ... + + // + // OnTick Handler ... + void OnTick() + { + // + // First Check Guards .... + XGuard guards[]; + bool hasGuard = CheckGuard(guards); + if (hasGuard) { + DoGuards(guards); + } + + // + XSignal signals[]; + bool hasSignal = SignalCheck(signals); + if (hasSignal) { + mTrader.ExecuteSignals(signals); + } + } + + // + // Handle On Trade ... + void OnTrade() + { + // + XOnTradeHandlerState state = mTrader.HandleOnTrade(); + + // + if ( + !state.hasNewDeal && + !state.hasNewOrder && + !state.hasNewPosition && + !state.hasNewHistoryOrder) + { + return; + } + + // + // STATE ... + + // + // Notfy Trade State Changed Event ... + OnTradeStateChangedHandler(state); + + // + // DEALS ... + if (state.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + OnDealsChangedHandler(state.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + mTrader.GetDeals(deals); + int dealsCount = ArraySize(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + OnTakeProfitTriggered(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + OnStopLossTriggered(lastDeal); + } + } + } + + // + // ORDERS ... + if (state.hasNewOrder || state.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + OnOrdersChangedHandler(state.newOrders + state.newHistoryOrders); + } + + // + // POSITIONS ... + if (state.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + OnPositionsChangedHandler(state.newPositions); + } + } + + // + // Retrieve Dept Of Market ... + void OnBookEvent(const string &symbol) + { + // + // TODO: Implement this ... + } + + // + // TOOLS ... + // + void GetPositions( + XPosition &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_POSITION_TYPE type = NULL, // Trading Type ... + ENUM_TIMEFRAMES period = NULL // Trading Period ... + ) + { + // + Clean(result); + + // + int positionsCount = mTrader.PositionsCount(); + if (positionsCount <= 0) + { + return; + } + + // + XPosition positions[]; + mTrader.GetPositions( + positions, + symbol, + period); + positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + if (type == NULL) + { + // + ArrayResize( + result, + ArraySize(positions)); + + // + for (int i = 0; i < positionsCount; i++) + { + // + Add( + positions[i], + result); + } + + // + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (type == NULL || iPosition.type == type) + { + // + Add( + iPosition, + result); + } + } + } + void GetPositions( + XPosition &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_POSITION_TYPE type = NULL, // Trading Type ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL // Signal Provider ... + ) + { + // + Clean(result); + + // + bool hasSymbol = !(symbol == NULL || StringLen(symbol) == 0); + bool hasProvider = !(provider == NULL || StringLen(provider) == 0); + + // + int positionsCount = mTrader.PositionsCount(); + if (positionsCount <= 0) + { + return; + } + + // + XPosition positions[]; + mTrader.GetPositions( + positions, + symbol, + period); + positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + if (!hasProvider && type == NULL) + { + // + ArrayResize( + result, + ArraySize(positions)); + + // + for (int i = 0; i < positionsCount; i++) + { + // + Add( + positions[i], + result); + } + + // + return; + } + + // + if (type == NULL) + { + // + ArrayResize( + result, + ArraySize(positions)); + + // + for (int i = 0; i < positionsCount; i++) + { + // + Add( + positions[i], + result); + } + + // + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + string iProvider = ExtractProvider(iPosition.comment); + if (hasProvider && iProvider != provider) + { + continue; + } + + // + if (type == NULL || iPosition.type == type) + { + // + Add( + iPosition, + result); + } + } + } + + // + // GUARD Handlers ... + + // + // Parse Recievd Guards and Do them ... + void DoGuards(XGuard &guards[]) + { + int guardsCount = ArraySize(guards); + if (guardsCount <= 0) + { + return; + } + + // + for (int i = 0; i < guardsCount; i++) + { + // + XGuard iGuard = guards[i]; + + // + switch (iGuard.action) + { + // + // Hedge In Profit Specified Positions ... + case X_GUARD_ACTION_HEDGE: + HandleGuardHedgeAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + + // + // Trail Stop Loss in Specified Positions ... + case X_GUARD_ACTION_TRAIL_STOP: + HandleGuardTrailingStopAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period, + iGuard.dblPayLoad); + break; + + // + // Force Close Specified Positions ... + case X_GUARD_ACTION_FORCE_CLOSE: + HandleGuardForceCloseAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + + // + // Generate and Place Support Signals ... + case X_GUARD_ACTION_ADD_SUPPORT_SIGNAL: + HandleGuardAddSupportPositionAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + + // + // Delete All Placed Pending Orders ... + case X_GUARD_ACTION_CANCEL_PENDING_ORDERS: + HandleGuardCancelPendingOrdersAction( + iGuard.provider, + iGuard.symbol, + iGuard.type, + iGuard.period); + break; + } + } + } + + // + // Close All Specified Provider's Positions in Profit Summary ... + void HandleGuardHedgeAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + double minProfitForHedging = 1 // Specified Profit for Hedge ... + ) + { + // + } + + // + // Force Close Specified Set Of Position ... + void HandleGuardForceCloseAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + ulong ticket = 0 // Specific Ticket + ) + { + // + string comment = ""; + + // + // Close All Positions ... + if (ticket == 0) + { + // + XPosition positions[]; + GetPositions( + positions, + symbol, + type, + period, + provider); + if (ArraySize(positions) <= 0) + { + return; + } + + // + comment = provider + " Force Close Guard ..."; + + // + mTrader.ClosePositions( + positions, + comment); + } + // + // Close Specific Position ... + else + { + // + XPosition position; + bool hasPosition = mTrader.GetPosition( + position, + ticket); + + // + if (hasPosition) + { + // + comment = provider + "(" + ToString(ticket) + ")" + " Force Close Guard ..."; + + // + mTrader.Close( + ticket, + comment); + } + } + + // + if (StringLen(comment) > 0) + { + LogMessage(comment); + } + } + + // + // Trailing Specified Set Of Positions Stop Losses ... + void HandleGuardTrailingStopAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + double sl // Desired SL Value ... + ) + { + // + // TODO: Implement this ... + } + + // + // Add Support Signal for Specified Positions ... + void HandleGuardAddSupportPositionAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period // Specified Time Frame + ) + { + // + // TODO: Implement this ... + } + + // + // Cancel all Placed Orders ... + void HandleGuardCancelPendingOrdersAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period // Specified Time Frame + ) + { + // + // TODO: Implement this ... + } + + // + // END Provided Functions ... + // + + // + // Protected ... +protected: + // + string GetTagPrefix() + { + // + string result = "(" + mSymbol + ")(" + ToString(mPeriod) + ")"; + + // + return result; + } + + // + // Symbol ... + string mSymbol; + + // + // Period ... + ENUM_TIMEFRAMES mPeriod; + + // + // ExpertAdviser MAgic Number ... + ulong mMagic; + + // + // Slipppage ... + int mSlippage; + + // + // Tag Identifier ... + string mTag; + + // + // Private ... +private: + // + // Define Requirements ... + + // + // XSCTrade Event Handlers ... + OnStopLoss mOnStopLossTriggered; + OnTakeProfit mOnTakeProfitTriggered; + OnDealsChanged mOnDealsChangedHandler; + OnOrdersChanged mOnOrdersChangedHandler; + OnPositionsChanged mOnPositionsChangedHandler; + OnTradeStateChanged mOnTradeStateChangedHandler; + + // + // Initi Requirements ... + void InitRequirements() + { + // + // Account Manager ... + mAccount = new XSCAccount(); + + // + // Trader ... + mTrader = new XSCTrade( + mSlippage, + mMagic); + + // + // Attach Event Handlers ... + + // + if (mOnStopLossTriggered != NULL) + { + mTrader.AddOnStopLossEventHandler(mOnStopLossTriggered); + } + + // + if (mOnTakeProfitTriggered != NULL) + { + mTrader.AddOnTakeProfitEventHandler(mOnTakeProfitTriggered); + } + + // + if (mOnDealsChangedHandler != NULL) + { + mTrader.AddOnDealsChangedEventHandler(mOnDealsChangedHandler); + } + + // + if (mOnOrdersChangedHandler != NULL) + { + mTrader.AddOnOrdersChangedEventHandler(mOnOrdersChangedHandler); + } + + // + if (mOnPositionsChangedHandler != NULL) + { + mTrader.AddOnPositionsChangedEventHandler(mOnPositionsChangedHandler); + } + + // + if (mOnTradeStateChangedHandler != NULL) + { + mTrader.AddOnTradeStateChangedEventHandler(mOnTradeStateChangedHandler); + } + } +}; + +// +// START Usefull Functions ... +// + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xhelper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xhelper.class.mq5 new file mode 100644 index 0000000..d9cea8b --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xhelper.class.mq5 @@ -0,0 +1,209 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCBaseHelper +// Description: provides all Base 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 + +// +// START Definitions ... +// + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Class for Handle base requirements ... +// for indicators ... +class XSCBaseHelper +{ + // + // Public ... +public: + // + // Constructor ... + void XSCBaseHelper( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period // Trading Time Frame + ) + { + // + mSymbol = symbol; + mPeriod = period; + + // + LoopBack(52); + } + + // + // Deconstructor ... + void ~XSCBaseHelper() + { + IndicatorRelease(mHandler); + } + + // + // START Properties ... + // + + // + // Loopback Bars ... + void LoopBack(int value) + { + mLoopbackBars = value; + } + + int Loopback() + { + return mLoopbackBars; + } + + // + // Symbol ... + string GetSymbol() + { + return mSymbol; + } + + // + // Period ... + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + // + // Tag ... + string GetTag() + { + return mTag; + } + + // + // Retrieve Bars ... + int GetBars() + { + // + int result = + Bars( + mSymbol, + mPeriod); + + // + return result; + } + + // + int GetCalculatedBars() + { + return BarsCalculated(mHandler); + } + + // + // END Properties ... + // + + // + // START Provided Functions ... + // + + // + // Prepare Tag ... + virtual void PrepareTag() {} + + // + // Reading Buffers based on Given Bar Index ... + virtual void Calculate( + int barIndex // Given Bar Index + ); + + // + // Retrieve MAx Required Length for Calculations ... + virtual int GetMaxLength(); + + // + // END Provided Functions ... + // + + // + // Protected ... +protected: + // + string GetTagPrefix() + { + // + string result = "(" + mSymbol + ")(" + ToString(mPeriod) + ")"; + + // + return result; + } + + // + // Symbol ... + string mSymbol; + + // + // Period ... + ENUM_TIMEFRAMES mPeriod; + + // + // Indicator Handler ... + int mHandler; + + // + // Number Of Items Read Per Tick ... + int mLoopbackBars; + + // + // Tag Identifier ... + string mTag; + + // + // Private ... +private: + // +}; + +// +// START Usefull Functions ... +// + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/Classes/x-saherelm.xnotifier.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xnotifier.class.mq5 similarity index 100% rename from MQLTestWorkspace/Classes/x-saherelm.xnotifier.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xnotifier.class.mq5 diff --git a/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xprovider.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xprovider.class.mq5 new file mode 100644 index 0000000..e60bb27 --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xprovider.class.mq5 @@ -0,0 +1,304 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCEABaseProvider +// Description: provides base requirements for +// Specific Sgnal Provider ... +// +// +// 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 + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.draw.lib.mq5" +#include "../Libraries/x-saherelm.models.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Definitions ... +// + +// +// Notified a Signal was Appears ... +typedef void (*OnSignal)( + XSignal &signal); + +// +// Notified a Guard Appears ... +typedef void (*OnGuard)(XGuard &guard); + +// +// END Definitions ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Base Class for All of our EA's ... +class XSCEABaseProvider +{ + // + // Public ... +public: + // + // Constructor ... + void XSCEABaseProvider() + { + mSymbol = _Symbol; + mPeriod = _Period; + } + void XSCEABaseProvider( + string symbol, + ENUM_TIMEFRAMES period) + { + // + mSymbol = symbol; + mPeriod = period; + + // + mTag = mSymbol + "," + ToString(mPeriod); + + // + mIsInTestMode = IsRunningOnTestMode(); + } + + // + // Deconstructor ... + void ~XSCEABaseProvider() + { + } + + // + bool CanIgnoreTick() { + // + mIsNewCandle = IsNewCandle( + mSymbol, + mPeriod); + bool result = mIsInTestMode + ? !mIsNewCandle + : !mIsNewCandle && mWaitUntilNewCandle; + + // + return result; + } + + // + // Prepare State ... + void OnTick() + { + // + mIsNewCandle = IsNewCandle( + mSymbol, + mPeriod); + mCanIgnoreTick = mIsInTestMode + ? !mIsNewCandle + : !mIsNewCandle && mWaitUntilNewCandle; + + // + ProcessBuffers(); + + // + if (mCanIgnoreTick) + { + return; + } + + // + mWaitUntilNewCandle = false; + + // + ProcessTick(); + } + + // + virtual void PrepareTag(); + + // + // Initialize Indicators and Requirements ... + virtual bool Init(); + + // + virtual int GetMaxLength(); + + // + virtual int GetCalculatedBars(); + + // + // Handle Update Buffers ... + virtual void ProcessBuffers() + { + return; + } + + // + // Handle On Tick Event ... + virtual void ProcessTick() + { + return; + } + + // + // Check for Guards ... + virtual bool GuardCheck(XGuard &guards[]); + + // + // Add Specific On Signal Event Handler ... + int AddOnSignalEventHandler(OnSignal handler) + { + // + ArrayResize( + mSignalEventHandlers, + ArraySize(mSignalEventHandlers) + 1); + + // + int result = ArraySize(mSignalEventHandlers) - 1; + mSignalEventHandlers[result] = handler; + + // + return result; + } + + // + // Remove All On Signal Event Handler ... + void ReoveOnSignalEventHandlers() + { + // + ArrayFree(mSignalEventHandlers); + } + + // + // Notify a Signal Found on all Event Listeners ... + void NotifyOnSignalEvent(XSignal &info) + { + // + int listenerCount = ArraySize(mSignalEventHandlers); + if (listenerCount <= 0) + { + return; + } + + // + // Loop Through Listeners ... + for (int i = 0; i < listenerCount; i++) + { + // + OnSignal listener = mSignalEventHandlers[i]; + + // + listener(info); + } + } + + // + // Protected ... +protected: + // + string mSymbol; + + // + ENUM_TIMEFRAMES mPeriod; + + // + string mTag; + + // + bool mIsNewCandle; + bool mIsInTestMode; + bool mCanIgnoreTick; + bool mWaitUntilNewCandle; + + // + // Private ... +private: + // + // Signal Event Handlers ... + OnSignal mSignalEventHandlers[]; +}; + +// +// START Definitions ... +// + +// +// Model Signal Providers Definitions ... +struct XBaseSignalProvider +{ + // + // Provider use Which Symbol ... + string symbol; + + // + // Provider use Which Time Frame ... + ENUM_TIMEFRAMES period; + + // + // Risk Amount Per Trades Related to Time Frames ... + // Percent of Available Balance ... + double riskAmount; + + // + // Desired Magic Number ... + ulong magicNumber; +}; + +// +struct XLastSignal +{ + datetime at; + string provider; +}; + +// +// END Definitions ... +// + +// +// START Usefull Functions ... +// + +// +// Add Specific Provider to List ... +void Add( + XBaseSignalProvider &item, // item want to add + XBaseSignalProvider &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xtrade.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xtrade.class.mq5 new file mode 100644 index 0000000..87694fa --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Classes/x-saherelm.xtrade.class.mq5 @@ -0,0 +1,4111 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCTrade +// Description: provides all Trade 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 + +// +// START Definitions ... +// + +// +// Model an Open Position ... +struct XPosition +{ + // + // Magic Number ... + ulong magic; + + // + // Ticket ID ... + ulong ticket; + + // + // Tradinng Symbol ... + string symbol; + + // + // Trading Period ... + ENUM_TIMEFRAMES period; + + // + // Position Type ... + ENUM_POSITION_TYPE type; + + // + // Take Profit ... + double tp; + + // + // Stop Loss ... + double sl; + + // + // Position Current Profit ... + double profit; + + // + // Position Open Price ... + double entry; + + // + // Current Symbol Price ... + double price; + + // + // Position Swap ... + double swap; + + // + // Position Commission ... + double commission; + + // + // Volume ... + double volume; + + // + // Position Open Time ... + datetime openAt; + + // + // Position Comment ... + string comment; +}; + +// +// Model an Order ... +struct XOrder +{ + // + // Time of order placement ... + datetime setupAt; + + // + // Time of order expiration ... + datetime expiredAt; + + // + // Time of order execution or cancellation ... + datetime executedAt; + + // + // Order type ... + ENUM_ORDER_TYPE type; + + // + // Order state ... + ENUM_ORDER_STATE state; + + // + // Type of execution by remainder ... + ENUM_ORDER_TYPE_FILLING filling; + + // + // Order lifetime ... + ENUM_ORDER_TYPE_TIME lifetime; + + // + // Order ticket ... + ulong ticket; + + // + // Magic Number ... + long magic; + + // + // Position id, that is placed on order, + // when it is executed. Each executed order invokes a + // deal, that opens new or changes existing + // position. Id of that position is placed on + // executed order in this moment. + long pocitionID; + + // + // Initial volume on order placement ... + double initialVolume; + + // + // Unfilled volume ... + double currentVolume; + + // + // Price, specified in the order ... + double openPrice; + + // + // Current price by order symbol ... + double currentPrice; + + // + // Price of placing Limit order when StopLimit order is triggered ... + double stopLimitPrice; + + // + // Take Profit level ... + double tp; + + // + // Stop Loss level ... + double sl; + + // + // Trading Symbol ... + string smybol; + + // + // Order Comment ... + string comment; +}; + +// +// Model a Deal ... +struct XDeal +{ + // + // the ID of the Expert Advisor, that executed the deal ... + ulong magic; + + // + // the ID of position, in which the deal was involved ... + ulong positionId; + + // + // Ticket ... + ulong ticket; + + // + // the name of the deal symbol ... + string symbol; + + // + // order by which the deal is executed ... + ulong order; + + // + // the time of deal execution ... + datetime time; + + // + // Deal price ... + double price; + + // + // the financial result of the deal (in deposit currency) ... + double profit; + + // + // the amount of swap when position is closed ... + double swap; + + // + // the amount of commission of the deal ... + double commission; + + // + // the volume of deal ... + double volume; + + // + // the deal comment ... + string comment; + + // + // the deal type ... + // ------------------------------------------------------------------ + // DEAL_TYPE_BUY => Buy ... + // DEAL_TYPE_SELL => Sell ... + // DEAL_TYPE_BUY_CANCELED => Canceled buy deal ... + // There can be a situation when a previously executed buy deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ... + // + // DEAL_TYPE_SELL_CANCELED => Canceled sell deal ... + // There can be a situation when a previously executed sell deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation + // + // DEAL_TYPE_BALANCE => Balance ... + // DEAL_TYPE_CREDIT => Credit ... + // DEAL_TYPE_CHARGE => Additional charge ... + // DEAL_TYPE_CORRECTION => Correction ... + // DEAL_TAX => Tax charges ... + // DEAL_TYPE_BONUS => Bonus ... + // DEAL_TYPE_INTEREST => Interest rate ... + // DEAL_DIVIDEND => Dividend operations... + // DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ... + // DEAL_TYPE_COMMISSION => Additional commission ... + // DEAL_TYPE_COMMISSION_DAILY => Daily commission ... + // DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ... + // DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ... + // DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission + ENUM_DEAL_TYPE type; + + // + // the deal direction ... + // ---------------------------------- + // DEAL_ENTRY_IN => Entry in ... + // DEAL_ENTRY_OUT => Entry out ... + // DEAL_ENTRY_INOUT => Reverse ... + // DEAL_ENTRY_OUT_BY => Close a position by an opposite one ... + ENUM_DEAL_ENTRY entry; + + // + // deal reson ... + // --------------------- + // DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ... + // DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ... + // DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ... + // DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ... + // DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ... + // DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ... + // DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ... + // DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ... + // DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ... + // DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ... + ENUM_DEAL_REASON reason; +}; + +// +// Model OnTrade Event Handler Result on XCTrade Class ... +struct XOnTradeHandlerState +{ + // + bool hasNewDeal; + int newDeals; + + // + bool hasNewOrder; + int newOrders; + + // + bool hasNewPosition; + int newPositions; + + // + bool hasNewHistoryOrder; + int newHistoryOrders; +}; + +// +typedef void (*OnDealsChanged)(int count); + +// +typedef void (*OnOrdersChanged)(int count); + +// +typedef void (*OnPositionsChanged)(int count); + +// +typedef void (*OnStopLoss)(const XDeal &deal); +typedef void (*OnTakeProfit)(const XDeal &deal); + +// +typedef void (*OnTradeStateChanged)(const XOnTradeHandlerState &state); + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Libraries/x-saherelm.seriallizer.lib.mq5" + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// XCTrade Base Class ... +class XSCTradeBase : public CTrade +{ +public: + // + // Modify Specific Position, by Specific Comment ... + bool PositionModify( + const string symbol, // Symbol + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!SelectPosition(symbol)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.symbol = symbol; + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + bool PositionModify( + const ulong ticket, // Position Ticket + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.position = ticket; + m_request.symbol = PositionGetString(POSITION_SYMBOL); + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + + // + // Close Specific Position, by Specific Comment ... + bool PositionClose( + const string symbol, // Symbol + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + bool partial_close = false; + int retry_count = 10; + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + do + { + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specify Comment ... + m_request.comment = comment; + + // + // check volume + double max_volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); + if (m_request.volume > max_volume) + { + // + m_request.volume = max_volume; + partial_close = true; + } + else + { + partial_close = false; + } + + // + // hedging? just send order + if (IsHedging()) + { + return (OrderSend(m_request, m_result)); + } + + // + // order send + if (!OrderSend(m_request, m_result)) + { + // + if (--retry_count != 0) + { + continue; + } + + // + if (retcode == TRADE_RETCODE_DONE_PARTIAL) + { + m_result.retcode = retcode; + } + + // + return (false); + } + + // + //--- WARNING. If position volume exceeds the maximum volume allowed for deal, + //--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely, + //--- but partially. It is decreased by the maximum volume allowed for deal. + if (m_async_mode) + { + break; + } + + // + retcode = TRADE_RETCODE_DONE_PARTIAL; + if (partial_close) + { + Sleep(1000); + } + } while (partial_close); + + // + // succeed + return (true); + } + bool PositionClose( + const ulong ticket, // Position Ticket + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specify Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } + + // + // Partial Close Specific Position, by Specific Comment ... + bool PositionClosePartial( + const string symbol, // Symbol + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // hedging? just send order + return (OrderSend(m_request, m_result)); + } + bool PositionClosePartial( + const ulong ticket, // Position Ticket + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } +}; + +// +// END Overrides ... +// + +// +// a Class for Manage Trades ... +class XSCTrade +{ + // + // Public ... +public: + // + // Constructor ... + void XSCTrade( + int slippage, // Specify Slippage + ulong magicNumber // Specify Magic Number + ) + { + // + mSlippage = slippage; + mMagicNumber = magicNumber; + + // + mPeriodPrefix = "PR"; + + // + mTrader = new XSCTradeBase(); + + // + mTrader.SetAsyncMode(false); + mTrader.SetDeviationInPoints(mSlippage); + mTrader.SetExpertMagicNumber(mMagicNumber); + + // + // Setting Log Level ... + mTrader.LogLevel(LOG_LEVEL_ERRORS); + + // + // Prepare Trade Event Materials ... + // + mDaysForRead = 1; + mScanStarted = false; + + // + // Reset On Trade Counter ... + ResetOnTradeContext(); + + // + // Init On Trade Context ... + InitOnTradeContext(); + } + + // + // Deconstructor ... + void ~XSCTrade() + { + } + + // + // START Event Processing ... + // + + // + // This Must be Called Every time OnTrade Event Happening ... + XOnTradeHandlerState HandleOnTrade() + { + // + // Handle OnTrade Event ... + XOnTradeHandlerState state = {}; + HandleOnTradeEvent(state); + if ( + !state.hasNewDeal && + !state.hasNewOrder && + !state.hasNewPosition && + !state.hasNewHistoryOrder) + { + return state; + } + + // + // STATE ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(state); + + // + // DEALS ... + if (state.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(state.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + GetDeals(deals); + int dealsCount = ArraySize(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // ORDERS ... + if (state.hasNewOrder || state.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(state.newOrders + state.newHistoryOrders); + } + + // + // POSITIONS ... + if (state.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(state.newPositions); + } + + // + return state; + } + + // + // Process On Trade Requirement + void HandleOnTradeEvent( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + if (mScanStarted) + { + ProcessOnTradeContext(result); + } + else + { + InitOnTradeContext(); + } + } + + // + // Event Emitters ... + + // + // STATE Changed ... + + // + // Clear Trade State Changed Event Handlers ... + void ClearOnTradeStateChangedEventHandlers() + { + // + ArrayFree(mTradeStateChangedEventHandlers); + + // + ArrayResize(mTradeStateChangedEventHandlers, 0); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnTradeStateChangedEventHandler(OnTradeStateChanged handler) + { + // + ArrayResize( + mTradeStateChangedEventHandlers, + ArraySize(mTradeStateChangedEventHandlers) + 1); + + // + mTradeStateChangedEventHandlers[ArraySize(mTradeStateChangedEventHandlers) - 1] = handler; + } + + // + // DEALS ... + + // + // Clear Deals Changed Event Handlers ... + void ClearOnDealsChangedEventHandlers() + { + // + ArrayFree(mDealsChangedEventHandlers); + + // + ArrayResize(mDealsChangedEventHandlers, 0); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnDealsChangedEventHandler(OnDealsChanged handler) + { + // + ArrayResize( + mDealsChangedEventHandlers, + ArraySize(mDealsChangedEventHandlers) + 1); + + // + mDealsChangedEventHandlers[ArraySize(mDealsChangedEventHandlers) - 1] = handler; + } + + // + // ORDERS ... + + // + // Clear Orders Changed Event Handlers ... + void ClearOnOrdersChangedEventHandlers() + { + // + ArrayFree(mOrdersChangedEventHandlers); + + // + ArrayResize(mOrdersChangedEventHandlers, 0); + } + + // + // Add New Orders Changed Event Handler ... + void AddOnOrdersChangedEventHandler(OnOrdersChanged handler) + { + // + ArrayResize( + mOrdersChangedEventHandlers, + ArraySize(mOrdersChangedEventHandlers) + 1); + + // + mOrdersChangedEventHandlers[ArraySize(mOrdersChangedEventHandlers) - 1] = handler; + } + + // + // POSITIONS ... + + // + // Clear Positions Changed Event Handlers ... + void ClearOnPositionsChangedEventHandlers() + { + // + ArrayFree(mPositionsChangedEventHandlers); + + // + ArrayResize(mPositionsChangedEventHandlers, 0); + } + + // + // Add New Positions Changed Event Handler ... + void AddOnPositionsChangedEventHandler(OnPositionsChanged handler) + { + // + ArrayResize( + mPositionsChangedEventHandlers, + ArraySize(mPositionsChangedEventHandlers) + 1); + + // + mPositionsChangedEventHandlers[ArraySize(mPositionsChangedEventHandlers) - 1] = handler; + } + + // + // TPSL ... + + // + // Clear Stop Loss Event Handlers ... + void ClearOnStopLossEventHandlers() + { + // + ArrayFree(mStopLossEventHandlers); + + // + ArrayResize(mStopLossEventHandlers, 0); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnStopLossEventHandler(OnStopLoss handler) + { + // + ArrayResize( + mStopLossEventHandlers, + ArraySize(mStopLossEventHandlers) + 1); + + // + mStopLossEventHandlers[ArraySize(mStopLossEventHandlers) - 1] = handler; + } + + // + // Clear Take Profit Event Handlers ... + void ClearOnTakeProfitEventHandlers() + { + // + ArrayFree(mTakeProfitEventHandlers); + + // + ArrayResize(mTakeProfitEventHandlers, 0); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnTakeProfitEventHandler(OnTakeProfit handler) + { + // + ArrayResize( + mTakeProfitEventHandlers, + ArraySize(mTakeProfitEventHandlers) + 1); + + // + mTakeProfitEventHandlers[ArraySize(mTakeProfitEventHandlers) - 1] = handler; + } + + // + // END Event Processing ... + // + + // + // START Provided Functions ... + // + + // + // Count Currently Open Positions ... + int PositionsCount( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + int result = 0; + + // + int allPositions = 0; + int longPositions = 0; + int shortPositions = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + allPositions++; + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + longPositions++; + } + else + { + shortPositions++; + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + allPositions++; + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + longPositions++; + } + else + { + shortPositions++; + } + + // + continue; + } + } + } + + // + // Specify Result ... + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + result = allPositions; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == POSITION_TYPE_BUY) + { + result = longPositions; + } + else + { + result = shortPositions++; + } + } + else if (StringLen(symbol) > 0) + { + // + result = allPositions; + } + else if (type != NULL) + { + // + if (type == POSITION_TYPE_BUY) + { + result = longPositions; + } + else + { + result = shortPositions; + } + } + + // + return result; + } + + // + // Retrieve Max In Profit Position Ticket ... + ulong GetMaxInProfitPosition( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + ulong result = -1; + + // + double profit = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + double positionAbsProfit = MathAbs(positionProfit); + if (positionProfit <= 0) + { + continue; + } + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Retrieve Max In DrawDown Position Ticket ... + ulong GetMaxInDrawDownPosition( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + ulong result = -1; + + // + double profit = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + double positionAbsProfit = MathAbs(positionProfit); + if (positionProfit >= 0) + { + continue; + } + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + else + { + // + if (profit < positionAbsProfit) + { + // + result = positionTicket; + profit = positionAbsProfit; + } + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Retrieve Specific Position's Profit ... + double GetPositionProfit( + const ulong ticket // Specified Position Ticket + ) + { + // + double result = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + result = mPositionInfo.Profit(); + break; + } + + // + return result; + } + + // + // Retrieve Specific Position's OpenDate ... + datetime GetPositionOpenDate( + const ulong ticket // Specified Position Ticket + ) + { + // + datetime result = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + result = mPositionInfo.Time(); + break; + } + + // + return result; + } + + // + // Retrieve Specific Position's Comment ... + string GetPositionComment( + const ulong ticket // Specified Position Ticket + ) + { + // + string result = ""; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + result = mPositionInfo.Comment(); + break; + } + + // + return result; + } + + // + // Retrieve All Open Positions Profit ... + double GetPositionsProfit( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + double result = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + result += positionProfit; + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + result += positionProfit; + } + else + { + result += positionProfit; + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + result += positionProfit; + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + result += positionProfit; + } + else + { + result += positionProfit; + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Find Oldes Position ... + ulong GetOldestPosition( + string symbol = "", // Specified Symbol + ENUM_POSITION_TYPE type = NULL // Specified Type + ) + { + // + ulong result = 0; + + // + int age = 0; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + + // + string positionSymbol = mPositionInfo.Symbol(); + + // + double positionProfit = mPositionInfo.Profit(); + double positionAbsProfit = MathAbs(positionProfit); + if (positionProfit >= 0) + { + continue; + } + + // + ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); + + // + string positionComment = mPositionInfo.Comment(); + ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(positionComment); + + // + // Calculate Position's Age ... + datetime positionOpenTime = mPositionInfo.Time(); + + // + // Retrieve Trade Open Bar Index based on Current Period ... + int positionOpenBarIndex = iBarShift( + positionSymbol, + positionPeriod, + positionOpenTime); + + // + // Calculate Trade Life ... + int positionAge = MathAbs(0 - positionOpenBarIndex); + + // + if ( + type == NULL && + StringLen(symbol) <= 0) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + + // + continue; + } + else if ( + type != NULL && + StringLen(symbol) > 0) + { + // + if (type == positionType && + symbol == positionSymbol) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + else + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + + // + continue; + } + } + else if (StringLen(symbol) > 0) + { + // + if (positionSymbol == symbol) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + + // + continue; + } + } + else if (type != NULL) + { + // + if (type == positionType) + { + // + if (type == POSITION_TYPE_BUY) + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + else + { + // + if (age < positionAge) + { + // + age = positionAge; + result = positionTicket; + } + } + + // + continue; + } + } + } + + // + return result; + } + + // + // Force Open a Buy/Long Position ... + bool Buy( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.Buy( + volume, + symbol, + price, + sl, + tp, + comment); + + // + return result; + } + + // + // Send BUY LIMIT order ... + bool BuyLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.BuyLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Send BUY STOP order ... + bool BuyStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.BuyStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Force Open a Sell/Short Position ... + bool Sell( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.Sell( + volume, + symbol, + price, + sl, + tp, + comment); + + // + return result; + } + + // + // Send SELL LIMIT order ... + bool SellLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.SellLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Send SELL STOP order ... + bool SellStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = "" // comment + ) + { + // + bool result = false; + + // + string mPeriodStr = GeneratePositionPeriodComment(period); + + // + comment += mPeriodStr; + + // + result = mTrader.SellStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment); + + // + return result; + } + + // + // Modify Position ... + bool Modify( + const ulong ticket, // position ticket + double sl = 0, // stop loss price + double tp = 0, // take profit + string comment = "" // comment + ) + { + // + bool result = false; + + // + // Validate Args ... + if (tp <= 0 && sl <= 0) + { + result = false; + return result; + } + + // + // Use Position Comment when there isn't new One ... + if (StringLen(comment) == 0) + { + comment = GetPositionComment(ticket); + } + + // + result = mTrader.PositionModify( + ticket, + sl, + tp, + comment); + + // + return result; + } + + // + // Close Position By Ticket ... + bool Close( + ulong ticket, // Position Ticket + string comment = "" // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + // Try to Select Position ... + if (!mPositionInfo.SelectByTicket(ticket)) + { + return result; + } + + // + // Close Position By Specific Comment ... + result = mTrader.PositionClose( + ticket, + mSlippage, + comment); + + // + return result; + } + + // + // Close All Positions ... + void CloseAllPositions( + string comment = "" // Close Position By Specific Comment + ) + { + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + Close( + positionTicket, + comment); + } + } + + // + // Close Partial By Ticket ... + bool ClosePartial( + ulong ticket, // Position Ticket + double volume, // Volume Size for Partial Closing + string comment = "" // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + if (!mPositionInfo.SelectByTicket(ticket)) + { + return result; + } + + // + result = mTrader.PositionClosePartial( + ticket, + volume, + mSlippage, + comment); + + // + return result; + } + + // + // Find Position Open Bar Index ... + int GetPositionOpenBarIndex( + const ulong ticket // position ticket + ) + { + // + int result = -1; + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong positionTicket = mPositionInfo.Ticket(); + if (positionTicket != ticket) + { + continue; + } + + // + string symbol = mPositionInfo.Symbol(); + datetime openAt = mPositionInfo.Time(); + string comment = mPositionInfo.Comment(); + ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment); + + // + result = iBarShift( + symbol, + period, + openAt); + } + + // + return result; + } + + // + bool GetPosition( + XPosition &position, // Holds result ... + ulong ticket // Required Position Ticket ... + ) + { + // + bool result = false; + + // + XPosition positions[]; + GetPositions(positions); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + result = iPosition.ticket == ticket; + if (!result) + { + continue; + } + + // + position = iPosition; + break; + } + + // + return result; + } + + // + // Retrieve Positions as an Array ... + void GetPositions( + XPosition &result[] // Hold Result ... + ) + { + // + Clean(result); + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + if (!mPositionInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mPositionInfo.Magic() != mMagicNumber) + { + continue; + } + + // + ulong magic = mPositionInfo.Magic(); + ulong ticket = mPositionInfo.Ticket(); + string symbol = mPositionInfo.Symbol(); + datetime openAt = mPositionInfo.Time(); + double swap = mPositionInfo.Swap(); + double sl = mPositionInfo.StopLoss(); + double tp = mPositionInfo.TakeProfit(); + double profit = mPositionInfo.Profit(); + double volume = mPositionInfo.Volume(); + string comment = mPositionInfo.Comment(); + double entry = mPositionInfo.PriceOpen(); + double price = mPositionInfo.PriceCurrent(); + double commission = mPositionInfo.Commission(); + ENUM_POSITION_TYPE type = mPositionInfo.PositionType(); + ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment); + + // + XPosition iPosition = {}; + + // + iPosition.tp = tp; + iPosition.sl = sl; + iPosition.swap = swap; + iPosition.type = type; + iPosition.magic = magic; + iPosition.entry = entry; + iPosition.price = price; + iPosition.ticket = ticket; + iPosition.symbol = symbol; + iPosition.period = period; + iPosition.volume = volume; + iPosition.openAt = openAt; + iPosition.profit = profit; + iPosition.comment = comment; + iPosition.commission = commission; + + // + Add( + iPosition, + result); + } + } + + // + void GetPositions( + XPosition &result[], // Hold Result ... + string symbol, // Trading Symbol ... + ENUM_TIMEFRAMES period // Trading Period ... + ) + { + // + Clean(result); + + // + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return; + } + + // + XPosition allPositions[]; + GetPositions(allPositions); + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = allPositions[i]; + + // + if (symbol != iPosition.symbol) + { + continue; + } + + // + ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(iPosition.comment); + if (period != positionPeriod) + { + continue; + } + + // + Add( + iPosition, + result); + } + } + + // + // Execute a Signal ... + bool ExecuteSignal( + XSignal &signal, // Signal ... + string comment = "", // Position Comment ... + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ... + datetime expiration = 0 // order expiration time + ) + + { + // + bool result = false; + + // + double currentEntry = GetEntry( + signal.symbol, + signal.type); + bool isLong = IsLong(signal.type); + + // + ResetLastError(); + + // + if (signal.mode == X_ORDER_MODE_MARKET) + { + // + // Execute MArket Orders ... + if (isLong) + { + // + result = Buy( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + comment); + } + else + { + // + result = Sell( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + comment); + } + } + else if (signal.mode == X_ORDER_MODE_LIMIT) + { + // + // Execute Limit Orders ... + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? signal.entry < currentEntry + : signal.entry > currentEntry; + if (!result) + { + return result; + } + + // + // Check Expiration Date ... + result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY) + ? expiration > 0 + : true; + if (!result) + { + return result; + } + + // + if (isLong) + { + // + result = BuyLimit( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + else + { + // + result = SellLimit( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + } + else if (signal.mode == X_ORDER_MODE_STOP) + { + // + // Execute Stop Orders ... + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? signal.entry > currentEntry + : signal.entry < currentEntry; + if (!result) + { + return result; + } + + // + // Check Expiration Date ... + result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY) + ? expiration > 0 + : true; + if (!result) + { + return result; + } + + // + if (isLong) + { + // + result = BuyStop( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + else + { + // + result = SellStop( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + signal.sl, + signal.tp, + lifetime, + expiration, + comment); + } + } + + // + if (!result) + { + // + LogMessage("Error: " + (string)GetLastError() + ", " + GetErrorDescription(GetLastError())); + } + + // + return result; + } + + // + // Execute a Collection of Signals ... + int ExecuteSignals( + const XSignal &signals[], // an Array of Signals ... + string comment = "", // Position Comment ... + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ... + datetime expiration = 0 // order expiration time + ) + { + // + int result = 0; + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < signalsCount; i++) + { + // + XSignal iSignal = signals[i]; + + // + bool isExecuted = ExecuteSignal( + iSignal, + comment, + lifetime, + expiration); + + // + if (isExecuted) + { + result++; + } + } + + // + return result; + } + + // + // Retrieve in Profit Positions ... + void GetInProfitPositions( + XPosition &result[] // Hold Result ... + ) + { + // + Clean(result); + + // + XPosition allPositions[]; + GetPositions(allPositions); + int positionsCount = ArraySize(allPositions); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = allPositions[i]; + + // + if (iPosition.profit > 0) + { + Add( + iPosition, + result); + } + } + } + + // + // Retrieve in Drawdown Positions ... + void GetInDrawdownPositions( + XPosition &result[] // Hold Result ... + ) + { + // + Clean(result); + + // + XPosition allPositions[]; + GetPositions(allPositions); + int positionsCount = ArraySize(allPositions); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = allPositions[i]; + + // + if (iPosition.profit < 0) + { + Add( + iPosition, + result); + } + } + } + + // + // Close a Collection Of Positions ... + void ClosePositions( + XPosition &positions[], // Positions to Close ... + string comment = "" // Specified Comment ... + ) + { + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + Close( + iPosition.ticket, + comment); + } + } + + // + // Retrieve All Orders ... + void GetOrders( + XOrder &result[], // Holdes Result .... + string symbol, // Trading Symbol ... + ENUM_TIMEFRAMES period, // Trading TimeFrame ... + ENUM_ORDER_STATE state = NULL // Order State ... + ) + { + // + Clean(result); + + // + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return; + } + + // + // Since Orders may be so more than positions ... + // start Orders Collectiong Loops reverse ... + for (int i = ordersCount - 1; i >= 0; i--) + { + // + if (!mOrderInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mOrderInfo.Magic() != mMagicNumber) + { + continue; + } + + // + // Reading Order Info ... + long magic = mOrderInfo.Magic(); + double sl = mOrderInfo.StopLoss(); + ulong ticket = mOrderInfo.Ticket(); + double tp = mOrderInfo.TakeProfit(); + string oSymbol = mOrderInfo.Symbol(); + string comment = mOrderInfo.Comment(); + long pocitionID = mOrderInfo.PositionId(); + double openPrice = mOrderInfo.PriceOpen(); + datetime setupAt = mOrderInfo.TimeSetup(); + datetime executedAt = mOrderInfo.TimeDone(); + ENUM_ORDER_STATE oState = mOrderInfo.State(); + ENUM_ORDER_TYPE type = mOrderInfo.OrderType(); + double currentPrice = mOrderInfo.PriceCurrent(); + datetime expiredAt = mOrderInfo.TimeExpiration(); + double initialVolume = mOrderInfo.VolumeInitial(); + double currentVolume = mOrderInfo.VolumeCurrent(); + double stopLimitPrice = mOrderInfo.PriceStopLimit(); + ENUM_ORDER_TYPE_TIME lifetime = mOrderInfo.TypeTime(); + ENUM_ORDER_TYPE_FILLING filling = mOrderInfo.TypeFilling(); + + // + if (StringLen(symbol) > 0 && symbol != oSymbol) + { + continue; + } + + // + ENUM_TIMEFRAMES oPeriod = ExtractPositionPeriod(comment); + if (period != NULL && period != oPeriod) + { + continue; + } + + // + if (state != NULL && oState != state) + { + continue; + } + + // + // Now Create an instance of XOrder struct and fill it by + // retrieved data, and add it to results ... + XOrder iOrder = {}; + + // + iOrder.sl = sl; + iOrder.tp = tp; + iOrder.type = type; + iOrder.magic = magic; + iOrder.state = oState; + iOrder.ticket = ticket; + iOrder.smybol = oSymbol; + iOrder.setupAt = setupAt; + iOrder.comment = comment; + iOrder.filling = filling; + iOrder.lifetime = lifetime; + iOrder.expiredAt = expiredAt; + iOrder.openPrice = openPrice; + iOrder.pocitionID = pocitionID; + iOrder.executedAt = executedAt; + iOrder.currentPrice = currentPrice; + iOrder.initialVolume = initialVolume; + iOrder.currentVolume = currentVolume; + iOrder.stopLimitPrice = stopLimitPrice; + + // + Add( + iOrder, + result); + } + } + + // + int OrdersCount() + { + return OrdersTotal(); + } + + // + // Cancel Specific Orders ... + bool CancelOrders( + XOrder &orders[]) + { + // + bool result = false; + + // + int ordersCount = ArraySize(orders); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + bool isDeleted = mTrader.OrderDelete(iOrder.ticket); + if (isDeleted && !result) + { + result = isDeleted; + } + } + + // + return result; + } + + // + // Retrieve All Deals ... + void GetDeals(XDeal &result[]) + { + // + Clean(result); + + // + int dealsCount = HistoryDealsTotal(); + if (dealsCount <= 0) + { + return; + } + + // + for (int i = dealsCount - 1; i >= 0; i--) + { + // + if (!mDealInfo.SelectByIndex(i)) + { + continue; + } + + // + if (mDealInfo.Magic() != mMagicNumber) + { + continue; + } + + // + // Reading Order Info ... + double swap = mDealInfo.Swap(); + ulong magic = mDealInfo.Magic(); + ulong order = mDealInfo.Order(); + ulong ticket = mDealInfo.Ticket(); + datetime time = mDealInfo.Time(); + double price = mDealInfo.Price(); + string symbol = mDealInfo.Symbol(); + double profit = mDealInfo.Profit(); + double volume = mDealInfo.Volume(); + string comment = mDealInfo.Comment(); + ulong positionId = mDealInfo.PositionId(); + ENUM_DEAL_ENTRY entry = mDealInfo.Entry(); + double commission = mDealInfo.Commission(); + ENUM_DEAL_TYPE type = mDealInfo.DealType(); + ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( + ticket, + DEAL_REASON); + + // + XDeal iDeal = {}; + + // + iDeal.swap = swap; + iDeal.time = time; + iDeal.type = type; + iDeal.magic = magic; + iDeal.entry = entry; + iDeal.order = order; + iDeal.price = price; + iDeal.ticket = ticket; + iDeal.symbol = symbol; + iDeal.profit = profit; + iDeal.volume = volume; + iDeal.reason = reason; + iDeal.comment = comment; + iDeal.positionId = positionId; + iDeal.commission = commission; + + // + Add( + iDeal, + result); + } + } + + // + // Generate String Representation Of Position's Time Frame ... + string GeneratePositionPeriodComment(ENUM_TIMEFRAMES period) + { + // + string result = mPeriodPrefix + "(" + ToString(period) + ")"; + + // + return result; + } + + // + // Extract Position Time Frame From it's Comment ... + ENUM_TIMEFRAMES ExtractPositionPeriod(string comment) + { + // + ENUM_TIMEFRAMES result = _Period; + + // + if (StringLen(comment) <= 0) + { + return result; + } + + // + string periodStr = ExtractString( + comment, + mPeriodPrefix + "(", + ")"); + if (StringLen(periodStr) <= 0) + { + return result; + } + + // + result = ToPeriod(periodStr); + + // + return result; + } + + // + // Retrieve Last Open Position Ticket ... + ulong GetLastOpenPositionTicket() + { + // + ulong result = 0; + + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + result = PositionGetTicket(PositionsTotal() - 1); + + // + return result; + } + + // + // Retrieve Last Placed Order Ticket ... + ulong GetLastPlacedOrderTicket() + { + // + ulong result = 0; + + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + if (mOrderInfo.SelectByIndex(ordersCount - 1)) + { + result = mOrderInfo.Ticket(); + } + + // + return result; + } + + // + // SUPPORT Signals ... + + // + // Find an Specific Position Has Support Signal Or not ... + bool HasSupport(ulong ticket) + { + // + bool result = false; + + // + int count = PositionsCount(); + if (count <= 1) + { + return result; + } + + // + XPosition position; + result = GetPosition( + position, + ticket); + if (!result) + { + return result; + } + + // + XPosition positions[]; + GetPositions(positions); + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + + // + string supportTicketStr = ExtractParentTicketOfSupport(iPosition.comment); + if (StringLen(supportTicketStr) == 0) + { + continue; + } + + // + ulong parentTicket = (ulong)supportTicketStr; + + // + result = + parentTicket == ticket && + iPosition.ticket != parentTicket; + if (result) + { + break; + } + } + + // + return result; + } + + // + // Get All Support Positions for Specific Position ... + bool GetSupportPositions( + ulong ticket, // Parent Position Ticket + XPosition &supports[] // Holds Result ... + ) + { + // + bool result = false; + + // + Clean(supports); + + // + int count = PositionsCount(); + if (count <= 0) + { + return result; + } + + // + XPosition parentPosition; + bool positionExist = GetPosition( + parentPosition, + ticket); + if (!positionExist) + { + return result; + } + + // + bool hasSupport = HasSupport(ticket); + if (!hasSupport) + { + return result; + } + + // + XPosition positions[]; + GetPositions(positions); + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.ticket == ticket) + { + continue; + } + + // + string pTicketStr = ExtractParentTicketOfSupport(iPosition.comment); + if (StringLen(pTicketStr) <= 0) + { + continue; + } + + // + ulong pTicket = (ulong)pTicketStr; + if (pTicket != ticket) + { + continue; + } + + // + Add( + iPosition, + supports); + } + + // + result = ArraySize(supports) > 0; + + // + return result; + } + + // + bool GetSupportOrders( + ulong ticket, // Parent Position Ticket + XOrder &supports[], // Holds Result ... + string symbol, // Trading Symbol ... + ENUM_TIMEFRAMES period, // Trading TimeFrame ... + ENUM_ORDER_STATE state = NULL // Order State ... + ) + { + // + bool result = false; + + // + Clean(supports); + + // + XOrder orders[]; + GetOrders( + orders, + symbol, + period, + state); + int ordersCount = ArraySize(orders); + result = ordersCount > 0; + if (!result) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + string pTicketStr = ExtractParentTicketOfSupport(iOrder.comment); + if (StringLen(pTicketStr) == 0) + { + continue; + } + + // + ulong pTicket = (ulong)pTicketStr; + if (pTicket != ticket) + { + continue; + } + + // + Add( + iOrder, + supports); + } + + // + result = ArraySize(supports) > 0; + + // + return result; + } + + // + // Generate SL Support Signal ... + bool GenerateSLSupportSignal( + XSignal &signal, // Holds Result .... + ulong ticket, // Specific Position Ticket ... + double slGapPoint = 10, // Which Distance to SL for Enabling Signal ... + double volumeMultiplier = 2 // Support Signals Volume Multiplier ... + ) + { + // + bool result = false; + + // + int count = PositionsCount(); + if (count <= 0) + { + return result; + } + + // + bool hasSupport = HasSupport(ticket); + if (hasSupport) + { + return result; + } + + // + XPosition position; + result = GetPosition( + position, + ticket); + if (!result) + { + return result; + } + + // + bool isLong = + IsLong(position.type); + + // + string symbol = position.symbol; + ENUM_TIMEFRAMES period = ExtractPositionPeriod(position.comment); + double volume = position.volume * volumeMultiplier; + volume = NormalizeVolume( + volume, + symbol); + + ENUM_POSITION_TYPE type = isLong + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + ENUM_X_ORDER_MODES mode = X_ORDER_MODE_STOP; + + // + double slGapPrice = PointToPrice( + symbol, + slGapPoint); + double riskPrice = MathAbs(position.entry - position.sl); + + // + double entry = + isLong + ? position.sl + slGapPrice + : position.sl - slGapPrice; + entry = NormalizePrice(entry, symbol); + + // + double sl = + isLong + ? entry + riskPrice + : entry - riskPrice; + sl = NormalizePrice(sl, symbol); + + // + double tp = + isLong + ? entry - riskPrice + : entry + riskPrice; + tp = NormalizePrice(tp, symbol); + + // + signal.sl = sl; + signal.tp = tp; + signal.type = type; + signal.mode = mode; + signal.entry = entry; + signal.volume = volume; + signal.symbol = symbol; + signal.period = period; + + // + return result; + } + + // + // Close a Position and it's Supports on a Profit ... + bool ClosePositionAndSupports( + ulong ticket, // Position Ticket + double minProfit = 4 // Minimum Profit For Closing + ) + { + // + bool result = false; + + // + if (minProfit <= 0) + { + return result; + } + + // + int count = PositionsCount(); + if (count <= 0) + { + return result; + } + + // + XPosition position; + bool isExist = GetPosition( + position, + ticket); + if (!isExist) + { + return result; + } + + // + bool hasSupport = HasSupport(ticket); + if (!hasSupport) + { + return result; + } + + // + XPosition supports[]; + hasSupport = GetSupportPositions( + ticket, + supports); + int supportsCount = ArraySize(supports); + if (!hasSupport || supportsCount <= 0) + { + return result; + } + + // + double profitSummary = 0; + for (int i = 0; i < supportsCount; i++) + { + // + XPosition iSupport = supports[i]; + + // + profitSummary += iSupport.profit; + } + + // + result = profitSummary > 0 && profitSummary >= minProfit; + if (!result) + { + return result; + } + + // + Add( + position, + supports); + + // + string comment = "Close Position (" + (string)ticket + ") and it's Supports in Profit: " + (string)profitSummary + " ..."; + ClosePositions( + supports, + comment); + + // + if (result) + { + LogMessage(comment); + } + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... +protected: + // + // Private ... + + // + // EVENTS Handlers Notifiers ... + + // + // STATE ... + void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) + { + // + int count = ArraySize(mTradeStateChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + OnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i]; + iHandler(state); + } + } + + // + // DEALS ... + void NotifyDealsChangeEvent(int changes) + { + // + int count = ArraySize(mDealsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + OnDealsChanged iHandler = mDealsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // ORDERS ... + void NotifyOrdersChangeEvent(int changes) + { + // + int count = ArraySize(mOrdersChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + OnOrdersChanged iHandler = mOrdersChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // POSITIONS ... + void NotifyPositionsChangeEvent(int changes) + { + // + int count = ArraySize(mPositionsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + OnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // TPSL ... + + // + void NotifyStopLossEvent(const XDeal &deal) + { + // + int count = ArraySize(mStopLossEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + OnStopLoss iHandler = mStopLossEventHandlers[i]; + iHandler(deal); + } + } + + // + void NotifyTakeProfitEvent(const XDeal &deal) + { + // + int count = ArraySize(mTakeProfitEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + OnTakeProfit iHandler = mTakeProfitEventHandlers[i]; + iHandler(deal); + } + } + +private: + // + // using deviation, it must be in Point ... + int mSlippage; + + // + // using magic number ... + ulong mMagicNumber; + + // + // using CTrade instance ... + XSCTradeBase mTrader; + + // + // Deals Info ... + CDealInfo mDealInfo; + + // + // Order Info ... + COrderInfo mOrderInfo; + + // + // using PositionInfo instance ... + CPositionInfo mPositionInfo; + + // + // ADDITIONAL Data ... + + // + string mPeriodPrefix; + + // + // START Trade Processing ... + // + + // + int mDaysForRead; + + // + // set the limits of the trade history on the global scope ... + + // + // // start date for trade history in cache ... + datetime mStartDate; + + // + // end date for trade history in cache ... + datetime mEndDate; + + // + // global OnTrade counters ... + + // + // number of active orders ... + int mOrdersCount; + + // + // number of open positions ... + int mPositionsCount; + + // + // number of deals in the trade history cache ... + int mDealsCount; + + // + // number of orders in the trade history cache ... + int mHistoryOrdersCount; + + // + // flag of counter relevance ... + bool mScanStarted; + + // + // Check Statrt Date In Trade History ... + void CheckStartDateInTradeHistory() + { + // + // initial interval, if we were to start working right now .. + datetime currStart = TimeCurrent() - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + + // + // make sure that the start limit of the trade history has not gone + // more than 1 day over the intended date ... + if (currStart - mStartDate > PeriodSeconds(PERIOD_D1)) + { + // + // correct the start date of history to be loaded in the cache ... + mStartDate = currStart; + + // + // now reload the trade history for the updated interval ... + HistorySelect(mStartDate, mEndDate); + + // + // correct the deal and order counters in history for further comparison + mHistoryOrdersCount = HistoryOrdersTotal(); + mDealsCount = HistoryDealsTotal(); + } + } + + // + // Process On Trade Context ... + void ProcessOnTradeContext( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + mEndDate = TimeCurrent(); + + // + ResetLastError(); + + // + // download trading history from the specified interval to the program cache ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current values ... + int currOrders = OrdersTotal(); + int currPositions = PositionsTotal(); + int currDeals = HistoryDealsTotal(); + int currHistoryOrders = HistoryOrdersTotal(); + + // + // Orders ... + // check if the number of active orders has been changed ... + if (currOrders != mOrdersCount) + { + // + // number of active orders has been changed ... + result.hasNewOrder = true; + result.newOrders = currOrders - mOrdersCount; + + // + // update the value ... + mOrdersCount = currOrders; + } + + // + // Positions ... + // changes in the number of open positions ... + if (currPositions != mPositionsCount) + { + // + // number of open positions has been changed ... + result.hasNewPosition = true; + result.newPositions = currPositions - mPositionsCount; + + // + // update the value ... + mPositionsCount = currPositions; + } + + // + // Deals ... + // changes in the number of deals in the trade history cache ... + if (currDeals != mDealsCount) + { + // + // number of deals in the trade history cache has been changed ... + result.hasNewDeal = true; + result.newDeals = currDeals - mDealsCount; + + // + // update the value ... + mDealsCount = currDeals; + } + + // + // History Orders ... + // changes in the number of history orders in the trade history cache ... + if (currHistoryOrders != mHistoryOrdersCount) + { + // + // number of history orders in the trade history cache has been changed ... + result.hasNewHistoryOrder = true; + result.newHistoryOrders = currHistoryOrders - mHistoryOrdersCount; + + // + // update the value ... + mHistoryOrdersCount = currHistoryOrders; + } + + // + // checking if it is necessary to change the limits of the trade history to be requested in cache ... + CheckStartDateInTradeHistory(); + } + + // + // Reset On Trade Scanner Context ... + void ResetOnTradeContext() + { + // + mEndDate = TimeCurrent(); + mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + } + + // + // Initial Context Of Trade Scanner ... + void InitOnTradeContext() + { + // + ResetLastError(); + + // + mOrdersCount = OrdersTotal(); + mPositionsCount = PositionsTotal(); + + // + // load history ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current value ... + mDealsCount = HistoryDealsTotal(); + mHistoryOrdersCount = HistoryOrdersTotal(); + + // + mScanStarted = true; + } + + // + // Deals Changed Event Handlers ... + OnDealsChanged mDealsChangedEventHandlers[]; + + // + // Orders Changed Event Handlers ... + OnOrdersChanged mOrdersChangedEventHandlers[]; + + // + // Positions Changed Event Handlers ... + OnPositionsChanged mPositionsChangedEventHandlers[]; + + // + // Trade State Changed Event Handlers ... + OnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + // TPSL ... + OnStopLoss mStopLossEventHandlers[]; + OnTakeProfit mTakeProfitEventHandlers[]; + + // + // END Trade Processing ... + // +}; + +// +// START Usefull Functions ... +// + +// +// Add Specific XPosition to Specified Array ... +void Add( + XDeal &item, + XDeal &buffer[]) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + XOrder &item, + XOrder &buffer[]) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + XPosition &item, + XPosition &buffer[]) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} + +// +// Clear All Items Inside Array ... +void Clean(XDeal &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(XOrder &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(XPosition &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} + +// +// Generate Identifier Tag ... +string GenerateTag(XSignal &info) +{ + // + string result = ""; + + // + result = info.symbol + "," + ToString(info.period); + + // + return result; +} + +// +// Convert Position to Signal ... +XSignal ToSignalInfo( + XPosition &position) +{ + // + XSignal result; + + // + result.tp = position.tp; + result.sl = position.sl; + result.type = position.type; + result.entry = position.entry; + result.symbol = position.symbol; + result.period = position.period; + result.volume = position.volume; + + // + return result; +} + +// +// END Usefull Functions ... +// diff --git a/MQLTestWorkspace/Experts/x-saherelm.xea.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Experts/x-saherelm.xea.ex5 similarity index 100% rename from MQLTestWorkspace/Experts/x-saherelm.xea.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Experts/x-saherelm.xea.ex5 diff --git a/MQLTestWorkspace/Experts/x-saherelm.xea.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Experts/x-saherelm.xea.mq5 similarity index 100% rename from MQLTestWorkspace/Experts/x-saherelm.xea.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Experts/x-saherelm.xea.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xama.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xama.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xama.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xama.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xama.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xama.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xama.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xama.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xcc.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xcc.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xcc.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xcc.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xcc.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xcc.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xcc.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xcc.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xche.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xche.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xche.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xche.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xche.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xche.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xche.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xche.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xct.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xct.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xct.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xct.helper.class.ex5 diff --git a/MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xct.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xct.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Helpers/x-saherelm.x121.xct.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xct.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xhk.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xhk.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xhk.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xhk.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xhk.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xhk.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xhk.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xhk.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xhull.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xhull.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xhull.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xhull.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xhull.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xhull.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xhull.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xhull.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xich.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xich.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xich.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xich.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xich.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xich.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xich.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xich.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xmrb.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xmrb.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xmrb.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xmrb.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xmrb.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xmrb.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xmrb.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xmrb.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xpv.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xpv.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xpv.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xpv.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xpv.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xpv.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xpv.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xpv.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xsslc.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xsslc.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xsslc.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xsslc.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xsslc.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xsslc.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xsslc.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xsslc.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xtm.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xtm.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xtm.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xtm.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xtm.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xtm.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xtm.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xtm.helper.class.mq5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xtrnd.helper.class.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xtrnd.helper.class.ex5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xtrnd.helper.class.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xtrnd.helper.class.ex5 diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xtrnd.helper.class.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xtrnd.helper.class.mq5 similarity index 100% rename from MQLTestWorkspace/Helpers/x-saherelm.x121.xtrnd.helper.class.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Helpers/x-saherelm.x121.xtrnd.helper.class.mq5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xama.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xama.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xama.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xama.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xama.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xama.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xama.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xama.mq5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xcc.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xcc.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xcc.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xcc.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xcc.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xcc.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xcc.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xcc.mq5 diff --git a/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xche.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xche.ex5 new file mode 100644 index 0000000..3960a6f Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xche.ex5 differ diff --git a/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xche.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xche.mq5 new file mode 100644 index 0000000..59e850f --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xche.mq5 @@ -0,0 +1,631 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121_XCHE +// Description: Chandelier Exit 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 X121_XCHE Indicator" +#property strict + +// +// START Constants ... +// + +// +#define ShortName "X121_XCHE" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input group "Market"; +input int length = 35; // Length +input int loopback = 26; // Loopback +input double multiplier1 = 3.0; // 1st Multiplier +input double multiplier2 = 3.5; // 2nd Multiplier + +// +input group "Calculation"; +input ENUM_APPLIED_PRICE upAppliedTo = PRICE_HIGH; // Up Zone Applied to +input ENUM_APPLIED_PRICE downAppliedTo = PRICE_LOW; // Down Zone Applied to + +// +input group "Presentation"; +input bool showLongExit1Line = true; // Show 1st Long Exit +input bool showShortExit1Line = true; // Show 1st Short Exit +input bool showLongExit2Line = true; // Show 2st Long Exit +input bool showShortExit2Line = true; // Show 2st Short Exit + +// +// END Inputs ... +// + +// +// START Includes and Imports ... +// + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Includes and Imports ... +// + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 8 +#property indicator_plots 8 + +// +// Long Exit 1 ... +#define longExit1BufferIndex 0 +double longExit1Buffer[]; + +// +#property indicator_label1 "X121_XCHE LE 1" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrLime +#property indicator_style1 STYLE_DOT + +// +// Short Exit 1 ... +#define shortExit1BufferIndex 1 +double shortExit1Buffer[]; + +// +#property indicator_label2 "X121_XCHE SE 1" +#property indicator_type2 DRAW_LINE +#property indicator_style2 STYLE_DOT +#property indicator_color2 clrRed + +// +// Long Exit 2 ... +#define longExit2BufferIndex 2 +double longExit2Buffer[]; + +// +#property indicator_label3 "X121_XCHE LE 2" +#property indicator_type3 DRAW_LINE +#property indicator_style2 STYLE_DOT +#property indicator_color3 clrAqua + +// +// Short Exit 2 ... +#define shortExit2BufferIndex 3 +double shortExit2Buffer[]; + +// +#property indicator_label4 "X121_XCHE SE 2" +#property indicator_type4 DRAW_LINE +#property indicator_style2 STYLE_DOT +#property indicator_color4 clrMagenta + +// +// START Arrows ... + +// +// Long Exit 1 Start ... +#define longExit1StartBufferIndex 4 +double longExit1StartBuffer[]; + +// +#property indicator_label5 "X121_XCHE LES 1" +#property indicator_type5 DRAW_ARROW +#property indicator_color5 clrLime + +// +// Short Exit 1 Start ... +#define shortExit1StartBufferIndex 5 +double shortExit1StartBuffer[]; + +// +#property indicator_label6 "X121_XCHE SES 1" +#property indicator_type6 DRAW_ARROW +#property indicator_color6 clrRed + +// +// Long Exit 2 Start ... +#define longExit2StartBufferIndex 6 +double longExit2StartBuffer[]; + +// +#property indicator_label7 "X121_XCHE LES 2" +#property indicator_type7 DRAW_ARROW +#property indicator_color7 clrAqua + +// +// Short Exit 2 Start ... +#define shortExit2StartBufferIndex 7 +double shortExit2StartBuffer[]; + +// +#property indicator_label8 "X121_XCHE SES 2" +#property indicator_type8 DRAW_ARROW +#property indicator_color8 clrMagenta + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +// Working Array ... +double work[][6]; +#define hi1Idx 0 +#define lo1Idx 1 +#define hi2Idx 2 +#define lo2Idx 3 +#define trend1Idx 4 +#define trend2Idx 5 + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + 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(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 mPeriod 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 +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + const int &spread[]) +{ + // + if (Bars(_Symbol, _Period) < rates_total) + { + return (prev_calculated); + } + + // + if (ArrayRange(work, 0) != rates_total) + { + ArrayResize(work, rates_total); + } + + // + // this counts Available Bars ... + int limit; + + // + limit = prev_calculated - 1; + if (limit < 0) + { + limit = 0; + } + + // + // Main Loop ... + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + low, + close); + } + + // + return rates_total; +} +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = true; + + // + result = + length >= 9 && + loopback >= 0; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(length, loopback); + + // + return result; +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + uint arrowCode = 159; + + // + // LEVEL 1 ... + + // + // Long Exit 1 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE longExit1DrawType = showLongExit1Line ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE longExit1StartDrawType = showLongExit1Line ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(longExit1BufferIndex, longExit1Buffer, INDICATOR_DATA); + PlotIndexSetInteger(longExit1BufferIndex, PLOT_SHOW_DATA, showLongExit1Line); + PlotIndexSetInteger(longExit1BufferIndex, PLOT_DRAW_TYPE, longExit1DrawType); + + // + // Start Buffer ... + SetIndexBuffer(longExit1StartBufferIndex, longExit1StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(longExit1StartBufferIndex, PLOT_ARROW, arrowCode); + PlotIndexSetInteger(longExit1StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(longExit1StartBufferIndex, PLOT_DRAW_TYPE, longExit1StartDrawType); + + // + // Short Exit 1 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE shortExit1DrawType = showShortExit1Line ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE shortExit1StartDrawType = showShortExit1Line ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(shortExit1BufferIndex, shortExit1Buffer, INDICATOR_DATA); + PlotIndexSetInteger(shortExit1BufferIndex, PLOT_SHOW_DATA, showShortExit1Line); + PlotIndexSetInteger(shortExit1BufferIndex, PLOT_DRAW_TYPE, shortExit1DrawType); + + // + // Start Buffer ... + SetIndexBuffer(shortExit1StartBufferIndex, shortExit1StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(shortExit1StartBufferIndex, PLOT_ARROW, arrowCode); + PlotIndexSetInteger(shortExit1StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(shortExit1StartBufferIndex, PLOT_DRAW_TYPE, shortExit1StartDrawType); + + // + // LEVEL 2 ... + + // + // Long Exit 2 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE longExit2DrawType = showLongExit2Line ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE longExit2StartDrawType = showLongExit2Line ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(longExit2BufferIndex, longExit2Buffer, INDICATOR_DATA); + PlotIndexSetInteger(longExit2BufferIndex, PLOT_SHOW_DATA, showLongExit2Line); + PlotIndexSetInteger(longExit2BufferIndex, PLOT_DRAW_TYPE, longExit2DrawType); + + // + // Start Buffer ... + SetIndexBuffer(longExit2StartBufferIndex, longExit2StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(longExit2StartBufferIndex, PLOT_ARROW, arrowCode); + PlotIndexSetInteger(longExit2StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(longExit2StartBufferIndex, PLOT_DRAW_TYPE, longExit2StartDrawType); + + // + // Short Exit 2 ... + + // + // Draw Type ... + ENUM_DRAW_TYPE shortExit2DrawType = showShortExit2Line ? DRAW_LINE : DRAW_NONE; + ENUM_DRAW_TYPE shortExit2StartDrawType = showShortExit2Line ? DRAW_ARROW : DRAW_NONE; + + // + // Buffer ... + SetIndexBuffer(shortExit2BufferIndex, shortExit2Buffer, INDICATOR_DATA); + PlotIndexSetInteger(shortExit2BufferIndex, PLOT_SHOW_DATA, showShortExit2Line); + PlotIndexSetInteger(shortExit2BufferIndex, PLOT_DRAW_TYPE, shortExit2DrawType); + + // + // Start Buffer ... + SetIndexBuffer(shortExit2StartBufferIndex, shortExit2StartBuffer, INDICATOR_DATA); + PlotIndexSetInteger(shortExit2StartBufferIndex, PLOT_ARROW, arrowCode); + PlotIndexSetInteger(shortExit2StartBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(shortExit2StartBufferIndex, PLOT_DRAW_TYPE, shortExit2StartDrawType); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index, // Selected Bar Index + int prevCalculated, // Previous Calculated + int ratesTotal, // Total Rates + const double &open[], // Rates Open ... + const double &high[], // Rates High ... + const double &low[], // Rates Low ... + const double &close[] // Rates Close ... +) +{ + // + // Cleanup Buffers ... + longExit1Buffer[bar_index] = longExit1StartBuffer[bar_index] = shortExit1Buffer[bar_index] = shortExit1StartBuffer[bar_index] = EMPTY_VALUE; + longExit2Buffer[bar_index] = longExit2StartBuffer[bar_index] = shortExit2Buffer[bar_index] = shortExit2StartBuffer[bar_index] = EMPTY_VALUE; + + // + int start = MathMax(bar_index - loopback, 0); + + // + // Calculate ATR Value ... + double atrValue = 0; + for (int k = 1; k <= length && (bar_index - k - 1) >= 0; k++) + { + // + atrValue += MathMax(high[bar_index - k], close[MathMax(bar_index - k - 1, 0)]) - + MathMin(low[bar_index - k], close[MathMax(bar_index - k - 1, 0)]); + } + atrValue /= (double)length; + + // + // Retrieve Highest High and Lowest Lows ... + double loopbackMax = high[ArrayMaximum(high, start, loopback)]; + double loopbackMin = low[ArrayMinimum(low, start, loopback)]; + + // + // Fill Multi Dimesional Working Array ... + work[bar_index][hi1Idx] = loopbackMax - multiplier1 * atrValue; + work[bar_index][lo1Idx] = loopbackMin + multiplier1 * atrValue; + work[bar_index][hi2Idx] = loopbackMax - multiplier2 * atrValue; + work[bar_index][lo2Idx] = loopbackMin + multiplier2 * atrValue; + work[bar_index][trend1Idx] = (bar_index > 0) ? work[bar_index - 1][trend1Idx] : 0; + work[bar_index][trend2Idx] = (bar_index > 0) ? work[bar_index - 1][trend2Idx] : 0; + + // + if (bar_index > 0) + { + // + // Calculate Trends ... + if (close[bar_index] > work[bar_index - 1][lo1Idx]) + { + work[bar_index][trend1Idx] = 1; + } + + // + if (close[bar_index] < work[bar_index - 1][hi1Idx]) + { + work[bar_index][trend1Idx] = -1; + } + + // + if (close[bar_index] > work[bar_index - 1][lo2Idx]) + { + work[bar_index][trend2Idx] = 1; + } + + // + if (close[bar_index] < work[bar_index - 1][hi2Idx]) + { + work[bar_index][trend2Idx] = -1; + } + + // + // Calculate Exit Values ... + + // + // Exit 1 ... + + // + // Long ... + if (multiplier1 > 0 && work[bar_index][trend1Idx] == 1) + { + // + if (work[bar_index][hi1Idx] < work[bar_index - 1][hi1Idx]) + { + work[bar_index][hi1Idx] = work[bar_index - 1][hi1Idx]; + } + + // + longExit1Buffer[bar_index] = work[bar_index][hi1Idx]; + + // + if (longExit1Buffer[bar_index - 1] == EMPTY_VALUE) + { + longExit1StartBuffer[bar_index] = longExit1Buffer[bar_index]; + } + } + + // + // Short ... + if (multiplier1 > 0 && work[bar_index][trend1Idx] == -1) + { + // + if (work[bar_index][lo1Idx] > work[bar_index - 1][lo1Idx]) + { + work[bar_index][lo1Idx] = work[bar_index - 1][lo1Idx]; + } + + // + shortExit1Buffer[bar_index] = work[bar_index][lo1Idx]; + + // + if (shortExit1Buffer[bar_index - 1] == EMPTY_VALUE) + { + shortExit1StartBuffer[bar_index] = shortExit1Buffer[bar_index]; + } + } + + // + // Exit 2 ... + + // + // Long ... + if (multiplier2 > 0 && work[bar_index][trend2Idx] == 1) + { + if (work[bar_index][hi2Idx] < work[bar_index - 1][hi2Idx]) + { + work[bar_index][hi2Idx] = work[bar_index - 1][hi2Idx]; + } + + // + longExit2Buffer[bar_index] = work[bar_index][hi2Idx]; + + // + if (longExit2Buffer[bar_index - 1] == EMPTY_VALUE) + { + longExit2StartBuffer[bar_index] = longExit2Buffer[bar_index]; + } + } + + // + // Short ... + if (multiplier2 > 0 && work[bar_index][trend2Idx] == -1) + { + // + if (work[bar_index][lo2Idx] > work[bar_index - 1][lo2Idx]) + { + work[bar_index][lo2Idx] = work[bar_index - 1][lo2Idx]; + } + + // + shortExit2Buffer[bar_index] = work[bar_index][lo2Idx]; + + // + if (shortExit2Buffer[bar_index - 1] == EMPTY_VALUE) + { + shortExit2StartBuffer[bar_index] = shortExit2Buffer[bar_index]; + } + } + } +} + +// +// END Functions ... +// diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xct.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xct.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xct.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xct.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xct.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xct.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xct.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xct.mq5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xhk.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xhk.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xhk.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xhk.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xhk.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xhk.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xhk.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xhk.mq5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xhull.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xhull.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xhull.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xhull.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xhull.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xhull.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xhull.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xhull.mq5 diff --git a/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xich.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xich.ex5 new file mode 100644 index 0000000..e0e91b2 Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xich.ex5 differ diff --git a/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xich.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xich.mq5 new file mode 100644 index 0000000..5493ba2 --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xich.mq5 @@ -0,0 +1,743 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: X121_XICH +// Description: Ichimoku Kinko Hyo ... +// +// +// 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_XICH Indicator" +#property strict + +// +// START Constants ... +// + +// +// Indicator Short Name ... +#define ShortName "X121_XICH" + +// +// Ichimoku Golden Numbers ... +enum ENUM_X_ICHIMOKU_GOLDEN_NUMBERS +{ + X_ICH_BASE = 9, + X_ICH_GOLDEN = 17, + X_ICH_CYCLE = 26, + X_ICH_PERIOD = 35, + X_ICH_STAR = 45, + X_ICH_MED = 52, + X_ICH_LONG = 63, + X_ICH_FULL = 72 +}; + +// +// Ichimoku Lines Calculator Mode ... +enum ENUM_X_ICHIMOKU_CALCULATION_MODE +{ + // + X_XICH_HH_LL_MODE = 1, // Highest High and Lowest Low + X_XICH_HO_LC_MODE = 2, // Highest Open and Lowest Close +}; + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +// ICHIMOKU Kinko Hyo ... + +// +// TENKANSEN ... +input group "Tenkan Sen"; +input int tenkanSenLength = 9; // Length +input ENUM_X_ICHIMOKU_CALCULATION_MODE tenkanSenMode = X_XICH_HH_LL_MODE; // Calculation Mode + +// +// KIJUNSEN ... +input group "Kijun Sen"; +input int kijunSenLength = 26; // Length +input ENUM_X_ICHIMOKU_CALCULATION_MODE kijunSenMode = X_XICH_HH_LL_MODE; // Calculation Mode + +// +// SENKOUSPANB ... +input group "Senkou Span B"; +input int senkouSpanBLength = 52; // Length +input ENUM_X_ICHIMOKU_CALCULATION_MODE senkouSpanBMode = X_XICH_HH_LL_MODE; // Calculation Mode + +// +// CHIKOUSPAN ... +input group "Chikou Span"; +input ENUM_APPLIED_PRICE chikuoSpanAppliedTo = PRICE_CLOSE; // Price Type + +// +input group "Presentation"; +input bool showTenkanSen = true; // Show Tenkan Sen +input bool showKijunSen = true; // Show Kijun Sen +input bool showKijunSenPlus = false; // Show Kijun Sen + +input bool showKijunSenNegative = false; // Show Kijun Sen - +input bool showChikouSpan = true; // Show Chikou Span +input bool showSenkouSpanA = true; // Show Senkou Span A +input bool showSenkouSpanB = true; // Show Senkou Span B +input bool showKumo = true; // Show Kumo +input bool shiftKumo = true; // Shift Kumo to Future + +// +// END Inputs ... +// + +// +// START Includes and Imports ... +// + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Includes and Imports ... +// + +// +// START Buffers ... +// +#property indicator_chart_window + +// +#property indicator_buffers 9 +#property indicator_plots 8 + +// +// PLOTTED Buffers ... + +// +// ICHIMOKU ... + +// +// TENKANSEN ... + +// +#define tenkanSenBufferIndex 0 +double tenkanSenBuffer[]; + +// +#property indicator_label1 "X121_XICH TK" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrBrown +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +// +// KIJUNSEN ... + +// +#define kijunSenBufferIndex 1 +double kijunSenBuffer[]; + +// +#property indicator_label2 "X121_XICH KJ" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrDodgerBlue +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +// +#define kijunSenPlusBufferIndex 2 +double kijunSenPlusBuffer[]; + +// +#property indicator_label3 "X121_XICH KJ+" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrMediumTurquoise +#property indicator_style3 STYLE_DOT +#property indicator_width3 1 + +// +#define kijunSenNegativeBufferIndex 3 +double kijunSenNegativeBuffer[]; + +// +#property indicator_label4 "X121_XICH KJ-" +#property indicator_type4 DRAW_LINE +#property indicator_color4 clrDarkSeaGreen +#property indicator_style4 STYLE_DOT +#property indicator_width4 1 + +// +// CHIKOUSPAN ... + +// +#define chikouSpanBufferIndex 4 +double chikouSpanBuffer[]; + +// +#property indicator_label5 "X121_XICH CS" +#property indicator_type5 DRAW_LINE +#property indicator_color5 clrDarkGreen +#property indicator_style5 STYLE_SOLID +#property indicator_width5 1 + +// +#define senkouABufferIndex 5 +double senkouABuffer[]; + +// +#property indicator_label6 "X121_XICH SSA" +#property indicator_type6 DRAW_LINE +#property indicator_color6 clrLightGray +#property indicator_style6 STYLE_DASHDOTDOT +#property indicator_width6 1 + +// +#define senkouBBufferIndex 6 +double senkouBBuffer[]; + +// +#property indicator_label7 "X121_XICH SSB" +#property indicator_type7 DRAW_LINE +#property indicator_color7 clrLightGray +#property indicator_style7 STYLE_DASHDOTDOT +#property indicator_width7 1 + +// +// KUMO ... + +// +// SENKOUSPANA ... + +// +#define senkouSpanABufferIndex 7 +double senkouSpanABuffer[]; + +// +// SENKOUSPANB ... + +// +#define senkouSpanBBufferIndex 8 +double senkouSpanBBuffer[]; + +// +// KUMOCLOUD ... + +// +#define kumoBufferIndex 7 + +// +#property indicator_label8 "X121_XICH Kumo" +#property indicator_type8 DRAW_FILLING +#property indicator_color8 clrAqua, clrMagenta +#property indicator_style8 STYLE_SOLID +#property indicator_width8 1 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +ENUM_SERIESMODE mTenkanSenTopMode = NULL; +ENUM_SERIESMODE mTenkanSenBottomMode = NULL; + +// +ENUM_SERIESMODE mKijunSenTopMode = NULL; +ENUM_SERIESMODE mKijunSenBottomMode = NULL; + +// +ENUM_SERIESMODE mSenkouSpanBTopMode = NULL; +ENUM_SERIESMODE mSenkouSpanBBottomMode = NULL; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + 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(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + 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); + + // + // this counts Available Bars ... + int limit; + + // + 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); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = + // + (tenkanSenLength > 2 && + kijunSenLength > tenkanSenLength && + senkouSpanBLength > kijunSenLength) + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // Ichimoku ... + result = MathMax(result, tenkanSenLength); + result = MathMax(result, kijunSenLength); + result = MathMax(result, senkouSpanBLength); + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // ICHIMOKU ... + + // + // TENKANSEN ... + + // + ENUM_DRAW_TYPE tenkanSenDrawType = showTenkanSen ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(tenkanSenBuffer, true); + SetIndexBuffer(tenkanSenBufferIndex, tenkanSenBuffer, INDICATOR_DATA); + PlotIndexSetInteger(tenkanSenBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(tenkanSenBufferIndex, PLOT_SHOW_DATA, showTenkanSen); + PlotIndexSetInteger(tenkanSenBufferIndex, PLOT_DRAW_TYPE, tenkanSenDrawType); + + // + // KIJUNSEN ... + + // + ENUM_DRAW_TYPE kijunSenDrawType = showKijunSen ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(kijunSenBuffer, true); + SetIndexBuffer(kijunSenBufferIndex, kijunSenBuffer, INDICATOR_DATA); + PlotIndexSetInteger(kijunSenBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(kijunSenBufferIndex, PLOT_SHOW_DATA, showKijunSen); + PlotIndexSetInteger(kijunSenBufferIndex, PLOT_DRAW_TYPE, kijunSenDrawType); + + // + // KIJUNSEN Plus ... + + // + ENUM_DRAW_TYPE kijunSenPlusDrawType = showKijunSenPlus ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(kijunSenPlusBuffer, true); + SetIndexBuffer(kijunSenPlusBufferIndex, kijunSenPlusBuffer, INDICATOR_DATA); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_SHIFT, kijunSenLength); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(kijunSenPlusBufferIndex, PLOT_DRAW_TYPE, kijunSenPlusDrawType); + + // + // KIJUNSEN Negative ... + + // + ENUM_DRAW_TYPE kijunSenNegativeDrawType = showKijunSenNegative ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(kijunSenNegativeBuffer, true); + SetIndexBuffer(kijunSenNegativeBufferIndex, kijunSenNegativeBuffer, INDICATOR_DATA); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_SHIFT, -kijunSenLength); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(kijunSenNegativeBufferIndex, PLOT_DRAW_TYPE, kijunSenNegativeDrawType); + + // + // CHIKOUSPAN ... + + // + ENUM_DRAW_TYPE chikouSpanDrawType = showChikouSpan ? DRAW_LINE : DRAW_NONE; + + // + ArraySetAsSeries(chikouSpanBuffer, true); + SetIndexBuffer(chikouSpanBufferIndex, chikouSpanBuffer, INDICATOR_DATA); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_SHIFT, -kijunSenLength); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_SHOW_DATA, showChikouSpan); + PlotIndexSetInteger(chikouSpanBufferIndex, PLOT_DRAW_TYPE, chikouSpanDrawType); + + // + // SENKOUSPAN A and B ... + int shiftSize = shiftKumo ? kijunSenLength : 0; + + // + // SENKOUSPANA ... + ENUM_DRAW_TYPE senkouSpanADrawType = showSenkouSpanA ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(senkouABuffer, true); + SetIndexBuffer(senkouABufferIndex, senkouABuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouABufferIndex, PLOT_SHIFT, shiftSize); + PlotIndexSetInteger(senkouABufferIndex, PLOT_SHOW_DATA, showSenkouSpanA); + PlotIndexSetInteger(senkouABufferIndex, PLOT_DRAW_TYPE, senkouSpanADrawType); + + // + // SENKOUSPANB ... + ENUM_DRAW_TYPE senkouSpanBDrawType = showSenkouSpanB ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(senkouBBuffer, true); + SetIndexBuffer(senkouBBufferIndex, senkouBBuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouBBufferIndex, PLOT_SHIFT, shiftSize); + PlotIndexSetInteger(senkouBBufferIndex, PLOT_SHOW_DATA, showSenkouSpanB); + PlotIndexSetInteger(senkouBBufferIndex, PLOT_DRAW_TYPE, senkouSpanBDrawType); + + // + // KUMO ... + + // + // SENKOUSPANA ... + ArraySetAsSeries(senkouSpanABuffer, true); + SetIndexBuffer(senkouSpanABufferIndex, senkouSpanABuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouSpanABufferIndex, PLOT_DRAW_BEGIN, maxLength); + + // + // SENKOUSPANB ... + ArraySetAsSeries(senkouSpanBBuffer, true); + SetIndexBuffer(senkouSpanBBufferIndex, senkouSpanBBuffer, INDICATOR_DATA); + PlotIndexSetInteger(senkouSpanBBufferIndex, PLOT_DRAW_BEGIN, maxLength); + + // + // KUMO ... + + // + ENUM_DRAW_TYPE kumoDrawType = showKumo ? DRAW_FILLING : DRAW_NONE; + + // + PlotIndexSetInteger(kumoBufferIndex, PLOT_SHIFT, shiftSize); + PlotIndexSetInteger(kumoBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(kumoBufferIndex, PLOT_DRAW_TYPE, kumoDrawType); +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index // Selected Bar Index +) +{ + // + // ICHIMOKU ... + + // + double topValue; + double bottomValue; + + // + // TENKANSEN ... + + // + // Extract Tenkan Sen Top/Bottom Calculation Mode based on User Input ... + if (mTenkanSenTopMode == NULL || mTenkanSenBottomMode == NULL) + { + // + switch (tenkanSenMode) + { + // + case X_XICH_HH_LL_MODE: + // + mTenkanSenTopMode = MODE_HIGH; + mTenkanSenBottomMode = MODE_LOW; + break; + + // + case X_XICH_HO_LC_MODE: + // + mTenkanSenTopMode = MODE_OPEN; + mTenkanSenBottomMode = MODE_CLOSE; + break; + } + } + + // + // Calculate Top ... + topValue = GetHighestHigh( + _Symbol, + _Period, + mTenkanSenTopMode, + tenkanSenLength, + bar_index); + + // + // Calculate Bottom ... + bottomValue = GetLowestLow( + _Symbol, + _Period, + mTenkanSenBottomMode, + tenkanSenLength, + bar_index); + + // + double tenkanSenValue = (topValue + bottomValue) / 2; + tenkanSenBuffer[bar_index] = tenkanSenValue; + + // + // KIJUNSEN ... + + // + // Extract Kijun Sen Top/Bottom Calculation Mode based on User Input ... + if (mKijunSenTopMode == NULL || mKijunSenBottomMode == NULL) + { + // + switch (kijunSenMode) + { + // + case X_XICH_HH_LL_MODE: + // + mKijunSenTopMode = MODE_HIGH; + mKijunSenBottomMode = MODE_LOW; + break; + + // + case X_XICH_HO_LC_MODE: + // + mKijunSenTopMode = MODE_OPEN; + mKijunSenBottomMode = MODE_CLOSE; + break; + } + } + + // + // Calculate Top ... + topValue = GetHighestHigh( + _Symbol, + _Period, + mKijunSenTopMode, + kijunSenLength, + bar_index); + + // + // Calculate Bottom ... + bottomValue = GetLowestLow( + _Symbol, + _Period, + mKijunSenBottomMode, + kijunSenLength, + bar_index); + + // + double kijunSenValue = (topValue + bottomValue) / 2; + kijunSenBuffer[bar_index] = kijunSenValue; + + // + kijunSenPlusBuffer[bar_index] = kijunSenValue; + kijunSenNegativeBuffer[bar_index] = kijunSenValue; + + // + // CHIKOUSPAN ... + double chikouSpanValue = GetAppliedPrice( + bar_index, + chikuoSpanAppliedTo); + chikouSpanBuffer[bar_index] = chikouSpanValue; + + // + // KUMO ... + + // + // SENKOUSPANA ... + double senkouSpanAValue = (tenkanSenValue + kijunSenValue) / 2; + senkouABuffer[bar_index] = senkouSpanAValue; + senkouSpanABuffer[bar_index] = senkouSpanAValue; + + // + // SENKOUSPANB ... + + // + // Extract Senkou Span B Top/Bottom Calculation Mode based on User Input ... + if (mSenkouSpanBTopMode == NULL || mSenkouSpanBBottomMode == NULL) + { + // + switch (senkouSpanBMode) + { + // + case X_XICH_HH_LL_MODE: + // + mSenkouSpanBTopMode = MODE_HIGH; + mSenkouSpanBBottomMode = MODE_LOW; + break; + + // + case X_XICH_HO_LC_MODE: + // + mSenkouSpanBTopMode = MODE_OPEN; + mSenkouSpanBBottomMode = MODE_CLOSE; + break; + } + } + + // + // Calculate Top ... + topValue = GetHighestHigh( + _Symbol, + _Period, + mSenkouSpanBTopMode, + senkouSpanBLength, + bar_index); + + // + // Calculate Bottom ... + bottomValue = GetLowestLow( + _Symbol, + _Period, + mSenkouSpanBBottomMode, + senkouSpanBLength, + bar_index); + + // + double senkouSpanBValue = (topValue + bottomValue) / 2; + senkouBBuffer[bar_index] = senkouSpanBValue; + senkouSpanBBuffer[bar_index] = senkouSpanBValue; +} + +// +// END Functions ... +// diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xmrb.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xmrb.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xmrb.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xmrb.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xmrb.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xmrb.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xmrb.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xmrb.mq5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xpv.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xpv.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xpv.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xpv.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xpv.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xpv.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xpv.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xpv.mq5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xsslc.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xsslc.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xsslc.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xsslc.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xsslc.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xsslc.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xsslc.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xsslc.mq5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xtm.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xtm.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xtm.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xtm.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xtm.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xtm.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xtm.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xtm.mq5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xtrnd.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xtrnd.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.x121.xtrnd.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xtrnd.ex5 diff --git a/MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xtrnd.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xtrnd.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Indicators/x-saherelm.x121.xtrnd.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.x121.xtrnd.mq5 diff --git a/MQLTestWorkspace/Indicators/x-saherelm.xchnl.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.xchnl.ex5 similarity index 100% rename from MQLTestWorkspace/Indicators/x-saherelm.xchnl.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.xchnl.ex5 diff --git a/MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.xchnl.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.xchnl.mq5 similarity index 100% rename from MQLTestWorkspace/XBEEA/14030224/Indicators/x-saherelm.xchnl.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Indicators/x-saherelm.xchnl.mq5 diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.alert.lib.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.alert.lib.ex5 new file mode 100644 index 0000000..0c761ae Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.alert.lib.ex5 differ diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.alert.lib.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.alert.lib.mq5 new file mode 100644 index 0000000..429d830 --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.alert.lib.mq5 @@ -0,0 +1,187 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Alert Library +// -------------------------------------- +// Name: XAlert +// Description: provides Alerts abilities ... +// +// +// 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 + +// +// START Inputs ... +// +input group "Alerts"; +input bool enableAlerts = true; // Enable Alerts +input bool logAlerts = true; // Log Alerts +input bool terminalAlerts = false; // Terminal Alerts +input bool mailAlerts = false; // Mail Alerts +input bool pushAlerts = false; // Push Alerts +// +// END Inputs ... +// + +// +#include "x-saherelm.log.lib.mq5" + +// +// START Global Definitions: Variables, Properties and etc ... +// +string alertPrefix = "X-Alert"; +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// +// +// Initial Library if required ... +bool OnInInitAlertLibrary() +{ + return false; +} + +// +// DeInitial Library if required ... +void OnDeinitAlertLibrary() +{ +} + +// +// Attach Alert Prefix to Message ... +string PrepareAlertMessage(string message) +{ + // + StringReplace(message, "\n", " | "); + + // + StringConcatenate(message, alertPrefix, " > ", message); + + // + return message; +} + +// +// Logging an Alert ... +void LogAlert(string message) +{ + // + // Validate Args ... + if (!enableAlerts || !logAlerts) + { + return; + } + + // + LogMessage(alertPrefix, message); +} + +// +// Terminal Alert ... +void TerminalAlert(string message) +{ + // + // Validate Args ... + if (!enableAlerts || !terminalAlerts) + { + return; + } + + // + // Prepare Message ... + message = PrepareAlertMessage(message); + + // Send Terminal Alert ... + Alert(message); +} + +// +// Mail Alert ... +void MailAlert(string message) +{ + // + // Validate Args ... + if (!enableAlerts || !mailAlerts) + { + return; + } + + // + // Send Mail Alert ... + SendMail(alertPrefix, message); +} + +// +// Send Push Notification ... +void PushAlert(string message) +{ + // + // Validate Args ... + if (!enableAlerts || !pushAlerts) + { + return; + } + + // + // Prepare Message ... + message = PrepareAlertMessage(message); + + // + // Send Push Notification Alert ... + SendNotification(message); +} + +// +// Alert Sending ... +void SendAlert(string message) +{ + // + // Validate Args ... + if (!enableAlerts) + { + return; + } + + // + // Log ... + if (logAlerts) + { + LogAlert(message); + } + + // + // Terminal ... + if (terminalAlerts) + { + TerminalAlert(message); + } + + // + // Mail ... + if (mailAlerts) + { + MailAlert(message); + } + + // + // Push ... + if (pushAlerts) + { + PushAlert(message); + } +} +// +// END Provided Functions ... +// diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.common.lib.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.common.lib.ex5 new file mode 100644 index 0000000..b41cad3 Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.common.lib.ex5 differ diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.common.lib.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.common.lib.mq5 new file mode 100644 index 0000000..f9b09b3 --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.common.lib.mq5 @@ -0,0 +1,5193 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: XCommon +// Description: provide all commonly used 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 + +// +// START Inputs ... +// + +// +// END Inputs ... +// + +// +// Include Models Library ... +#include "x-saherelm.models.lib.mq5" + +// +// START Global Definitions: Variables, Properties and etc ... +// +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// + +// +// Detect is new Candle or not ... +bool IsNewCandle() +{ + // + bool result = false; + + // + static int barsOnChart = 0; + int currentBarsOnChart = Bars(_Symbol, _Period); + result = currentBarsOnChart > barsOnChart; + if (!result) + { + return result; + } + + // + barsOnChart = currentBarsOnChart; + result = true; + + // + return result; +} +bool IsNewCandle( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod // Trading Time Frame ... +) +{ + // + bool result = false; + + // + static string mChartTags[]; + static int mChartBars[]; + + // + string chTag = mSymbol + "," + ToString(mPeriod); + + // + int currChTagIdx = -1; + int chCountedBars = 0; + int currentBars = Bars(mSymbol, mPeriod); + + // + if (ArraySize(mChartTags) > 0) + { + // + for (int i = 0; i < ArraySize(mChartTags); i++) + { + // + string iTag = mChartTags[i]; + if (iTag != chTag) + { + continue; + } + + // + currChTagIdx = i; + break; + } + + // + if (currChTagIdx > -1) + { + chCountedBars = mChartBars[currChTagIdx]; + } + } + + // + result = currentBars > chCountedBars; + if (result) + { + // + if (currChTagIdx > -1) + { + // + mChartTags[currChTagIdx] = chTag; + mChartBars[currChTagIdx] = currentBars; + } + else + { + // + Add(chTag, mChartTags); + Add(currentBars, mChartBars); + } + } + + // + return result; +} + +// +double XNZ(double check, double val = 0) +{ + if (check == EMPTY_VALUE || check == 0) + { + return val; + } + else + { + return check; + } +} + +// +// Retrive Ask Price ... +double GetAsk() +{ + return SymbolInfoDouble(_Symbol, SYMBOL_ASK); +} +double GetAsk( + string symbol // selected symbol for calculations +) +{ + // + double result = SymbolInfoDouble(symbol, SYMBOL_ASK); + + // + return result; +} + +// +// Retrieve Bid Price ... +double GetBid() +{ + return SymbolInfoDouble(_Symbol, SYMBOL_BID); +} +double GetBid( + string symbol // selected symbol for calculations +) +{ + // + double result = SymbolInfoDouble(symbol, SYMBOL_BID); + + // + return result; +} + +// +// Calculate and Retrieve Spread Price ... +double GetSpread() +{ + // + double ask = GetAsk(); + double bid = GetBid(); + double result = MathAbs(ask - bid); + + // + return result; +} +double GetSpread( + string symbol // selected symbol for calculations +) +{ + // + double ask = GetAsk(symbol); + double bid = GetBid(symbol); + double result = MathAbs(ask - bid); + + // + return result; +} + +// +// Get Points ... +double GetPoints() +{ + return _Point; +} +double GetPoints( + string symbol // selected symbol for calculations +) +{ + // + double result = SymbolInfoDouble(symbol, SYMBOL_POINT); + + // + return result; +} + +// +// Get Digits ... +int GetDigits() +{ + return _Digits; +} +int GetDigits( + string symbol // selected symbol for calculations +) +{ + // + int result = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); + + // + return result; +} + +// +// Get Signal Entry ... +double GetEntry( + ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + // Validate Arg ... + if (type == NULL) + { + return result; + } + + // + bool isLong = type == POSITION_TYPE_BUY; + result = isLong ? GetAsk() : GetBid(); + result = NormalizePrice(result); + + // + return result; +} +double GetEntry( + string symbol, // Specified Symbol + ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + bool isLong = type == POSITION_TYPE_BUY; + result = isLong ? GetAsk(symbol) : GetBid(symbol); + result = NormalizePrice(result, symbol); + + // + return result; +} + +// +// Get Signal Exit ... +double GetExit( + ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + // Validate Arg ... + if (type == NULL) + { + return result; + } + + // + bool isLong = type == POSITION_TYPE_BUY; + result = isLong ? GetBid() : GetAsk(); + result = NormalizePrice(result); + + // + return result; +} +double GetExit( + string symbol, // Specified Symbol + ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + // Validate Arg ... + if (type == NULL) + { + return result; + } + + // + bool isLong = type == POSITION_TYPE_BUY; + result = isLong ? GetBid(symbol) : GetAsk(symbol); + result = NormalizePrice(result, symbol); + + // + return result; +} + +// +// Determine a Position type is Long or not ... +bool IsLong(ENUM_POSITION_TYPE type) +{ + // + bool result = type == POSITION_TYPE_BUY; + + // + return result; +} +bool IsLong(ENUM_ORDER_TYPE type) +{ + // + bool result = type == ORDER_TYPE_BUY; + + // + return result; +} + +// +// Determine a Position type is Short or not ... +bool IsShort(ENUM_POSITION_TYPE type) +{ + // + bool result = type == POSITION_TYPE_SELL; + + // + return result; +} +bool IsShort(ENUM_ORDER_TYPE type) +{ + // + bool result = type == ORDER_TYPE_SELL; + + // + return result; +} + +// +// Get 1 Pip in Price Value ... +double GetPipPrice() +{ + // + double result = _Point; + if (_Digits == 3 || _Digits == 5) + { + result *= 10; + } + + // + return result; +} +double GetPipPrice( + string symbol // selected symbol for calculations +) +{ + // + double symbolPoint = GetPoints(symbol); + int symbolDigits = GetDigits(symbol); + + // + double result = symbolPoint; + if (symbolDigits == 3 || symbolDigits == 5) + { + result *= 10; + } + + // + return result; +} + +// +// Converts Pips To Price ... +double PipsToPrice( + int pips // pips amount +) +{ + // + int digits = GetDigits(); + double pipValue = GetPipPrice(); + double result = pips * pipValue; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} +double PipsToPrice( + double pips // pips amount +) +{ + // + int digits = GetDigits(); + double pipValue = GetPipPrice(); + double result = pips * pipValue; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} +double PipsToPrice( + string symbol, // selected symbol for calculation + int pips // pips amount +) +{ + // + int digits = GetDigits(symbol); + double pipValue = GetPipPrice(symbol); + double result = pips * pipValue; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} +double PipsToPrice( + string symbol, // selected symbol for calculation + double pips // pips amount +) +{ + // + int digits = GetDigits(symbol); + double pipValue = GetPipPrice(symbol); + double result = pips * pipValue; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +// Converts Price to Pips ... +double PriceToPips( + double price // the price amount which required to calculate +) +{ + // + int digits = GetDigits(); + double pipPrice = GetPipPrice(); + + // + double result = price / pipPrice; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} +double PriceToPips( + string symbol, // Selected Symbol + double price // the price amount which required to calculate +) +{ + // + int digits = GetDigits(symbol); + double pipPrice = GetPipPrice(symbol); + + // + double result = price / pipPrice; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +// Convert Price to Point ... +double PriceToPoint( + double price // the price amount which required to calculate +) +{ + return PriceToPoint(_Symbol, price); +} +double PriceToPoint( + string symbol, // Selected Symbol + double price // the price amount which required to calculate +) +{ + // + double result = 0; + + // + double point = GetPoints(symbol); + result = price / point; + + // + return result; +} + +// +// Converts Point to Price ... +double PointToPrice( + double points // Points Size +) +{ + return PointToPrice(_Symbol, points); +} +double PointToPrice( + string symbol, // Selected Symbol + double points // Points Size +) +{ + // + double result = 0; + + // + double point = GetPoints(symbol); + result = points * point; + + // + return result; +} + +// +// Get a Candle Body ... +double GetCandleBody( + XOHCL &candle // specified candle +) +{ + // + double result = MathAbs(candle.open - candle.close); + + // + return result; +} + +// +// Get a Candle Range ... +double GetCandleRange( + XOHCL &candle // specified candle +) +{ + // + double result = MathAbs(candle.high - candle.low); + + // + return result; +} + +// +// Get a Candle Shadow ... +double GetCandleShadow( + XOHCL &candle // specified candle +) +{ + // + double range = GetCandleRange(candle); + double body = GetCandleBody(candle); + + // + double result = MathAbs(range - body); + + // + return result; +} + +// +// Check a Candle is Base Candle for RTM or not ... +bool IsBaseCandle( + XOHCL &candle // specified candle +) +{ + // + double range = GetCandleRange(candle); + double body = GetCandleBody(candle); + + // + bool result = body > range; + + // + return result; +} + +// +// Retrieve Applied Price at Specific Candle ... +double GetAppliedPrice( + XOHCL &candle, // specified candle + ENUM_APPLIED_PRICE source = PRICE_CLOSE // specified Applied To +) +{ + // + double result = EMPTY_VALUE; + + // + switch (source) + { + // + // Open ... + case PRICE_OPEN: + result = candle.open; + break; + + // + // High ... + case PRICE_HIGH: + result = candle.high; + break; + + // + // Low ... + case PRICE_LOW: + result = candle.low; + break; + + // + // Median ((High + Low) / 2) ... + case PRICE_MEDIAN: + result = (candle.high + candle.low) / 2; + break; + + // + // Typical ((High + Low + Close)/3) ... + case PRICE_TYPICAL: + result = (candle.high + candle.low + candle.close) / 3; + break; + + // + // Weighted ((High + Low + Close + Close)/4) ... + case PRICE_WEIGHTED: + result = (candle.high + candle.low + (candle.close * 2)) / 4; + break; + + // + // Close ... + default: + case PRICE_CLOSE: + result = candle.close; + break; + } + + // + return result; +} +double GetAppliedPrice( + int bar_index, // specify candle index + ENUM_APPLIED_PRICE source = PRICE_CLOSE // specified Applied To +) +{ + // + double result = EMPTY_VALUE; + + // + XOHCL candle = GetCandle(bar_index); + result = GetAppliedPrice(candle, source); + + // + return result; +} +double GetAppliedPrice( + int bar_index, // specify candle index + ENUM_SERIESMODE mode // converts Series Mode to Applied Price ... +) +{ + // + double result = 0; + + // + ENUM_APPLIED_PRICE mAppliedTo = To(mode); + result = GetAppliedPrice( + bar_index, + mAppliedTo); + + // + return result; +} + +// +// Converts ... +ENUM_APPLIED_PRICE To( + ENUM_SERIESMODE mode // converts Series Mode to Applied Price ... +) +{ + // + ENUM_APPLIED_PRICE result = PRICE_CLOSE; + + // + switch (mode) + { + // + // High ... + case MODE_HIGH: + result = PRICE_HIGH; + break; + + // + // Open ... + case MODE_OPEN: + result = PRICE_OPEN; + break; + + // + // Low ... + case MODE_LOW: + result = PRICE_LOW; + break; + + // + // Close ... + // Default ... + case MODE_CLOSE: + default: + result = PRICE_CLOSE; + break; + } + + // + return result; +} + +// +// Retrieve a Candel Data ... +XOHCL GetCandle(int bar_index) +{ + // + XOHCL result = {}; + + // + double open = iOpen(_Symbol, _Period, bar_index); + double high = iHigh(_Symbol, _Period, bar_index); + double close = iClose(_Symbol, _Period, bar_index); + double low = iLow(_Symbol, _Period, bar_index); + + // + result.low = low; + result.open = open; + result.high = high; + result.close = close; + + // + return result; +} +XOHCL GetCandle( + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // specify candle index +) +{ + // + XOHCL result = {}; + + // + double open = iOpen(_Symbol, mPeriod, bar_index); + double high = iHigh(_Symbol, mPeriod, bar_index); + double close = iClose(_Symbol, mPeriod, bar_index); + double low = iLow(_Symbol, mPeriod, bar_index); + + // + result.low = low; + result.open = open; + result.high = high; + result.close = close; + + // + return result; +} +XOHCL GetCandle( + string symbol, // specify symbol + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // specify candle index +) +{ + // + XOHCL result = {}; + + // + double open = iOpen(symbol, mPeriod, bar_index); + double high = iHigh(symbol, mPeriod, bar_index); + double close = iClose(symbol, mPeriod, bar_index); + double low = iLow(symbol, mPeriod, bar_index); + + // + result.low = low; + result.open = open; + result.high = high; + result.close = close; + + // + return result; +} + +// +// Retrieve a candle index in current timeframe inside another timeframe ... +int GetCandleBarIndex( + int bar_index, // Specify Candle index in current timeframe + ENUM_TIMEFRAMES destPeriod // Specify destination timeframe +) +{ + // + int result = -1; + + // + datetime barTime = iTime(_Symbol, _Period, bar_index); + result = iBarShift(_Symbol, destPeriod, barTime); + + // + return result; +} + +// +// Retrieve a symbol candle index in source time frame inside dest timeframe ... +int GetCandleBarIndex( + int bar_index, // Specify Candle index in current timeframe + string symbol, // Specify desired Symbol + ENUM_TIMEFRAMES sourcePeriod, // Specify bar_index timeframe + ENUM_TIMEFRAMES destPeriod // Specify destination timeframe +) +{ + // + int result = -1; + + // + datetime barTime = iTime(symbol, sourcePeriod, bar_index); + result = iBarShift(symbol, destPeriod, barTime); + + // + return result; +} + +// +// Check a Candle is Bullish or not ... +bool IsBullishCandle( + XOHCL &candle // specified candle +) +{ + // + bool result = false; + + // + result = candle.open < candle.close; + + // + return result; +} +bool IsBullishCandle( + int bar_index // candle index +) +{ + // + bool result = false; + + // + XOHCL candle = GetCandle(bar_index); + + // + result = IsBullishCandle(candle); + + // + return result; +} +bool IsBullishCandle( + string symbol, // specify symbol + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // candle index +) +{ + // + bool result = false; + + // + XOHCL candle = GetCandle( + symbol, + mPeriod, + bar_index); + + // + result = IsBullishCandle(candle); + + // + return result; +} + +// +// Check a Candle is Bullish or not ... +bool IsBearishCandle( + XOHCL &candle // specified candle +) +{ + // + bool result = false; + + // + result = candle.open > candle.close; + + // + return result; +} +bool IsBearishCandle( + int bar_index // candle index +) +{ + // + bool result = false; + + // + XOHCL candle = GetCandle(bar_index); + + // + result = IsBearishCandle(candle); + + // + return result; +} +bool IsBearishCandle( + string symbol, // specify symbol + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // candle index +) +{ + // + bool result = false; + + // + XOHCL candle = GetCandle( + symbol, + mPeriod, + bar_index); + + // + result = IsBearishCandle(candle); + + // + return result; +} + +// +// Check Candle Body Bigger Than it's Shadow ... +bool CandleHasStrongBody(XOHCL &candle) +{ + // + double bodySize = MathAbs(candle.open - candle.close); + double shadowSize = MathAbs(candle.high - candle.low) - bodySize; + + // + bool result = bodySize > (shadowSize * 1.5); + + // + return result; +} + +// +// Determines a cnadle is Swing High +// or Swing Low order block ... +ENUM_X_SWING_TYPE GetCandleSwing(int bar_index) +{ + // + ENUM_X_SWING_TYPE result = X_NO_SWING; + + // + // Reading Candle Models ... + XOHCL candles[3]; + candles[0] = GetCandle(bar_index + 1); + candles[1] = GetCandle(bar_index + 2); + candles[2] = GetCandle(bar_index + 3); + + // + // Check Swing Start Candle has Strong Body ... + bool isStrongBodyCandle = CandleHasStrongBody(candles[2]); + if (!isStrongBodyCandle) + { + return result; + } + + // + // Check Swing Low Conditions ... + bool isSwingLowOrderBlock = + candles[2].low < candles[1].low && + candles[1].low < candles[0].low && + candles[2].low < candles[0].low; + if (isSwingLowOrderBlock) + { + result = X_SWING_LOW; + } + + // + // Check Swing High Conditions ... + bool isSwingHighOrderBlock = + candles[2].high > candles[1].high && + candles[1].high > candles[0].high && + candles[2].high > candles[0].high; + if (isSwingHighOrderBlock) + { + result = X_SWING_HIGH; + } + + // + return result; +} +ENUM_X_SWING_TYPE GetCandleSwing( + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // specify candle index +) +{ + // + ENUM_X_SWING_TYPE result = X_NO_SWING; + + // + // Reading Candle Models ... + XOHCL candles[3]; + candles[0] = GetCandle(mPeriod, bar_index + 1); + candles[1] = GetCandle(mPeriod, bar_index + 2); + candles[2] = GetCandle(mPeriod, bar_index + 3); + + // + // Check Swing Start Candle has Strong Body ... + bool isStrongBodyCandle = CandleHasStrongBody(candles[2]); + if (!isStrongBodyCandle) + { + return result; + } + + // + // Check Swing Low Conditions ... + bool isSwingLowOrderBlock = + candles[2].low < candles[1].low && + candles[1].low < candles[0].low && + candles[2].low < candles[0].low; + if (isSwingLowOrderBlock) + { + result = X_SWING_LOW; + } + + // + // Check Swing High Conditions ... + bool isSwingHighOrderBlock = + candles[2].high > candles[1].high && + candles[1].high > candles[0].high && + candles[2].high > candles[0].high; + if (isSwingHighOrderBlock) + { + result = X_SWING_HIGH; + } + + // + return result; +} +ENUM_X_SWING_TYPE GetCandleSwing( + string symbol, // specify symbol + ENUM_TIMEFRAMES mPeriod, // specify timeframe + int bar_index // specify candle index +) +{ + // + ENUM_X_SWING_TYPE result = X_NO_SWING; + + // + // Reading Candle Models ... + XOHCL candles[3]; + candles[0] = GetCandle(symbol, mPeriod, bar_index + 1); + candles[1] = GetCandle(symbol, mPeriod, bar_index + 2); + candles[2] = GetCandle(symbol, mPeriod, bar_index + 3); + + // + // Check Swing Start Candle has Strong Body ... + bool isStrongBodyCandle = CandleHasStrongBody(candles[2]); + if (!isStrongBodyCandle) + { + return result; + } + + // + // Check Swing Low Conditions ... + bool isSwingLowOrderBlock = + candles[2].low < candles[1].low && + candles[1].low < candles[0].low && + candles[2].low < candles[0].low; + if (isSwingLowOrderBlock) + { + result = X_SWING_LOW; + } + + // + // Check Swing High Conditions ... + bool isSwingHighOrderBlock = + candles[2].high > candles[1].high && + candles[1].high > candles[0].high && + candles[2].high > candles[0].high; + if (isSwingHighOrderBlock) + { + result = X_SWING_HIGH; + } + + // + return result; +} + +// +// Find Swing Points ... +int FindSwing( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod, // Trading Period ... + ENUM_SERIESMODE mode, // Swing Based On Price mode ... + int mLength, // Loopback ... + int bar_index // BarIndex ... +) +{ + // + int result = -1; + + // + if (StringLen(mSymbol) == 0 || (mode != MODE_HIGH && mode != MODE_LOW)) + { + return result; + } + + // + int current = bar_index; + int founded = FindNextSwing( + mSymbol, + mPeriod, + mode, + (mLength * 2) + 1, + current - mLength); + + // + while (founded != current) + { + // + current = FindNextSwing( + mSymbol, + mPeriod, + mode, + mLength, + current + 1); + + // + founded = FindNextSwing( + mSymbol, + mPeriod, + mode, + (mLength * 2) + 1, + current - mLength); + } + + // + result = current; + + // + return result; +} + +// +// Find Next Swing ... +int FindNextSwing( + string mSymbol, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod, // Trading Period ... + ENUM_SERIESMODE mode, // Swing Based On Price mode ... + int mLength, // Loopback ... + int bar_index // BarIndex ... +) +{ + // + int result = -1; + + // + if (bar_index < 0) + { + mLength += bar_index; + bar_index = 0; + } + + // + result = mode == MODE_HIGH + ? iHighest( + mSymbol, + mPeriod, + mode, + mLength, + bar_index) + : iLowest( + mSymbol, + mPeriod, + mode, + mLength, + bar_index); + + // + return result; +} + +// +// Retrieve Market Highest High ... +double GetHighestHigh( + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iHighest( + _Symbol, + _Period, + MODE_HIGH, + mLength, + bar_index); + + // + result = iHigh( + _Symbol, + _Period, + rIdx); + + // + return result; +} +double GetHighestHigh( + int mLength, // Which market Length use + int bar_index, // bar index + ENUM_SERIESMODE mode // Calculation mode +) +{ + // + double result = -1; + + // + int rIdx = iHighest( + _Symbol, + _Period, + mode, + mLength, + bar_index); + + // + result = iHigh( + _Symbol, + _Period, + rIdx); + + // + return result; +} +double GetHighestHigh( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES mPeriod, // Specified Period + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iHighest( + symbol, + mPeriod, + MODE_HIGH, + mLength, + bar_index); + + // + result = iHigh( + symbol, + mPeriod, + rIdx); + + // + return result; +} +double GetHighestHigh( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES mPeriod, // Specified Period + ENUM_SERIESMODE mode, // Calculation mode + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iHighest( + symbol, + mPeriod, + mode, + mLength, + bar_index); + + // + result = iHigh( + symbol, + mPeriod, + rIdx); + + // + return result; +} + +// +// Retrieve Market Lowest Low ... +double GetLowestLow( + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iLowest( + _Symbol, + _Period, + MODE_LOW, + mLength, + bar_index); + + // + result = iLow( + _Symbol, + _Period, + rIdx); + + // + return result; +} +double GetLowestLow( + int mLength, // Which market Length use + int bar_index, // bar index + ENUM_SERIESMODE mode // Calculation mode +) +{ + // + double result = -1; + + // + int rIdx = iLowest( + _Symbol, + _Period, + mode, + mLength, + bar_index); + + // + result = iLow( + _Symbol, + _Period, + rIdx); + + // + return result; +} +double GetLowestLow( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES mPeriod, // Specified Period + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iLowest( + symbol, + mPeriod, + MODE_LOW, + mLength, + bar_index); + + // + result = iLow( + symbol, + mPeriod, + rIdx); + + // + return result; +} +double GetLowestLow( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES mPeriod, // Specified Period + ENUM_SERIESMODE mode, // Calculation mode + int mLength, // Which market Length use + int bar_index // bar index +) +{ + // + double result = -1; + + // + int rIdx = iLowest( + symbol, + mPeriod, + mode, + mLength, + bar_index); + + // + result = iLow( + symbol, + mPeriod, + rIdx); + + // + return result; +} + +// +// Find Support and Resistance for Specific Bar based on provided Buffer ... +XOHCLSupRes ExtractSupportAndResistance( + int barIndex, // Bar Index ... + const double &pivots[], // Provided Pivot Points ... + int count = 3, // Number of Requireds ... + string mSymbol = NULL, // Trading Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period ... +) +{ + // + if (StringLen(mSymbol) == 0 || mSymbol == NULL) + { + mSymbol = _Symbol; + } + + // + if (mPeriod == NULL) + { + mPeriod = _Period; + } + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + XOHCLSupRes result; + Clean(result.res); + Clean(result.sup); + + // + int pivotsCount = ArraySize(pivots); + if (pivotsCount <= 0) + { + return result; + } + + // + if (count <= 0 || + count > pivotsCount - 1) + { + return result; + } + + // + XOHCL cBar = GetCandle( + mSymbol, + mPeriod, + barIndex); + + // + double tmpR[]; + + // + double tmpS[]; + + // + // Extract Supports ... + // which prices is under low of candle ... + // + // Extract Resistance ... + // which prices is over high of candle ... + for (int i = 0; i < pivotsCount; i++) + { + // + double iFlat = pivots[i]; + + // + if (iFlat > cBar.high) + { + Add( + iFlat, + tmpR); + } + else if (iFlat < cBar.low) + { + Add( + iFlat, + tmpS); + } + } + + // + // Sorting Founded Resistance and Supports ... + + // + // Since Resistance Levels must be Increasing ... + ArraySort(tmpR); + + // + // Since Support Levels must be Decreasing ... + ArraySort(tmpS); + ArrayReverse(tmpS); + + // + // Fill Resistance ... + int tmpRCount = ArraySize(tmpR); + if (tmpRCount > 0) + { + // + if (tmpRCount < count) + { + // + ArrayCopy( + result.res, + tmpR); + } + else + { + // + ArrayCopy( + result.res, + tmpR, + 0, + 0, + count); + } + } + + // + // Fill Supports ... + int tmpSCount = ArraySize(tmpS); + if (tmpSCount > 0) + { + // + if (tmpSCount < count) + { + // + ArrayCopy( + result.sup, + tmpS); + } + else + { + // + ArrayCopy( + result.sup, + tmpS, + 0, + 0, + count); + } + } + + // + return result; +} + +// +// Find a Value less than Specified ... +double FindLesserThanValue( + double value, // Specified Value ... + const double &source[], // Source ... + bool isDescend = false // Find Biggest Lesser Value ... +) +{ + // + double result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + double tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source)); + + // + ArrayCopy( + tmp, + source); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + double iValue = tmp[i]; + + // + if (iValue < value) + { + // + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find a Value less than Specified ... +double FindBiggerThanValue( + double value, // Specified Value ... + const double &source[], // Source ... + bool isDescend = false // Find Smallest Bigger Value ... +) +{ + // + double result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + double tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source)); + + // + ArrayCopy( + tmp, + source); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (!isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + double iValue = tmp[i]; + + // + if (iValue > value) + { + // + result = iValue; + break; + } + } + + // + return result; +} + +// +// Calculate Fib Level ... +double GetFibonacciLevel( + double upPrice, + double downPrice, + double level, + int direction) +{ + // + double ling = upPrice - downPrice; + double pLevel = (ling / 100) * (level * 100); + + // + double result = direction > 0 ? upPrice - pLevel : downPrice + pLevel; + result = NormalizeDouble(result, _Digits); + + // + return result; +} + +// +// Check first Cross Over second at bar_index ... +bool IsCrossOver( + const double &first[], // the buffer which check crossing over second buffer + const double &second[], // first buffer checks based on this buffer + const int bar_index // check crosses in specific index +) +{ + // + bool result = false; + + // + ArraySetAsSeries(first, true); + ArraySetAsSeries(second, true); + + // + // Validate Args ... + if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) + { + return result; + } + + // + result = first[bar_index] > second[bar_index] && + !(first[bar_index + 1] > second[bar_index + 1]); + + // + return result; +} + +// +// Check first is Over second at bar_index ... +bool IsOver( + const double &first[], // the buffer which check over second buffer + const double &second[], // first buffer checks based on this buffer + const int bar_index // check crosses in specific index +) +{ + // + bool result = false; + + // + ArraySetAsSeries(first, true); + ArraySetAsSeries(second, true); + + // + // Validate Args ... + if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) + { + return result; + } + + // + result = first[bar_index] > second[bar_index] && + first[bar_index + 1] > second[bar_index + 1]; + + // + return result; +} + +// +// Check first Cross Under second at bar_index ... +bool IsCrossUnder( + const double &first[], // the buffer which check crossing under second buffer + const double &second[], // first buffer checks based on this buffer + const int bar_index // check crosses in specific index +) +{ + // + bool result = false; + + // + ArraySetAsSeries(first, true); + ArraySetAsSeries(second, true); + + // + // Validate Args ... + if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) + { + return result; + } + + // + result = first[bar_index] < second[bar_index] && + !(first[bar_index + 1] < second[bar_index + 1]); + + // + return result; +} + +// +// Check first is Under second at bar_index ... +bool IsUnder( + const double &first[], // the buffer which check under second buffer + const double &second[], // first buffer checks based on this buffer + const int bar_index // check crosses in specific index +) +{ + // + bool result = false; + + // + ArraySetAsSeries(first, true); + ArraySetAsSeries(second, true); + + // + // Validate Args ... + if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) + { + return result; + } + + // + result = first[bar_index] < second[bar_index] && + first[bar_index + 1] < second[bar_index + 1]; + + // + return result; +} + +// +// Calculate Slope of Specified Buffer at Specified Index ... +double GetSlope( + int from, // In Past Index ... + int to, // In Past Index ... + double &buffer[]) +{ + // + double result = 0; + + // + double toValue = buffer[to]; + double fromValue = buffer[from]; + double deltaValue = toValue - fromValue; + double deltaTime = from - to; + + // + result = deltaValue / deltaTime; + + // + return result; +} + +// +// Check if a Value Increasing in Loopback ... +bool IsIncreasing( + int from, // Last Time Index + int to, // Fisr Tima Index + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + result = toValue > fromValue; + for (int i = to + 1; i <= from - 1; i++) + { + // + double iValue = buffer[i]; + bool isPassed = toValue >= iValue; + + // + bool isIIncreasing = IsIncreasing( + from, + i, + buffer); + + // + // Check Result ... + result = result && isPassed && isIIncreasing; + if (!result) + { + break; + } + } + + // + return result; +} + +// +// Check if a Value Decreasing in Loopback ... +bool IsDecreasing( + int from, // Last Time Index + int to, // Fisr Tima Index + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + result = toValue < fromValue; + for (int i = to + 1; i <= from - 1; i++) + { + // + double iValue = buffer[i]; + bool isPassed = toValue <= iValue; + + // + bool isIDecreasing = IsDecreasing( + from, + i, + buffer); + + // + // Check Result ... + result = result && isPassed && isIDecreasing; + if (!result) + { + break; + } + } + + // + return result; +} + +// +// Get Max Value of Specific Loopback of a Buffer ... +double GetMaxValue( + int mLoopback, // loopback length + double &buffer[] // the Buffer which required to search +) +{ + // + double result = 0; + + // + // Validate Args ... + if ( + mLoopback < 2 || + ArraySize(buffer) < mLoopback) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < mLoopback; i++) + { + // + double iValue = buffer[i]; + + // + result = + // + result == 0 || result < iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} + +// +// Get Min Value of Specific Loopback of a Buffer ... +double GetMinValue( + int mLoopback, // loopback length + double &buffer[] // the Buffer which required to search +) +{ + // + double result = 0; + + // + // Validate Args ... + if ( + mLoopback < 2 || + ArraySize(buffer) < mLoopback) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < mLoopback; i++) + { + // + double iValue = buffer[i]; + + // + result = + // + result == 0 || result > iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} + +// +// Find Same Values in Array ... +void FindSameValueInBuffer( + double &result[], // Holds Result ... + double &source[], // Source ... + int verifications = 3 // Number of Consequence Repeat ... +) +{ + // + Clean(result); + + // + // TenkanSen Flats ... + int sourceCount = ArraySize(source); + if (sourceCount > verifications) + { + // + double mLast = 0; + int mVerified = 0; + for (int i = 0; i < sourceCount; i++) + { + // + double iVal = source[i]; + if (mLast == 0) + { + mLast = iVal; + } + else if (mLast == iVal) + { + mVerified++; + } + else + { + mLast = iVal; + mVerified = 0; + } + + // + if (iVal == mLast && mVerified >= verifications) + { + // + Add( + iVal, + result); + + // + mLast = 0; + mVerified = 0; + } + } + } +} + +// +bool IsInPeak( + int mLoopback, // loopback length + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + mLoopback < 2 || + ArraySize(buffer) < mLoopback + 1) + { + return result; + } + + // + int q1Length = mLoopback / 4; + int halfLength = mLoopback / 2; + int q2Length = halfLength + q1Length; + + // + double firstValue = buffer[1]; + double q1Value = buffer[q1Length]; + double q2Value = buffer[q2Length]; + double halfValue = buffer[halfLength]; + double lastValue = buffer[ArraySize(buffer) - 1]; + + // + // Peak ... + result = + // + firstValue > lastValue + // + && + // + ( + firstValue > q1Value && + firstValue > halfValue) + // + ; + + // + return result; +} + +// +bool IsInVale( + int mLoopback, // loopback length + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + mLoopback < 2 || + ArraySize(buffer) < mLoopback + 1) + { + return result; + } + + // + int q1Length = mLoopback / 4; + int halfLength = mLoopback / 2; + int q2Length = halfLength + q1Length; + + // + double firstValue = buffer[1]; + double q1Value = buffer[q1Length]; + double q2Value = buffer[q2Length]; + double halfValue = buffer[halfLength]; + double lastValue = buffer[ArraySize(buffer) - 1]; + + // + // Peak ... + result = + // + firstValue < lastValue + // + && + // + ( + firstValue < q1Value && + firstValue < halfValue) + // + ; + + // + return result; +} + +// +// Check Sharp Happens or not ... +bool IsSharpChanged( + double fromValue, // Past Value + double toValue, // Present Value + double maxValue, // Max in Range Value + double minValue // Min in Range Value +) +{ + // + bool result = false; + + // + // This Used In Increased or Decreased Sharp Detection ... + bool isIncreased = toValue > fromValue; + + // + double toFromDelta = MathAbs(toValue - fromValue); + double minMaxDelta = maxValue - minValue; + + // + result = toFromDelta >= (minMaxDelta / 3); + + // + return result; +} +bool IsSharpChanged( + int from, // Past Index in Series + int to, // Present Index in Series + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + + // + // This Used In Increased or Decreased Sharp Detection ... + bool isIncreased = toValue > fromValue; + + // + double minValue = GetMinValue( + ArraySize(buffer) - 1, + buffer); + double maxValue = GetMaxValue( + ArraySize(buffer) - 1, + buffer); + double minMaxDelta = maxValue - minValue; + + // + // Sharp Detection ... + result = IsSharpChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} +bool IsSharpChanged( + int from, // Past Bar Index + int to, // Present Bar Index + ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To +) +{ + // + bool result = false; + + // + double toValue = GetAppliedPrice( + to, + appliedPrice); + double fromValue = GetAppliedPrice( + from, + appliedPrice); + + // + int hIdx = iHighest( + _Symbol, + _Period, + MODE_HIGH, + from, + to); + double maxValue = iHigh( + _Symbol, + _Period, + hIdx); + + // + int lIdx = iLowest( + _Symbol, + _Period, + MODE_LOW, + from, + to); + double minValue = iLow( + _Symbol, + _Period, + lIdx); + + // + result = IsSharpChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} + +// +// Check InCreased Sharp Happens or not ... +bool IsSharpIncreasedChanged( + double fromValue, // Past Value + double toValue, // Present Value + double maxValue, // Max in Range Value + double minValue // Min in Range Value +) +{ + // + bool result = false; + + // + // This Used In Increased or Decreased Sharp Detection ... + bool isIncreased = toValue > fromValue; + + // + double toFromDelta = MathAbs(toValue - fromValue); + double minMaxDelta = maxValue - minValue; + + // + result = + isIncreased && + toFromDelta >= (minMaxDelta / 3); + + // + return result; +} +bool IsSharpIncreasedChanged( + int from, // Past Index in Series + int to, // Present Index in Series + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + + // + double minValue = GetMinValue( + ArraySize(buffer) - 1, + buffer); + double maxValue = GetMaxValue( + ArraySize(buffer) - 1, + buffer); + double minMaxDelta = maxValue - minValue; + + // + // Sharp Detection ... + result = IsSharpIncreasedChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} +bool IsSharpIncreasedChanged( + int from, // Past Bar Index + int to, // Present Bar Index + ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To +) +{ + // + bool result = false; + + // + double toValue = GetAppliedPrice( + to, + appliedPrice); + double fromValue = GetAppliedPrice( + from, + appliedPrice); + + // + int hIdx = iHighest( + _Symbol, + _Period, + MODE_HIGH, + from, + to); + double maxValue = iHigh( + _Symbol, + _Period, + hIdx); + + // + int lIdx = iLowest( + _Symbol, + _Period, + MODE_LOW, + from, + to); + double minValue = iLow( + _Symbol, + _Period, + lIdx); + + // + result = IsSharpIncreasedChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} + +// +// Check Decreased Sharp Happens or not ... +bool IsSharpDecreasedChanged( + double fromValue, // Past Value + double toValue, // Present Value + double maxValue, // Max in Range Value + double minValue // Min in Range Value +) +{ + // + bool result = false; + + // + // This Used In Increased or Decreased Sharp Detection ... + bool isIncreased = toValue > fromValue; + + // + double toFromDelta = MathAbs(toValue - fromValue); + double minMaxDelta = maxValue - minValue; + + // + result = + !isIncreased && + toFromDelta >= (minMaxDelta / 3); + + // + return result; +} +bool IsSharpDecreasedChanged( + int from, // Past Index in Series + int to, // Present Index in Series + double &buffer[] // the Buffer which required to search +) +{ + // + bool result = false; + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + + // + double minValue = GetMinValue( + ArraySize(buffer) - 1, + buffer); + double maxValue = GetMaxValue( + ArraySize(buffer) - 1, + buffer); + double minMaxDelta = maxValue - minValue; + + // + // Sharp Detection ... + result = IsSharpDecreasedChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} +bool IsSharpDecreasedChanged( + int from, // Past Bar Index + int to, // Present Bar Index + ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To +) +{ + // + bool result = false; + + // + double toValue = GetAppliedPrice( + to, + appliedPrice); + double fromValue = GetAppliedPrice( + from, + appliedPrice); + + // + int hIdx = iHighest( + _Symbol, + _Period, + MODE_HIGH, + from, + to); + double maxValue = iHigh( + _Symbol, + _Period, + hIdx); + + // + int lIdx = iLowest( + _Symbol, + _Period, + MODE_LOW, + from, + to); + double minValue = iLow( + _Symbol, + _Period, + lIdx); + + // + result = IsSharpDecreasedChanged( + fromValue, + toValue, + maxValue, + minValue); + + // + return result; +} + +// +void Clean(int &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(ulong &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(string &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} +void Clean(double &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} + +// +bool GetLastItem( + double &item, // Holds Result + double &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + item = buffer[bufferSize - 1]; + + // + result = true; + return result; +} +bool GetLastItem( + datetime &item, // Holds Result + datetime &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + item = buffer[bufferSize - 1]; + + // + result = true; + return result; +} + +// +void Add( + int item, // item want to add + int &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + ulong item, // item want to add + ulong &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + string item, // item want to add + string &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + double item, // item want to add + double &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + XOHCL &item, // item want to add + XOHCL &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} +void Add( + datetime &item, // item want to add + datetime &buffer[] // Destination buffer +) +{ + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; +} + +// +// Add an Item to a Buffer if not Exists ... +void AddIfNotExists( + double value, + double &values[], + double smoothingPoint = 3) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int valuesCount = ArraySize(values); + if (valuesCount <= 0) + { + // + Add(value, + values); + } + else + { + // + bool isExists = false; + for (int i = 0; i < valuesCount; i++) + { + // + double iVal = values[i]; + + // + double diff = MathAbs(iVal - value); + + // + if (iVal == value || diff < smoothingValue) + { + // + isExists = true; + break; + } + } + + // + if (!isExists) + { + // + Add(value, + values); + } + } +} + +// +// Add a Buffers Child to another Buffer +// if it's not Contains them ... +void AddsIfNotExists( + double &source[], + double &dest[], + double smoothingPoint = 3) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + double iSource = source[i]; + + // + AddIfNotExists( + iSource, + dest, + smoothingPoint); + } +} + +// +// Converts a Buffer to String Representation ... +string ToString( + const int &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator + +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} +string ToString( + const double &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator + +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} +string ToString( + const string &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator + +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} +string ToString( + const datetime &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} +template +string ToString(T value) +{ + return (string)value; +} + +// +// Extract Data from String ... +string ExtractString( + const string source, // Source String used for Extracting + const string startString, // Expression Start String must be Unique + const string endString // Where to End Extraction, usually a Sign +) +{ + // + string result = ""; + + // + // Validate String ... + if ( + StringLen(source) == 0 || + StringLen(endString) == 0 || + StringLen(startString) == 0) + { + return result; + } + + // + // Find Start String Position ... + int sPos = StringFind( + source, + startString); + if (sPos < 0) + { + return result; + } + + // + // Find End String Position after Start String ... + int searchEndFromPos = sPos + StringLen(startString); + int ePos = StringFind( + source, + endString, + searchEndFromPos); + if (ePos < 0) + { + return result; + } + + // + // Extract Data from Source ... + int dLength = ePos - searchEndFromPos; + result = StringSubstr( + source, + searchEndFromPos, + dLength); + + // + return result; +} + +// +// Normalize a give Volume ... +double NormalizeVolume( + double volume, // desired volume to normalize + string symbol = NULL, // Specified Symbol for Normalization + int mLength = 2 // Length of Digits +) +{ + // + double result = volume; + + // + // Normalize Symbol ... + if (StringLen(symbol) == 0) + { + symbol = _Symbol; + } + + // + // Normalize Digits ... + int digits = GetDigits(symbol); + mLength = + mLength == 0 || mLength > digits + ? digits + : MathMin(mLength, digits); + + // + // Normalize Volume ... + result = NormalizeDouble(result, mLength); + + // + double maxAvailableVolume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); + double minAvailableVolume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); + + // + // Validate Result ... + if (result > maxAvailableVolume) + { + result = maxAvailableVolume; + } + else if (result < minAvailableVolume) + { + result = minAvailableVolume; + } + + // + return result; +} + +// +// Normallize Price ... +double NormalizePrice( + double price, // desired Price for normalization + string symbol = NULL // Specified Symbol for Normalization +) +{ + // + double result = 0; + + // + // Mormalize Symbol ... + if (StringLen(symbol) == 0) + { + symbol = _Symbol; + } + + // + int digits = GetDigits(symbol); + result = NormalizeDouble(price, digits); + + // + return result; +} + +// +// Error Descriptions Functions ... +// + +// +// Retrieve Specified Error Code Description ... +string GetErrorDescription(int err_code) +{ + // + string result = ""; + + // + switch (err_code) + { + // + //--- Constant Description + + // + case ERR_SUCCESS: + result = "The operation completed successfully"; + break; + + // + case ERR_INTERNAL_ERROR: + result = "Unexpected internal error"; + break; + + // + case ERR_WRONG_INTERNAL_PARAMETER: + result = "Wrong parameter in the inner call of the client terminal function"; + break; + + // + case ERR_INVALID_PARAMETER: + result = "Wrong parameter when calling the system function"; + break; + + // + case ERR_NOT_ENOUGH_MEMORY: + result = "Not enough memory to perform the system function"; + break; + + // + case ERR_STRUCT_WITHOBJECTS_ORCLASS: + result = "The structure contains objects of strings and/or dynamic arrays and/or structure of such objects and/or classes"; + break; + + // + case ERR_INVALID_ARRAY: + result = "Array of a wrong type, wrong size, or a damaged object of a dynamic array"; + break; + + // + case ERR_ARRAY_RESIZE_ERROR: + result = "Not enough memory for the relocation of an array, or an attempt to change the size of a static array"; + break; + + // + case ERR_STRING_RESIZE_ERROR: + result = "Not enough memory for the relocation of string"; + break; + + // + case ERR_NOTINITIALIZED_STRING: + result = "Not initialized string"; + break; + + // + case ERR_INVALID_DATETIME: + result = "Invalid date and/or time"; + break; + + // + case ERR_ARRAY_BAD_SIZE: + result = "Requested array size exceeds 2 GB"; + break; + + // + case ERR_INVALID_POINTER: + result = "Wrong pointer"; + break; + + // + case ERR_INVALID_POINTER_TYPE: + result = "Wrong type of pointer"; + break; + + // + case ERR_FUNCTION_NOT_ALLOWED: + result = "System function is not allowed to call"; + break; + + // + //--- Charts + + // + case ERR_CHART_WRONG_ID: + result = "Wrong chart ID"; + break; + + // + case ERR_CHART_NO_REPLY: + result = "Chart does not respond"; + break; + + // + case ERR_CHART_NOT_FOUND: + result = "Chart not found"; + break; + + // + case ERR_CHART_NO_EXPERT: + result = "No Expert Advisor in the chart that could handle the event"; + break; + + // + case ERR_CHART_CANNOT_OPEN: + result = "Chart opening error"; + break; + + // + case ERR_CHART_CANNOT_CHANGE: + result = "Failed to change chart symbol and period"; + break; + + // + case ERR_CHART_CANNOT_CREATE_TIMER: + result = "Failed to create timer"; + break; + + // + case ERR_CHART_WRONG_PROPERTY: + result = "Wrong chart property ID"; + break; + + // + case ERR_CHART_SCREENSHOT_FAILED: + result = "Error creating screenshots"; + break; + + // + case ERR_CHART_NAVIGATE_FAILED: + result = "Error navigating through chart"; + break; + + // + case ERR_CHART_TEMPLATE_FAILED: + result = "Error applying template"; + break; + + // + case ERR_CHART_WINDOW_NOT_FOUND: + result = "Subwindow containing the indicator was not found"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_ADD: + result = "Error adding an indicator to chart"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_DEL: + result = "Error deleting an indicator from the chart"; + break; + + // + case ERR_CHART_INDICATOR_NOT_FOUND: + result = "Indicator not found on the specified chart"; + break; + + // + //--- Graphical Objects + case ERR_OBJECT_ERROR: + result = "Error working with a graphical object"; + break; + + // + case ERR_OBJECT_NOT_FOUND: + result = "Graphical object was not found"; + break; + + // + case ERR_OBJECT_WRONG_PROPERTY: + result = "Wrong ID of a graphical object property"; + break; + + // + case ERR_OBJECT_GETDATE_FAILED: + result = "Unable to get date corresponding to the value"; + break; + + // + case ERR_OBJECT_GETVALUE_FAILED: + result = "Unable to get value corresponding to the date"; + break; + + // + //--- MarketInfo + + // + case ERR_MARKET_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_MARKET_NOT_SELECTED: + result = "Symbol is not selected in MarketWatch"; + break; + + // + case ERR_MARKET_WRONG_PROPERTY: + result = "Wrong identifier of a symbol property"; + break; + + // + case ERR_MARKET_LASTTIME_UNKNOWN: + result = "Time of the last tick is not known (no ticks)"; + break; + + // + case ERR_MARKET_SELECT_ERROR: + result = "Error adding or deleting a symbol in MarketWatch"; + break; + + // + //--- History Access + + // + case ERR_HISTORY_NOT_FOUND: + result = "Requested history not found"; + break; + + // + case ERR_HISTORY_WRONG_PROPERTY: + result = "Wrong ID of the history property"; + break; + + // + //--- Global_Variables + + // + case ERR_GLOBALVARIABLE_NOT_FOUND: + result = "Global variable of the client terminal is not found"; + break; + + // + case ERR_GLOBALVARIABLE_EXISTS: + result = "Global variable of the client terminal with the same name already exists"; + break; + + // + case ERR_MAIL_SEND_FAILED: + result = "Email sending failed"; + break; + + // + case ERR_PLAY_SOUND_FAILED: + result = "Sound playing failed"; + break; + + // + case ERR_MQL5_WRONG_PROPERTY: + result = "Wrong identifier of the program property"; + break; + + // + case ERR_TERMINAL_WRONG_PROPERTY: + result = "Wrong identifier of the terminal property"; + break; + + // + case ERR_FTP_SEND_FAILED: + result = "File sending via ftp failed"; + break; + + // + case ERR_NOTIFICATION_SEND_FAILED: + result = "Error in sending notification"; + break; + + // + //--- Custom Indicator Buffers + + // + case ERR_BUFFERS_NO_MEMORY: + result = "Not enough memory for the distribution of indicator buffers"; + break; + + // + case ERR_BUFFERS_WRONG_INDEX: + result = "Wrong indicator buffer index"; + break; + + // + //--- Custom Indicator Properties + + // + case ERR_CUSTOM_WRONG_PROPERTY: + result = "Wrong ID of the custom indicator property"; + break; + + // + //--- Account + + // + case ERR_ACCOUNT_WRONG_PROPERTY: + result = "Wrong account property ID"; + break; + + // + case ERR_TRADE_WRONG_PROPERTY: + result = "Wrong trade property ID"; + break; + + // + case ERR_TRADE_DISABLED: + result = "Trading by Expert Advisors prohibited"; + break; + + // + case ERR_TRADE_POSITION_NOT_FOUND: + result = "Position not found"; + break; + + // + case ERR_TRADE_ORDER_NOT_FOUND: + result = "Order not found"; + break; + + // + case ERR_TRADE_DEAL_NOT_FOUND: + result = "Deal not found"; + break; + + // + case ERR_TRADE_SEND_FAILED: + result = "Trade request sending failed"; + break; + + // + //--- Indicators + + // + case ERR_INDICATOR_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_INDICATOR_CANNOT_CREATE: + result = "Indicator cannot be created"; + break; + + // + case ERR_INDICATOR_NO_MEMORY: + result = "Not enough memory to add the indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_APPLY: + result = "The indicator cannot be applied to another indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_ADD: + result = "Error applying an indicator to chart"; + break; + + // + case ERR_INDICATOR_DATA_NOT_FOUND: + result = "Requested data not found"; + break; + + // + case ERR_INDICATOR_WRONG_HANDLE: + result = "Wrong indicator handle"; + break; + + // + case ERR_INDICATOR_WRONG_PARAMETERS: + result = "Wrong number of parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_PARAMETERS_MISSING: + result = "No parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_CUSTOM_NAME: + result = "The first parameter in the array must be the name of the custom indicator"; + break; + + // + case ERR_INDICATOR_PARAMETER_TYPE: + result = "Invalid parameter type in the array when creating an indicator"; + break; + + // + case ERR_INDICATOR_WRONG_INDEX: + result = "Wrong index of the requested indicator buffer"; + break; + + // + //--- Depth of Market + + // + case ERR_BOOKS_CANNOT_ADD: + result = "Depth Of Market can not be added"; + break; + + // + case ERR_BOOKS_CANNOT_DELETE: + result = "Depth Of Market can not be removed"; + break; + + // + case ERR_BOOKS_CANNOT_GET: + result = "The data from Depth Of Market can not be obtained"; + break; + + // + case ERR_BOOKS_CANNOT_SUBSCRIBE: + result = "Error in subscribing to receive new data from Depth Of Market"; + break; + + // + //--- File Operations + + // + case ERR_TOO_MANY_FILES: + result = "More than 64 files cannot be opened at the same time"; + break; + + // + case ERR_WRONG_FILENAME: + result = "Invalid file name"; + break; + + // + case ERR_TOO_LONG_FILENAME: + result = "Too long file name"; + break; + + // + case ERR_CANNOT_OPEN_FILE: + result = "File opening error"; + break; + + // + case ERR_FILE_CACHEBUFFER_ERROR: + result = "Not enough memory for cache to read"; + break; + + // + case ERR_CANNOT_DELETE_FILE: + result = "File deleting error"; + break; + + // + case ERR_INVALID_FILEHANDLE: + result = "A file with this handle was closed, or was not opening at all"; + break; + + // + case ERR_WRONG_FILEHANDLE: + result = "Wrong file handle"; + break; + + // + case ERR_FILE_NOTTOWRITE: + result = "The file must be opened for writing"; + break; + + // + case ERR_FILE_NOTTOREAD: + result = "The file must be opened for reading"; + break; + + // + case ERR_FILE_NOTBIN: + result = "The file must be opened as a binary one"; + break; + + // + case ERR_FILE_NOTTXT: + result = "The file must be opened as a text"; + break; + + // + case ERR_FILE_NOTTXTORCSV: + result = "The file must be opened as a text or CSV"; + break; + + // + case ERR_FILE_NOTCSV: + result = "The file must be opened as CSV"; + break; + + // + case ERR_FILE_READERROR: + result = "File reading error"; + break; + + // + case ERR_FILE_BINSTRINGSIZE: + result = "String size must be specified, because the file is opened as binary"; + break; + + // + case ERR_INCOMPATIBLE_FILE: + result = "A text file must be for string arrays, for other arrays - binary"; + break; + + // + case ERR_FILE_IS_DIRECTORY: + result = "This is not a file, this is a directory"; + break; + + // + case ERR_FILE_NOT_EXIST: + result = "File does not exist"; + break; + + // + case ERR_FILE_CANNOT_REWRITE: + result = "File can not be rewritten"; + break; + + // + case ERR_WRONG_DIRECTORYNAME: + result = "Wrong directory name"; + break; + + // + case ERR_DIRECTORY_NOT_EXIST: + result = "Directory does not exist"; + break; + + // + case ERR_FILE_ISNOT_DIRECTORY: + result = "This is a file, not a directory"; + break; + + // + case ERR_CANNOT_DELETE_DIRECTORY: + result = "The directory cannot be removed"; + break; + + // + case ERR_CANNOT_CLEAN_DIRECTORY: + result = "Failed to clear the directory (probably one or more files are blocked and removal operation failed)"; + break; + + // + case ERR_FILE_WRITEERROR: + result = "Failed to write a resource to a file"; + break; + + // + //--- String Casting + + // + case ERR_NO_STRING_DATE: + result = "No date in the string"; + break; + + // + case ERR_WRONG_STRING_DATE: + result = "Wrong date in the string"; + break; + + // + case ERR_WRONG_STRING_TIME: + result = "Wrong time in the string"; + break; + + // + case ERR_STRING_TIME_ERROR: + result = "Error converting string to date"; + break; + + // + case ERR_STRING_OUT_OF_MEMORY: + result = "Not enough memory for the string"; + break; + + // + case ERR_STRING_SMALL_LEN: + result = "The string length is less than expected"; + break; + + // + case ERR_STRING_TOO_BIGNUMBER: + result = "Too large number, more than ULONG_MAX"; + break; + + // + case ERR_WRONG_FORMATSTRING: + result = "Invalid format string"; + break; + + // + case ERR_TOO_MANY_FORMATTERS: + result = "Amount of format specifiers more than the parameters"; + break; + + // + case ERR_TOO_MANY_PARAMETERS: + result = "Amount of parameters more than the format specifiers"; + break; + + // + case ERR_WRONG_STRING_PARAMETER: + result = "Damaged parameter of string type"; + break; + + // + case ERR_STRINGPOS_OUTOFRANGE: + result = "Position outside the string"; + break; + + // + case ERR_STRING_ZEROADDED: + result = "0 added to the string end, a useless operation"; + break; + + // + case ERR_STRING_UNKNOWNTYPE: + result = "Unknown data type when converting to a string"; + break; + + // + case ERR_WRONG_STRING_OBJECT: + result = "Damaged string object"; + break; + + // + //--- Operations with Arrays + + // + case ERR_INCOMPATIBLE_ARRAYS: + result = "Copying incompatible arrays. String array can be copied only to a string array, and a numeric array - in numeric array only"; + break; + + // + case ERR_SMALL_ASSERIES_ARRAY: + result = "The receiving array is declared as AS_SERIES, and it is of insufficient size"; + break; + + // + case ERR_SMALL_ARRAY: + result = "Too small array, the starting position is outside the array"; + break; + + // + case ERR_ZEROSIZE_ARRAY: + result = "An array of zero length"; + break; + + // + case ERR_NUMBER_ARRAYS_ONLY: + result = "Must be a numeric array"; + break; + + // + case ERR_ONEDIM_ARRAYS_ONLY: + result = "Must be a one-dimensional array"; + break; + + // + case ERR_SERIES_ARRAY: + result = "Timeseries cannot be used"; + break; + + // + case ERR_DOUBLE_ARRAY_ONLY: + result = "Must be an array of type double"; + break; + + // + case ERR_FLOAT_ARRAY_ONLY: + result = "Must be an array of type float"; + break; + + // + case ERR_LONG_ARRAY_ONLY: + result = "Must be an array of type long"; + break; + + // + case ERR_INT_ARRAY_ONLY: + result = "Must be an array of type int"; + break; + + // + case ERR_SHORT_ARRAY_ONLY: + result = "Must be an array of type short"; + break; + + // + case ERR_CHAR_ARRAY_ONLY: + result = "Must be an array of type char"; + break; + + // + //--- Operations with OpenCL + + // + case ERR_OPENCL_NOT_SUPPORTED: + result = "OpenCL functions are not supported on this computer"; + break; + + // + case ERR_OPENCL_INTERNAL: + result = "Internal error occurred when running OpenCL"; + break; + + // + case ERR_OPENCL_INVALID_HANDLE: + result = "Invalid OpenCL handle"; + break; + + // + case ERR_OPENCL_CONTEXT_CREATE: + result = "Error creating the OpenCL context"; + break; + + // + case ERR_OPENCL_QUEUE_CREATE: + result = "Failed to create a run queue in OpenCL"; + break; + + // + case ERR_OPENCL_PROGRAM_CREATE: + result = "Error occurred when compiling an OpenCL program"; + break; + + // + case ERR_OPENCL_TOO_LONG_KERNEL_NAME: + result = "Too long kernel name (OpenCL kernel)"; + break; + + // + case ERR_OPENCL_KERNEL_CREATE: + result = "Error creating an OpenCL kernel"; + break; + + // + case ERR_OPENCL_SET_KERNEL_PARAMETER: + result = "Error occurred when setting parameters for the OpenCL kernel"; + break; + + // + case ERR_OPENCL_EXECUTE: + result = "OpenCL program runtime error"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_SIZE: + result = "Invalid size of the OpenCL buffer"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_OFFSET: + result = "Invalid offset in the OpenCL buffer"; + break; + + // + case ERR_OPENCL_BUFFER_CREATE: + result = "Failed to create and OpenCL buffer"; + break; + + // + //--- User-Defined Errors + default: + result = "UNKNOWN Erro ..."; + break; + } + + // + return result; +} + +// +// Retrieve Specified Error Code Description ... +string GetTradeServerReturnCodeDescription(int return_code) +{ + // + string result = ""; + + // + switch (return_code) + { + // + case TRADE_RETCODE_REQUOTE: + result = "Requote"; + break; + + // + case TRADE_RETCODE_REJECT: + result = "Request rejected"; + break; + + // + case TRADE_RETCODE_CANCEL: + result = "Request canceled by trader"; + break; + + // + case TRADE_RETCODE_PLACED: + result = "Order placed"; + break; + + // + case TRADE_RETCODE_DONE: + result = "Request completed"; + break; + + // + case TRADE_RETCODE_DONE_PARTIAL: + result = "Only part of the request was completed"; + break; + + // + case TRADE_RETCODE_ERROR: + result = "Request processing error"; + break; + + // + case TRADE_RETCODE_TIMEOUT: + result = "Request canceled by timeout"; + break; + + // + case TRADE_RETCODE_INVALID: + result = "Invalid request"; + break; + + // + case TRADE_RETCODE_INVALID_VOLUME: + result = "Invalid volume in the request"; + break; + + // + case TRADE_RETCODE_INVALID_PRICE: + result = "Invalid price in the request"; + break; + + // + case TRADE_RETCODE_INVALID_STOPS: + result = "Invalid stops in the request"; + break; + + // + case TRADE_RETCODE_TRADE_DISABLED: + result = "Trade is disabled"; + break; + + // + case TRADE_RETCODE_MARKET_CLOSED: + result = "Market is closed"; + break; + + // + case TRADE_RETCODE_NO_MONEY: + result = "There is not enough money to complete the request"; + break; + + // + case TRADE_RETCODE_PRICE_CHANGED: + result = "Prices changed"; + break; + + // + case TRADE_RETCODE_PRICE_OFF: + result = "There are no quotes to process the request"; + break; + + // + case TRADE_RETCODE_INVALID_EXPIRATION: + result = "Invalid order expiration date in the request"; + break; + + // + case TRADE_RETCODE_ORDER_CHANGED: + result = "Order state changed"; + break; + + // + case TRADE_RETCODE_TOO_MANY_REQUESTS: + result = "Too frequent requests"; + break; + + // + case TRADE_RETCODE_NO_CHANGES: + result = "No changes in request"; + break; + + // + case TRADE_RETCODE_SERVER_DISABLES_AT: + result = "Autotrading disabled by server"; + break; + + // + case TRADE_RETCODE_CLIENT_DISABLES_AT: + result = "Autotrading disabled by client terminal"; + break; + + // + case TRADE_RETCODE_LOCKED: + result = "Request locked for processing"; + break; + + // + case TRADE_RETCODE_FROZEN: + result = "Order or position frozen"; + break; + + // + case TRADE_RETCODE_INVALID_FILL: + result = "Invalid order filling type"; + break; + + // + case TRADE_RETCODE_CONNECTION: + result = "No connection with the trade server"; + break; + + // + case TRADE_RETCODE_ONLY_REAL: + result = "Operation is allowed only for live accounts"; + break; + + // + case TRADE_RETCODE_LIMIT_ORDERS: + result = "The number of pending orders has reached the limit"; + break; + + // + case TRADE_RETCODE_LIMIT_VOLUME: + result = "The volume of orders and positions for the symbol has reached the limit"; + break; + + // + default: + result = "Invalid return code of the trade server"; + break; + } + + // + return result; +} + +// +// Check Expert Running in Testing Mode or not ... +bool IsRunningOnTestMode() +{ + // + bool result = false; + + // + // check programm mode ... + result = MQL5InfoInteger(MQL5_TESTING); + + // + return result; +} + +// +// Date Time Manipulation Functions ... +// + +// +// Representation of Time Struct ... +// struct MqlDateTime +// { +// int year; // Year +// int mon; // Month +// int day; // Day +// int hour; // Hour +// int min; // Minutes +// int sec; // Seconds +// int day_of_week; // Day of week (0-Sunday, 1-Monday, ... ,6-Saturday) +// int day_of_year; // Day number of the year (January 1st is assigned the number value of zero) +// }; + +// +// Converts Time to Seconds ... +ulong TimeToSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = (ulong)time; + + // + return result; +} +ulong TimeToSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToSeconds(dTime); + + // + return result; +} + +// +// Converts Seconds To Time ... +datetime SecondsToTime( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime result = (datetime)seconds; + + // + return result; +} +MqlDateTime SecondsToStruct( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime dTime = SecondsToTime(seconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Converts Time to MilliSeconds ... +ulong TimeToMilliSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = TimeToSeconds(time) * 1000; + + // + return result; +} +ulong TimeToMilliSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToMilliSeconds(dTime); + + // + return result; +} + +// +// Converts MillisSeconds to Time ... +datetime MilliSecondsToTiem( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + ulong seconds = milliSeconds / 1000; + + // + datetime result = SecondsToTime(seconds); + + // + return result; +} +MqlDateTime MilliSecondsToStruct( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + datetime dTime = MilliSecondsToTiem(milliSeconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Retrieve DateTime Structure ... +MqlDateTime GetCurrentTime() +{ + // + MqlDateTime result = {}; + + // + TimeCurrent(result); + + // + return result; +} + +// +// Retrieve Current Time as Seconds ... +ulong GetCurrentTimeAsSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Current Time as MilliSeconds ... +ulong GetCurrentTimeAsMilliSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +// Retrieve Specified Candle Time ... +datetime GetCandleTime( + string symbol = "", // Specify Symbol + ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame + int bar_index = 0 // Specify Bar Index +) +{ + // + // Validate and Normalize Args ... + + // + // Normalize Symbol ... + symbol = StringLen(symbol) == 0 + ? _Symbol + : symbol; + + // + // Normalize Period ... + period = period == NULL + ? _Period + : period; + + // + // Retrieve Bar Time ... + datetime result = iTime( + symbol, + period, + bar_index); + + // + return result; +} + +// +// Retrieve Specified Candle Time ... +ulong GetCandleTimeAsSeconds( + string symbol = "", // Specify Symbol + ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame + int bar_index = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetCandleTime( + symbol, + period, + bar_index); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Specified Candle Time ... +ulong GetCandleTimeAsMilliSeconds( + string symbol = "", // Specify Symbol + ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame + int bar_index = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetCandleTime( + symbol, + period, + bar_index); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +// Retrieve a Candle Time Structure ... +MqlDateTime GetCandleTimeStruct( + string symbol = "", // Specify Symbol + ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame + int bar_index = 0 // Specify Bar Index +) +{ + // + MqlDateTime result = {}; + + // + // Retrieve Bar Time ... + datetime barTime = GetCandleTime( + symbol, + period, + bar_index); + + // + // Convert to Structure ... + TimeToStruct(barTime, result); + + // + return result; +} + +// +// Retrieve Number of Candles in a Day ... +int GetDailyCandleCount(ENUM_TIMEFRAMES mPeriod) +{ + // + int seconds = PeriodSeconds(mPeriod); + + // + int daySeconds = 24 * 60 * 60; + + // + int result = daySeconds / seconds; + + // + return result; +} + +int GetDailyCandleCount() +{ + // + int result = GetDailyCandleCount(_Period); + + // + return result; +} + +// +// +// + +// +// Holds Month ... +static int xMonth = -1; + +// +// Holds Day Of Week ... +static int xDayOfWeek = -1; +static int xForWeekDay = -1; + +// +// Holds Day ... +static int xDay = -1; + +// +// Holds Hour ... +static int xHour = -1; + +// +// Reset Timing Variables ... +void ResetTiming() +{ + // + xHour = -1; + xDay = -1; + xDayOfWeek = -1; + xMonth = -1; +} + +// +// Detecting New Houre ... +bool IsNewHour() +{ + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.hour != xHour; + if (result) + { + xHour = timeStruct.hour; + } + + // + return result; +} + +// +// Detecting New Day ... +bool IsNewDay() +{ + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.day_of_year != xDay; + if (result) + { + xDay = timeStruct.day_of_year; + } + + // + return result; +} + +// +// Detecting New Week ... +bool IsNewWeek() +{ + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Week ... + // Since Week Starts From Monday in Forex World ... + // we Calculate Start of Week by 1-Monday ... + result = + xDayOfWeek == -1 && + xForWeekDay == -1 + ? true + : timeStruct.day_of_week == 1 && + timeStruct.day_of_year > xForWeekDay; + + // + xForWeekDay = timeStruct.day_of_year; + xDayOfWeek = timeStruct.day_of_week; + + // + return result; +} + +// +// Detecting End Of Week ... +bool IsWeekEnd() +{ + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check WeekEnd ... + // Since Week Starts From Monday in Forex World ... + // we Calculate End of Week by 5-Friday ... + result = + xDayOfWeek != -1 && + timeStruct.day_of_week == 5 && + timeStruct.hour == 23 && + timeStruct.min == 59 && + timeStruct.sec == 59; + + // + return result; +} + +// +// Detecting New Month ... +bool IsNewMonth() +{ + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.mon != xMonth; + if (result) + { + xMonth = timeStruct.mon; + } + + // + return result; +} + +// +// Find Hindmost Time Frame ... +ENUM_TIMEFRAMES GetHindmostTimeFrame( + ENUM_TIMEFRAMES mPeriod // Specified Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + // Normalize Period ... + if ( + mPeriod < 0 || + mPeriod == NULL) + { + mPeriod = _Period; + } + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_H12; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + case PERIOD_H4: + result = PERIOD_D1; + break; + + // + case PERIOD_H6: + case PERIOD_H8: + case PERIOD_H12: + case PERIOD_D1: + result = PERIOD_W1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Find Farest Time Frame ... +ENUM_TIMEFRAMES GetFarestTimeFrame( + ENUM_TIMEFRAMES mPeriod // Specified Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + // Normalize Period ... + if ( + mPeriod < 0 || + mPeriod == NULL) + { + mPeriod = _Period; + } + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H4; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + case PERIOD_H4: + result = PERIOD_H12; + break; + + // + case PERIOD_H6: + case PERIOD_H8: + case PERIOD_H12: + case PERIOD_D1: + result = PERIOD_W1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Find Medium Time Frame ... +ENUM_TIMEFRAMES GetMediestTimeFrame( + ENUM_TIMEFRAMES mPeriod // Specified Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + // Normalize Period ... + if ( + mPeriod < 0 || + mPeriod == NULL) + { + mPeriod = _Period; + } + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_H1; + break; + + // + case PERIOD_M30: + result = PERIOD_H2; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H4; + break; + + // + case PERIOD_H4: + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_H12; + break; + + // + case PERIOD_H12: + result = PERIOD_D1; + break; + + // + case PERIOD_D1: + result = PERIOD_W1; + break; + + // + case PERIOD_W1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Find Nearest Time Frame ... +ENUM_TIMEFRAMES GetNearestTimeFrame( + ENUM_TIMEFRAMES mPeriod // Specified Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + // Normalize Period ... + if ( + mPeriod < 0 || + mPeriod == NULL) + { + mPeriod = _Period; + } + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_M5; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_M15; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_M30; + break; + + // + case PERIOD_M30: + result = PERIOD_H1; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H4; + break; + + // + case PERIOD_H4: + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_H12; + break; + + // + case PERIOD_H12: + result = PERIOD_D1; + break; + + // + case PERIOD_D1: + result = PERIOD_W1; + break; + + // + case PERIOD_W1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Get Specific Time Frame Start Candle Time ... +datetime GetPeriodStartTime( + string mSymbol = NULL, // Specified Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... + datetime mTime = NULL // Specified Bar Time ... +) +{ + // + // Normalize Arg ... + + // + if ( + mSymbol == NULL || + StringLen(mSymbol) == 0) + { + mSymbol = _Symbol; + } + + // + if ( + mPeriod < 0 || + mPeriod == NULL) + { + mPeriod = _Period; + } + + // + if ( + mTime < 0 || + mTime == NULL) + { + mTime = TimeCurrent(); + } + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false); + + // + datetime result = iTime( + mSymbol, + mPeriod, + barIndex); + + // + return result; +} + +// +struct XCandleRemains +{ + // + int days; + int hours; + int minutes; + int seconds; +}; + +// +string ToString( + XCandleRemains &item, + string dayId = "d", + string hourId = "h", + string minuteId = "m", + string secondId = "s", + string idSeparator = ": ", + string separator = ", ", + bool ignoreZeroValues = true) +{ + // + string result = ""; + + // + // Days ... + if (!ignoreZeroValues || item.days > 0) + { + result += dayId + idSeparator + (string)item.days + separator; + } + + // + // Hours ... + if (!ignoreZeroValues || item.hours > 0) + { + result += hourId + idSeparator + (string)item.hours + separator; + } + + // + // Minutes ... + if (!ignoreZeroValues || item.minutes > 0) + { + result += minuteId + idSeparator + (string)item.minutes + separator; + } + + // + // Seconds ... + if (!ignoreZeroValues || item.seconds > 0) + { + result += secondId + idSeparator + (string)item.seconds; + } + + // + return result; +} + +// +// Retrieve Specific Candles Ramained Time ... +void GetCandleRemainsTime( + XCandleRemains &result, // Holds Result ... + string mSymbol = NULL, // Specified Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... + int mBarIndex = 0 // Specified Bar Index ... +) +{ + // + int minuteSecoonds = 60; + int hourSeconds = minuteSecoonds * 60; + int daySeconds = 24 * hourSeconds; + + // + int periodSeconds = PeriodSeconds( + mPeriod); + datetime startTime = GetCandleTime( + mSymbol, + mPeriod, + mBarIndex); + + // + int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent(); + + // + int days = 0; + int hours = 0; + int minutes = 0; + int seconds = 0; + + // + int mWorkingSecondsDiff = secondsDiff; + if (mWorkingSecondsDiff > daySeconds) + { + // + days = mWorkingSecondsDiff / daySeconds; + mWorkingSecondsDiff -= days * daySeconds; + } + if (mWorkingSecondsDiff > hourSeconds) + { + // + hours = mWorkingSecondsDiff / hourSeconds; + mWorkingSecondsDiff -= hours * hourSeconds; + } + if (mWorkingSecondsDiff > minuteSecoonds) + { + // + minutes = mWorkingSecondsDiff / minuteSecoonds; + mWorkingSecondsDiff -= minutes * minuteSecoonds; + } + seconds = mWorkingSecondsDiff; + + // + result.days = days; + result.hours = hours; + result.minutes = minutes; + result.seconds = seconds; +} + +// +// Converts an String to TimeFrame ... +ENUM_TIMEFRAMES ToPeriod(string value) +{ + // + if (StringLen(value) == 0) + { + return _Period; + } + + // + StringTrimLeft(value); + StringTrimRight(value); + + // + ENUM_TIMEFRAMES result = _Period; + + // + if (value == "M1") + { + result = PERIOD_M1; + } + else if (value == "M2") + { + result = PERIOD_M2; + } + else if (value == "M3") + { + result = PERIOD_M3; + } + else if (value == "M4") + { + result = PERIOD_M4; + } + else if (value == "M5") + { + result = PERIOD_M5; + } + else if (value == "M6") + { + result = PERIOD_M6; + } + else if (value == "M10") + { + result = PERIOD_M10; + } + else if (value == "M12") + { + result = PERIOD_M12; + } + else if (value == "M15") + { + result = PERIOD_M15; + } + else if (value == "M20") + { + result = PERIOD_M20; + } + else if (value == "M30") + { + result = PERIOD_M30; + } + else if (value == "H1") + { + result = PERIOD_H1; + } + else if (value == "H2") + { + result = PERIOD_H2; + } + else if (value == "H3") + { + result = PERIOD_H3; + } + else if (value == "H4") + { + result = PERIOD_H4; + } + else if (value == "H6") + { + result = PERIOD_H6; + } + else if (value == "H8") + { + result = PERIOD_H8; + } + else if (value == "H12") + { + result = PERIOD_H12; + } + else if (value == "D1") + { + result = PERIOD_D1; + } + else if (value == "W1") + { + result = PERIOD_W1; + } + else if (value == "MN1") + { + result = PERIOD_MN1; + } + + // + return result; +} + +// +// Converts Period to String ... +string ToString(ENUM_TIMEFRAMES period) +{ + // + string result = ""; + + // + string mPStr = EnumToString(period); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[1]; + + // + return result; +} + +// +// END Provided Functions ... +// diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.draw.lib.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.draw.lib.ex5 new file mode 100644 index 0000000..4f61b18 Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.draw.lib.ex5 differ diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.draw.lib.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.draw.lib.mq5 new file mode 100644 index 0000000..7771f54 --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.draw.lib.mq5 @@ -0,0 +1,2462 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Draw Library +// -------------------------------------- +// Name: XDraw +// Description: provides Draw abilities ... +// +// +// 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 + +// +// START Inputs ... +// +// +// END Inputs ... +// + +// +// Include Logger Library ... +#include "x-saherelm.log.lib.mq5" +#include "x-saherelm.common.lib.mq5" + +// +// START Global Definitions: Variables, Properties and etc ... +// +string drawPrefix = "X-OBJ"; +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// +// +// DeInitial Library if required ... +void OnDeinitDrawLibrary() +{ + RemoveDraws(); +} + +// +// remove drawn objects ... +void RemoveDraws( + string tag = NULL, + int chartId = -1, + int subWindow = -1) +{ + // + // Normalize Args ... + // + if (tag == NULL) + { + tag = drawPrefix; + } + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + if (StringFind(on, tag) >= 0) + { + ObjectDelete(chartId, on); + } + } + + // + // Redraw Chart ... + ChartRedraw(); +} + +// +bool RemoveDraw( + string name, + int chartId = -1, + int subWindow = -1) +{ + // + bool result = false; + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + string objName = ""; + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + if (StringFind(on, name) >= 0) + { + // + objName = on; + break; + } + } + + // + if (StringLen(objName) > 0) + { + result = ObjectDelete(chartId, objName); + } + + // + return result; +} + +// +// Deselect All Draws ... +void DeselectAllDraws() +{ + // + int objs = ObjectsTotal(ChartID(), 0); + for (int o = 0; o < objs; o++) + { + ObjectSetInteger(ChartID(), ObjectName(ChartID(), o, 0), OBJPROP_SELECTED, false); + } + + // + ChartRedraw(); +} + +// +// Check Object Exists ... +bool IsDrawExists( + string name, + int chartId = -1, + int subWindow = -1) +{ + // + bool result = false; + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + result = StringFind(on, name) >= 0; + if (result) + { + break; + } + } + + // + return result; +} +// +// END Provided Functions ... +// + +// +// START Regular Draws ... +// + +// +// START Arrow Functions ... +// +// +// Draw an Arrow Object on Chart ... +bool DrawArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow", // arrow name + const int subWindow = 0, // subwindow index + datetime time = 0, // anchor point time + double price = 0, // anchor point price + const uchar arrowCode = 252, // arrow code + const ENUM_ARROW_ANCHOR anchor = ANCHOR_BOTTOM, // anchor point position + const color clr = clrAqua, // arrow color + const ENUM_LINE_STYLE style = STYLE_SOLID, // border line style + const int width = 3, // arrow size + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // Order Object ... +) +{ + // + // set anchor point coordinates if they are not set ... + ChangeArrowEmptyPoint(time, price); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create an arrow ... + if (!ObjectCreate(chartID, objName, OBJ_ARROW, subWindow, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to create an arrow! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set the arrow code ... + ObjectSetInteger(chartID, objName, OBJPROP_ARROWCODE, arrowCode); + + // + // set anchor type ... + ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + // set the arrow color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set the border line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set the arrow's size ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the arrow by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is false by default, if you want making it possible to highlight and move the object + // change it to true ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move the anchor point of Arrow ... +bool MoveArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // reset the error value + ResetLastError(); + + // + // move the anchor point ... + if (!ObjectMove(chartID, name, 0, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to move the anchor point! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete an arrow ... +bool DeleteArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow" // arrow name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete an arrow ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete an arrow! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Change the arrow code ... +bool ArrowCodeChange( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + const uchar code = 252 // arrow code +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // change the arrow code ... + if (!ObjectSetInteger(chartID, name, OBJPROP_ARROWCODE, code)) + { + // + string message = + __FUNCTION__ + + ": failed to change the arrow code! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Change anchor type ... +bool ArrowAnchorChange( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + const ENUM_ARROW_ANCHOR anchor = ANCHOR_TOP // anchor type +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // change anchor type ... + if (!ObjectSetInteger(chartID, name, OBJPROP_ANCHOR, anchor)) + { + // + string message = + __FUNCTION__ + + ": failed to change anchor type! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Check anchor point values and set default values +// for empty ones ... +void ChangeArrowEmptyPoint( + datetime &time, + double &price) +{ + // + // if the point's time is not set, it will be on the current bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // if the point's price is not set, it will have Bid value ... + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } +} +// +// END Arrow Functions ... +// + +// +// START Horizontal Line Functions ... +// +// +// Create, Draw the horizontal line ... +bool DrawHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine", // line name + const int subWindow = 0, // subwindow index + double price = 0, // line price + const color clr = clrRed, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // if the price is not set, set it at the current Bid price level ... + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a horizontal line ... + if (!ObjectCreate(chartID, objName, OBJ_HLINE, subWindow, 0, price)) + { + // + string message = + __FUNCTION__ + + ": failed to create a horizontal line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move horizontal line ... +bool MoveHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine", // line name + double price = 0 // line price +) +{ + // + // if the line price is not set, move it to the current Bid price level ... + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // reset the error value ... + ResetLastError(); + + // + // move a horizontal line ... + if (!ObjectMove(chartID, name, 0, 0, price)) + { + // + string message = + __FUNCTION__ + + ": failed to move the horizontal line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete a horizontal line ... +bool DeleteHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine" // line name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete a horizontal line ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete a horizontal line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} +// +// END Horizontal Line Functions ... +// + +// +// START Vertical Line Functions ... +// +// +// Create the vertical line ... +bool DrawVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine", // line name + const int subWindow = 0, // subwindow index + datetime time = 0, // line time + const color clr = clrRed, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // if the line time is not set, draw it via the last bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // reset the error value + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a vertical line ... + if (!ObjectCreate(chartID, objName, OBJ_VLINE, subWindow, time, 0)) + { + // + string message = + __FUNCTION__ + + ": failed to create a vertical line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move the vertical line ... +bool MoveVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine", // line name + datetime time = 0 // line time +) +{ + // + // if line time is not set, move the line to the last bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // reset the error value ... + ResetLastError(); + + // + // move the vertical line ... + if (!ObjectMove(chartID, name, 0, time, 0)) + { + // + string message = + __FUNCTION__ + + ": failed to move the vertical line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete the vertical line ... +bool DeleteVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine" // line name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete the vertical line ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete the vertical line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} +// +// END Vertical Line Functions ... +// + +// +// START RectangleLabel Functions ... +// +// +// Create Rectangle Label Object ... +bool DrawRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int subWindow = 0, // subwindow index + const int x = 0, // X coordinate + const int y = 0, // Y coordinate + const int width = 50, // width + const int height = 18, // height + const color bgColor = clrWhiteSmoke, // background color + const ENUM_BORDER_TYPE border = BORDER_SUNKEN, // border type + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring + const color clr = clrRed, // flat border color (Flat) + const ENUM_LINE_STYLE style = STYLE_SOLID, // flat border style + const int lineWidth = 1, // flat border width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // + // create a rectangle label + if (!ObjectCreate(chartID, objName, OBJ_RECTANGLE_LABEL, subWindow, 0, 0)) + { + // + string message = + __FUNCTION__ + + ": failed to create a rectangle label! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set label coordinates ... + ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + // set label size ... + ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + // set background color ... + ObjectSetInteger(chartID, objName, OBJPROP_BGCOLOR, bgColor); + + // + // set border type ... + ObjectSetInteger(chartID, objName, OBJPROP_BORDER_TYPE, border); + + // + // set the chart's corner, relative to which point coordinates are defined ... + ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + // set flat border color (in Flat mode) ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set flat border line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set flat border width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, lineWidth); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the label by mouse ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move Rectangle Label .. +bool MoveRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int x = 0, // X coordinate + const int y = 0 // Y coordinate +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // move the rectangle label ... + if (!ObjectSetInteger(chartID, name, OBJPROP_XDISTANCE, x)) + { + // + string message = + __FUNCTION__ + + ": failed to move X coordinate of the label! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + if (!ObjectSetInteger(chartID, name, OBJPROP_YDISTANCE, y)) + { + // + string message = + __FUNCTION__ + + ": failed to move Y coordinate of the label! Error code = " + + (string)GetLastError(); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete the rectangle label ... +bool DeleteRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel" // label name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete the label ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete a rectangle label! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Change Rectangle Label Size ... +bool ChangeSizeRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int width = 50, // label width + const int height = 18 // label height +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // change label size ... + if (!ObjectSetInteger(chartID, name, OBJPROP_XSIZE, width)) + { + // + string message = + __FUNCTION__ + + ": failed to change the label's width! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + if (!ObjectSetInteger(chartID, name, OBJPROP_YSIZE, height)) + { + // + string message = + __FUNCTION__ + + ": failed to change the label's height! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Change rectangle label border type ... +bool RectLabelChangeBorderType( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const ENUM_BORDER_TYPE border = BORDER_SUNKEN // border type +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // change border type ... + if (!ObjectSetInteger(chartID, name, OBJPROP_BORDER_TYPE, border)) + { + // + string message = + __FUNCTION__ + + ": failed to change the border type! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} +// +// END RectangleLabel Functions ... +// + +// +// START TrendLine Funcions ... +// +// Create a trend line by the given coordinates ... +bool DrawTrendLine( + const long chartID = 0, // chart's ID + const string name = "TrendLine", // line name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrYellow, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool rayRight = false, // line's continuation to the right + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // set anchor points' coordinates if they are not set ... + ChangeTrendLineEmptyPoints( + time1, + price1, + time2, + price2); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a trend line by the given coordinates ... + if (!ObjectCreate(chartID, objName, OBJ_TREND, subWindow, time1, price1, time2, price2)) + { + // + string message = + __FUNCTION__ + + ": failed to create a trend line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the line's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move trend line anchor point ... | +bool ChangeTrendLinePoint( + const long chartID = 0, // chart's ID + const string name = "TrendLine", // line name + const int pointindex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // reset the error value ... + ResetLastError(); + + // + // move trend line's anchor point ... + if (!ObjectMove(chartID, name, pointindex, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to move the anchor point! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// The function deletes the trend line from the chart ... +bool DeleteTrendLine( + const long chartID = 0, // chart's ID + const string name = "TrendLine" // line name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete a trend line ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete a trend line! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Check the values of trend line's anchor points and set default ... +// values for empty ones ... +void ChangeTrendLineEmptyPoints( + datetime &time1, + double &price1, + datetime &time2, + double &price2) +{ + // + // if the first point's time is not set, it will be on the current bar ... + if (!time1) + { + time1 = TimeCurrent(); + } + + // + // if the first point's price is not set, it will have Bid value ... + if (!price1) + { + price1 = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // if the second point's time is not set, it is located 9 bars left from the second one ... + if (!time2) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time1, 10, temp); + + // + // set the second point 9 bars left from the first one ... + time2 = temp[0]; + } + + // + // if the second point's price is not set, it is equal to the first point's one ... + if (!price2) + { + price2 = price1; + } +} +// +// END TrendLine Functions ... +// + +// +// START Text Functions ... +// +// Create and Draw a Text Object ... +bool DrawText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + const int subWindow = 0, // subwindow index + datetime time = 0, // anchor point time + double price = 0, // anchor point price + const string text = "Text", // the text itself + const string font = "Arial", // font + const int fontSize = 10, // font size + const color clr = clrRed, // color + const double angle = 0.0, // text slope + const ENUM_ANCHOR_POINT anchor = ANCHOR_CENTER, // anchor type + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // set anchor point coordinates if they are not set ... + ChangeTextEmptyPoint(time, price); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // + // create Text object + if (!ObjectCreate(chartID, objName, OBJ_TEXT, subWindow, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to create \"Text\" object! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set the text ... + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set text font ... + ObjectSetString(chartID, objName, OBJPROP_FONT, font); + + // + // set font size ... + ObjectSetInteger(chartID, objName, OBJPROP_FONTSIZE, fontSize); + + // + // set the slope angle of the text ... + ObjectSetDouble(chartID, objName, OBJPROP_ANGLE, angle); + + // + // set anchor type ... + ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the object by mouse ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Move the anchor point ... +bool MoveText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + // + // if point position is not set, move it to the current bar having Bid price + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // reset the error value ... + ResetLastError(); + + // + // move the anchor point .. + if (!ObjectMove(chartID, name, 0, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to move the anchor point! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Change the object text ... +bool ChangeText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + const string text = "Text" // text +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // change object text ... + if (!ObjectSetString(chartID, name, OBJPROP_TEXT, text)) + { + // + string message = + __FUNCTION__ + + ": failed to change the text! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete Text object ... +bool DeleteText( + const long chartID = 0, // chart's ID + const string name = "Text" // object name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete the object ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete \"Text\" object! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution + return true; +} + +// +// Check anchor point values and set default values +// for empty ones ... +void ChangeTextEmptyPoint( + datetime &time, + double &price) +{ + // + // if the point's time is not set, it will be on the current bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // if the point's price is not set, it will have Bid value ... + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } +} +// +// END Text Functions ... +// + +// +// START Fibonacchi Functions ... +// +// +// Create Fibonacci Retracement by the given coordinates ... +bool DrawFibonacci( + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrRed, // object color + const ENUM_LINE_STYLE style = STYLE_SOLID, // object line style + const int width = 1, // object line width + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool rayRight = false, // object's continuation to the right + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // set anchor points' coordinates if they are not set ... + ChangeFibonacciEmptyPoints(time1, price1, time2, price2); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create Fibonacci Retracement by the given coordinates ... + if (!ObjectCreate(chartID, objName, OBJ_FIBO, subWindow, time1, price1, time2, price2)) + { + // + string message = + __FUNCTION__ + + ": failed to create \"Fibonacci Retracement\"! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of highlighting the channel for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the object's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return true; +} + +// +// Create Fibonacci Retracement by the given coordinates ... +bool DrawCustomFibonacci( + // + int levels, // number of level lines + double &values[], // values of level lines + color &colors[], // color of level lines + ENUM_LINE_STYLE &styles[], // style of level lines + int &widths[], // width of level lines + string &descriptions[], // level Descriptions + // + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrAqua, // object color + const ENUM_LINE_STYLE style = STYLE_DOT, // object line style + const int width = 1, // object line width + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool rayRight = false, // object's continuation to the right + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + // set anchor points' coordinates if they are not set ... + ChangeFibonacciEmptyPoints(time1, price1, time2, price2); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create Fibonacci Retracement by the given coordinates ... + if (!ObjectCreate(chartID, name, OBJ_FIBO, subWindow, time1, price1, time2, price2)) + { + // + string message = + __FUNCTION__ + + ": failed to create \"Fibonacci Retracement\"! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of highlighting the channel for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the object's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // Change Levels Of Fibonacci ... + bool result = FibonacciLevelsSet( + levels, + values, + colors, + styles, + widths, + descriptions, + chartID, + objName); + + // + // successful execution ... + return result; +} + +// +// Set number of levels and their parameters ... +bool FibonacciLevelsSet( + int levels, // number of level lines + double &values[], // values of level lines + color &colors[], // color of level lines + ENUM_LINE_STYLE &styles[], // style of level lines + int &widths[], // width of level lines + string &descriptions[], // level Descriptions + const long chartID = 0, // chart's ID + const string name = "Fibonacci" // object name +) +{ + // + // check array sizes ... + if ( + levels != ArraySize(colors) || + levels != ArraySize(styles) || + levels != ArraySize(widths) || + levels != ArraySize(widths)) + { + // + string message = + __FUNCTION__ + + ": array length does not correspond to the number of levels, error!"; + + // + LogMessage(message); + + // + return false; + } + + // + // set the number of levels ... + ObjectSetInteger(chartID, name, OBJPROP_LEVELS, levels); + + // + // set the properties of levels in the loop ... + for (int i = 0; i < levels; i++) + { + // + // level value ... + ObjectSetDouble(chartID, name, OBJPROP_LEVELVALUE, i, values[i]); + + // + // level color ... + ObjectSetInteger(chartID, name, OBJPROP_LEVELCOLOR, i, colors[i]); + + // + // level style ... + ObjectSetInteger(chartID, name, OBJPROP_LEVELSTYLE, i, styles[i]); + + // + // level width ... + ObjectSetInteger(chartID, name, OBJPROP_LEVELWIDTH, i, widths[i]); + + // + // level description ... + // ObjectSetString(chartID, name, OBJPROP_LEVELTEXT, i, DoubleToString(100 * values[i], 1)); + ObjectSetString(chartID, name, OBJPROP_LEVELTEXT, i, descriptions[i]); + } + + // + // successful execution ... + return true; +} + +// +// Move Fibonacci Retracement anchor point ... +bool FibonacciPointChange( + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int pointIndex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // reset the error value ... + ResetLastError(); + + // + // move the anchor point ... + if (!ObjectMove(chartID, name, pointIndex, time, price)) + { + // + string message = + __FUNCTION__ + + ": failed to move the anchor point! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Delete Fibonacci Retracement ... +bool DeleteFibonachi( + const long chartID = 0, // chart's ID + const string name = "Fibonacci" // object name +) +{ + // + // reset the error value ... + ResetLastError(); + + // + // delete the object ... + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete \"Fibonacci Retracement\"! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution ... + return true; +} + +// +// Check the values of Fibonacci Retracement anchor points and set +// default values for empty ones ... +void ChangeFibonacciEmptyPoints( + datetime &time1, + double &price1, + datetime &time2, + double &price2) +{ + // + // if the second point's time is not set, it will be on the current bar ... + if (!time2) + { + time2 = TimeCurrent(); + } + + // + // if the second point's price is not set, it will have Bid value ... + if (!price2) + { + price2 = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // if the first point's time is not set, it is located 9 bars left from the second one ... + if (!time1) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time2, 10, temp); + + // + // set the first point 9 bars left from the second one ... + time1 = temp[0]; + } + + // + // if the first point's price is not set, move it 200 points below the second one ... + if (!price1) + { + price1 = price2 - 200 * SymbolInfoDouble(_Symbol, SYMBOL_POINT); + } +} +// +// END Fibonacci Functions ... +// + +// +// START Event Functions ... +// + +// +// Create an Event ... +bool EventCreate( + const long chartID = 0, // chart's ID + const string name = "Event", // object name + const int subWindow = 0, // subwindow index + const string text = "Content", // event text + datetime time = 0, // anchor point time + const color clr = clrRed, // color + const int width = 1, // point width when highlighted + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + if (!time) + { + time = TimeCurrent(); + } + + // + ResetLastError(); + + // + if (!ObjectCreate(chartID, name, OBJ_EVENT, subWindow, time, 0)) + { + // + string message = + __FUNCTION__ + + ": failed to create \"Event\" object! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // set event text + ObjectSetString(chartID, name, OBJPROP_TEXT, text); + + // + // set color + ObjectSetInteger(chartID, name, OBJPROP_COLOR, clr); + + // + // set anchor point width if the object is highlighted + ObjectSetInteger(chartID, name, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true + ObjectSetInteger(chartID, name, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving event by mouse + ObjectSetInteger(chartID, name, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, name, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list + ObjectSetInteger(chartID, name, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, name, OBJPROP_ZORDER, zOrder); + + // + // successful execution + return true; +} + +// +// Change Event object text +bool EventTextChange( + const long chartID = 0, // chart's ID + const string name = "Event", // event name + const string text = "Content" // text +) +{ + // + // reset the error value + ResetLastError(); + + // + // change object text + if (!ObjectSetString(chartID, name, OBJPROP_TEXT, text)) + { + // + string message = + __FUNCTION__ + + ": failed to change the text! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution + return true; +} + +// +// Move Event object +bool EventMove( + const long chartID = 0, // chart's ID + const string name = "Event", // event name + datetime time = 0 // time +) +{ + // + // if time is not set, move event to the last bar + if (!time) + { + time = TimeCurrent(); + } + + // + // reset the error value + ResetLastError(); + + // + // move the object + if (!ObjectMove(chartID, name, 0, time, 0)) + { + // + string message = + __FUNCTION__ + + ": failed to move \"Event\" object! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution + return true; +} + +// +// Delete Event object +bool EventDelete( + const long chartID = 0, // chart's ID + const string name = "Event" // event name +) +{ + // + // reset the error value + ResetLastError(); + + // + // delete the object + if (!ObjectDelete(chartID, name)) + { + // + string message = + __FUNCTION__ + + ": failed to delete \"Event\" object! Error code = " + + (string)GetLastError(); + + // + LogMessage(message); + + // + return false; + } + + // + // successful execution + return true; +} + +// +// END Event Functions ... +// + +// +// START Button Functions ... +// + +// +// Create the button ... +bool ButtonCreate( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int subWindow = 0, // subwindow index + const int x = 0, // X coordinate + const int y = 0, // Y coordinate + const int width = 50, // button width + const int height = 15, // button height + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring + const string text = "Button", // text + const string font = "Arial", // font + const int fontSize = 8, // font size + const color clr = clrBlack, // text color + const color bgColor = clrLightGray, // background color + const color borderColor = clrNONE, // border color + const bool state = false, // pressed/released + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // create the button + result = ObjectCreate(chartID, name, OBJ_BUTTON, subWindow, 0, 0); + if (!result) + { + return result; + } + + // + // set button coordinates + ObjectSetInteger(chartID, name, OBJPROP_XDISTANCE, x); + ObjectSetInteger(chartID, name, OBJPROP_YDISTANCE, y); + + // + // set button size + ObjectSetInteger(chartID, name, OBJPROP_XSIZE, width); + ObjectSetInteger(chartID, name, OBJPROP_YSIZE, height); + + // + // set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(chartID, name, OBJPROP_CORNER, corner); + + // + // set the text + ObjectSetString(chartID, name, OBJPROP_TEXT, text); + + // + // set text font + ObjectSetString(chartID, name, OBJPROP_FONT, font); + + // + // set font size + ObjectSetInteger(chartID, name, OBJPROP_FONTSIZE, fontSize); + + // + // set text color + ObjectSetInteger(chartID, name, OBJPROP_COLOR, clr); + + // + // set background color + ObjectSetInteger(chartID, name, OBJPROP_BGCOLOR, bgColor); + + // + // set border color + ObjectSetInteger(chartID, name, OBJPROP_BORDER_COLOR, borderColor); + + // + // display in the foreground false or background true + ObjectSetInteger(chartID, name, OBJPROP_BACK, back); + + // + // set button state + ObjectSetInteger(chartID, name, OBJPROP_STATE, state); + + // + // enable true or disable false the mode of moving the button by mouse + ObjectSetInteger(chartID, name, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, name, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list + ObjectSetInteger(chartID, name, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, name, OBJPROP_ZORDER, zOrder); + + // + return result; +} + +// +// Move the button ... +bool ButtonMove( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int x = 0, // X coordinate + const int y = 0 // Y coordinate +) +{ + // + bool result = false; + + // + // move the button + + // + result = ObjectSetInteger(chartID, name, OBJPROP_XDISTANCE, x); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, name, OBJPROP_YDISTANCE, y); + + // + return result; +} + +// +// Change button size ... +bool ButtonChangeSize( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int width = 50, // button width + const int height = 18 // button height +) +{ + // + bool result = false; + + // + // change the button size + + // + result = ObjectSetInteger(chartID, name, OBJPROP_XSIZE, width); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, name, OBJPROP_YSIZE, height); + + // + return result; +} + +// +// Change corner of the chart for binding the button ... +bool ButtonChangeCorner( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER // chart corner for anchoring +) +{ + // + bool result = false; + + // + // change anchor corner + + // + result = ObjectSetInteger(chartID, name, OBJPROP_CORNER, corner); + + // + return result; +} + +// +// Change button text ... +bool ButtonTextChange( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const string text = "Text" // text +) +{ + // + bool result = false; + + // + // change object text + result = ObjectSetString(chartID, name, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Delete the button ... +bool ButtonDelete( + const long chartID = 0, // chart's ID + const string name = "Button" // button name +) +{ + // + bool result = false; + + // + // delete the button + result = ObjectDelete(chartID, name); + + // + return result; +} +// +// END Button Functions ... +// + +// +// END Regular Draws ... +// + +// +// START Chart Style Drawers ... +// +// +// Apply Styles On Chart ... +void ApplyChartStyle( + long mChartId = -1, // chart's ID + ENUM_CHART_MODE mMode = CHART_CANDLES, // chart's mMode + bool mShowBidLine = true, // show bid line + bool mShowAskLine = true, // show ask line + bool mShowGrid = false, // show grids on chart + bool mShowVolumes = false, // show volumes + bool mShowTradeLevels = true, // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) + bool mAutoScroll = true, // chart autoscroll + bool mQuickNavigation = true, // chart quick navigation state + color mForeGroundColor = clrWhite, // chart's foreground color + color mBackGroundColor = clrBlack, // chart's background color + color mUpColor = clrGreen, // Up Color + color mDownColor = clrRed, // Down Color + color mBullishColor = clrGreen, // Bullish color + color mBearishColor = clrRed, // Bearish color + color mGridColor = clrGray, // grid color + color mBidLineColor = clrGray, // bid line color + color mAskLineColor = clrRed, // ask line color + color mLineColor = clrLime, // line mMode and doji candlestick color + color mStopColor = clrGold, // Color of stop order levels (Stop Loss and Take Profit) + color mVolumesColor = clrGreen // volumes color +) +{ + // + // Validate Args ... + if (mChartId == -1) + { + mChartId = 0; + } + + // + ChartSetInteger(mChartId, CHART_MODE, mMode); + ChartSetInteger(mChartId, CHART_SHOW_BID_LINE, mShowBidLine); + ChartSetInteger(mChartId, CHART_SHOW_ASK_LINE, mShowAskLine); + ChartSetInteger(mChartId, CHART_SHOW_GRID, mShowGrid); + ChartSetInteger(mChartId, CHART_SHOW_VOLUMES, mShowVolumes); + ChartSetInteger(mChartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels); + ChartSetInteger(mChartId, CHART_AUTOSCROLL, mAutoScroll); + ChartSetInteger(mChartId, CHART_QUICK_NAVIGATION, mQuickNavigation); + ChartSetInteger(mChartId, CHART_COLOR_FOREGROUND, mForeGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_BACKGROUND, mBackGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_UP, mUpColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_DOWN, mDownColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BULL, mBullishColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BEAR, mBearishColor); + ChartSetInteger(mChartId, CHART_COLOR_GRID, mGridColor); + ChartSetInteger(mChartId, CHART_COLOR_BID, mBidLineColor); + ChartSetInteger(mChartId, CHART_COLOR_ASK, mAskLineColor); + ChartSetInteger(mChartId, CHART_COLOR_STOP_LEVEL, mStopColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_LINE, mLineColor); + ChartSetInteger(mChartId, CHART_COLOR_VOLUME, mVolumesColor); +} + +// +// Retrieve Chart Size in Pixel ... +struct XSize +{ + long width; + long height; + + // + int x; + int y; + int w; + int h; + + // + int wStep; + int hStep; +}; + +// +// Retrieve Chart Size ... +bool GetChartSize( + XSize &result, // Holds Result ... + long chartID = 0 // Specified Chart ID ... +) +{ + // + bool mResult = false; + + // + mResult = ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0, result.width); + if (!mResult) + { + return mResult; + } + + // + mResult = ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0, result.height); + + // + return mResult; +} + +// +// END Chart Style Drawers ... +// \ No newline at end of file diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.http.lib.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.http.lib.ex5 new file mode 100644 index 0000000..134ec79 Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.http.lib.ex5 differ diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.http.lib.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.http.lib.mq5 new file mode 100644 index 0000000..97f7ac0 --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.http.lib.mq5 @@ -0,0 +1,177 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Http Library +// ------------------------------------------ +// Name: XHttp +// Description: provide http communication +// abilities ... +// +// +// 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 + +// +// START Model Definition ... +// +enum X_HTTP_METHOD +{ + X_HTTP_GET, + X_HTTP_POST +}; +// +// END Model Definition ... +// + +// +// START Inputs ... +// +// +// END Inputs ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// +// +// Initial Library if required ... +bool OnInInitHttpLibrary() +{ + return false; +} + +// +// DeInitial Library if required ... +void OnDeinitHttpLibrary() +{ +} + +// +// Convert enum to String ... +string ToString(X_HTTP_METHOD method) +{ + // + string result = ""; + + // + switch (method) + { + // + case X_HTTP_GET: + result = "GET"; + break; + + // + case X_HTTP_POST: + result = "POST"; + break; + } + + // + return result; +} + +// +// Send Global Request ... +int SendRequest( + X_HTTP_METHOD method, // Httm Request Method + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 +) +{ + // + int result = -1; + + // + string strMethod = ToString(method); + if (StringLen(strMethod) == 0) { + return result; + } + + // + result = WebRequest( + strMethod, + url, + headers, + timeout, + payload, + response, + responseHeaders + ); + + // + return result; +} + +// +// Get Request ... +int GetRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 +) { + // + int result = SendRequest( + X_HTTP_GET, + url, + headers, + payload, + response, + responseHeaders, + timeout + ); + + // + return result; +} + +// +// Post Request ... +int PostRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 +) { + // + int result = SendRequest( + X_HTTP_POST, + url, + headers, + payload, + response, + responseHeaders, + timeout + ); + + // + return result; +} +// +// END Provided Functions ... +// diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.log.lib.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.log.lib.ex5 new file mode 100644 index 0000000..ef1ae04 Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.log.lib.ex5 differ diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.log.lib.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.log.lib.mq5 new file mode 100644 index 0000000..3235c63 --- /dev/null +++ b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.log.lib.mq5 @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Logger Library +// --------------------------------------- +// Name: XLogger +// Description: provides Logging abilities ... +// +// +// 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 + +// +// START Inputs ... +// +input group "Logging"; +input bool enableLogging = true; // Enable Logging +// +// END Inputs ... +// + +// +// Including Models ... +#include "x-saherelm.models.lib.mq5" + +// +// START Global Definitions: Variables, Properties and etc ... +// +string logTag = "X-Logger"; // LogTag +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Provided Functions ... +// +// +// Logging a Message ... +void LogMessage(string message) +{ + // + if (!enableLogging) + { + return; + } + + // + Print(logTag, " > ", message); +} +void LogMessage(string tag, string message) +{ + // + if (!enableLogging) + { + return; + } + + // + Print(tag, " > ", message); +} + +// +void LogEmptyLine() +{ + LogMessage(" "); +} + +// +// Logging an Array ... +void LogArray(int &array[]) +{ + // + if (!enableLogging) + { + return; + } + + // + Print(logTag, ">"); + ArrayPrint(array); +} +void LogArray(double &array[]) +{ + // + if (!enableLogging) + { + return; + } + + // + Print(logTag, ">"); + ArrayPrint(array); +} +void LogArray(string &array[]) +{ + // + if (!enableLogging) + { + return; + } + + // + Print(logTag, ">"); + ArrayPrint(array); +} +// +// END Provided Functions ... +// diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.models.lib.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.models.lib.ex5 new file mode 100644 index 0000000..6fce75c Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.models.lib.ex5 differ diff --git a/MQLTestWorkspace/Libraries/x-saherelm.models.lib.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.models.lib.mq5 similarity index 100% rename from MQLTestWorkspace/Libraries/x-saherelm.models.lib.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.models.lib.mq5 diff --git a/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.seriallizer.lib.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.seriallizer.lib.ex5 new file mode 100644 index 0000000..71e9aa6 Binary files /dev/null and b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.seriallizer.lib.ex5 differ diff --git a/MQLTestWorkspace/Libraries/x-saherelm.seriallizer.lib.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.seriallizer.lib.mq5 similarity index 100% rename from MQLTestWorkspace/Libraries/x-saherelm.seriallizer.lib.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.seriallizer.lib.mq5 diff --git a/MQLTestWorkspace/Libraries/x-saherelm.x121.draw.lib.ex5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.x121.draw.lib.ex5 similarity index 100% rename from MQLTestWorkspace/Libraries/x-saherelm.x121.draw.lib.ex5 rename to MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.x121.draw.lib.ex5 diff --git a/MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.draw.lib.mq5 b/MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.x121.draw.lib.mq5 similarity index 100% rename from MQLTestWorkspace/X121/Old/Libraries/x-saherelm.x121.draw.lib.mq5 rename to MQLTestWorkspace/BKPS/before 14030228/Libraries/x-saherelm.x121.draw.lib.mq5 diff --git a/MQLTestWorkspace/Classes/x-saherelm.http.class.ex5 b/MQLTestWorkspace/Classes/x-saherelm.http.class.ex5 new file mode 100644 index 0000000..4314b81 Binary files /dev/null and b/MQLTestWorkspace/Classes/x-saherelm.http.class.ex5 differ diff --git a/MQLTestWorkspace/Classes/x-saherelm.x121.provider.class.ex5 b/MQLTestWorkspace/Classes/x-saherelm.x121.provider.class.ex5 index 86ed200..9306aaf 100644 Binary files a/MQLTestWorkspace/Classes/x-saherelm.x121.provider.class.ex5 and b/MQLTestWorkspace/Classes/x-saherelm.x121.provider.class.ex5 differ diff --git a/MQLTestWorkspace/Classes/x-saherelm.x121.provider.class.mq5 b/MQLTestWorkspace/Classes/x-saherelm.x121.provider.class.mq5 index 4a423b0..70d67e2 100644 --- a/MQLTestWorkspace/Classes/x-saherelm.x121.provider.class.mq5 +++ b/MQLTestWorkspace/Classes/x-saherelm.x121.provider.class.mq5 @@ -2,8 +2,8 @@ // // SaherElm IT Center MQL5 Class Library // ---------------------------------------------- -// Name: XSCX121Provider -// Description: X121 Signal Provider ... +// Name: XSC121Provider +// Description: a Market Analyser and Signal Provider // // // Maintainer: @@ -20,1769 +20,43 @@ #property strict // -// START Definitions ... -// +// TODO: +// - [] add XCT for Candle Timing ... +// - [] add XCS for Candle Styling ... +// - [] add Support for XZG Indicator ... +// - [] implement XPV based on Market Cycles ... +// - [] create XPV Helper class ... +// - [] create XZG Helper class ... +// - [] add Pivots Functionality based on XZG and XPV ... +// - [] add File as Struct functionality and implement it ... +// - [] add Support for OnSignal Event ... +// - [] add support for Alerting ... +// - [] Refactor XSignal: +// -- [] Add support for Multiple TPS and Trailing Stops ... +// -- [] Add support for Clean, Constructor and Init Functions on struct ... +// -- [] Add support for Prepare Signal inside struct ... +// -- [] Add Support for Position Management inside XTrade Class for Handling +// Trail SL, or Partial Close Positions ... +// -- [] Convert providers from Array to string ... +// -- [] Add Support For Serializing and also Deseriallizing functionality ... // -// START Import and Inclused requirements ... -// +// Imports ... // -// Includes ... -#include "../Classes/x-saherelm.xprovider.class.mq5" -#include "../Helpers/x-saherelm.x121.xct.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xcc.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xhk.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xtm.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xpv.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xama.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xmrb.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xche.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xich.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xtrnd.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xsslc.helper.class.mq5" -#include "../Helpers/x-saherelm.x121.xhull.helper.class.mq5" +#include "../Classes/x-saherelm.x121.xmcycle.class.mq5" // -// Seriallizer Library ... -#include "../Libraries/x-saherelm.seriallizer.lib.mq5" +// Definitions ... // -// END Import and Inclused requirements ... -// - -// -// Here we Have to Define an Input Structure Model -// for Provider Class to Handle Helpers Definitions ... +// Configuration of X121 Provider ... struct X121ProviderInputs { - // - // XCT ... - // Candle Timer ... - XCTInputs xctConfig; - - // - // XCC ... - // Candle Styling ... - XCCInputs xccConfig; - - // - // XHK ... - // HikenAshi Candle Representing ... - XHKInputs xhkConfig; - - // - // XTM ... - // Trend Magic ... - XTMInputs xtmConfig; - - // - // XPV ... - // Peaks And Vales ... - XPVInputs xpvConfig; - - // - // XAMA ... - // Adaptive Moving Average ... - XAMAInputs xamaConfig; - - // - // XMRB ... - // Moving Average Ribbon ... - XMRBInputs xmrbConfig; - - // - // XCHE ... - // Chandelier Exit Points ... - XCHEInputs xcheConfig; - - // - // XICH ... - // Ichimopku Kinko Hyo ... - XICHInputs xichConfig; - - // - // XTRND ... - // Trend Detector ... - XTRNDInputs xtrndConfig; - - // - // XSSLC ... - // SSL Channel ... - XSSLCInputs xsslcConfig; - - // - // XHULL ... - // Hull Trend Detection Channel ... - XHULLInputs xhullConfig; }; // -// Model Market Sense based On Current Captured conditions ... -struct X121MarketConditions -{ - // - // Commonly Used Info ... - - // - // Symbol ... - string symbol; - - // - // Period ... - ENUM_TIMEFRAMES period; - - // - // Bar Time ... - datetime barTime; - - // - XCandleRemains barRemains; - - // - // Bar Index ... - int barIndex; - - // - // Check Current Market Condition has Signal or not ... - bool hasSignal; - - // - // If has any Signal, Models it's related info here ... - XSignal signal; - - // - // Support and Resistances ... - // if provides Signal ... - XOHCLSupRes supportResistances; - - // - // Change Price Steps ... - double momentumStep; - - // - // INDICATORS Market Sense ... - - // - // XCT ... - // there is not any Info provided here ... - - // - // XCC ... - // there is not any Info provided here ... - - // - // XHK ... - XHKInfo xhkInfo; - - // - // XTM ... - XTMInfo xtmInfo; - - // - // XPV ... - XPVInfo xpvInfo; - - // - // XAMA ... - XAMAInfo xamaInfo; - - // - // XMRB ... - XMRBInfo xmrbInfo; - - // - // XCHE ... - XCHEInfo xcheInfo; - - // - // XICH ... - XICHInfo xichInfo; - - // - // XTRND ... - XTRNDInfo xtrndInfo; - - // - // XSSLC ... - XSSLCInfo xsslcInfo; - - // - // XHULL ... - XHULLInfo xhullInfo; -}; +// Class ... // -// Notified a Signal was Appears ... -typedef void (*TOnSignalConditions)( - X121MarketConditions &info); - -// -// All Available Signal Types ... -enum ENUM_X121_SIGNAL_PROVIDERS -{ - NONE, // NONE ... - XPVF, // Peakse and Vales Using Fibo ... - XCHNL, // SSL Channel and MRB Signals ... - XTRND, // Trend Base ... -}; - -// -// END Definitions ... -// - -// -// START Overrides ... -// - -// -// END Overrides ... -// - -// -// a Base Class for All of our EA's ... -class XSCX121Provider : public XSCEABaseProvider -{ - // - // Public ... -public: - // - // Props ... - X121ProviderInputs providedConfig; - X121ProviderInputs currentConfig; - X121ProviderInputs cleanConfig; - - // - // Indicator Helper Classes Instance ... - - // - // XCT ... - XSCXCTHelper *mXCTHelper; - - // - // XCC ... - XSCXCCHelper *mXCCHelper; - - // - // XHK ... - XSCXHKHelper *mXHKHelper; - - // - // XTM ... - XSCXTMHelper *mXTMHelper; - - // - // XPV ... - XSCXPVHelper *mXPVHelper; - - // - // XAMA ... - XSCXAMAHelper *mXAMAHelper; - - // - // XMRB ... - XSCXMRBHelper *mXMRBHelper; - - // - // XCHE ... - XSCXCHEHelper *mXCHEHelper; - - // - // XICH ... - XSCXICHHelper *mXICHHelper; - - // - // XTRND ... - XSCXTRNDHelper *mXTRNDHelper; - - // - // XSSLC ... - XSCXSSLCHelper *mXSSLCHelper; - - // - // XHULL ... - XSCXHULLHelper *mXHULLHelper; - - // - // Hull Pivot Points ... - double upZonePivots[]; - double downZonePivots[]; - - // - // Peaks and Vales Verifications Number ... - double peaksPivots[]; - double valesPivots[]; - - // - double ichPivots[]; - - // - double fiboPivots[]; - - // - int pvConsequences; - - // - // Constructor ... - void XSCX121Provider( - string symbol, // Trading Symbol ... - ENUM_TIMEFRAMES period // Trading Time Frame ... - ) - { - // - mMinPivots = 100; - pvConsequences = 26; - mDisableXPVFShort = false; - mDisableXPVFLong = false; - - // - PrepareTag(); - } - - // - // Deconstructor ... - void ~XSCX121Provider() - { - // - IndicatorRelease(mCTimerHandler); - - // - // De construct Helpers ... - delete mXCTHelper; - delete mXCCHelper; - delete mXHKHelper; - delete mXTMHelper; - delete mXPVHelper; - delete mXAMAHelper; - delete mXMRBHelper; - delete mXCHEHelper; - delete mXICHHelper; - delete mXTRNDHelper; - delete mXSSLCHelper; - delete mXHULLHelper; - } - - // - int GetMinPivots() { - return mMinPivots; - } - - // - virtual void PrepareTag() - { - mTag = "X121Provider((" + mSymbol + ")(" + ToString(mPeriod) + ")"; - } - - // - virtual bool Init() - { - // - bool result = false; - - // - // Instantiate all Indicators Helper Classes ... - - // - // XCT ... - mXCTHelper = new XSCXCTHelper( - mSymbol, - mPeriod); - result = mXCTHelper.SetConfig(currentConfig.xctConfig); - if (!result) - { - return result; - } - - // - // XCC ... - mXCCHelper = new XSCXCCHelper( - mSymbol, - mPeriod); - result = mXCCHelper.SetConfig(currentConfig.xccConfig); - if (!result) - { - return result; - } - - // - // XHK ... - mXHKHelper = new XSCXHKHelper( - mSymbol, - mPeriod); - result = mXHKHelper.SetConfig(currentConfig.xhkConfig); - if (!result) - { - return result; - }; - - // - // XTM ... - mXTMHelper = new XSCXTMHelper( - mSymbol, - mPeriod); - result = mXTMHelper.SetConfig(currentConfig.xtmConfig); - if (!result) - { - return result; - }; - - // - // XPV ... - mXPVHelper = new XSCXPVHelper( - mSymbol, - mPeriod); - result = mXPVHelper.SetConfig(currentConfig.xpvConfig); - if (!result) - { - return result; - }; - - // - // XAMA ... - mXAMAHelper = new XSCXAMAHelper( - mSymbol, - mPeriod); - result = mXAMAHelper.SetConfig(currentConfig.xamaConfig); - if (!result) - { - return result; - }; - - // - // XMRB ... - mXMRBHelper = new XSCXMRBHelper( - mSymbol, - mPeriod); - result = mXMRBHelper.SetConfig(currentConfig.xmrbConfig); - if (!result) - { - return result; - }; - - // - // XCHE ... - mXCHEHelper = new XSCXCHEHelper( - mSymbol, - mPeriod); - result = mXCHEHelper.SetConfig(currentConfig.xcheConfig); - if (!result) - { - return result; - }; - - // - // XICH ... - mXICHHelper = new XSCXICHHelper( - mSymbol, - mPeriod); - result = mXICHHelper.SetConfig(currentConfig.xichConfig); - if (!result) - { - return result; - }; - - // - // XTRND ... - mXTRNDHelper = new XSCXTRNDHelper( - mSymbol, - mPeriod); - result = mXTRNDHelper.SetConfig(currentConfig.xtrndConfig); - if (!result) - { - return result; - }; - - // - // XSSLC ... - mXSSLCHelper = new XSCXSSLCHelper( - mSymbol, - mPeriod); - result = mXSSLCHelper.SetConfig(currentConfig.xsslcConfig); - if (!result) - { - return result; - }; - - // - // XHULL ... - mXHULLHelper = new XSCXHULLHelper( - mSymbol, - mPeriod); - result = mXHULLHelper.SetConfig(currentConfig.xhullConfig); - if (!result) - { - return result; - }; - - // - return result; - } - - // - virtual int GetMaxLength() - { - // - int result = -1; - - // - result = MathMax(result, mXCTHelper.GetMaxLength()); - result = MathMax(result, mXCCHelper.GetMaxLength()); - result = MathMax(result, mXHKHelper.GetMaxLength()); - result = MathMax(result, mXTMHelper.GetMaxLength()); - result = MathMax(result, mXPVHelper.GetMaxLength()); - result = MathMax(result, mXAMAHelper.GetMaxLength()); - result = MathMax(result, mXMRBHelper.GetMaxLength()); - result = MathMax(result, mXCHEHelper.GetMaxLength()); - result = MathMax(result, mXICHHelper.GetMaxLength()); - result = MathMax(result, mXTRNDHelper.GetMaxLength()); - result = MathMax(result, mXSSLCHelper.GetMaxLength()); - result = MathMax(result, mXHULLHelper.GetMaxLength()); - - // - return result; - } - - // - virtual int GetCalculatedBars() - { - // - int result = -1; - - // - int mXCTBars = mXCTHelper.GetCalculatedBars(); - int mXCCBars = mXCCHelper.GetCalculatedBars(); - int mXHKBars = mXHKHelper.GetCalculatedBars(); - int mXTMBars = mXTMHelper.GetCalculatedBars(); - int mXPVBars = mXPVHelper.GetCalculatedBars(); - int mXAMABars = mXAMAHelper.GetCalculatedBars(); - int mXMRBBars = mXMRBHelper.GetCalculatedBars(); - int mXCHEBars = mXCHEHelper.GetCalculatedBars(); - int mXICHBars = mXICHHelper.GetCalculatedBars(); - int mXTRNDBars = mXTRNDHelper.GetCalculatedBars(); - int mXSSLCBars = mXSSLCHelper.GetCalculatedBars(); - int mXHULLBars = mXHULLHelper.GetCalculatedBars(); - - // - int min = MathMin(mXCTBars, mXCCBars); - min = MathMin(min, mXHKBars); - min = MathMin(min, mXTMBars); - min = MathMin(min, mXPVBars); - min = MathMin(min, mXAMABars); - min = MathMin(min, mXMRBBars); - min = MathMin(min, mXCHEBars); - min = MathMin(min, mXICHBars); - min = MathMin(min, mXTRNDBars); - min = MathMin(min, mXSSLCBars); - min = MathMin(min, mXHULLBars); - - // - int max = MathMax(mXCTBars, mXCCBars); - max = MathMax(max, mXHKBars); - max = MathMax(max, mXTMBars); - max = MathMax(max, mXPVBars); - max = MathMax(max, mXAMABars); - max = MathMax(max, mXMRBBars); - max = MathMax(max, mXCHEBars); - max = MathMax(max, mXICHBars); - max = MathMax(max, mXTRNDBars); - max = MathMax(max, mXSSLCBars); - max = MathMax(max, mXHULLBars); - - // - result = min; - - // - return result; - } - - // - virtual void ProcessBuffers() - { - UpdatePivotPoints(); - } - - // - virtual bool ProcessTick(X121MarketConditions &conditions) - { - // - if (CanIgnoreTick()) { - return false; - } - - // - return ProcessSignals(conditions); - } - - // - X121ProviderInputs GetConfig() - { - // - X121ProviderInputs result; - - // - result = currentConfig; - - // - return result; - } - - // - bool SetConfig(X121ProviderInputs &config) - { - // - bool result = false; - - // - PrepareConfig(config); - - // - result = Init(); - - // - return result; - } - - // - bool ResetDefaultConfig() - { - // - bool result = SetConfig(providedConfig); - - // - return result; - } - - // - bool ShowCleanConfig() - { - // - currentConfig = cleanConfig; - - // - bool result = Init(); - - // - return result; - } - - // - bool ShowDefaultConfig() - { - // - currentConfig = providedConfig; - - // - bool result = Init(); - - // - return result; - } - - // - // Generate Market Sense ... - X121MarketConditions GetMarketConditions( - int barIndex // Specified Bar Index - ) - { - // - X121MarketConditions result; - - // - // Fill Common Data ... - result.symbol = mSymbol; - result.period = mPeriod; - result.barIndex = barIndex; - - // - datetime barTime = GetCandleTime( - mSymbol, - mPeriod, - barIndex); - result.barTime = barTime; - - // - int remainedCandle = barIndex > 0 - ? barIndex - 1 - : barIndex; - GetCandleRemainsTime( - result.barRemains, - mSymbol, - mPeriod, - remainedCandle); - - // - result.xhkInfo = mXHKHelper.GetInfo(barIndex); - result.xtmInfo = mXTMHelper.GetInfo(barIndex); - result.xpvInfo = mXPVHelper.GetInfo(barIndex); - result.xamaInfo = mXAMAHelper.GetInfo(barIndex); - result.xmrbInfo = mXMRBHelper.GetInfo(barIndex); - result.xcheInfo = mXCHEHelper.GetInfo(barIndex); - result.xichInfo = mXICHHelper.GetInfo(barIndex); - result.xtrndInfo = mXTRNDHelper.GetInfo(barIndex); - result.xsslcInfo = mXSSLCHelper.GetInfo(barIndex); - result.xhullInfo = mXHULLHelper.GetInfo(barIndex); - - // - return result; - } - - // - // TODO: Complete this ... - XOHCLSupRes GetSupportsAndResistances( - XSignal &signal, // Signal - int requirements = 10) - { - // - XOHCLSupRes result; - - // - int totalBars = Bars( - mSymbol, - mPeriod); - - // - int idx = 0; - - // - while ( - idx < totalBars - 17 || - ArraySize(result.sup) < requirements || - ArraySize(result.res) < requirements) - { - // - // Here we Try to Find Support and Resistances ... - - // - idx++; - } - - // - return result; - } - - // - bool GuardCheck(XGuard &guards[]) - { - // - bool result = false; - - // - Clean(guards); - - // - // Implement Guards Check ... - - // - return result; - } - - // - // Add Specific On SignalConditions Event Handler ... - int AddOnSignalConditionEventHandler(TOnSignalConditions handler) - { - // - ArrayResize( - mSignalConditionsEventHandlers, - ArraySize(mSignalConditionsEventHandlers) + 1); - - // - int result = ArraySize(mSignalConditionsEventHandlers) - 1; - mSignalConditionsEventHandlers[result] = handler; - - // - return result; - } - - // - // Remove All On Signal Event Handler ... - void ReoveOnSignalEventHandlers() - { - // - ArrayFree(mSignalConditionsEventHandlers); - } - - // - // Notify a Signal Found on all Event Listeners ... - void NotifyOnSignalConditionsEvent(X121MarketConditions &info) - { - // - int listenerCount = ArraySize(mSignalConditionsEventHandlers); - if (listenerCount <= 0) - { - return; - } - - // - // Loop Through Listeners ... - for (int i = 0; i < listenerCount; i++) - { - // - TOnSignalConditions listener = mSignalConditionsEventHandlers[i]; - - // - listener(info); - } - } - - // - void ProccessPivotPoints() - { - // - if (mStartPivotScan) - { - return; - } - - // - mStartPivotScan = true; - - // - int maxLength = GetMaxLength(); - int cBars = GetCalculatedBars(); - int scanSize = cBars - maxLength - 1; - for (int i = 1; i < scanSize; i++) - { - // - UpdatePivotPoints(i); - - // - int pivotsCount = CountPivots(); - if (pivotsCount >= mMinPivots) - { - break; - } - } - } - - // - int CountPivots() - { - // - int pivotSizes[]; - int upZoneCount = ArraySize(upZonePivots); - if (upZoneCount > 0) - { - // - Add( - upZoneCount, - pivotSizes); - } - - // - int downZoneCount = ArraySize(downZonePivots); - if (downZoneCount > 0) - { - // - Add( - downZoneCount, - pivotSizes); - } - - // - int peaksCount = ArraySize(peaksPivots); - if (peaksCount > 0) - { - // - Add( - peaksCount, - pivotSizes); - } - - // - int valesCount = ArraySize(valesPivots); - if (valesCount > 0) - { - // - Add( - valesCount, - pivotSizes); - } - - // - int fibsCount = ArraySize(fiboPivots); - if (fibsCount > 0) - { - // - Add( - fibsCount, - pivotSizes); - } - - // - int ichsCount = ArraySize(ichPivots); - if (ichsCount > 0) - { - // - Add( - ichsCount, - pivotSizes); - } - - // - int result = ArraySize(pivotSizes) > 0 - ? pivotSizes[ArrayMaximum(pivotSizes)] - : 0; - - // - return result; - } - - // - // Protected ... -protected: - // - // Private ... -private: - // - // CCandle Timer ... - int mCTimerHandler; - - // - // Signal Event Handlers ... - TOnSignalConditions mSignalConditionsEventHandlers[]; - - // - // Make Provided Config in Clean Style ... - void PrepareConfig(X121ProviderInputs &config) - { - // - cleanConfig = config; - - // - // XCT ... - // Candle Timing ... - cleanConfig.xctConfig.showCandleTime = false; - - // - // XCC ... - // Candle Styling ... - cleanConfig.xccConfig.showCandles = true; - - // - // XHK ... - // HikenAshi Candle Representing ... - cleanConfig.xhkConfig.drawCandles = false; - cleanConfig.xhkConfig.drawCandleLines = false; - - // - // XTM ... - // Trend Magic ... - cleanConfig.xtmConfig.showLine = false; - - // - // XPV ... - // Peaks And Vales ... - cleanConfig.xpvConfig.showPeaksAndVales = false; - cleanConfig.xpvConfig.showLevels = false; - cleanConfig.xpvConfig.showFibo1Levels = false; - cleanConfig.xpvConfig.showFibo2Levels = false; - cleanConfig.xpvConfig.showFibo3Levels = false; - - // - // XAMA ... - // Adaptive Moving Average ... - cleanConfig.xamaConfig.showLine = false; - - // - // XMRB ... - // Moving Average Ribbon ... - cleanConfig.xmrbConfig.showFastMa = false; - cleanConfig.xmrbConfig.showSlowMa = false; - cleanConfig.xmrbConfig.showRibbon = false; - - // - // XCHE ... - // Chandelier Exit Points ... - cleanConfig.xcheConfig.showLongExit1Line = false; - cleanConfig.xcheConfig.showShortExit1Line = false; - cleanConfig.xcheConfig.showLongExit2Line = false; - cleanConfig.xcheConfig.showShortExit2Line = false; - - // - // XICH ... - // Ichimopku Kinko Hyo ... - cleanConfig.xichConfig.showTenkanSen = false; - cleanConfig.xichConfig.showKijunSen = false; - cleanConfig.xichConfig.showKijunSenPlus = false; - cleanConfig.xichConfig.showKijunSenNegative = false; - cleanConfig.xichConfig.showChikouSpan = false; - cleanConfig.xichConfig.showSenkouSpanA = false; - cleanConfig.xichConfig.showSenkouSpanB = false; - cleanConfig.xichConfig.showKumo = false; - - // - // XTRND ... - // Trend Detector ... - cleanConfig.xtrndConfig.showConsolidations = false; - cleanConfig.xtrndConfig.showTrend = false; - cleanConfig.xtrndConfig.showL1Trend = false; - cleanConfig.xtrndConfig.showL2Trend = false; - cleanConfig.xtrndConfig.showL3Trend = false; - - // - // XSSLC ... - // SSL Channel ... - cleanConfig.xsslcConfig.showUp = false; - cleanConfig.xsslcConfig.showDown = false; - - // - // XHULL ... - // Hull Trend Detection Channel ... - cleanConfig.xhullConfig.showUpZone = false; - cleanConfig.xhullConfig.showDownZone = false; - - // - providedConfig = config; - currentConfig = config; - } - - // - int mMinPivots; - bool mStartPivotScan; - bool mDisableXPVFLong; - bool mDisableXPVFShort; - double mLastMomentumStep; - - // - // Find Required Pivots for Support and Resistance ... - void UpdatePivotPoints( - int barIndex = 1 // Specified Candle ... - ) - { - // - mXCTHelper.Calculate(barIndex); - mXCCHelper.Calculate(barIndex); - mXHKHelper.Calculate(barIndex); - mXTMHelper.Calculate(barIndex); - mXPVHelper.Calculate(barIndex); - mXAMAHelper.Calculate(barIndex); - mXMRBHelper.Calculate(barIndex); - mXCHEHelper.Calculate(barIndex); - mXICHHelper.Calculate(barIndex); - mXTRNDHelper.Calculate(barIndex); - mXSSLCHelper.Calculate(barIndex); - mXHULLHelper.Calculate(barIndex); - - // - // Detect Peask and Vales Pivots ... - - // - // Detect Hull Pivots ... - // find Hull Trend Changes ... - int idx = 1; - bool isHullUpChanged = - // - ( - // - (XHULL_ZONE_STATES)mXHULLHelper.upStateBuffer[idx] == XHULL_STATE_BULLISH && - (XHULL_ZONE_STATES)mXHULLHelper.upStateBuffer[idx + 1] != XHULL_STATE_BULLISH - // - ) - // - || - // - ( - // - (XHULL_ZONE_STATES)mXHULLHelper.upStateBuffer[idx] == XHULL_STATE_BEARISH && - (XHULL_ZONE_STATES)mXHULLHelper.upStateBuffer[idx + 1] != XHULL_STATE_BEARISH - // - ) - // - ; - - // - bool isHullDownChanged = - // - ( - // - (XHULL_ZONE_STATES)mXHULLHelper.downStateBuffer[idx] == XHULL_STATE_BULLISH && - (XHULL_ZONE_STATES)mXHULLHelper.downStateBuffer[idx + 1] != XHULL_STATE_BULLISH - // - ) - // - || - // - ( - // - (XHULL_ZONE_STATES)mXHULLHelper.downStateBuffer[idx] == XHULL_STATE_BEARISH && - (XHULL_ZONE_STATES)mXHULLHelper.downStateBuffer[idx + 1] != XHULL_STATE_BEARISH - // - ) - // - ; - - // - // Find Change State ... - if (isHullUpChanged || - isHullDownChanged) - { - // - AddIfNotExists( - mXHULLHelper.upBuffer[idx], - upZonePivots); - - // - AddIfNotExists( - mXHULLHelper.downBuffer[idx], - downZonePivots); - } - - // - // Find Momentom Step ... - if (isHullUpChanged && - isHullDownChanged) - { - // - mLastMomentumStep = MathAbs(mXHULLHelper.upBuffer[idx] - mXHULLHelper.downBuffer[idx]); - mLastMomentumStep = NormalizePrice( - mLastMomentumStep, - mSymbol); - } - - // - // Find Peaks and Vales ... - double selectedFib1 = mXPVHelper.fl1Buffer[idx]; - double selectedFib2 = mXPVHelper.fl2Buffer[idx]; - double selectedFib3 = mXPVHelper.fl3Buffer[idx]; - double selectedPeak = mXPVHelper.peaksBuffer[idx]; - double selectedVale = mXPVHelper.valesBuffer[idx]; - - // - double selectedTenkanSen = mXICHHelper.tenkanSenBuffer[idx]; - double selectedKijunSen = mXICHHelper.kijunSenBuffer[idx]; - - // - int fib1Verified = 0; - int fib2Verified = 0; - int fib3Verified = 0; - int peaksVerified = 0; - int valesVerified = 0; - int kijunSenVerified = 0; - int tenkanSenVerified = 0; - int senkouSpanAVerified = 0; - int senkouSpanBVerified = 0; - for (int i = barIndex + 1; i < pvConsequences + barIndex + 1; i++) - { - // - int idx = i - barIndex; - - // - // PEAKS and VALES ... - - // - if (selectedPeak == mXPVHelper.peaksBuffer[idx]) - { - peaksVerified++; - } - else - { - peaksVerified = 0; - } - - // - if (selectedVale == mXPVHelper.valesBuffer[idx]) - { - valesVerified++; - } - else - { - valesVerified = 0; - } - - // - if (selectedFib1 == mXPVHelper.fl1Buffer[idx]) - { - fib1Verified++; - } - else - { - fib1Verified = 0; - } - - // - if (selectedFib2 == mXPVHelper.fl2Buffer[idx]) - { - fib2Verified++; - } - else - { - fib2Verified = 0; - } - - // - if (selectedFib3 == mXPVHelper.fl3Buffer[idx]) - { - fib3Verified++; - } - else - { - fib3Verified = 0; - } - - // - // ICHIMOKU Kinko Hyo ... - - // - if (selectedTenkanSen == mXICHHelper.tenkanSenBuffer[idx]) - { - tenkanSenVerified++; - } - else - { - tenkanSenVerified = 0; - } - - // - if (selectedKijunSen == mXICHHelper.kijunSenBuffer[idx]) - { - kijunSenVerified++; - } - else - { - kijunSenVerified++; - } - } - - // - if (peaksVerified >= pvConsequences) - { - // - AddIfNotExists( - selectedPeak, - peaksPivots); - } - - // - if (valesVerified >= pvConsequences) - { - // - AddIfNotExists( - selectedVale, - valesPivots); - } - - // - if (fib1Verified >= pvConsequences) - { - // - AddIfNotExists( - selectedFib1, - fiboPivots); - } - - // - if (fib2Verified >= pvConsequences) - { - // - AddIfNotExists( - selectedFib2, - fiboPivots); - } - - // - if (fib3Verified >= pvConsequences) - { - // - AddIfNotExists( - selectedFib3, - fiboPivots); - } - - // - if (tenkanSenVerified >= pvConsequences) - { - // - AddIfNotExists( - selectedTenkanSen, - ichPivots); - } - - // - if (kijunSenVerified >= pvConsequences) - { - // - AddIfNotExists( - selectedKijunSen, - ichPivots); - } - - // // - // if (senkouSpanAVerified >= pvConsequences) - // { - // // - // AddIfNotExists( - // selectedSenkouSpanA, - // ichPivots); - // } - - // // - // if (senkouSpanBVerified >= pvConsequences) - // { - // // - // AddIfNotExists( - // selectedSenkouSpanB, - // ichPivots); - // } - } - - // - void FillPivotPoints( - double &result[]) - { - // - Clean(result); - - // - int pCount = CountPivots(); - if (pCount <= 0) - { - return; - } - - // - AddsIfNotExists( - upZonePivots, - result); - - // - AddsIfNotExists( - downZonePivots, - result); - - // - AddsIfNotExists( - peaksPivots, - result); - - // - AddsIfNotExists( - valesPivots, - result); - - // - AddsIfNotExists( - fiboPivots, - result); - - // - AddsIfNotExists( - ichPivots, - result); - } - - // - // Here we are Capture Conditions and Check Signals ... - // The Signals Must be Unique for each providers ... - bool ProcessSignals(X121MarketConditions &conditions) - { - // - X121MarketConditions mConditions = GetMarketConditions(1); - - // - // BUY ... - - // - Clean(mConditions.signal); - bool hasLongSignal = HasLongSignal(mConditions); - if (hasLongSignal) - { - // - NotifyOnSignalEvent( - mConditions.signal); - NotifyOnSignalConditionsEvent(mConditions); - mWaitUntilNewCandle = true; - - // - conditions = mConditions; - return true; - } - - // - // SELL ... - - // - Clean(mConditions.signal); - bool hasShortignal = HasShortSignal(mConditions); - if (hasShortignal) - { - // - NotifyOnSignalEvent( - mConditions.signal); - NotifyOnSignalConditionsEvent(mConditions); - mWaitUntilNewCandle = true; - - // - conditions = mConditions; - return true; - } - - // - return false; - } - - // - // Check has Long Signal on Each Strategies ... - bool HasLongSignal(X121MarketConditions &conditions) - { - // - bool result = false; - - // - double entry = GetEntry( - mSymbol, - POSITION_TYPE_BUY); - - // - XOHCL c1 = GetCandle( - mSymbol, - mPeriod, - 1); - - // - double pivots[]; - FillPivotPoints(pivots); - XOHCLSupRes supRes = ExtractSupportAndResistance( - 1, - pivots, - 15); - X121MarketConditions mConditions = GetMarketConditions(1); - - // - mXPVHelper.Calculate(1); - - // - Clean(mConditions.signal); - - // - // XPVF Signal Provider ... - bool xPVFSignal = false; - if (!mDisableXPVFLong) - { - // - xPVFSignal = - // - mConditions.xpvInfo.isNewPeak && - mXPVHelper.peaksBuffer[0] < mXPVHelper.peaksBuffer[1] && - mXPVHelper.valesBuffer[0] == mXPVHelper.valesBuffer[1] - // - ; - - // - if (xPVFSignal) - { - // - Add( - ToString(XPVF), - mConditions.signal.providers); - - // - mConditions.signal.r2r = 1.5; - mConditions.signal.riskAmount = 0.005; - mConditions.signal.mode = X_ORDER_MODE_MARKET; - mConditions.signal.entry = entry; - mConditions.signal.sl = 0; // mXCHEHelper.longExit2[1]; - mConditions.signal.tp = 0; - - // - // mConditions.signal.calculateTP = true; - // mConditions.signal.useRiskAmountAsVolume = false; - // mConditions.signal.useSupportAndResistance = true; - - // - // mDisableXPVFLong = true; - // mDisableXPVFShort = false; - } - } - - // - result = - // - xPVFSignal - // - ; - - // - if (result) - { - // - conditions = mConditions; - - // - conditions.supportResistances = supRes; - conditions.momentumStep = mLastMomentumStep; - - // - conditions.signal.symbol = mSymbol; - conditions.signal.period = mPeriod; - conditions.signal.type = POSITION_TYPE_BUY; - - // - conditions.hasSignal = true; - } - - // - return result; - } - - // - // Check has Short Signal on Each Strategies ... - bool HasShortSignal(X121MarketConditions &conditions) - { - // - bool result = false; - - // - double entry = GetEntry( - mSymbol, - POSITION_TYPE_SELL); - - // - XOHCL c1 = GetCandle( - mSymbol, - mPeriod, - 1); - - // - double pivots[]; - FillPivotPoints(pivots); - XOHCLSupRes supRes = ExtractSupportAndResistance( - 1, - pivots, - 15); - - // - X121MarketConditions mConditions = GetMarketConditions(1); - - // - mXPVHelper.Calculate(1); - - // - Clean(mConditions.signal); - - // - // XPVF Signal Provider ... - bool xPVFSignal = false; - if (!mDisableXPVFShort) - { - // - xPVFSignal = - // - mConditions.xpvInfo.isNewVale && - mXPVHelper.valesBuffer[0] > mXPVHelper.valesBuffer[1] && - mXPVHelper.peaksBuffer[0] == mXPVHelper.peaksBuffer[1] - // - ; - - // - if (xPVFSignal) - { - // - Add( - ToString(XPVF), - mConditions.signal.providers); - - // - mConditions.signal.r2r = 1.5; - mConditions.signal.riskAmount = 0.005; - mConditions.signal.mode = X_ORDER_MODE_STOP; - mConditions.signal.entry = entry; - mConditions.signal.sl = 0; - mConditions.signal.tp = mXPVHelper.valesBuffer[1]; - - // - mConditions.signal.calculateTP = true; - mConditions.signal.useRiskAmountAsVolume = false; - mConditions.signal.useSupportAndResistance = true; - - // - // mDisableXPVFShort = true; - // mDisableXPVFLong = false; - } - } - - // - result = - // - xPVFSignal - // - ; - - // - if (result) - { - // - conditions = mConditions; - - // - conditions.supportResistances = supRes; - conditions.momentumStep = mLastMomentumStep; - - // - conditions.signal.symbol = mSymbol; - conditions.signal.period = mPeriod; - conditions.signal.type = POSITION_TYPE_SELL; - - // - conditions.hasSignal = true; - } - - // - return result; - } -}; - -// -// START Definitions ... -// - -// -// Model Signal Providers Definitions ... -struct X121SignalProvider -{ - // - // Provider use Which Symbol ... - string symbol; - - // - // Provider use Which Time Frame ... - ENUM_TIMEFRAMES period; - - // - // Risk Amount Per Trades Related to Time Frames ... - // Percent of Available Balance ... - double riskAmount; - - // - // Desired Magic Number ... - ulong magicNumber; - - // - // Provider ... - XSCX121Provider *provider; -}; - -// -// END Definitions ... -// - -// -// START Usefull Functions ... -// - -// -// Add Specific Provider to List ... -void Add( - X121SignalProvider &item, // item want to add - X121SignalProvider &buffer[] // Destination buffer -) -{ - // - ArrayResize( - buffer, - ArraySize(buffer) + 1); - - // - buffer[ArraySize(buffer) - 1] = item; -} - -// -// Generate Identifier Tag ... -string GenerateTag(X121SignalProvider &descriptor) -{ - // - string result = ""; - - // - result = descriptor.symbol + "," + ToString(descriptor.period); - - // - return result; -} - -// -// Converts a Signal provider to String ... -string ToString(ENUM_X121_SIGNAL_PROVIDERS provider) -{ - return EnumToString(provider); -} - -// -// convert an String to Signal provider ... -ENUM_X121_SIGNAL_PROVIDERS ToProvider(string provider) -{ - // - ENUM_X121_SIGNAL_PROVIDERS result = NONE; - - // - if (ToString(NONE) == provider) - { - result = NONE; - } - else if (ToString(XPVF) == provider) - { - result = XPVF; - } - else if (ToString(XCHNL) == provider) - { - result = XCHNL; - } - else if (ToString(XTRND) == provider) - { - result = XTRND; - } - - // - return result; -} - -// -// Extract Provider Type from Signal Commnet ... -ENUM_X121_SIGNAL_PROVIDERS ExtractPositionProvider(XPosition &position) -{ - // - ENUM_X121_SIGNAL_PROVIDERS result = NONE; - - // - string providerStr = - ExtractString( - position.comment, - XProviderToken + "(", - ")"); - if (StringLen(providerStr) <= 0) - { - return result; - } - - // - result = ToProvider(providerStr); - - // - return result; -} - -// -// Generate Provider String for Using in Positions Comment ... -// NOTE: if there is more than One Provider, it takes first -// provider as main and the others used to increase volume ... -string GenerateProvidersString(XSignal &signal) -{ - // - string result = ""; - - // - int providersCount = ArraySize(signal.providers); - if (providersCount <= 0) - { - return result; - } - - // - result = XProviderToken + "(" + signal.providers[0] + ")"; - - // - return result; -} - -// -// END Usefull Functions ... -// +// Tools ... \ No newline at end of file diff --git a/MQLTestWorkspace/Classes/x-saherelm.x121.xmcycle.class.ex5 b/MQLTestWorkspace/Classes/x-saherelm.x121.xmcycle.class.ex5 new file mode 100644 index 0000000..907eb05 Binary files /dev/null and b/MQLTestWorkspace/Classes/x-saherelm.x121.xmcycle.class.ex5 differ diff --git a/MQLTestWorkspace/Classes/x-saherelm.x121.xmcycle.class.mq5 b/MQLTestWorkspace/Classes/x-saherelm.x121.xmcycle.class.mq5 new file mode 100644 index 0000000..fdb370b --- /dev/null +++ b/MQLTestWorkspace/Classes/x-saherelm.x121.xmcycle.class.mq5 @@ -0,0 +1,3086 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSC121MCycle +// Description: provides all requirements for +// Handling Specified Market Cycle Analysis... +// +// +// 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-saherelm.draw.lib.mq5" + +// +#include "../Helpers/x-saherelm.x121.xmc.helper.mq5" +#include "../Helpers/x-saherelm.x121.xche.helper.mq5" +#include "../Helpers/x-saherelm.x121.xosc.helper.mq5" +#include "../Helpers/x-saherelm.x121.xstr.helper.mq5" +#include "../Helpers/x-saherelm.x121.xich.helper.mq5" + +// +// Definitions ... + +// +struct X121MCycleInputs +{ + // + // Props ... + + // + XMarketCycle cycle; // Cycle Descriptor ... + + // + // Draw Props ... + + // + XDrawSpecifications cBarMidDrawSpecs; // Current Bar MidLine Draw Specifications + XOHCLDrawSpecification cBarDrawSpecs; // Current Bar Draw Specifications + + // + XDrawSpecifications pBarMidDrawSpecs; // Previous Bar MidLine Draw Specifications + XOHCLDrawSpecification pBarDrawSpecs; // Previous Bar Draw Specifications + + // + bool drawLabels; // Draw Labels + bool drawCBar; // Draw Current Bar + bool drawPBar; // Draw Previous Bar + bool drawCBarMid; // Draw Current Bar Mid Line + bool drawPBarMid; // Draw Previous Bar Mid Line + + // + X121MCInputs mcInputs; // MC Inputs ... + X121STRInputs strInputs; // STR Inputs ... + X121OSCInputs oscInputs; // OSC Inputs ... + X121CHEInputs cheInputs; // CHE Inputs ... + X121ICHInputs ichInputs; // ICH Inputs ... + + // + // Constructor ... + X121MCycleInputs() + { + Clean(); + } + + // + // Tools ... + + // + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + ENUM_TIMEFRAMES mPeriod, // Cycle Period + ENUM_X_PERIOD_METHOD mPeriodMethod, // Cycle Period Method + string mPrefix = "", // Prefix + bool useDefaults = true // Use Inputs Default Settings ... + ) + { + // + bool result = false; + + // + cycle.period = mPeriod; + cycle.method = mPeriodMethod; + + // + // Initial Cycle Model ... + result = cycle.Init( + mSymbol, + mHostPeriod, + mCycle, + mPrefix + // + ); + if (!result) + { + return result; + } + + // + if (useDefaults) + { + // + mcInputs.Default(); + strInputs.Default(); + oscInputs.Default(); + cheInputs.Default(); + ichInputs.Default(); + } + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + return result; + } + + // + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + X121MCInputs &mMcInputs, // MC Inputs + X121STRInputs &mStrInputs, // STR Inputs + X121OSCInputs &mOscInputs, // OSC Inputs + X121CHEInputs &mCheInputs, // CHE Inputs + int mHostBarIndex = 0, // Specified Host Period Bar Index + string mPrefix = "" // Prefix + ) + { + // + bool result = false; + + // + // Initial Cycle Model ... + result = cycle.Init( + mSymbol, + mHostPeriod, + mCycle, + mPrefix + // + ); + if (!result) + { + return result; + } + + // + mcInputs = mMcInputs; + strInputs = mStrInputs; + oscInputs = mOscInputs; + cheInputs = mCheInputs; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + return result; + } + + // + void Clean() + { + // + cycle.Clean(); + mcInputs.Clean(); + strInputs.Clean(); + oscInputs.Clean(); + cheInputs.Clean(); + ichInputs.Clean(); + + // + cBarDrawSpecs.Clean(); + pBarDrawSpecs.Clean(); + cBarMidDrawSpecs.Clean(); + pBarMidDrawSpecs.Clean(); + + // + drawLabels = false; + drawCBar = false; + drawPBar = false; + drawCBarMid = false; + drawPBarMid = false; + } + + // + void Default() + { + // + mcInputs.Default(); + strInputs.Default(); + oscInputs.Default(); + cheInputs.Default(); + ichInputs.Default(); + + // + drawLabels = false; + drawCBar = false; + drawPBar = false; + drawCBarMid = false; + drawPBarMid = false; + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = cycle.IsValid(); + if (!result) + { + return result; + } + + // + result = mcInputs.IsValid(); + if (!result) + { + return result; + } + + // + result = strInputs.IsValid(); + if (!result) + { + return result; + } + + // + result = oscInputs.IsValid(); + if (!result) + { + return result; + } + + // + result = cheInputs.IsValid(); + if (!result) + { + return result; + } + + // + result = ichInputs.IsValid(); + if (!result) + { + return result; + } + + // + return result; + } +}; + +// +// Specific Market Sense Based on Specified Bar Index on Host Period ... +struct X121MCycleConditions +{ + // + // Props ... + + // + // Common ... + string prefix; // Cycle Prefix ... + string symbol; // Analysing Symbol ... + ENUM_TIMEFRAMES period; // Analysing Time Frame ... + ENUM_TIMEFRAMES hostPeriod; // Hosting Time Frame ... + ENUM_X_MARKET_CYCLES cycle; // Init Cycle ... + + // + // Bars ... + XOHCL bars[]; // Some Bars ... + datetime time; // Extracting Time ... + + // + // Candlestic Conditions ... + bool isLastBullish; + bool isLastBearish; + bool isCurrentBullish; + bool isCurrentBearish; + bool isCurrentMidLineOverLastHigh; + bool isCurrentMidLineUnderLastLow; + bool isCurrentMidLineOverLastUp; + bool isCurrentMidLineUnderLastDown; + bool isCurrentMidLineOverLastMidLine; + bool isCurrentMidLineUnderLastMidLine; + + // + // XICH ... + // Ichimoku strategy + // Strategy one: Ichimoku trend identifier: + // According to this strategy, we need a trigger that can be used + // to inform us about the trend type, + // if it is an uptrend or downtrend. + // We will check three values to do that and these values are the: + // closing price, Senkou Span A, and Senkou Span B. + // If the closing price is greater than the Senkou Span B and at the same time + // the closing price is greater than Senkou Span A, + // this will be the trigger to know that the trend is up. + // Vice versa, if the closing price is lower than the Senkou Span B and at the same time + // the closing price is lower than the Senkou Span A, + // this will be the trigger to the downtrend. + // + // Closing price > Senkou Span B and closing price > Senkou Span A --> Uptrend + // Closing price < Senkou Span B and closing price < Senkou Span A --> Downtrend + // + // Strategy two: Ichimoku trend strength: + // Based on this strategy, we need a trigger that can inform us the current trend is strong. + // We will check three values to do that and these values are the: + // - current Senkou Span A, + // - the previous Senkou Span A, and + // - the Senkou Span B. + // If the current Senkou Span A is greater than the previous Senkous Span A and at the same time + // the current Senkou Span A is greater than the Senkou Span B, + // this is a trigger that the trend is up and strong. + // Vice versa, if the current Senkou Span A is lower than the previous Senkou Span A and at the + // same time, the current Senkou Span A is lower than the Senkou Span B, + // this will be a signal that the trend is down and strong. + // + // Current Senkou Span A > previous Senkou Span A and current Senkou Span A > Senkou Span B --> the uptrend is strong + // Current Senkou Span A < previous Senkou Span A and current Senkou Span A < Senkou Span B --> the downtrend is strong + bool isSenkouSpanAOverB; + bool isSenkouSpanAUnderB; + bool isSenkouSpanAOverLast; + bool isSenkouSpanAUnderLast; + bool isFutureSenkouSpanAOverB; + bool isFutureSenkouSpanAUnderB; + bool isFutureSenkouSpanAOverLast; + bool isFutureSenkouSpanAUnderLast; + // + // Strategy three: Ichimoku price-Ki signal: + // According to this strategy, during the uptrend, we need a trigger that can + // alert us about the bullish signal, and during the downtrend, we need a trigger than can alert us about the bearish signal. + // We will check based on this strategy two values, closing price, and Kijun-Sen. + // If the closing price is greater than the Kijun-sen value, + // this will be a trigger to a bullish signal. + // Vice versa, if the closing price is lower than the Kijun-sen value, + // this will be a bearish signal. + // + // During uptrend, closing price > Kijun -sen --> bullish signal + // Duuring downtrend, closing price < Kijun -sen --> bearish signal + bool isCloseOverKijunSen; + bool isCloseUnderKijunSen; + // + // Strategy four: Ichimoku ten-ki signal: + // According to this strategy, during the uptrend, we need another trigger or + // method to alert us when there is a bullish signal or + // during the downtrend, we need a signal of bearishness. + // We will check based on this strategy two values, Tenkan-sen and Kijum-sen. + // If the Tenkan-sen value is greater than the Kijun-sen, + // this will be a signal of bullishness. + // Vice versa, if the Tenkan-sen is lower than the Kijun-sen, + // this will be a signal of bearishness. + // + // Tenkan-sen > Kijun-sen --> bullish signal + // Tenkan-sen < Kijun-sen --> bearish signal + bool isTenkanSenOverKijunSen; + bool isTenkanSenUnderKijunSen; + + // + // XMC ... + // Three Moving Averages Crossover + // In this strategy, we will use three simple moving averages: + // the shorter simple moving average period is 10, the longer one period is 48, and in between a period of 24. + // + // According to the strategy, we need the three simple moving averages to be checked at every tick: + // + // If 10 SMA > 24 SMA, 10 SMA > 48 SMA, and 24 SMA > 48 SMA: the signal will be to buy and we need to be appeared as a comment on the chart. + // If 10 SMA < 24 SMA, 10 SMA < 48 SMA, and 24 SMA < 48 SMA: the signal will be to sell and we need to be appeared as a comment on the chart. + // If anything, else do nothing. + bool isFastOverSlow; + bool isFastUnderSlow; + bool isFastOverVerifier; + bool isFastUnderVerifier; + bool isSlowOverVerifier; + bool isSlowUnderVerifier; + bool isCloseOverFast; + bool isCloseUnderFast; + bool isCloseOverSlow; + bool isCloseUnderSlow; + bool isCloseOverVerifier; + bool isCloseUnderVerifier; + + // + // XSTR ... + bool isTrendBullish; + bool isTrendBearish; + + // + // XCHE ... + bool isCHEInLong; + bool isCHEInStrongLong; + bool isCHEInShort; + bool isCHEInStrongShort; + + // + // XOSC ... + + // + // RVI Signals ... + // Strategy one: RVI Crossover - Uptrend: + // Based on this strategy, we need to get buy and close signals during the uptrend by a specific condition. + // When the RVI current value and RVI signal current value are greater than the zero level at the same time + // that RVI current value is greater than the current value of the RVI signal, this will be a buy signal. + // Vice Versa, when the RVI current value and RVI signal current value is below zero level at + // the same time that the RVI current value is below the current value of the RVI signal, this will be a close signal. + // + // RVI value > 0 and RVI signal value > 0 and RVI value > RVI signal value --> buy + // RVI value < 0 and RVI signal value < 0 and RVI value < RVI signal value --> close + bool isRVILongStart; + bool isRVILongStop; + // + // Strategy two: RVI Crossover - Downtrend: + // Based on this strategy, we need to get the opposite signals of the previous RVI Crossover - + // Uptrend strategy as we need to get short and cover signals. + // When the RVI current value and RVI signal current value are lower than the zero level at + // the same time that RVI current value is lower than the current value of the RVI signal, this will be a short signal. + // Vice Versa, when the RVI current value and RVI signal current value is above the zero level + // at the same time that the RVI current value is above the current value of the RVI signal, this will be a cover signal. + // + // RVI value < 0 and RVI signal value < 0 and RVI value < RVI signal value --> short + // RVI value > 0 and RVI signal value > 0 and RVI value > RVI signal value --> cover + bool isRVIShortStart; + bool isRVIShortStop; + // + // Strategy three: RVI and MA Crossover + // Based on this strategy, we need to get buy and sell signals based on specific conditions + // as we need to get a + // buy signal + // when the closing price is greater than the 100 -period moving average + // at the same time that the current RVI value is greater than the current RVI signal value. + // In the other scenario, we need to get a + // sell signal + // when the closing price is lower than the 100 -period moving average + // at the same time that the current RVI value is lower than the current RVI signal value. + + // + // RSI strategy ... + // During Uptrend + // In this case, most of the time RSI values move between or moving between + // the mid range and level 70 (Overbought level). + // The trading strategy for the uptrend is: + // + // RSI Value < 50 = Buy + // RSI Value > 70 = Take Profit + bool isRSIUnder50; + bool isRSIOver70; + // + // During Downtrend + // During the downtrend, the RSI moves most of the time between + // the mid range and level 30 (Oversold level). + // The trading strategy will be as follows: + // + // RSI Value > 50 = Short + // RSI Value < 30 = Take Profit + bool isRSIOver50; + bool isRSIUnder30; + // + // During Sideways: + // RSI spends most of the time between levels 30 (Oversold level) and 70 (Oversbought level). + // The trading strategy will be as follows: + // RSI Value < 30 = Buy + // RSI Value > 50 = Take Profit + // RSI Value > 70 = Short + // RSI Value < 50 = Take Profit + + // + // Bull's Power strategy: + // In this part, we will learn how we can use Bull's Power through simple strategies + // that can be used based on the basic concept of this indicator. + // The following are for these strategies and their conditions. + // I need to confirm here, that these strategies for education only as the main objective + // is to understand the main concept behind the indicator and how we can use them in our favor, + // so you must test any of them before using them on your real account to make sure that + // it will be good for your trading as there is no strategy is suitable for everyone. + // + // Strategy one: Bull's Power Movement: + // Based on this strategy, we need to get signals based on the position of current and previous bull's power values. + // If the current bull's power value is greater than the previous one, + // we will consider it as a signal of the rising of the Bull's Power indicator. + // Vice versa, if the current value is lower than the previous one, we will consider that as a signal of + // declining Bull's Power. + // + // To simplify that, it will be the same as the following: + // + // Current Bull's Power > Previous Bull's Power --> Bull's Power is Rising + // Current Bull's Power < Previous Bull's Power --> Bull's Power is declining + bool isBullPowerOverLast; + bool isBullPoswerUnderLast; + // + // Strategy two: Bull's Power - Strong or Divergence + // Based on this strategy, we want to get a signal that informs us if there is a strong movement + // or there is a divergence by evaluating four values and these values are current high, + // the previous high, bull power, and previous bull power. + // If the current high is higher than the previous high and + // the current bull power value is higher than the previous one, + // we will consider that as a signal of a strong move. + // In the other case, if the current high is higher than the previous high and the current + // bull value is lower than the previous one, we will consider that as a signal of bearish divergence. + // + // To simplify that, it will be the same as the following: + // + // Current high > previous high and current bull's power > previous bull's power --> strong move + // Current high < previous high and current bull's power > previous bull's power --> bearish divergence + // + // Strategy three: Bull's Power signals + // Based on this strategy, we need a signal that can be used to get buy and sell signals and we will + // evaluate four values to do that based on this strategy. + // These four values are: + // - current bull's power, + // - zero level, + // - current close value, and + // - current exponential moving average. + // If the current bull's power is lower than the zero level and + // the current close is lower than the exponential moving average, + // we will consider it as a signal of selling. + // If the current bull's power is greater than the zero level and the current close is greater than + // the exponential moving average, this will be a signal of buying. + // + // To simplify that, it will be the same as the following: + // + // Current bull's power < zero level and current close < EMA --> sell + // Current bear's power > zero level and current close > EMA --> buy + bool isBullPowerOverZero; + bool isBullPoswerUnderZero; + + // + // Bear's Power strategy + // In this part, we will learn how we can use Bear's Power through simple strategies + // that can be used based on the basic concept of this indicator. + // The following are for these strategies and their conditions. + // I need to confirm here, that these strategies for education as the main objective + // is to understand the main concept behind the indicator and how we can use it, + // so you must test any of them before using them on your real account to + // make sure that it will be good for your trading. + // + // Strategy one: Bear's Power Movement + // According to this strategy, we need to get signals based on the position of current and previous + // bear's power values. + // If the current value is greater than the previous, this will be a signal of the rising of + // Bear's Power indicator. + // Vice versa, if the current value is lower than the previous value, + // this will be a signal of declining Bear's Power. + // + // Simply, + // + // Current Bear's Power > Previous Bear's Power --> Bear's Power is Rising + // Current Bear's Power < Previous Bear's Power --> Bear's Power is declining + bool isBearPowerOverLast; + bool isBearPoswerUnderLast; + // + // Strategy two: Bear's Power - Strong or Divergence + // According to this strategy, we need to get a signal that informs us if there are strong movements or + // there are divergences by evaluating four values and they are: + // -current low, + // - previous low, + // - bear power, and + // - previous bear power. + // If the current low is lower than the previous low and the current bear power value + // is lower than the previous one, this will be a signal of a strong move. + // In the other case, if the current low is lower than the previous low and the current + // bear value is greater than the previous one, this will be a signal of bullish divergence. + // + // Simply, + // + // Current low < previous low and current bear's power < previous bear's power --> strong move + // Current low < previous low and current bear's power > previous bear's power --> bullish divergence + // + // Strategy three + // According to this strategy, we need a trigger that can be used to get buy and sell signals and + // we will evaluate four values to do that based on this strategy. + // These four values are current: + // - bear's power, + // - zero level, + // - current close value, and + // - current exponential moving average. + // If the current bear's power is greater than the zero level and the current close is greater than + // the exponential moving average, this will be a signal of buy. + // If the current bear's power is lower than the zero level and the current close is lower than + // the exponential moving average, this will be a signal of selling. + // + // Simply, + // + // Current bear's power > zero level and current close > EMA --> buy + // Current bear's power < zero level and current close < EMA --> sell + bool isBearPowerOverZero; + bool isBearPoswerUnderZero; + + // + // CCI ... + bool isCCIPositive; + bool isCCINegative; + bool isCCIOverPositiveHundred; + bool isCCIUnderNegativeHundred; + + // + // STDDEV ... + // Based on this strategy, we need to measure the volatility based on the comparison between the + // current Std Dev and the average of the five previous Std values. + // If the current Std Dev is greater than the Std Dev 5-periods average, this will be a high volatility signal. + // If the current Std is lower than the Std Dev 5- period average, this will be low volatility. + // + // Based on this strategy, we need to get buy and sell signals based on specific conditions. + // If the current Std Dev is greater than the previous Std Dev and the Ask value is greater than the moving average, + // this will be a buy signal. + // If the current Std Dev is greater than the previous Std Dev and the Bid value is lower than the moving average, + // this will be a sell signal. + // + // Current Std > Prev. Std and Ask > MA --> Buy signal + // Current Std > Prev. Std and Bid < MA --> Sell signal + // + // Based on this strategy, we need to get buy and sell signals based on other conditions. + // If the current Std Dev is greater than Std Dev Avg and Ask is greater than the moving average, + // this will be a buy signal. + // If the current Std Dev is greater than Std Dev Avg and Bid is lower than the moving average, + // this will be a sell signal. + // + // Current Std > Std Avg and Ask > MA --> Buy signal + // Current Std > Std Avg and Bid < Ma --> Sell signal + bool isSTDDEVOverAVG; + bool isSTDDEVOverLast; + bool isSTDDEVUnderAVG; + bool isSTDDEVUnderLast; + + // + // MACD ... + // According to this strategy, we need to identify the market setup: + // is it buying setup or shorting setup. + // In other words we need to identify the market direction, if it is bullish or bearish market, + // and this will be identified by MACD. + // If the MACD main line breaks above zero level, this will be a buying setup or bullish setup and + // vice versa if MACD main line breaks below zero level, this will be a shorting setup or bearish. + // + // MACD main line > 0 = Bullish Setup + // MACD main line < 0 = Bearish Setup + // + // According to this strategy, we need to identify generated signals + // if there is a buy signal or a sell signal based on MACD main line and Signal line crossover. + // If MACD main line breaks above Signal line, this will be a buy signal and if MACD main line breaks + // below Signal line, this will be a short signal. + // + // MACD main line > MACD signal line = Buying Signal + // MACD main line < MACD signal line = Shorting signal + bool isMACDPositiove; + bool isMACDNegative; + bool isMACDOverSignal; + bool isMACDUnderSignal; + + // + // STOCHASTIC ... + // Stochastic strategy + // In this part, we will talk about how we can use this indicator through simple strategies. + // We can get signals from the stochastic indicator according to market trend and these strategies are + // uptrend strategy, downtrend strategy, and sideways strategy. + // + // Strategy one: Uptrend strategy + // According to this strategy, we need to check if the %K line and %D line are below the 50 level, + // then, the buy signal will be generated + // when the %K line crosses above the %D line. + // We can take profit according to another effective tool like price action by searching + // for a lower low for example. + // + // %K, %D < 50 --> %K > %D = buy signal + bool isStochKOverD; + bool isStochKDUnder50; + // + // Strategy two: downtrend strategy + // According to this strategy, we need to check if the %K line and %D line are above the 50 level, + // then, the sell signal will be generated + // when the %K line crosses below the %D line. + // We can take profit according to another effective tool like price action by searching + // for a higher high for example. + // + // %K, %D > 50 --> %K < %D = sell signal + bool isStochKUnderD; + bool isStochKDOver50; + // + // Strategy three: sideways strategy + // + // The buy signal: + // According to this strategy, we need to check if the %K line and %D line are below the 20 level, + // then, the buy signal will be generated + // when the %K line crosses above the %D line. + // When the %K line and %D line are above 80, then the take profit signal will be generated + // when the %K line crosses below the %D line. + // %K, %D < 20 --> %K > %D = buy signal + // %K, %D > 80 --> %K < %D = take profit + bool isStochKDUnder20; + // + // The sell signal + // According to this strategy, we need to check if the %K line and %D line are above the 80 level, + // then, the sell signal will be generated + // when the %K line crosses below the %D line. + // When the %K line and %D are below the 20 level, then, the take profit signal will be generated + // when the %K line crosses above the %D line. + // + // %K, %D > 80 --> %K < %D = sell signal + // %K, %D < 20 --> %K > %D = take profit + bool isStochKDOver80; + + // + // Constructor(s) ... + X121MCycleConditions() + { + Clean(); + } + + // + void Clean() + { + // + // Commons ... + time = 0; + cycle = NULL; + prefix = NULL; + symbol = NULL; + period = NULL; + hostPeriod = NULL; + + // + Clean(bars); + + // + // Candlestic ... + isLastBullish = false; + isLastBearish = false; + isCurrentBullish = false; + isCurrentBearish = false; + isCurrentMidLineOverLastHigh = false; + isCurrentMidLineUnderLastLow = false; + isCurrentMidLineOverLastUp = false; + isCurrentMidLineUnderLastDown = false; + isCurrentMidLineOverLastMidLine = false; + isCurrentMidLineUnderLastMidLine = false; + + // + // XTSR ... + isTrendBullish = false; + isTrendBearish = false; + + // + // XCHE ... + isCHEInLong = false; + isCHEInStrongLong = false; + isCHEInShort = false; + isCHEInStrongShort = false; + + // + // XICH ... + isSenkouSpanAOverB = false; + isSenkouSpanAUnderB = false; + isSenkouSpanAOverLast = false; + isSenkouSpanAUnderLast = false; + isFutureSenkouSpanAOverB = false; + isFutureSenkouSpanAUnderB = false; + isFutureSenkouSpanAOverLast = false; + isFutureSenkouSpanAUnderLast = false; + isCloseOverKijunSen = false; + isCloseUnderKijunSen = false; + isTenkanSenOverKijunSen = false; + isTenkanSenUnderKijunSen = false; + + // + // XMC ... + isFastOverSlow = false; + isFastUnderSlow = false; + isFastOverVerifier = false; + isFastUnderVerifier = false; + isSlowOverVerifier = false; + isSlowUnderVerifier = false; + isCloseOverFast = false; + isCloseUnderFast = false; + isCloseOverSlow = false; + isCloseUnderSlow = false; + isCloseOverVerifier = false; + isCloseUnderVerifier = false; + + // + // XOSC ... + + // + // STDDEV ... + isSTDDEVOverAVG = false; + isSTDDEVUnderAVG = false; + isSTDDEVOverLast = false; + isSTDDEVUnderLast = false; + + // + // RVI ... + isRVILongStart = false; + isRVILongStop = false; + isRVIShortStart = false; + isRVIShortStop = false; + + // + // RSI ... + isRSIUnder50 = false; + isRSIOver70 = false; + isRSIOver50 = false; + isRSIUnder30 = false; + + // + // BULLPOWER ... + isBullPowerOverLast = false; + isBullPoswerUnderLast = false; + isBullPowerOverZero = false; + isBullPoswerUnderZero = false; + + // + // BEARPOWER ... + isBearPowerOverLast = false; + isBearPoswerUnderLast = false; + isBearPowerOverZero = false; + isBearPoswerUnderZero = false; + + // + // CCI ... + isCCIPositive = false; + isCCINegative = false; + isCCIOverPositiveHundred = false; + isCCIUnderNegativeHundred = false; + + // + // MACD ... + isMACDPositiove = false; + isMACDNegative = false; + isMACDOverSignal = false; + isMACDUnderSignal = false; + + // + // STOCH ... + isStochKOverD = false; + isStochKDUnder50 = false; + isStochKUnderD = false; + isStochKDOver50 = false; + isStochKDUnder20 = false; + isStochKDOver80 = false; + } + + // + // Tools ... + + // + // Generate Score ... + void GenerateScore( + double &bullishScore, // Holds Bullish Score ... + double &bearishScore, // Holds Bearish Score ... + double multiplier = 1 // Score Multiplier ... + ) + { + // + double bullScore = 0; + double bearScore = 0; + + // + if (multiplier <= 0) + { + multiplier = 1; + } + + // + // Candlestic ... + + // + // BULLISH ... + if (isLastBullish) + { + bullScore++; + } + if (isCurrentBullish) + { + bullScore++; + } + if (isCurrentMidLineOverLastUp) + { + bullScore++; + } + if (isCurrentMidLineOverLastHigh) + { + bullScore++; + } + if (isCurrentMidLineOverLastMidLine) + { + bullScore++; + } + + // + // BEARISH ... + if (isLastBearish) + { + bearScore++; + } + if (isCurrentBearish) + { + bearScore++; + } + if (isCurrentMidLineUnderLastLow) + { + bearScore++; + } + if (isCurrentMidLineUnderLastDown) + { + bearScore++; + } + if (isCurrentMidLineUnderLastMidLine) + { + bearScore++; + } + + // + // XSTR ... + if (isTrendBullish) + { + bullScore++; + } + if (isTrendBearish) + { + bearScore++; + } + + // + // XICH ... + + // + // BULLISH ... + if (isSenkouSpanAOverB) + { + bullScore++; + } + if (isSenkouSpanAOverLast) + { + bullScore++; + } + if (isCloseOverKijunSen) + { + bullScore++; + } + if (isTenkanSenOverKijunSen) + { + bullScore++; + } + if (isFutureSenkouSpanAOverB) + { + bullScore++; + } + if (isFutureSenkouSpanAOverLast) + { + bullScore++; + } + + // + // BEARISH ... + if (isSenkouSpanAUnderB) + { + bearScore++; + } + if (isSenkouSpanAUnderLast) + { + bearScore++; + } + if (isCloseUnderKijunSen) + { + bearScore++; + } + if (isTenkanSenUnderKijunSen) + { + bearScore++; + } + if (isFutureSenkouSpanAUnderB) + { + bearScore++; + } + if (isFutureSenkouSpanAUnderLast) + { + bearScore++; + } + + // + // XMC ... + + // + // BULLISH ... + if (isFastOverSlow) + { + bullScore++; + } + if (isFastOverVerifier) + { + bullScore++; + } + if (isSlowOverVerifier) + { + bullScore++; + } + if (isCloseOverFast) + { + bullScore++; + } + if (isCloseOverSlow) + { + bullScore++; + } + if (isCloseOverVerifier) + { + bullScore++; + } + + // + // BEARISH ... + if (isFastUnderSlow) + { + bearScore++; + } + if (isFastUnderVerifier) + { + bearScore++; + } + if (isSlowUnderVerifier) + { + bearScore++; + } + if (isCloseUnderFast) + { + bearScore++; + } + if (isCloseUnderSlow) + { + bearScore++; + } + if (isCloseUnderVerifier) + { + bearScore++; + } + + // + // XOSC ... + + // + // STDDEV ... + + // + // BULLISH ... + if (isSTDDEVOverAVG) + { + bullScore++; + } + if (isSTDDEVOverLast) + { + bullScore++; + } + + // + // BEARISH ... + if (isSTDDEVUnderAVG) + { + bearScore++; + } + if (isSTDDEVUnderLast) + { + bearScore++; + } + + // + // RVI ... + if (isRVILongStart && !isRVILongStop) + { + bullScore++; + } + if (isRVIShortStart && isRVIShortStop) + { + bearScore++; + } + + // + // RSI ... + + // + // BULLISH ... + if (isRSIUnder30 || (!isRSIUnder30 && isRSIOver50 && isRSIOver70)) + { + bullScore++; + } + + // + // BEARISH ... + if (isRSIOver70 || (!isRSIOver70 && !isRSIOver50 && isRSIUnder30)) + { + bearScore++; + } + + // + // BULLPOWER ... + + // + // BULLISH ... + if (isBullPowerOverLast) + { + bullScore++; + } + if (isBullPowerOverZero) + { + bullScore++; + } + + // + // BEARISH ... + if (isBullPoswerUnderLast) + { + bearScore++; + } + if (isBullPoswerUnderZero) + { + bearScore++; + } + + // + // BEARPOWER ... + + // + // BULLISH ... + if (isBearPoswerUnderLast) + { + bullScore++; + } + if (isBearPoswerUnderZero) + { + bullScore++; + } + + // + // BEARISH ... + if (isBearPowerOverLast) + { + bearScore++; + } + if (isBearPowerOverZero) + { + bearScore++; + } + + // + // CCI ... + + // + // BULLISH ... + if (isCCIPositive) + { + bullScore++; + } + if (isCCIOverPositiveHundred) + { + bullScore++; + } + + // + // BEARISH ... + if (isCCINegative) + { + bearScore++; + } + if (isCCIUnderNegativeHundred) + { + bearScore++; + } + + // + // MACD ... + + // + // BULLISH ... + if (isMACDPositiove) + { + bullScore++; + } + if (isMACDOverSignal) + { + bullScore++; + } + + // + // BEARISH ... + if (isMACDNegative) + { + bearScore++; + } + if (isMACDUnderSignal) + { + bearScore++; + } + + // + // STOCH ... + + // + // BULLISH ... + if (isStochKOverD) + { + bullScore++; + } + if (isStochKDUnder20) + { + bullScore++; + } + if (isStochKDUnder50) + { + bullScore++; + } + + // + // BEARISH ... + if (isStochKUnderD) + { + bearScore++; + } + if (isStochKDOver50) + { + bearScore++; + } + if (isStochKDOver80) + { + bearScore++; + } + + // + bullishScore = bullScore * multiplier; + bearishScore = bearScore * multiplier; + } + + // + // Generate Summary ... + string GenerateSummary( + double multiplier = 1, // Score Multiplier + bool ignoreFalseConditions = true // Ignore False Conditions + ) + { + // + string result = ""; + + // + double bullScore = 0; + double bearScore = 0; + GenerateScore( + bullScore, + bearScore, + multiplier + // + ); + + // + // Commons ... + string commons = + // + ToString(cycle) + "[" + prefix + "]" + "\n" + + "-------------" + "\n" + + "Time: " + ToString(time) + "\n" + + "\n" + + "Scores:" + "\n" + + "-------------" + "\n" + + "Bullish: " + ToString(bullScore) + "\n" + + "Bearish: " + ToString(bearScore) + "\n" + + "\n" + // + ; + + // + string candlestic = + // + ((isLastBullish || !ignoreFalseConditions) ? "isLastBullish: " + ToString(isLastBullish) + "\n" : "") + + ((isLastBearish || !ignoreFalseConditions) ? "isLastBearish: " + ToString(isLastBearish) + "\n" : "") + + ((isCurrentBullish || !ignoreFalseConditions) ? "isCurrentBullish: " + ToString(isCurrentBullish) + "\n" : "") + + ((isCurrentBearish || !ignoreFalseConditions) ? "isCurrentBearish: " + ToString(isCurrentBearish) + "\n" : "") + + ((isCurrentMidLineOverLastHigh || !ignoreFalseConditions) ? "isCurrentMidLineOverLastHigh: " + ToString(isCurrentMidLineOverLastHigh) + "\n" : "") + + ((isCurrentMidLineUnderLastLow || !ignoreFalseConditions) ? "isCurrentMidLineUnderLastLow: " + ToString(isCurrentMidLineUnderLastLow) + "\n" : "") + + ((isCurrentMidLineOverLastUp || !ignoreFalseConditions) ? "isCurrentMidLineOverLastUp: " + ToString(isCurrentMidLineOverLastUp) + "\n" : "") + + ((isCurrentMidLineUnderLastDown || !ignoreFalseConditions) ? "isCurrentMidLineUnderLastDown: " + ToString(isCurrentMidLineUnderLastDown) + "\n" : "") + + ((isCurrentMidLineOverLastMidLine || !ignoreFalseConditions) ? "isCurrentMidLineOverLastMidLine: " + ToString(isCurrentMidLineOverLastMidLine) + "\n" : "") + + ((isCurrentMidLineUnderLastMidLine || !ignoreFalseConditions) ? "isCurrentMidLineUnderLastMidLine: " + ToString(isCurrentMidLineUnderLastMidLine) + "\n" : "") + + "" + // + ; + if (StringLen(candlestic) > 0) + { + // + candlestic = + // + "XOHCL(s):" + "\n" + + "-------------" + "\n" + + candlestic + + "\n" + // + ; + } + + // + // XSTR ... + string str = + // + ((isTrendBullish || !ignoreFalseConditions) ? "isTrendBullish: " + ToString(isTrendBullish) + "\n" : "") + + ((isTrendBearish || !ignoreFalseConditions) ? "isTrendBearish: " + ToString(isTrendBearish) + "\n" : "") + + "" + // + ; + if (StringLen(str) > 0) + { + // + str = + // + "XSTR:" + "\n" + + "-------------" + "\n" + + str + + "\n" + // + ; + } + + // + // XCHE ... + string che = + // + ((isCHEInLong || !ignoreFalseConditions) ? "isCHEInLong: " + ToString(isCHEInLong) + "\n" : "") + + ((isCHEInStrongLong || !ignoreFalseConditions) ? "isCHEInStrongLong: " + ToString(isCHEInStrongLong) + "\n" : "") + + ((isCHEInShort || !ignoreFalseConditions) ? "isCHEInShort: " + ToString(isCHEInShort) + "\n" : "") + + ((isCHEInStrongShort || !ignoreFalseConditions) ? "isCHEInStrongShort: " + ToString(isCHEInStrongShort) + "\n" : "") + + "" + // + ; + if (StringLen(che) > 0) + { + // + che = + // + "XCHE:" + "\n" + + "-------------" + "\n" + + che + + "\n" + // + ; + } + + // + // XICH ... + string ich = + // + ((isSenkouSpanAOverB || !ignoreFalseConditions) ? "isSenkouSpanAOverB: " + ToString(isSenkouSpanAOverB) + "\n" : "") + + ((isSenkouSpanAUnderB || !ignoreFalseConditions) ? "isSenkouSpanAUnderB: " + ToString(isSenkouSpanAUnderB) + "\n" : "") + + ((isSenkouSpanAOverLast || !ignoreFalseConditions) ? "isSenkouSpanAOverLast: " + ToString(isSenkouSpanAOverLast) + "\n" : "") + + ((isSenkouSpanAUnderLast || !ignoreFalseConditions) ? "isSenkouSpanAUnderLast: " + ToString(isSenkouSpanAUnderLast) + "\n" : "") + + ((isCloseOverKijunSen || !ignoreFalseConditions) ? "isCloseOverKijunSen: " + ToString(isCloseOverKijunSen) + "\n" : "") + + ((isCloseUnderKijunSen || !ignoreFalseConditions) ? "isCloseUnderKijunSen: " + ToString(isCloseUnderKijunSen) + "\n" : "") + + ((isTenkanSenOverKijunSen || !ignoreFalseConditions) ? "isTenkanSenOverKijunSen: " + ToString(isTenkanSenOverKijunSen) + "\n" : "") + + ((isTenkanSenUnderKijunSen || !ignoreFalseConditions) ? "isTenkanSenUnderKijunSen: " + ToString(isTenkanSenUnderKijunSen) + "\n" : "") + + ((isFutureSenkouSpanAOverB || !ignoreFalseConditions) ? "isFutureSenkouSpanAOverB: " + ToString(isFutureSenkouSpanAOverB) + "\n" : "") + + ((isFutureSenkouSpanAUnderB || !ignoreFalseConditions) ? "isFutureSenkouSpanAUnderB: " + ToString(isFutureSenkouSpanAUnderB) + "\n" : "") + + ((isFutureSenkouSpanAOverLast || !ignoreFalseConditions) ? "isFutureSenkouSpanAOverLast: " + ToString(isFutureSenkouSpanAOverLast) + "\n" : "") + + ((isFutureSenkouSpanAUnderLast || !ignoreFalseConditions) ? "isFutureSenkouSpanAUnderLast: " + ToString(isFutureSenkouSpanAUnderLast) + "\n" : "") + + "" + // + ; + if (StringLen(ich) > 0) + { + // + ich = + // + "XICH:" + "\n" + + "-------------" + "\n" + + ich + + "\n" + // + ; + } + + // + // XMC ... + string mc = + // + ((isFastOverSlow || !ignoreFalseConditions) ? "isFastOverSlow: " + ToString(isFastOverSlow) + "\n" : "") + + ((isFastUnderSlow || !ignoreFalseConditions) ? "isFastUnderSlow: " + ToString(isFastUnderSlow) + "\n" : "") + + ((isFastOverVerifier || !ignoreFalseConditions) ? "isFastOverVerifier: " + ToString(isFastOverVerifier) + "\n" : "") + + ((isFastUnderVerifier || !ignoreFalseConditions) ? "isFastUnderVerifier: " + ToString(isFastUnderVerifier) + "\n" : "") + + ((isSlowOverVerifier || !ignoreFalseConditions) ? "isSlowOverVerifier: " + ToString(isSlowOverVerifier) + "\n" : "") + + ((isSlowUnderVerifier || !ignoreFalseConditions) ? "isSlowUnderVerifier: " + ToString(isSlowUnderVerifier) + "\n" : "") + + ((isCloseOverFast || !ignoreFalseConditions) ? "isCloseOverFast: " + ToString(isCloseOverFast) + "\n" : "") + + ((isCloseUnderFast || !ignoreFalseConditions) ? "isCloseUnderFast: " + ToString(isCloseUnderFast) + "\n" : "") + + ((isCloseOverSlow || !ignoreFalseConditions) ? "isCloseOverSlow: " + ToString(isCloseOverSlow) + "\n" : "") + + ((isCloseUnderSlow || !ignoreFalseConditions) ? "isCloseUnderSlow: " + ToString(isCloseUnderSlow) + "\n" : "") + + ((isCloseOverVerifier || !ignoreFalseConditions) ? "isCloseOverVerifier: " + ToString(isCloseOverVerifier) + "\n" : "") + + ((isCloseUnderVerifier || !ignoreFalseConditions) ? "isCloseUnderVerifier: " + ToString(isCloseUnderVerifier) + "\n" : "") + + "" + // + ; + if (StringLen(mc) > 0) + { + // + mc = + // + "XMC:" + "\n" + + "-------------" + "\n" + + mc + + "\n" + // + ; + } + + // + // XOSC ... + + // + // STDDEV ... + string stddev = + // + ((isSTDDEVOverAVG || !ignoreFalseConditions) ? "isSTDDEVOverAVG: " + ToString(isSTDDEVOverAVG) + "\n" : "") + + ((isSTDDEVUnderAVG || !ignoreFalseConditions) ? "isSTDDEVUnderAVG: " + ToString(isSTDDEVUnderAVG) + "\n" : "") + + ((isSTDDEVOverLast || !ignoreFalseConditions) ? "isSTDDEVOverLast: " + ToString(isSTDDEVOverLast) + "\n" : "") + + ((isSTDDEVUnderLast || !ignoreFalseConditions) ? "isSTDDEVUnderLast: " + ToString(isSTDDEVUnderLast) + "\n" : "") + + "" + // + ; + if (StringLen(stddev) > 0) + { + // + stddev = + // + "STDDev:" + "\n" + + "-------------" + "\n" + + stddev + + "\n" + // + ; + } + + // + // RVI ... + string rvi = + // + ((isRVILongStart || !ignoreFalseConditions) ? "isRVILongStart: " + ToString(isRVILongStart) + "\n" : "") + + ((isRVILongStop || !ignoreFalseConditions) ? "isRVILongStop: " + ToString(isRVILongStop) + "\n" : "") + + ((isRVIShortStart || !ignoreFalseConditions) ? "isRVIShortStart: " + ToString(isRVIShortStart) + "\n" : "") + + ((isRVIShortStop || !ignoreFalseConditions) ? "isRVIShortStop: " + ToString(isRVIShortStop) + "\n" : "") + + "" + // + ; + if (StringLen(rvi) > 0) + { + // + rvi = + // + "RVI:" + "\n" + + "-------------" + "\n" + + rvi + + "\n" + // + ; + } + + // + // RSI ... + string rsi = + // + ((isRSIOver50 || !ignoreFalseConditions) ? "isRSIOver50: " + ToString(isRSIOver50) + "\n" : "") + + ((isRSIUnder50 || !ignoreFalseConditions) ? "isRSIUnder50: " + ToString(isRSIUnder50) + "\n" : "") + + ((isRSIOver70 || !ignoreFalseConditions) ? "isRSIOver70: " + ToString(isRSIOver70) + "\n" : "") + + ((isRSIUnder30 || !ignoreFalseConditions) ? "isRSIUnder30: " + ToString(isRSIUnder30) + "\n" : "") + + "" + // + ; + if (StringLen(rsi) > 0) + { + // + rsi = + // + "RSI:" + "\n" + + "-------------" + "\n" + + rsi + + "\n" + // + ; + } + + // + // XCCI ... + string cci = + // + ((isCCIPositive || !ignoreFalseConditions) ? "isCCIPositive: " + ToString(isCCIPositive) + "\n" : "") + + ((isCCINegative || !ignoreFalseConditions) ? "isCCINegative: " + ToString(isCCINegative) + "\n" : "") + + ((isCCIOverPositiveHundred || !ignoreFalseConditions) ? "isCCIOverPositiveHundred: " + ToString(isCCIOverPositiveHundred) + "\n" : "") + + ((isCCIUnderNegativeHundred || !ignoreFalseConditions) ? "isCCIUnderNegativeHundred: " + ToString(isCCIUnderNegativeHundred) + "\n" : "") + + "" + // + ; + if (StringLen(cci) > 0) + { + // + cci = + // + "CCI:" + "\n" + + "-------------" + "\n" + + cci + + "\n" + // + ; + } + + // + // MACD ... + string macd = + // + ((isMACDPositiove || !ignoreFalseConditions) ? "isMACDPositiove: " + ToString(isMACDPositiove) + "\n" : "") + + ((isMACDNegative || !ignoreFalseConditions) ? "isMACDNegative: " + ToString(isMACDNegative) + "\n" : "") + + ((isMACDOverSignal || !ignoreFalseConditions) ? "isMACDOverSignal: " + ToString(isMACDOverSignal) + "\n" : "") + + ((isMACDUnderSignal || !ignoreFalseConditions) ? "isMACDUnderSignal: " + ToString(isMACDUnderSignal) + "\n" : "") + + "" + // + ; + if (StringLen(macd) > 0) + { + // + macd = + // + "MACD:" + "\n" + + "-------------" + "\n" + + macd + + "\n" + // + ; + } + + // + // BULLP ... + string bullp = + // + ((isBullPowerOverLast || !ignoreFalseConditions) ? "isBullPowerOverLast: " + ToString(isBullPowerOverLast) + "\n" : "") + + ((isBullPoswerUnderLast || !ignoreFalseConditions) ? "isBullPoswerUnderLast: " + ToString(isBullPoswerUnderLast) + "\n" : "") + + ((isBullPowerOverZero || !ignoreFalseConditions) ? "isBullPowerOverZero: " + ToString(isBullPowerOverZero) + "\n" : "") + + ((isBullPoswerUnderZero || !ignoreFalseConditions) ? "isBullPoswerUnderZero: " + ToString(isBullPoswerUnderZero) + "\n" : "") + + "" + // + ; + if (StringLen(bullp) > 0) + { + // + bullp = + // + "BullPower:" + "\n" + + "-------------" + "\n" + + bullp + + "\n" + // + ; + } + + // + // BEARP ... + string bearp = + // + ((isBearPowerOverLast || !ignoreFalseConditions) ? "isBearPowerOverLast: " + ToString(isBearPowerOverLast) + "\n" : "") + + ((isBearPoswerUnderLast || !ignoreFalseConditions) ? "isBearPoswerUnderLast: " + ToString(isBearPoswerUnderLast) + "\n" : "") + + ((isBearPowerOverZero || !ignoreFalseConditions) ? "isBearPowerOverZero: " + ToString(isBearPowerOverZero) + "\n" : "") + + ((isBearPoswerUnderZero || !ignoreFalseConditions) ? "isBearPoswerUnderZero: " + ToString(isBearPoswerUnderZero) + "\n" : "") + + "" + // + ; + if (StringLen(bearp) > 0) + { + // + bearp = + // + "BearPower:" + "\n" + + "-------------" + "\n" + + bearp + + "\n" + // + ; + } + + // + // STOCH ... + string stoch = + // + ((isStochKOverD || !ignoreFalseConditions) ? "isStochKOverD: " + ToString(isStochKOverD) + "\n" : "") + + ((isStochKUnderD || !ignoreFalseConditions) ? "isStochKUnderD: " + ToString(isStochKUnderD) + "\n" : "") + + ((isStochKDOver50 || !ignoreFalseConditions) ? "isStochKDOver50: " + ToString(isStochKDOver50) + "\n" : "") + + ((isStochKDOver80 || !ignoreFalseConditions) ? "isStochKDOver80: " + ToString(isStochKDOver80) + "\n" : "") + + ((isStochKDUnder20 || !ignoreFalseConditions) ? "isStochKDUnder20: " + ToString(isStochKDUnder20) + "\n" : "") + + ((isStochKDUnder50 || !ignoreFalseConditions) ? "isStochKDUnder50: " + ToString(isStochKDUnder50) + "\n" : "") + + "" + // + ; + if (StringLen(stoch) > 0) + { + // + stoch = + // + "Stoch:" + "\n" + + "-------------" + "\n" + + stoch + + "\n" + // + ; + } + + string osc = + // + stddev + + rvi + + rsi + + cci + + macd + + bullp + + bearp + + stoch + + "" + // + ; + if (StringLen(osc) > 0) + { + // + osc = + // + "XOSC:" + "\n" + + "-------------" + "\n" + + osc + + "\n" + // + ; + } + + // + result = + // + commons + + candlestic + + str + + che + + ich + + mc + + osc + + "" + // + ; + + // + return result; + } +}; + +// +// Class ... + +// +class XSC121Market +{ + // + // Public ... +public: + // + // Props ... + XSCX121MCHelper mc; + XSCX121STRHelper str; + XSCX121CHEHelper che; + XSCX121OSCHelper osc; + XSCX121ICHHelper ich; + + // + // Constructors ... + XSC121Market() {} + + // + // Deconstructors ... + ~XSC121Market() {} + + // + // Props ... + + // + // Retrieve Trading Symbol ... + string GetSymbol() + { + return mInputs.cycle.symbol; + } + + // + // Retrieve Cycle Time Frame ... + ENUM_TIMEFRAMES GetPeriod() + { + return mInputs.cycle.period; + } + + // + // Retrieve Market Host Time Frame ... + ENUM_TIMEFRAMES GetHostPeriod() + { + return mInputs.cycle.hostPeriod; + } + + // + // Retrieve Current Market Config ... + X121MCycleInputs GetInputs() + { + return mInputs; + } + + // + // Count Total Available Bars in Market ... + int CountBars() + { + // + Update(0); + return mInputs.cycle.CountBars(); + } + + // + // Check Market is in new Bar ... + int IsNewBar() + { + // + Update(0); + return mInputs.cycle.IsNewBar(); + } + + // + // Retrieve Current Cycles Specific Bar ... + XOHCL GetBar(int barIndex) + { + // + Update(0); + return mInputs.cycle.GetBar(barIndex); + } + + // + // Retrieve Current Bar Index based on Host Period bar Index ... + int GetBarIndex(int barIndex) + { + // + Update(barIndex); + return mInputs.cycle.GetBarIndex(barIndex); + } + + // + // Retrieve Bar Time ... + datetime GetBarTime(int barIndex) + { + // + Update(0); + return mInputs.cycle.GetBarTime(barIndex); + } + + // + // Set Market Inputs and Re Initial ... + bool SetInputs( + X121MCycleInputs &inputs // Config + ) + { + // + return Init(inputs); + } + + // + // Tools ... + + // + // Initial Market Cycle ... + bool Init( + X121MCycleInputs &inputs // Inputs for Initialization + ) + { + // + bool result = false; + + // + // Validate Input ... + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + string symbol = mInputs.cycle.symbol; + ENUM_TIMEFRAMES period = mInputs.cycle.period; + + // + // Init Helpers ... + + // + // XMC ... + result = mc.Init( + symbol, + period, + mInputs.mcInputs + // + ); + if (!result) + { + return result; + } + + // + // XSTR ... + result = str.Init( + symbol, + period, + mInputs.strInputs + // + ); + if (!result) + { + return result; + } + + // + // XCHE ... + result = che.Init( + symbol, + period, + mInputs.cheInputs + // + ); + if (!result) + { + return result; + } + + // + // XOSC ... + result = osc.Init( + symbol, + period, + mInputs.oscInputs + // + ); + if (!result) + { + return result; + } + + // + // XICH ... + result = ich.Init( + symbol, + period, + mInputs.ichInputs + // + ); + if (!result) + { + return result; + } + + // + return result; + } + + // + // Retrieve Current Market Conditions ... + X121MCycleConditions GetMarketConditions( + int barIndex // Specified Bar Index + ) + { + // + X121MCycleConditions result; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex >= CountBars()) + { + barIndex = CountBars() + 2; + } + + // + // Here i Have to Calculate Market Conditions based on + // Several Indicator/Oscillator(s) ... + + // + // Set Commons ... + result.time = GetBarTime(barIndex); + result.cycle = mInputs.cycle.cycle; + result.prefix = mInputs.cycle.prefix; + result.symbol = mInputs.cycle.symbol; + result.period = mInputs.cycle.period; + result.hostPeriod = mInputs.cycle.hostPeriod; + + // + Clean(result.bars); + GetBars( + result.bars, + result.symbol, + result.period, + barIndex, + barIndex + 5); + + // + XOHCL cBar = GetBar(barIndex); + XOHCL pBar = GetBar(barIndex + 1); + + // + // CANDELSTICK ... + + // + bool isLastBullish = + // + pBar.IsBullish() + // + ; + + // + bool isLastBearish = + // + pBar.IsBearish() + // + ; + + // + bool isCurrentBullish = + // + cBar.IsBullish() + // + ; + + // + bool isCurrentBearish = + // + cBar.IsBearish() + // + ; + + // + bool isCurrentMidLineOverLastHigh = + // + cBar.GetMid() > pBar.high; + // + ; + + // + bool isCurrentMidLineUnderLastLow = + // + cBar.GetMid() < pBar.low + // + ; + + // + bool isCurrentMidLineOverLastUp = + // + cBar.GetMid() > pBar.GetUp() + // + ; + + // + bool isCurrentMidLineUnderLastDown = + // + cBar.GetMid() < pBar.GetDown() + // + ; + + // + bool isCurrentMidLineOverLastMidLine = + // + cBar.GetMid() > pBar.GetMid() + // + ; + + // + bool isCurrentMidLineUnderLastMidLine = + // + cBar.GetMid() < pBar.GetMid() + // + ; + + // + result.isLastBullish = isLastBullish; + result.isLastBearish = isLastBearish; + result.isCurrentBullish = isCurrentBullish; + result.isCurrentBearish = isCurrentBearish; + result.isCurrentMidLineOverLastHigh = isCurrentMidLineOverLastHigh; + result.isCurrentMidLineUnderLastLow = isCurrentMidLineUnderLastLow; + result.isCurrentMidLineOverLastUp = isCurrentMidLineOverLastUp; + result.isCurrentMidLineUnderLastDown = isCurrentMidLineUnderLastDown; + result.isCurrentMidLineOverLastMidLine = isCurrentMidLineOverLastMidLine; + result.isCurrentMidLineUnderLastMidLine = isCurrentMidLineUnderLastMidLine; + + // + // XSTR ... + bool isTrendBullish = + // + str.IsBullish(str.GetState(barIndex)) + // + ; + bool isTrendBearish = + // + str.IsBearish(str.GetState(barIndex)) + // + ; + + // + result.isTrendBullish = isTrendBullish; + result.isTrendBearish = isTrendBearish; + + // + // XCHE ... + bool isCHEInLong = + // + NotEmpty(che.GetLongExit1(barIndex)) + // + ; + bool isCHEInStrongLong = + // + isCHEInLong && + NotEmpty(che.GetLongExit2(barIndex)) + // + ; + bool isCHEInShort = + // + NotEmpty(che.GetShortExit1(barIndex)) + // + ; + bool isCHEInStrongShort = + // + isCHEInShort && + NotEmpty(che.GetShortExit2(barIndex)) + // + ; + + // + result.isCHEInLong = isCHEInLong; + result.isCHEInShort = isCHEInShort; + result.isCHEInStrongLong = isCHEInStrongLong; + result.isCHEInStrongShort = isCHEInStrongShort; + + // + // XMC ... + + // + double fasts[]; + mc.CopyFast( + barIndex, + 2, + fasts + // + ); + + // + double slows[]; + mc.CopySlow( + barIndex, + 2, + slows + // + ); + + // + double verifiers[]; + mc.CopyVerifier( + barIndex, + 2, + verifiers + // + ); + + // + bool isFastOverSlow = + // + fasts[0] > slows[0] && + fasts[1] > slows[1] + // + ; + bool isFastUnderSlow = + // + fasts[0] < slows[0] && + fasts[1] < slows[1] + // + ; + bool isFastOverVerifier = + // + fasts[0] > verifiers[0] && + fasts[1] > verifiers[1] + // + ; + bool isFastUnderVerifier = + // + fasts[0] < verifiers[0] && + fasts[1] < verifiers[1] + // + ; + bool isSlowOverVerifier = + // + slows[0] > verifiers[0] && + slows[1] > verifiers[1] + // + ; + bool isSlowUnderVerifier = + // + slows[0] < verifiers[0] && + slows[1] < verifiers[1] + // + ; + bool isCloseOverFast = + // + pBar.close > fasts[1] + // + ; + bool isCloseUnderFast = + // + pBar.close < fasts[1] + // + ; + bool isCloseOverSlow = + // + pBar.close > slows[1] + // + ; + bool isCloseUnderSlow = + // + pBar.close < slows[1] + // + ; + bool isCloseOverVerifier = + // + pBar.close > verifiers[1] + // + ; + bool isCloseUnderVerifier = + // + pBar.close < verifiers[1] + // + ; + + // + result.isFastOverSlow = isFastOverSlow; + result.isFastUnderSlow = isFastUnderSlow; + result.isFastOverVerifier = isFastOverVerifier; + result.isFastUnderVerifier = isFastUnderVerifier; + result.isSlowOverVerifier = isSlowOverVerifier; + result.isSlowUnderVerifier = isSlowUnderVerifier; + result.isCloseOverFast = isCloseOverFast; + result.isCloseUnderFast = isCloseUnderFast; + result.isCloseOverSlow = isCloseOverSlow; + result.isCloseUnderSlow = isCloseUnderSlow; + result.isCloseOverVerifier = isCloseOverVerifier; + result.isCloseUnderVerifier = isCloseUnderVerifier; + + // + // XICH ... + + // + // XOSC ... + + // + // STDDEV ... + + // + double stdDev = osc.GetSTDDEV(barIndex); + double stdDevLast = osc.GetSTDDEV(barIndex + 1); + double stdDevs[]; + osc.CopySTDDEV( + barIndex + 1, + 5, + stdDevs // + ); + double stdDevAVG = GetAverage(stdDevs); + + // + bool isSTDDEVOverAVG = + // + stdDev > stdDevAVG + // + ; + bool isSTDDEVUnderAVG = + // + stdDev < stdDevAVG + // + ; + bool isSTDDEVOverLast = + // + stdDev > stdDevLast + // + ; + bool isSTDDEVUnderLast = + // + stdDev < stdDevLast + // + ; + + // + result.isSTDDEVOverAVG = isSTDDEVOverAVG; + result.isSTDDEVUnderAVG = isSTDDEVUnderAVG; + result.isSTDDEVOverLast = isSTDDEVOverLast; + result.isSTDDEVUnderLast = isSTDDEVUnderLast; + + // + // RVI ... + + // + double rvi = osc.GetRVI(barIndex); + double rviSignal = osc.GetRVISignal(barIndex); + + // + bool isRVILongStart = + // + rvi > 0 && + rviSignal > 0 && + rvi > rviSignal + // + ; + bool isRVILongStop = + // + rvi < 0 && + rviSignal < 0 && + rvi < rviSignal + // + ; + bool isRVIShortStart = + // + rvi < 0 && + rviSignal < 0 && + rvi < rviSignal + // + ; + bool isRVIShortStop = + // + rvi > 0 && + rviSignal > 0 && + rvi > rviSignal + // + ; + + // + result.isRVILongStart = isRVILongStart; + result.isRVILongStop = isRVILongStop; + result.isRVIShortStart = isRVIShortStart; + result.isRVIShortStop = isRVIShortStop; + + // + // RSI ... + double rsi = osc.GetRSI(barIndex); + + // + bool isRSIUnder50 = + // + rsi < 50 + // + ; + bool isRSIOver70 = + // + rsi > 70 + // + ; + bool isRSIOver50 = + // + rsi > 50 + // + ; + bool isRSIUnder30 = + // + rsi < 30 + // + ; + + // + result.isRSIUnder50 = isRSIUnder50; + result.isRSIOver70 = isRSIOver70; + result.isRSIOver50 = isRSIOver50; + result.isRSIUnder30 = isRSIUnder30; + + // + // BULLPOWER ... + + // + double bullp = osc.GetBullPower(barIndex); + double bullpLast = osc.GetBullPower(barIndex + 1); + + // + bool isBullPowerOverLast = + // + bullp > bullpLast + // + ; + bool isBullPoswerUnderLast = + // + bullp < bullpLast + // + ; + bool isBullPowerOverZero = + // + bullp > 0 + // + ; + bool isBullPoswerUnderZero = + // + bullp < 0 + // + ; + + // + result.isBullPowerOverLast = isBullPowerOverLast; + result.isBullPoswerUnderLast = isBullPoswerUnderLast; + result.isBullPowerOverZero = isBullPowerOverZero; + result.isBullPoswerUnderZero = isBullPoswerUnderZero; + + // + // BEARPOWER ... + + // + double bearp = osc.GetBearPower(barIndex); + double bearpLast = osc.GetBearPower(barIndex + 1); + + // + bool isBearPowerOverLast = + // + bearp > bearpLast + // + ; + bool isBearPoswerUnderLast = + // + bearp < bearpLast + // + ; + bool isBearPowerOverZero = + // + bearp > 0 + // + ; + bool isBearPoswerUnderZero = + // + bearp < 0 + // + ; + + // + result.isBearPowerOverLast = isBearPowerOverLast; + result.isBearPoswerUnderLast = isBearPoswerUnderLast; + result.isBearPowerOverZero = isBearPowerOverZero; + result.isBearPoswerUnderZero = isBearPoswerUnderZero; + + // + // CCI ... + + // + double cci = osc.GetCCI(barIndex); + + // + bool isCCIPositive = + // + cci > 0 + // + ; + bool isCCINegative = + // + cci < 0 + // + ; + bool isCCIOverPositiveHundred = + // + cci > 100 + // + ; + bool isCCIUnderNegativeHundred = + // + cci < -100 + // + ; + + // + result.isCCIPositive = isCCIPositive; + result.isCCINegative = isCCINegative; + result.isCCIOverPositiveHundred = isCCIOverPositiveHundred; + result.isCCIUnderNegativeHundred = isCCIUnderNegativeHundred; + + // + // MACD ... + + // + double macd = osc.GetMACD(barIndex); + double macdSignal = osc.GetMACDSignal(barIndex); + + // + bool isMACDPositiove = + // + macd > 0 + // + ; + bool isMACDNegative = + // + macd < 0 + // + ; + bool isMACDOverSignal = + // + macd > macdSignal + // + ; + bool isMACDUnderSignal = + // + macd < macdSignal + // + ; + + // + result.isMACDPositiove = isMACDPositiove; + result.isMACDNegative = isMACDNegative; + result.isMACDOverSignal = isMACDOverSignal; + result.isMACDUnderSignal = isMACDUnderSignal; + + // + // STOCH ... + + // + double stoch = osc.GetSTOCH(barIndex); + double stochSignal = osc.GetSTOCHSignal(barIndex); + + // + bool isStochKOverD = + // + stoch > stochSignal + // + ; + bool isStochKDUnder50 = + // + stoch < 50 && + stochSignal < 50 + // + ; + bool isStochKUnderD = + // + stoch < stochSignal + // + ; + bool isStochKDOver50 = + // + stoch > 50 && + stochSignal > 50 + // + ; + bool isStochKDUnder20 = + // + stoch < 20 && + stochSignal < 20 + // + ; + bool isStochKDOver80 = + // + stoch > 80 && + stochSignal > 80 + // + ; + + // + result.isStochKOverD = isStochKOverD; + result.isStochKDUnder50 = isStochKDUnder50; + result.isStochKUnderD = isStochKUnderD; + result.isStochKDOver50 = isStochKDOver50; + result.isStochKDUnder20 = isStochKDUnder20; + result.isStochKDOver80 = isStochKDOver80; + + // + return result; + } + + // + // Completely Draw Bars ... + void Draw( + long chartID, // Chart ID ... + int subWindow, // Chart Sub Window ... + int &offset // Distance used for Labels ... + ) + { + // + if (mInputs.drawCBar || mInputs.drawPBar) + { + // + DrawOHCL( + chartID, + subWindow, + mInputs.drawLabels, + !mInputs.drawCBar && mInputs.drawPBar, + !mInputs.drawPBar && mInputs.drawCBar, + offset + // + ); + + // + if (mInputs.drawLabels) + { + offset += 3; + } + } + + // + if (mInputs.drawCBarMid || mInputs.drawPBarMid) + { + // + DrawMidLine( + chartID, + subWindow, + mInputs.drawLabels, + !mInputs.drawCBarMid && mInputs.drawPBarMid, + !mInputs.drawPBarMid && mInputs.drawCBarMid, + offset + // + ); + + // + if (mInputs.drawLabels) + { + // + if (mInputs.drawCBarMid) + { + offset++; + } + + // + if (mInputs.drawPBarMid) + { + offset++; + } + } + } + } + + // + // Draw Functions ... + // + // Draw Middle Line of Cycle ... + void DrawOHCL( + long chartID, + int subWindow, + bool drawLabel = false, // Specify Draw Label of Mid Line or not ... + bool drawOnlyPrev = false, // Specify Draw Only Prev Bar of Cycle ... + bool drawOnlyCurrent = false, // Specify Draw Only Current Bar of Cycle ... + int offset = 0 // Distance used for Labels ... + ) + { + // + if (offset < 0) + { + offset = 0; + } + + // + string baseTag = ToString(mInputs.cycle.cycle); + + // + XOHCL cBar = GetBar(0); + XOHCL pBar = GetBar(1); + + // + datetime fromCDate = GetBarTime(0); + datetime fromPDate = GetBarTime(1); + + // + datetime cTime = TimeCurrent(); + + // + // Try to Draw ... + + // + bool canDrawPrev = !drawOnlyCurrent; + bool canDrawCurrent = !drawOnlyPrev; + + // + // Set Cycles Color based on Current Candle ... + + // + bool isCBarBullish = + cBar.IsBullish(); + + // + bool isPBarBullish = + pBar.IsBearish(); + + // + color clrTemoBullishColor = mInputs.cBarDrawSpecs.openStyle.clr; + color clrTemoBearishColor = mInputs.cBarDrawSpecs.closeStyle.clr; + + // + color cBarSelectedColor = isCBarBullish ? clrTemoBullishColor : clrTemoBearishColor; + color pBarSelectedColor = isPBarBullish ? clrTemoBullishColor : clrTemoBearishColor; + + // + mInputs.cBarDrawSpecs.openStyle.clr = cBarSelectedColor; + mInputs.cBarDrawSpecs.openStyle.labelColor = cBarSelectedColor; + + // + mInputs.cBarDrawSpecs.closeStyle.clr = cBarSelectedColor; + mInputs.cBarDrawSpecs.closeStyle.labelColor = cBarSelectedColor; + + // + mInputs.pBarDrawSpecs.openStyle.clr = pBarSelectedColor; + mInputs.pBarDrawSpecs.openStyle.labelColor = pBarSelectedColor; + + // + mInputs.pBarDrawSpecs.closeStyle.clr = pBarSelectedColor; + mInputs.pBarDrawSpecs.closeStyle.labelColor = pBarSelectedColor; + + // + if (canDrawPrev) + { + offset++; + } + + // + // Label ... + if (drawLabel) + { + // + if (canDrawPrev) + { + // + // Draw Prev Bar Lables ... + + // + DrawXOHCLLabel( + chartID, + subWindow, + pBar, + mInputs.pBarDrawSpecs, + "P", + cTime, + offset - 1 + // + ); + + // + offset += 3; + } + + // + if (canDrawCurrent) + { + // + // Draw Current Bar Lables ... + + // + DrawXOHCLLabel( + chartID, + subWindow, + cBar, + mInputs.cBarDrawSpecs, + "C", + cTime, + offset + // + ); + } + } + + // + // Line ... + + // + if (canDrawPrev) + { + // + // Draw Cycle Prev Bar ... + DrawXOHCLContent( + chartID, + subWindow, + pBar, + mInputs.pBarDrawSpecs, + "P", + fromPDate + // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Cycle Current Bar ... + DrawXOHCLContent( + chartID, + subWindow, + cBar, + mInputs.cBarDrawSpecs, + "C", + fromCDate + // + ); + } + } + + // + // Draw Middle Line of Cycle ... + void DrawMidLine( + long chartID, + int subWindow, + bool drawLabel = false, // Specify Draw Label of Mid Line or not ... + bool drawOnlyPrev = false, // Specify Draw Only Prev Bar of Cycle ... + bool drawOnlyCurrent = false, // Specify Draw Only Current Bar of Cycle ... + int offset = 0 // Distance used for Labels ... + ) + { + // + if (offset < 0) + { + offset = 0; + } + + // + // Calculate Mid Line ... + XOHCL cBar = GetBar(0); + double cMidLine = cBar.GetMid(); + + // + XOHCL pBar = GetBar(1); + double pMidLine = pBar.GetMid(); + + // + string baseTag = ToString(mInputs.cycle.cycle); + + // + string midCTag = baseTag + "|MID|C|"; + string midPTag = baseTag + "|MID|P|"; + + // + string midCLblTag = midCTag + "lbl"; + string midPLblTag = midPTag + "lbl"; + + // + datetime fromCDate = GetBarTime(0); + datetime fromPDate = GetBarTime(1); + + // + datetime cTime = TimeCurrent(); + + // + // Try to Draw ... + + // + bool canDrawPrev = !drawOnlyCurrent; + bool canDrawCurrent = !drawOnlyPrev; + + // + if (canDrawPrev) + { + offset++; + } + + // + // Label ... + if (drawLabel) + { + // + if (canDrawPrev) + { + // + // Draw Prev Candle MidLine Lable ... + DrawLabel( + chartID, + subWindow, + mInputs.pBarMidDrawSpecs, + midPLblTag, + cTime, + pMidLine, + offset // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Current Candle MidLine Label ... + DrawLabel( + chartID, + subWindow, + mInputs.cBarMidDrawSpecs, + midCLblTag, + cTime, + cMidLine, + offset - 1 // + ); + } + } + + // + // Line ... + + // + if (canDrawPrev) + { + // + // Draw Prev Candle MidLine ... + DrawLine( + chartID, + subWindow, + mInputs.pBarMidDrawSpecs, + midPTag, + fromPDate, + pMidLine // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Current Candle MidLine ... + DrawLine( + chartID, + subWindow, + mInputs.cBarMidDrawSpecs, + midCTag, + fromCDate, + cMidLine // + ); + } + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + + // + X121MCycleInputs mInputs; + + // + // Tools ... + + // + bool Update(int hostBarIndex = 0) + { + return mInputs.cycle.Update(hostBarIndex); + } + + // + // Draw Functions ... + // + // Draw OHCL Labels ... + void DrawXOHCLLabel( + long chartID, + int subWindow, + XOHCL &bar, // Specify Cycle XOHCL Model to Draw ... + XOHCLDrawSpecification &specs, // Specify Cycle XOHCL Draw Specifications ... + string baseTag, // Specify a Unique Tag ... + datetime time, // Draw Time ... + int offset = 0 // + ) + { + // + // Open ... + string openTag = mInputs.cycle.prefix + "_" + baseTag + "_O_lbl"; + DrawLabel( + chartID, + subWindow, + specs.openStyle, + openTag, + time, + bar.open, + offset + // + ); + + // + // High ... + string highTag = mInputs.cycle.prefix + "_" + baseTag + "_H_lbl"; + DrawLabel( + chartID, + subWindow, + specs.highStyle, + highTag, + time, + bar.high, + offset + 1 + // + ); + + // + // Close ... + string closeTag = mInputs.cycle.prefix + "_" + baseTag + "_C_lbl"; + DrawLabel( + chartID, + subWindow, + specs.closeStyle, + closeTag, + time, + bar.close, + offset + 2 + // + ); + + // + // Low ... + string lowTag = mInputs.cycle.prefix + "_" + baseTag + "_L_lbl"; + DrawLabel( + chartID, + subWindow, + specs.lowStyle, + lowTag, + time, + bar.low, + offset + 3 + // + ); + } + + // + // Draw XOHCL Content ... + void DrawXOHCLContent( + long chartID, + int subWindow, + XOHCL &bar, // Specify Cycle XOHCL Model to Draw ... + XOHCLDrawSpecification &specs, // Specify Cycle XOHCL Draw Specifications ... + string baseTag, // Specify a Unique Tag ... + datetime time // Draw Time ... + ) + { + // + // Open ... + string openTag = mInputs.cycle.prefix + "_" + baseTag + "_O"; + DrawLine( + chartID, + subWindow, + specs.openStyle, + openTag, + time, + bar.open + // + ); + + // + // High ... + string highTag = mInputs.cycle.prefix + "_" + baseTag + "_H"; + DrawLine( + chartID, + subWindow, + specs.highStyle, + highTag, + time, + bar.high + // + ); + + // + // Close ... + string closeTag = mInputs.cycle.prefix + "_" + baseTag + "_C"; + DrawLine( + chartID, + subWindow, + specs.closeStyle, + closeTag, + time, + bar.close + // + ); + + // + // Low ... + string lowTag = mInputs.cycle.prefix + "_" + baseTag + "_L"; + DrawLine( + chartID, + subWindow, + specs.lowStyle, + lowTag, + time, + bar.low + // + ); + } + + // + // Draw Label Using Specifications ... + void DrawLabel( + long chartID, + int subWindow, + XDrawSpecifications &specs, + string tag, + datetime time, + double price, + int offset = 0 // + ) + { + // + if (offset < 0) + { + offset = 0; + } + + // + int offsetSeconds = PeriodSeconds(mInputs.cycle.hostPeriod) * offset; + + // + string value = specs.label; + + // + DrawText( + chartID, + tag, + subWindow, + time - offsetSeconds, + price, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw TrendLine Using Specifications ... + void DrawLine( + long chartID, + int subWindow, + XDrawSpecifications &specs, + string tag, + datetime fromDate, + double fromPrice, + datetime toDate = NULL, + double toPrice = 0 // + ) + { + // + if (toPrice <= 0) + { + toPrice = fromPrice; + } + + // + if (toDate == 0 || toDate == NULL) + { + toDate = TimeCurrent(); + } + + // + DrawTrendLine( + chartID, + tag, + subWindow, + fromDate, + fromPrice, + toDate, + toPrice, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); + } +}; diff --git a/MQLTestWorkspace/Classes/x-saherelm.xaccount.class.ex5 b/MQLTestWorkspace/Classes/x-saherelm.xaccount.class.ex5 new file mode 100644 index 0000000..afafc70 Binary files /dev/null and b/MQLTestWorkspace/Classes/x-saherelm.xaccount.class.ex5 differ diff --git a/MQLTestWorkspace/Classes/x-saherelm.xdata-collector.ex5 b/MQLTestWorkspace/Classes/x-saherelm.xdata-collector.ex5 new file mode 100644 index 0000000..fc681af Binary files /dev/null and b/MQLTestWorkspace/Classes/x-saherelm.xdata-collector.ex5 differ diff --git a/MQLTestWorkspace/Classes/x-saherelm.xdata-collector.mq5 b/MQLTestWorkspace/Classes/x-saherelm.xdata-collector.mq5 new file mode 100644 index 0000000..5a2c9ed --- /dev/null +++ b/MQLTestWorkspace/Classes/x-saherelm.xdata-collector.mq5 @@ -0,0 +1,444 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCDataCollector +// Description: provides Data Collection 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 "../Libraries/x-saherelm.common.lib.mq5" + +// +template +class XSCDataCollector +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + void XSCDataCollector( + string path = NULL, // Base Folder for Data Store + string fileName = NULL // File Name for Data Store + ) + { + // + if (!IsValid(path)) + { + path = GetType(); + } + + // + if (!IsValid(fileName)) + { + fileName = GetType() + ".txt"; + } + + // + Path(path); + FileName(fileName); + } + + // + // Deconstructor ... + void ~XSCDataCollector() {} + + // + // Properties ... + + // + bool Path(string value) + { + // + bool result = false; + + // + result = IsValid(value); + if (!result) + { + return result; + } + + // + result = value != mPath; + if (!result) + { + return result; + } + + // + mPath = value; + + // + return result; + } + + // + string Path() + { + return mPath; + } + + // + bool FileName(string value) + { + // + bool result = false; + + // + result = IsValid(value); + if (!result) + { + return result; + } + + // + result = value != mFileName; + if (!result) + { + return result; + } + + // + mFileName = value; + + // + return result; + } + + // + string FileName() + { + return mFileName; + } + + // + // Tools ... + + // + // Clear Exists Collected Data ... + void Clear() + { + // + ResetLastError(); + + // + string dataStorePath = GetStorePath(); + + // + // Check Data Store Exists or not ... + bool isExists = FileIsExist(dataStorePath); + if (!isExists) + { + return; + } + + // + FileDelete(dataStorePath); + } + + // + // Collect All Stored Items ... + int Collect( + T &items[] // Hold Result + ) + { + // + int result = 0; + + // + Clean(items); + + // + // Reading Store Whole Content ... + + // + string storePath = GetStorePath(); + int mFileHandler = FileOpen( + storePath, + FILE_READ | FILE_TXT); + result = mFileHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // Parse Store Content and Read Data ... + while (!FileIsEnding(mFileHandler)) + { + // + // Each Line Represent One Model ... + string content = FileReadString(mFileHandler); + + // + T iItem; + bool isValid = iItem.Parse(content); + if (isValid) + { + // + AddRef( + iItem, + items + // + ); + } + } + + // + // Close File ... + FileClose(mFileHandler); + + // + result = ArraySize(items); + + // + return result; + } + + // + // Add Item ... + bool Add( + T &item // Item to Store + ) + { + // + bool result = false; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + string content = item.ToString(); + result = IsValid(content); + if (!result) + { + return result; + } + + // + string storePath = GetStorePath(); + int mFileHandler = FileOpen( + storePath, + FILE_READ | FILE_WRITE | FILE_TXT); + result = mFileHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileSeek(mFileHandler, 0, SEEK_END); + FileWrite(mFileHandler, content); + FileFlush(mFileHandler); + FileClose(mFileHandler); + + // + return result; + } + + // + // Add Items ... + int Add( + T &items[] // Items to Add ... + ) + { + // + int result = 0; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < itemsCount; i++) + { + // + T iItem = items[i]; + + // + if (!iItem.IsValid()) + { + continue; + } + + // + bool isAdded = Add(iItem); + if (isAdded) + { + result++; + } + } + + // + return result; + } + + // + // Remove Item ... + bool Remove( + T &item // Item to Remove + ) + { + // + bool result = false; + + // + result = item.IsValid(); + if (!result) + { + return result; + } + + // + T items[]; + int itemsCount = Collect(items); + if (itemsCount <= 0) + { + return result; + } + + // + int itemIndex = item.FindIndex(items); + result = ArrayRemove( + items, + itemIndex, + 1); + if (!result) + { + return result; + } + + // + Clear(); + + // + int itemsAdded = Add(items); + + // + result = itemsAdded == ArraySize(items); + + // + return result; + } + + // + // Protected ... +protected: + // + // Tools ... + + // + // Retrieve Type of Class as String ... + string GetType() + { + // + string mType = (string) typename(T); + + // + string result = mType; + + // + string parts[]; + int partsCount = SplitContent( + parts, + result, + " " + // + ); + if (partsCount <= 0) + { + // + result = mType; + return result; + } + + // + bool hasLastPart = GetLastItem( + result, + parts + // + ); + if (!hasLastPart) + { + // + result = mType; + return result; + } + + // + return result; + } + + // + // Pricate ... +private: + // + // Props ... + + // + string mPath; // Path + string mFileName; // Data Store File Name + + // + // Tools ... + + // + // Generate Full File Path ... + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + Path() + "\\" + fileName + // + ; + + // + return result; + } + + // + // Retrieve Data Store File Address ... + string GetStorePath() + { + // + string result = NULL; + + // + result = GetFilePath(mFileName); + + // + return result; + } +}; + +// \ No newline at end of file diff --git a/MQLTestWorkspace/Classes/x-saherelm.xea.class.ex5 b/MQLTestWorkspace/Classes/x-saherelm.xea.class.ex5 index a52c19f..8d6e45c 100644 Binary files a/MQLTestWorkspace/Classes/x-saherelm.xea.class.ex5 and b/MQLTestWorkspace/Classes/x-saherelm.xea.class.ex5 differ diff --git a/MQLTestWorkspace/Classes/x-saherelm.xea.class.mq5 b/MQLTestWorkspace/Classes/x-saherelm.xea.class.mq5 index 92dbc7f..626a8cd 100644 --- a/MQLTestWorkspace/Classes/x-saherelm.xea.class.mq5 +++ b/MQLTestWorkspace/Classes/x-saherelm.xea.class.mq5 @@ -23,6 +23,17 @@ // START Definitions ... // +// +// if Signal Execution Failed this is the reason ... +enum ENUM_X_SIGNAL_EXECUTION_FAILED +{ + X_NOTHING, // Succeeded ... + X_UNKNOWN, // Failed, but Unknown ... + X_FAILED_REASON_EQUITY, // Failed, Since Equity ... + X_FAILED_REASON_SPREAD, // Failed, Since Spread ... + X_FAILED_REASON_MAX_REACHED // Failed Signce Max Allowed Reached ... +}; + // // END Definitions ... // @@ -81,16 +92,21 @@ public: // // Constructor ... void XSCBaseEA( - string symbol, // Trading Symbol - ENUM_TIMEFRAMES period, // Trading Time Frame - ulong magic, // Magic Number - int slippage, // Slippgae - OnStopLoss onStopLossTriggered = NULL, // On StopLoass Triggered Event Handler - OnTakeProfit onTakeProfitTriggered = NULL, // On TakeProfit Triggered Event Handler - OnDealsChanged onDealsChangedHandler = NULL, // On Deals Changed Event Handler - OnOrdersChanged onOrdersChangedHandler = NULL, // On Orders Changed Event Handler - OnPositionsChanged onPositionsChangedHandler = NULL, // On Positions Changed Event Handler - OnTradeStateChanged onTradeStateChangedHandler = NULL // On Trade State Changed Event Handler + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Time Frame + ulong magic, // Magic Number + int slippage, // Slippgae + double maxAllowedSpread, // Max Allowed Spread to Execute Signal + int maxAllowedPositions, // Maximum Allowed Same Time Position + double minProfitPerTrade, // Min Profit Per Trade based On Volume Factor (Hedge) + double minProfitPerVolumeFactor, // Min Volume Factor for Calculating Profit (Hedge) + double maxAllowedDrawDownFactor, // Max Allowed Drawdown factor for Open New Positions + TOnStopLoss onStopLossTriggered = NULL, // On StopLoass Triggered Event Handler + TOnTakeProfit onTakeProfitTriggered = NULL, // On TakeProfit Triggered Event Handler + TOnDealsChanged onDealsChangedHandler = NULL, // On Deals Changed Event Handler + TOnOrdersChanged onOrdersChangedHandler = NULL, // On Orders Changed Event Handler + TOnPositionsChanged onPositionsChangedHandler = NULL, // On Positions Changed Event Handler + TOnTradeStateChanged onTradeStateChangedHandler = NULL // On Trade State Changed Event Handler ) { // @@ -101,6 +117,17 @@ public: mMagic = magic; mSlippage = slippage; + // + mMaxAllowedSpread = maxAllowedSpread; + + // + mMaxAllowedPositions = maxAllowedPositions; + mMaxAllowedDrawDownFactor = maxAllowedDrawDownFactor; + + // + mMinProfitPerTrade = minProfitPerTrade; + mMinProfitPerVolumeFactor = minProfitPerVolumeFactor; + // mOnStopLossTriggered = onStopLossTriggered; mOnTakeProfitTriggered = onTakeProfitTriggered; @@ -163,6 +190,167 @@ public: return mSlippage; } + // + // Check Long Signalling State ... + bool EnableLongs() + { + return mEnableLongs; + } + + // + // Set Long Signalling State ... + void EnableLongs(bool enable) + { + // + if (enable == mEnableLongs) + { + return; + } + + // + mEnableLongs = enable; + } + + // + // Check Short Signalling State ... + bool EnableShorts() + { + return mEnableShorts; + } + + // + // Set Short Signalling State ... + void EnableShorts(bool enable) + { + // + if (enable == mEnableShorts) + { + return; + } + + // + mEnableShorts = enable; + } + + // + double MaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + // + void MaxAllowedSpread(double value) + { + // + if (value <= 0) + { + value = 0; + } + + // + if (value == mMaxAllowedSpread) + { + return; + } + + // + mMaxAllowedSpread = value; + } + + // + // Get Max Allowed Positions at Same Time ... + int MaxAllowedPositions() + { + return mMaxAllowedPositions; + } + + // + // Set Max Allowed Positions at Same Time ... + void MaxAllowedPositions(int value) + { + // + if (value < 0 || + value == mMaxAllowedPositions) + { + return; + } + + // + mMaxAllowedPositions = value; + } + + // + // Get Max Allowed DrawDown Factor ... + double MaxAllowedDrawDownFactor() + { + return mMaxAllowedDrawDownFactor; + } + + // + // Set Max Allowed Positions at Same Time ... + void MaxAllowedDrawDownFactor(double value) + { + // + if (value < 0 || + value == mMaxAllowedDrawDownFactor) + { + return; + } + + // + mMaxAllowedDrawDownFactor = value; + } + + // + double MinProfitPerTrade() + { + return mMinProfitPerTrade; + } + + // + void MinProfitPerTrade(double value) + { + // + if (value <= 0) + { + value = 0; + } + + // + if (value == mMinProfitPerTrade) + { + return; + } + + // + mMinProfitPerTrade = value; + } + + // + double MinProfitPerVolumeFactor() + { + return mMinProfitPerVolumeFactor; + } + + // + void MinProfitPerVolumeFactor(double value) + { + // + if (value <= 0) + { + value = 0; + } + + // + if (value == mMinProfitPerVolumeFactor) + { + return; + } + + // + mMinProfitPerVolumeFactor = value; + } + // // END Properties ... // @@ -191,16 +379,21 @@ public: // // Check any Registered Providers Signalling ... - virtual bool SignalCheck(XSignal &signals[]) { + virtual bool SignalCheck(XSignal &signals[]) + { return false; } // // Check for any Custom Guard Actions Guard Actions ... - virtual bool CheckGuard(XGuard &guards[]) { + virtual bool CheckGuard(XGuard &guards[]) + { return false; } + // + virtual void BeforeSignalExecution(XSignal &signals[]) {} + // // NOTE: you have to call these Functions on Static Classes to Handle Works ... @@ -237,17 +430,76 @@ public: { // // First Check Guards .... + // Only when Open Positions Exists or Has Pending Order ... XGuard guards[]; bool hasGuard = CheckGuard(guards); - if (hasGuard) { + if (hasGuard) + { DoGuards(guards); } // XSignal signals[]; bool hasSignal = SignalCheck(signals); - if (hasSignal) { - mTrader.ExecuteSignals(signals); + if (hasSignal) + { + // + // Here we have to Check Signals and also it's State ... + XSignal enabledSignals[]; + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return; + } + + // + // Filter Signals by their type and + // also Check EA Enable their type ... + for (int i = 0; i < signalsCount; i++) + { + // + XSignal iSignal = signals[i]; + bool isLong = IsLong(iSignal.type); + if ((isLong && mEnableLongs) || + (!isLong && mEnableShorts)) + { + // + Add( + iSignal, + enabledSignals); + } + } + + // + int enabledSignalsCount = ArraySize(enabledSignals); + if (enabledSignalsCount <= 0) + { + return; + } + + // + // Here we have do All things before Signals Execution ... + // in this way we can implement custom searios on Inherited Classes ... + BeforeSignalExecution(enabledSignals); + + // + // Now double chack signals Array .... + // if there isn't any signal we prevent moving forward ... + // this helps us to Manage Signal Executions on Above Part ... + // for inherited classes ... + enabledSignalsCount = ArraySize(enabledSignals); + if (enabledSignalsCount <= 0) + { + return; + } + + // + ENUM_X_SIGNAL_EXECUTION_FAILED reasons[]; + ExecuteSignals( + enabledSignals, + reasons, + true // Check Policiese ... + ); } } @@ -257,7 +509,7 @@ public: { // XOnTradeHandlerState state = mTrader.HandleOnTrade(); - + // if ( !state.hasNewDeal && @@ -334,74 +586,137 @@ public: // // TOOLS ... + // - void GetPositions( - XPosition &result[], // Hold Result ... - string symbol = NULL, // Trading Symbol ... - ENUM_POSITION_TYPE type = NULL, // Trading Type ... - ENUM_TIMEFRAMES period = NULL // Trading Period ... + // Execute Specific Signal by Checking Spreads ... + // if provided ... + bool ExecuteSignal( + const XSignal &signal, // Source Signal ... + ENUM_X_SIGNAL_EXECUTION_FAILED &reason, // Provides Error Reason ... + bool checkPoliciese = true // Check Account Policies Before Execute Signal ... ) { // - Clean(result); + bool result = false; + reason = X_NOTHING; // - int positionsCount = mTrader.PositionsCount(); - if (positionsCount <= 0) - { - return; - } - - // - XPosition positions[]; - mTrader.GetPositions( - positions, - symbol, - period); - positionsCount = ArraySize(positions); - if (positionsCount <= 0) - { - return; - } - - // - if (type == NULL) + // Check Account Policies ... + if (checkPoliciese) { // - ArrayResize( - result, - ArraySize(positions)); - - // - for (int i = 0; i < positionsCount; i++) + // First Check Equity ... + result = CheckEquityForTrade(); + if (!result) { // - Add( - positions[i], - result); + reason = X_FAILED_REASON_EQUITY; + return result; } // - return; + // Check Positions Count ... + result = ChecPositionsForTrade(); + if (!result) + { + // + reason = X_FAILED_REASON_MAX_REACHED; + return result; + } + + // + // Check Spread ... + result = IsSpreadOkForSignalExecution(signal); + if (!result) + { + // + reason = X_FAILED_REASON_SPREAD; + return result; + } } // - for (int i = 0; i < positionsCount; i++) - { - // - XPosition iPosition = positions[i]; + XSignal tmpSignal = signal; + PrepareSignal(tmpSignal); - // - if (type == NULL || iPosition.type == type) - { - // - Add( - iPosition, - result); - } + // + // Generate Provider Comment ... + string comment = GenerateProvidersString(tmpSignal); + + // + result = mTrader + .ExecuteSignal( + tmpSignal, + comment // + ); + if (!result) + { + reason = X_UNKNOWN; } + + // + return result; } - void GetPositions( + + // + // Execute Specific Signals by Checking Spreads ... + // if provided ... + int ExecuteSignals( + const XSignal &signals[], // Signals Collection ... + ENUM_X_SIGNAL_EXECUTION_FAILED &reasons[], // Provides Error Reason ... + bool checkPoliciese = true // Check Account Policies Before Execute Signal ... + ) + { + // + int result = 0; + + // + Clean(reasons); + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + // Here we Have to Check Account Policies + // and Execute Signals base on them ... + + // + for (int i = 0; i < signalsCount; i++) + { + // + XSignal iSignal = signals[i]; + + // + ENUM_X_SIGNAL_EXECUTION_FAILED iReason = X_NOTHING; + + // + bool isExecuted = ExecuteSignal( + iSignal, + iReason, + checkPoliciese // + ); + if (isExecuted) + { + result++; + } + + // + Add( + iReason, + reasons); + } + + // + return result; + } + + // + // Get All Open Trades ... + int GetPositions( XPosition &result[], // Hold Result ... string symbol = NULL, // Trading Symbol ... ENUM_POSITION_TYPE type = NULL, // Trading Type ... @@ -409,6 +724,9 @@ public: string provider = NULL // Signal Provider ... ) { + // + int mResult = 0; + // Clean(result); @@ -417,10 +735,10 @@ public: bool hasProvider = !(provider == NULL || StringLen(provider) == 0); // - int positionsCount = mTrader.PositionsCount(); + int positionsCount = mTrader.CountPositions(); if (positionsCount <= 0) { - return; + return mResult; } // @@ -432,28 +750,19 @@ public: positionsCount = ArraySize(positions); if (positionsCount <= 0) { - return; + return mResult; } // if (!hasProvider && type == NULL) { // - ArrayResize( - result, - ArraySize(positions)); + Copy( + positions, + result); // - for (int i = 0; i < positionsCount; i++) - { - // - Add( - positions[i], - result); - } - - // - return; + return ArraySize(result); } // @@ -474,7 +783,7 @@ public: } // - return; + return ArraySize(result); } // @@ -499,6 +808,584 @@ public: result); } } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + // Extract Positions by it's Profits ... + void ExtractPositionsBasedOnProfits( + const XPosition &positions[], // Check as Data Source + XPosition &inDPositions[], // Hold In Drawdown Positions + XPosition &inPPositions[] // Hold In Profit Positions + ) + { + // + Clean(inDPositions); + Clean(inPPositions); + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit > 0) + { + // + Add( + iPosition, + inPPositions); + } + else if (iPosition.profit < 0) + { + // + Add( + iPosition, + inDPositions); + } + } + } + + // + // Get All In Profit Trades ... + int GetInProfitPositions( + XPosition &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_POSITION_TYPE type = NULL, // Trading Type ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL, // Signal Provider ... + ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + if (method == NULL) + { + method = X_POSITION_SELECT_ALL; + } + + // + // Prevent Going Forwars Since selection type is NONE ... + if (method == X_POSITION_SELECT_NONE) + { + return mResult; + } + + // + bool isMinSelectable = method == X_POSITION_SELECT_MIN; + bool isMaxSelectable = method == X_POSITION_SELECT_MAX; + + // + XPosition positions[]; + GetPositions( + positions, + symbol, + type, + period, + provider); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return mResult; + } + + // + // Define Temp Position for Selecting Max Position ... + XPosition maxPos; + maxPos.profit = INVALID_HANDLE; + + // + // Define Temp Position for Selecting Min Position ... + XPosition minPos; + minPos.profit = INVALID_HANDLE; + + // + // Loop through available Positions for Selecting Positions ... + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + // Check Profit State ... + if (iPosition.profit <= 0) + { + continue; + } + + // + // Check Selection State ... + if (isMinSelectable) + { + // + if (minPos.profit == INVALID_HANDLE || + minPos.profit > iPosition.profit) + { + minPos = iPosition; + } + + // + continue; + } + else if (isMaxSelectable) + { + // + if (maxPos.profit == INVALID_HANDLE || + maxPos.profit < iPosition.profit) + { + maxPos = iPosition; + } + + // + continue; + } + else + { + // + Add( + iPosition, + result); + } + } + + // + // Add Selected Position if Provided to Results ... + if (isMinSelectable) + { + // + Add( + minPos, + result); + } + else if (isMaxSelectable) + { + // + Add( + maxPos, + result); + } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + // Get All In Drawdown Trades ... + int GetInDrawdownPositions( + XPosition &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_POSITION_TYPE type = NULL, // Trading Type ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL, // Signal Provider ... + ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + if (method == NULL) + { + method = X_POSITION_SELECT_ALL; + } + + // + // Prevent Going Forwars Since selection type is NONE ... + if (method == X_POSITION_SELECT_NONE) + { + return mResult; + } + + // + bool isMinSelectable = method == X_POSITION_SELECT_MIN; + bool isMaxSelectable = method == X_POSITION_SELECT_MAX; + + // + XPosition positions[]; + GetPositions( + positions, + symbol, + type, + period, + provider); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return mResult; + } + + // + // Define Temp Position for Selecting Max Position ... + XPosition maxPos; + maxPos.profit = INVALID_HANDLE; + + // + // Define Temp Position for Selecting Min Position ... + XPosition minPos; + minPos.profit = INVALID_HANDLE; + + // + // Loop through available Positions for Selecting Positions ... + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + // Check Profit State ... + if (iPosition.profit >= 0) + { + continue; + } + + // + // Check Selection State ... + if (isMinSelectable) + { + // + if (minPos.profit == INVALID_HANDLE || + minPos.profit < iPosition.profit) + { + minPos = iPosition; + } + + // + continue; + } + else if (isMaxSelectable) + { + // + if (maxPos.profit == INVALID_HANDLE || + maxPos.profit > iPosition.profit) + { + maxPos = iPosition; + } + + // + continue; + } + else + { + // + Add( + iPosition, + result); + } + } + + // + // Add Selected Position if Provided to Results ... + if (isMinSelectable) + { + // + Add( + minPos, + result); + } + else if (isMaxSelectable) + { + // + Add( + maxPos, + result); + } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + // Retrieve Orders ... + int GetOrders( + XOrder &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_ORDER_TYPE type = NULL, // Trading Type ... + ENUM_ORDER_STATE state = NULL, // Trading State ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL // Signal Provider ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + XOrder orders[]; + mTrader.GetOrders( + orders, + symbol, + period, + state); + int ordersCount = ArraySize(orders); + if (ordersCount <= 0) + { + return mResult; + } + + // + if (type == NULL && + (provider == NULL || + StringLen(provider) == 0)) + { + // + Copy( + orders, + result); + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + if (type != NULL && iOrder.type != type) + { + continue; + } + + // + if (provider != NULL && + StringLen(provider) > 0) + { + // + // Generate Order Provider ... + string iProvider = ExtractProvider(iOrder.comment); + if (iProvider != provider) + { + continue; + } + } + + // + Add( + iOrder, + result); + } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + int GetHistoryOrders( + XOrder &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_ORDER_TYPE type = NULL, // Trading Type ... + ENUM_ORDER_STATE state = NULL, // Trading State ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL, // Signal Provider ... + datetime startDate = 0, // Start Date ... + datetime endDate = 0 // End Date ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + XOrder history[]; + int historyCount = mTrader + .GetHistoryOrders( + history, + symbol, + period, + type, + state, + startDate, + endDate); + if (historyCount <= 0) + { + return mResult; + } + + // + if (StringLen(provider) == 0 || provider == NULL) + { + // + Copy( + history, + result); + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + for (int i = 0; i < historyCount; i++) + { + // + XOrder iHistory = history[i]; + + // + if (provider != NULL && + StringLen(provider) > 0) + { + // + // Generate Order Provider ... + string iProvider = ExtractProvider(iHistory.comment); + if (iProvider != provider) + { + continue; + } + } + + // + Add( + iHistory, + result); + } + + // + mResult = ArraySize(result); + + // + return mResult; + } + + // + int GetHistoryDeals( + XDeal &result[], // Hold Result ... + string symbol = NULL, // Trading Symbol ... + ENUM_DEAL_TYPE type = NULL, // Specify Deal Type ... + ENUM_DEAL_REASON reason = NULL, // Specify Deal Reason ... + ENUM_TIMEFRAMES period = NULL, // Trading Period ... + string provider = NULL, // Signal Provider ... + datetime startDate = 0, // Start Date ... + datetime endDate = 0 // End Date ... + ) + { + // + int mResult = 0; + + // + Clean(result); + + // + XDeal history[]; + int historyCount = mTrader + .GetHistoryDeals( + history, + symbol, + type, + reason, + startDate, + endDate); + if (historyCount <= 0) + { + return mResult; + } + + // + bool canCheckPeriod = period != NULL; + bool canCheckProvider = provider != NULL && + StringLen(provider) > 0; + + // + if (!canCheckPeriod && !canCheckProvider) + { + // + Copy( + history, + result); + + // + mResult = ArraySize(history); + + // + return mResult; + } + + // + for (int i = 0; i < historyCount; i++) + { + // + XDeal iDeal = history[i]; + + // + if (canCheckPeriod) + { + // + ENUM_TIMEFRAMES dealPeriod = mTrader.GetDealPeriod(iDeal); + if (dealPeriod != period) + { + continue; + } + } + + // + if (canCheckProvider) + { + // + string comment = mTrader.GetDealPositionComment(iDeal); + if (StringLen(comment) <= 0) + { + continue; + } + + // + string oProvider = ExtractPeriodString(comment); + if (oProvider != provider) + { + continue; + } + } + + // + Add( + iDeal, + result); + } + + // + mResult = ArraySize(result); + + // + return mResult; } // @@ -508,6 +1395,7 @@ public: // Parse Recievd Guards and Do them ... void DoGuards(XGuard &guards[]) { + // int guardsCount = ArraySize(guards); if (guardsCount <= 0) { @@ -584,10 +1472,118 @@ public: string symbol, // Trading Symbol ENUM_POSITION_TYPE type, // Trading Type ENUM_TIMEFRAMES period, // Specified Time Frame - double minProfitForHedging = 1 // Specified Profit for Hedge ... + double minProfitForHedging = 1 // Specified Profit for Hedge ) { // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + type, + period, + provider); + if (positionsCount <= 1) + { + return; + } + + // + double profit = CalculatePositionsProfit(positions); + double requiredProfit = CalculateRequiredProfitForHedge(positions); + + // + bool isReadyForHedge = profit >= requiredProfit; + if (!isReadyForHedge) + { + return; + } + + // + string comment = "Guard Hedge " + provider; + int closed = mTrader.ClosePositions( + positions, + comment); + if (closed > 0) + { + // + string message = "Guard Hedge " + provider + "'s Positions on Profit: " + ToString(profit); + + // + LogMessage(message); + } + } + + // + // Close Max In Profit Trade Guard Action ... + void HandleGuardCloseInProfitAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method + ) + { + // + XPosition positions[]; + GetInProfitPositions( + positions, + symbol, + type, + period, + provider, + method); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + string comment = "Close InProfit ..."; + mTrader.ClosePositions( + positions, + comment); + + // + string message = "Guard Close (" + ToString(positionsCount) + ") Postion(s) In Profit ..."; + LogMessage(message); + } + + // + // Close Max In Drawdown Trade Guard Action ... + void HandleGuardCloseInDrawdownAction( + string provider, // Positions Provided by Specific Provider + string symbol, // Trading Symbol + ENUM_POSITION_TYPE type, // Trading Type + ENUM_TIMEFRAMES period, // Specified Time Frame + ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method + ) + { + // + XPosition positions[]; + GetInDrawdownPositions( + positions, + symbol, + type, + period, + provider, + method); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + string comment = "Close InDrawdown ..."; + mTrader.ClosePositions( + positions, + comment); + + // + string message = "Guard Close (" + ToString(positionsCount) + ") Position(s) In Drawdown ..."; + LogMessage(message); } // @@ -669,7 +1665,67 @@ public: ) { // - // TODO: Implement this ... + if (sl <= 0) + { + return; + } + + // + NormalizePrice( + sl, + symbol); + + // + XPosition positions[]; + GetPositions( + positions, + symbol, + type, + period, + provider); + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return; + } + + // + int modified = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + string comment = PrepareSLTrailComment(iPosition.comment); + + // + if (iPosition.sl == sl) + { + continue; + } + + // + bool isModified = mTrader.Modify( + iPosition.ticket, + sl, + iPosition.tp, + comment); + if (isModified) + { + modified++; + } + } + + // + if (modified > 0) + { + // + string msg = "(" + ToString(modified) + ") Position's Stop Trailed Successfully ..."; + + // + LogMessage(msg); + } } // @@ -735,6 +1791,278 @@ protected: // Tag Identifier ... string mTag; + // + bool mEnableLongs; + bool mEnableShorts; + + // + double mMaxAllowedSpread; + + // + int mMaxAllowedPositions; + double mMaxAllowedDrawDownFactor; + + // + double mMinProfitPerTrade; + double mMinProfitPerVolumeFactor; + + // + // Prepare a Signal and Do Calculations ... + void PrepareSignal( + XSignal &signal // a Signal for Preparation ... + ) + { + // + // Normalize Signal ... + NormalizeSignal(signal); + } + + // + // Check Acocunt Balance is Allow new Trades or not ... + bool CheckEquityForTrade() + { + // + bool result = false; + + // + if (mMaxAllowedDrawDownFactor <= 0) + { + // + result = true; + return result; + } + + // + double equity = mAccount.GetEquity(); + double balance = mAccount.GetBalance(); + + // + double selectedBalance = MathMax(equity, balance) - MathMin(equity, balance); + + // + double balanceForFactor = MathAbs(equity - balance); + if (balanceForFactor <= 0) + { + balanceForFactor = balance; + } + else + { + balanceForFactor = equity; + } + + // + double maxAllowedBalanceDrawDown = balanceForFactor * mMaxAllowedDrawDownFactor; + + // + result = equity > balance || + (equity <= balance && + selectedBalance <= maxAllowedBalanceDrawDown); + + // + return result; + } + + // + // Check Max Allowed Positions Policy for Trade ... + bool ChecPositionsForTrade() + { + // + bool result = false; + + // + if (mMaxAllowedPositions <= 0) + { + // + result = true; + return result; + } + + // + int positionsCount = mTrader.CountPositions(); + if (positionsCount <= 0) + { + // + result = true; + return result; + } + + // + result = positionsCount <= mMaxAllowedPositions; + + // + return result; + } + + // + // Check Spread is Ok for Executing Specific Signal ... + bool IsSpreadOkForSignalExecution(const XSignal &signal) + { + // + bool result = false; + + // + bool isSpreadCheckEnable = mMaxAllowedSpread > 0; + if (!isSpreadCheckEnable) + { + result = true; + } + else + { + // + // Retrieve Signal Spread ... + double spread = PriceToPoint( + signal.symbol, + GetSpread(signal.symbol)); + result = spread <= mMaxAllowedSpread; + } + + // + return result; + } + + // + // Calculate Required Profit for Hedging ... + double CalculateRequiredProfitForHedge( + XPosition &positions[] // Source + ) + { + // + double result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + bool isHedgingEnable = mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0; + if (!isHedgingEnable) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0) + { + // + result += + ((iPosition.volume / mMinProfitPerVolumeFactor) * + mMinProfitPerTrade) + + (-1 * iPosition.swap); + } + } + + // + return result; + } + + // + // Calculate Positions Profit Summary ... + double CalculatePositionsProfit( + XPosition &positions[] // Source + ) + { + // + double result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + result += iPosition.profit; + } + + // + return result; + } + + // + // Close a Position Pack and Cancel All of it's Supports ... + bool HandleClosePack(XPositionPack &pack) + { + // + bool result = false; + + // + if (pack.ticket <= 0) + { + return result; + } + + // + XOrder orders[]; + XPosition positions[]; + + // + bool hasPos = pack.position.ticket > 0; + if (hasPos) + { + Add( + pack.position, + positions); + } + + // + bool hasSupportPos = pack.supportPositionsCount > 0; + if (hasSupportPos) + { + // + Copy( + pack.supportPositions, + positions, + false); + } + + // + bool hasSupportOrd = pack.supportOrdersCount > 0; + if (hasSupportOrd) + { + // + Copy( + pack.supportOrders, + orders); + } + + // + string comment = "Close Pack"; + + // + int closed = mTrader.ClosePositions(positions, comment); + int canceled = mTrader.CancelOrders(orders); + + // + result = closed + canceled == ArraySize(orders) + ArraySize(positions); + if (result) + { + // + string message = "Close Position(" + ToString(pack.ticket) + ")'s Pack ..."; + + // + LogMessage(message); + } + + // + return result; + } + // // Private ... private: @@ -743,12 +2071,12 @@ private: // // XSCTrade Event Handlers ... - OnStopLoss mOnStopLossTriggered; - OnTakeProfit mOnTakeProfitTriggered; - OnDealsChanged mOnDealsChangedHandler; - OnOrdersChanged mOnOrdersChangedHandler; - OnPositionsChanged mOnPositionsChangedHandler; - OnTradeStateChanged mOnTradeStateChangedHandler; + TOnStopLoss mOnStopLossTriggered; + TOnTakeProfit mOnTakeProfitTriggered; + TOnDealsChanged mOnDealsChangedHandler; + TOnOrdersChanged mOnOrdersChangedHandler; + TOnPositionsChanged mOnPositionsChangedHandler; + TOnTradeStateChanged mOnTradeStateChangedHandler; // // Initi Requirements ... diff --git a/MQLTestWorkspace/Classes/x-saherelm.xhelper.class.ex5 b/MQLTestWorkspace/Classes/x-saherelm.xhelper.class.ex5 new file mode 100644 index 0000000..99adfcc Binary files /dev/null and b/MQLTestWorkspace/Classes/x-saherelm.xhelper.class.ex5 differ diff --git a/MQLTestWorkspace/Classes/x-saherelm.xhelper.class.mq5 b/MQLTestWorkspace/Classes/x-saherelm.xhelper.class.mq5 index d9cea8b..ea582f5 100644 --- a/MQLTestWorkspace/Classes/x-saherelm.xhelper.class.mq5 +++ b/MQLTestWorkspace/Classes/x-saherelm.xhelper.class.mq5 @@ -20,33 +20,12 @@ #property version "1.00" #property strict -// -// START Definitions ... -// - -// -// END Definitions ... -// - -// -// START Import and Inclused requirements ... -// - // // Includes ... #include "../Libraries/x-saherelm.common.lib.mq5" // -// END Import and Inclused requirements ... -// - -// -// START Overrides ... -// - -// -// END Overrides ... -// +// Definitions ... // // a Class for Handle base requirements ... @@ -59,40 +38,25 @@ public: // // Constructor ... void XSCBaseHelper( - string symbol, // Trading Symbol - ENUM_TIMEFRAMES period // Trading Time Frame + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period // Trading Time Frame ) { // mSymbol = symbol; mPeriod = period; - - // - LoopBack(52); } // // Deconstructor ... void ~XSCBaseHelper() { + // IndicatorRelease(mHandler); } // - // START Properties ... - // - - // - // Loopback Bars ... - void LoopBack(int value) - { - mLoopbackBars = value; - } - - int Loopback() - { - return mLoopbackBars; - } + // Setter(s) / Getter(s) ... // // Symbol ... @@ -108,16 +72,9 @@ public: return mPeriod; } - // - // Tag ... - string GetTag() - { - return mTag; - } - // // Retrieve Bars ... - int GetBars() + int CountBars() { // int result = @@ -130,49 +87,19 @@ public: } // - int GetCalculatedBars() + int CountCalculatedBars() { return BarsCalculated(mHandler); } // - // END Properties ... - // - - // - // START Provided Functions ... - // - - // - // Prepare Tag ... - virtual void PrepareTag() {} - - // - // Reading Buffers based on Given Bar Index ... - virtual void Calculate( - int barIndex // Given Bar Index - ); - - // - // Retrieve MAx Required Length for Calculations ... - virtual int GetMaxLength(); - - // - // END Provided Functions ... - // + // Functions ... // // Protected ... protected: // - string GetTagPrefix() - { - // - string result = "(" + mSymbol + ")(" + ToString(mPeriod) + ")"; - - // - return result; - } + // Props ... // // Symbol ... @@ -186,14 +113,6 @@ protected: // Indicator Handler ... int mHandler; - // - // Number Of Items Read Per Tick ... - int mLoopbackBars; - - // - // Tag Identifier ... - string mTag; - // // Private ... private: @@ -201,9 +120,4 @@ private: }; // -// START Usefull Functions ... -// - -// -// END Usefull Functions ... -// +// Tools .... \ No newline at end of file diff --git a/MQLTestWorkspace/Classes/x-saherelm.xmd5.class.ex5 b/MQLTestWorkspace/Classes/x-saherelm.xmd5.class.ex5 new file mode 100644 index 0000000..7903eb1 Binary files /dev/null and b/MQLTestWorkspace/Classes/x-saherelm.xmd5.class.ex5 differ diff --git a/MQLTestWorkspace/Classes/x-saherelm.xmd5.class.mq5 b/MQLTestWorkspace/Classes/x-saherelm.xmd5.class.mq5 new file mode 100644 index 0000000..3311aa5 --- /dev/null +++ b/MQLTestWorkspace/Classes/x-saherelm.xmd5.class.mq5 @@ -0,0 +1,441 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCMD5 +// Description: Provides MD5 Hashing 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 + +// +// START Definitions ... +// + +// +static uchar _md5_PADDING[64] = + { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +// +#define _md5_F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define _md5_G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define _md5_H(x, y, z) ((x) ^ (y) ^ (z)) +#define _md5_I(x, y, z) ((y) ^ ((x) | (~z))) +#define _md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +// +#define _md5_FF(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_F((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_GG(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_G((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_HH(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_H((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_II(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_I((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_INIT_STATE_0 0x67452301 +#define _md5_INIT_STATE_1 0xefcdab89 +#define _md5_INIT_STATE_2 0x98badcfe +#define _md5_INIT_STATE_3 0x10325476 + +// +#define _md5_S11 7 +#define _md5_S12 12 +#define _md5_S13 17 +#define _md5_S14 22 + +// +#define _md5_S21 5 +#define _md5_S22 9 +#define _md5_S23 14 +#define _md5_S24 20 + +// +#define _md5_S31 4 +#define _md5_S32 11 +#define _md5_S33 16 +#define _md5_S34 23 + +// +#define _md5_S41 6 +#define _md5_S42 10 +#define _md5_S43 15 +#define _md5_S44 21 + +// +// END Definitions ... +// + +// +// XCMD5 a library for Hashing ... +class XSCMD5 +{ + // + // Public Provides ... +public: + // + // Protected Provides ... + + // + // Constructor ... + XSCMD5(void) {} + + // + // Deconstructor ... + ~XSCMD5(void) {} + + // + // Hash Specified Char Array ... + string Hash( + uchar &mSource[], // Specify Char Array to Hash + int mLength = 0 // Specify Length of Char Array which required to hash + ) + { + // + string result = ""; + + // + int sourceCount = ArraySize(mSource); + + // + // Validate Args ... + if ( + sourceCount <= 0 || + (sourceCount > 0 && mLength > sourceCount)) + { + return result; + } + + // + // Normalize Args ... + if (mLength == 0) + { + mLength = sourceCount; + } + + // + // Init MD5 ... + MD5Init(); + + // + // Update Buffer ... + MD5Update(mSource, mLength); + + // + // Calculate Result ... + result = MD5Final(); + + // + return result; + } + + // + // Hash Specified String ... + string Hash( + string mSource // Specified String + ) + { + // + string result = ""; + + // + // Converts String to Char Array ... + uchar bytes[]; + StringToCharArray( + mSource, + bytes, + 0, + StringLen(mSource)); + + // + result = Hash( + bytes, + ArraySize(bytes)); + + // + return result; + } + +protected: + // + // Private Provides ... +private: + // + uint m_lMD5[4]; + uint m_nCount[2]; + uchar m_lpszBuffer[64]; + + // + // Convert Byte to DWord ... + void ByteToDWord(int &out[], uint &in[], uint len) + { + // + uint i = 0; + uint j = 0; + + // + for (; j < len; i++, j += 4) + { + out[i] = (int)in[j] | (int)in[j + 1] << 8 | (int)in[j + 2] << 16 | (int)in[j + 3] << 24; + } + } + + // + // Convert DWord to Byte ... + void DWordToByte(uchar &out[], int &in[], uint len) + { + // + uint i = 0; + uint j = 0; + + // + for (; j < len; i++, j += 4) + { + // + out[j] = (uchar)(in[i] & 0xff); + out[j + 1] = (uchar)((in[i] >> 8) & 0xff); + out[j + 2] = (uchar)((in[i] >> 16) & 0xff); + out[j + 3] = (uchar)((in[i] >> 24) & 0xff); + } + } + + // + // Init MD5 Array ... + void MD5Init() + { + // + ArrayInitialize(m_lpszBuffer, 64); + + // + m_nCount[0] = m_nCount[1] = 0; + m_lMD5[0] = _md5_INIT_STATE_0; + m_lMD5[1] = _md5_INIT_STATE_1; + m_lMD5[2] = _md5_INIT_STATE_2; + m_lMD5[3] = _md5_INIT_STATE_3; + } + + // + // Update MD5 ... + void MD5Update(uchar &inBuf[], uint inLen) + { + // + int i, ii; + int mdi; + + // + uint in[16]; + int i0 = 0; + + // + mdi = (int)((m_nCount[0] >> 3) & 0x3F); + + // + if ((m_nCount[0] + ((uint)inLen << 3)) < m_nCount[0]) + { + m_nCount[1]++; + } + + // + m_nCount[0] += ((uint)inLen << 3); + m_nCount[1] += ((uint)inLen >> 29); + + // + while ((inLen--) > 0) + { + // + m_lpszBuffer[mdi++] = inBuf[i0++]; + if (mdi == 0x40) + { + // + for (i = 0, ii = 0; i < 16; i++, ii += 4) + { + in[i] = (((uint)m_lpszBuffer[ii + 3]) << 24) | (((uint)m_lpszBuffer[ii + 2]) << 16) | (((uint)m_lpszBuffer[ii + 1]) << 8) | ((uint)m_lpszBuffer[ii]); + } + + // + Transform(m_lMD5, in); + + // + mdi = 0; + } + } + } + + // + // Finalize an MD5 Expression ... + string MD5Final() + { + // + uchar bits[8]; + int nIndex; + uint nPadLen; + const int nMD5Size = 16; + uchar lpszMD5[16]; + string temp; + string out = ""; + int i; + + // + DWordToByte(bits, m_nCount, 8); + nIndex = (int)((m_nCount[0] >> 3) & 0x3f); + nPadLen = (nIndex < 56) ? (56 - nIndex) : (120 - nIndex); + MD5Update(_md5_PADDING, nPadLen); + MD5Update(bits, 8); + DWordToByte(lpszMD5, m_lMD5, nMD5Size); + + // + for (i = 0; i < nMD5Size; i++) + { + // + if (lpszMD5[i] == 0) + { + temp = "00"; + } + else if (lpszMD5[i] <= 15) + { + temp = StringFormat("0%x", lpszMD5[i]); + } + else + { + temp = StringFormat("%x", lpszMD5[i]); + } + + // + out += temp; + } + + // + lpszMD5[0] = '\0'; + + // + return (out); + } + + // + // Transform Buffers ... + void Transform(uint &buf[], uint &in[]) + { + // + uint a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + // + _md5_FF(a, b, c, d, in[0], _md5_S11, 0xD76AA478); + _md5_FF(d, a, b, c, in[1], _md5_S12, 0xE8C7B756); + _md5_FF(c, d, a, b, in[2], _md5_S13, 0x242070DB); + _md5_FF(b, c, d, a, in[3], _md5_S14, 0xC1BDCEEE); + _md5_FF(a, b, c, d, in[4], _md5_S11, 0xF57C0FAF); + _md5_FF(d, a, b, c, in[5], _md5_S12, 0x4787C62A); + _md5_FF(c, d, a, b, in[6], _md5_S13, 0xA8304613); + _md5_FF(b, c, d, a, in[7], _md5_S14, 0xFD469501); + _md5_FF(a, b, c, d, in[8], _md5_S11, 0x698098D8); + _md5_FF(d, a, b, c, in[9], _md5_S12, 0x8B44F7AF); + _md5_FF(c, d, a, b, in[10], _md5_S13, 0xFFFF5BB1); + _md5_FF(b, c, d, a, in[11], _md5_S14, 0x895CD7BE); + _md5_FF(a, b, c, d, in[12], _md5_S11, 0x6B901122); + _md5_FF(d, a, b, c, in[13], _md5_S12, 0xFD987193); + _md5_FF(c, d, a, b, in[14], _md5_S13, 0xA679438E); + _md5_FF(b, c, d, a, in[15], _md5_S14, 0x49B40821); + + // + _md5_GG(a, b, c, d, in[1], _md5_S21, 0xF61E2562); + _md5_GG(d, a, b, c, in[6], _md5_S22, 0xC040B340); + _md5_GG(c, d, a, b, in[11], _md5_S23, 0x265E5A51); + _md5_GG(b, c, d, a, in[0], _md5_S24, 0xE9B6C7AA); + _md5_GG(a, b, c, d, in[5], _md5_S21, 0xD62F105D); + _md5_GG(d, a, b, c, in[10], _md5_S22, 0x02441453); + _md5_GG(c, d, a, b, in[15], _md5_S23, 0xD8A1E681); + _md5_GG(b, c, d, a, in[4], _md5_S24, 0xE7D3FBC8); + _md5_GG(a, b, c, d, in[9], _md5_S21, 0x21E1CDE6); + _md5_GG(d, a, b, c, in[14], _md5_S22, 0xC33707D6); + _md5_GG(c, d, a, b, in[3], _md5_S23, 0xF4D50D87); + _md5_GG(b, c, d, a, in[8], _md5_S24, 0x455A14ED); + _md5_GG(a, b, c, d, in[13], _md5_S21, 0xA9E3E905); + _md5_GG(d, a, b, c, in[2], _md5_S22, 0xFCEFA3F8); + _md5_GG(c, d, a, b, in[7], _md5_S23, 0x676F02D9); + _md5_GG(b, c, d, a, in[12], _md5_S24, 0x8D2A4C8A); + + // + _md5_HH(a, b, c, d, in[5], _md5_S31, 0xFFFA3942); + _md5_HH(d, a, b, c, in[8], _md5_S32, 0x8771F681); + _md5_HH(c, d, a, b, in[11], _md5_S33, 0x6D9D6122); + _md5_HH(b, c, d, a, in[14], _md5_S34, 0xFDE5380C); + _md5_HH(a, b, c, d, in[1], _md5_S31, 0xA4BEEA44); + _md5_HH(d, a, b, c, in[4], _md5_S32, 0x4BDECFA9); + _md5_HH(c, d, a, b, in[7], _md5_S33, 0xF6BB4B60); + _md5_HH(b, c, d, a, in[10], _md5_S34, 0xBEBFBC70); + _md5_HH(a, b, c, d, in[13], _md5_S31, 0x289B7EC6); + _md5_HH(d, a, b, c, in[0], _md5_S32, 0xEAA127FA); + _md5_HH(c, d, a, b, in[3], _md5_S33, 0xD4EF3085); + _md5_HH(b, c, d, a, in[6], _md5_S34, 0x04881D05); + _md5_HH(a, b, c, d, in[9], _md5_S31, 0xD9D4D039); + _md5_HH(d, a, b, c, in[12], _md5_S32, 0xE6DB99E5); + _md5_HH(c, d, a, b, in[15], _md5_S33, 0x1FA27CF8); + _md5_HH(b, c, d, a, in[2], _md5_S34, 0xC4AC5665); + + // + _md5_II(a, b, c, d, in[0], _md5_S41, 0xF4292244); + _md5_II(d, a, b, c, in[7], _md5_S42, 0x432AFF97); + _md5_II(c, d, a, b, in[14], _md5_S43, 0xAB9423A7); + _md5_II(b, c, d, a, in[5], _md5_S44, 0xFC93A039); + _md5_II(a, b, c, d, in[12], _md5_S41, 0x655B59C3); + _md5_II(d, a, b, c, in[3], _md5_S42, 0x8F0CCC92); + _md5_II(c, d, a, b, in[10], _md5_S43, 0xFFEFF47D); + _md5_II(b, c, d, a, in[1], _md5_S44, 0x85845DD1); + _md5_II(a, b, c, d, in[8], _md5_S41, 0x6FA87E4F); + _md5_II(d, a, b, c, in[15], _md5_S42, 0xFE2CE6E0); + _md5_II(c, d, a, b, in[6], _md5_S43, 0xA3014314); + _md5_II(b, c, d, a, in[13], _md5_S44, 0x4E0811A1); + _md5_II(a, b, c, d, in[4], _md5_S41, 0xF7537E82); + _md5_II(d, a, b, c, in[11], _md5_S42, 0xBD3AF235); + _md5_II(c, d, a, b, in[2], _md5_S43, 0x2AD7D2BB); + _md5_II(b, c, d, a, in[9], _md5_S44, 0xEB86D391); + + // + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; + } +}; diff --git a/MQLTestWorkspace/Classes/x-saherelm.xprovider.class.ex5 b/MQLTestWorkspace/Classes/x-saherelm.xprovider.class.ex5 new file mode 100644 index 0000000..dedfe7e Binary files /dev/null and b/MQLTestWorkspace/Classes/x-saherelm.xprovider.class.ex5 differ diff --git a/MQLTestWorkspace/Classes/x-saherelm.xprovider.class.mq5 b/MQLTestWorkspace/Classes/x-saherelm.xprovider.class.mq5 index e60bb27..75c1a76 100644 --- a/MQLTestWorkspace/Classes/x-saherelm.xprovider.class.mq5 +++ b/MQLTestWorkspace/Classes/x-saherelm.xprovider.class.mq5 @@ -76,7 +76,8 @@ public: } void XSCEABaseProvider( string symbol, - ENUM_TIMEFRAMES period) + ENUM_TIMEFRAMES period, + bool ignoreTicksAfterSignalTillNewCandle = true) { // mSymbol = symbol; @@ -87,6 +88,9 @@ public: // mIsInTestMode = IsRunningOnTestMode(); + + // + mIgnoreTicksAfterSignalTillNewCandle = ignoreTicksAfterSignalTillNewCandle; } // @@ -96,15 +100,23 @@ public: } // - bool CanIgnoreTick() { + bool CanIgnoreTick() + { // mIsNewCandle = IsNewCandle( mSymbol, mPeriod); bool result = mIsInTestMode - ? !mIsNewCandle - : !mIsNewCandle && mWaitUntilNewCandle; - + ? !mIsNewCandle + : !mIsNewCandle && mWaitUntilNewCandle; + + // + if (result) + { + // + result = mIgnoreTicksAfterSignalTillNewCandle; + } + // return result; } @@ -240,6 +252,9 @@ private: // // Signal Event Handlers ... OnSignal mSignalEventHandlers[]; + + // + bool mIgnoreTicksAfterSignalTillNewCandle; }; // diff --git a/MQLTestWorkspace/Classes/x-saherelm.xtrade.class.ex5 b/MQLTestWorkspace/Classes/x-saherelm.xtrade.class.ex5 new file mode 100644 index 0000000..5955e67 Binary files /dev/null and b/MQLTestWorkspace/Classes/x-saherelm.xtrade.class.ex5 differ diff --git a/MQLTestWorkspace/Classes/x-saherelm.xtrade.class.mq5 b/MQLTestWorkspace/Classes/x-saherelm.xtrade.class.mq5 index 87694fa..d6e38f2 100644 --- a/MQLTestWorkspace/Classes/x-saherelm.xtrade.class.mq5 +++ b/MQLTestWorkspace/Classes/x-saherelm.xtrade.class.mq5 @@ -20,326 +20,14 @@ #property strict // -// START Definitions ... -// +// Imports ... +#include "../Libraries/x-saherelm.xtrade.lib.mq5" // -// Model an Open Position ... -struct XPosition -{ - // - // Magic Number ... - ulong magic; - - // - // Ticket ID ... - ulong ticket; - - // - // Tradinng Symbol ... - string symbol; - - // - // Trading Period ... - ENUM_TIMEFRAMES period; - - // - // Position Type ... - ENUM_POSITION_TYPE type; - - // - // Take Profit ... - double tp; - - // - // Stop Loss ... - double sl; - - // - // Position Current Profit ... - double profit; - - // - // Position Open Price ... - double entry; - - // - // Current Symbol Price ... - double price; - - // - // Position Swap ... - double swap; - - // - // Position Commission ... - double commission; - - // - // Volume ... - double volume; - - // - // Position Open Time ... - datetime openAt; - - // - // Position Comment ... - string comment; -}; +// Definitions ... // -// Model an Order ... -struct XOrder -{ - // - // Time of order placement ... - datetime setupAt; - - // - // Time of order expiration ... - datetime expiredAt; - - // - // Time of order execution or cancellation ... - datetime executedAt; - - // - // Order type ... - ENUM_ORDER_TYPE type; - - // - // Order state ... - ENUM_ORDER_STATE state; - - // - // Type of execution by remainder ... - ENUM_ORDER_TYPE_FILLING filling; - - // - // Order lifetime ... - ENUM_ORDER_TYPE_TIME lifetime; - - // - // Order ticket ... - ulong ticket; - - // - // Magic Number ... - long magic; - - // - // Position id, that is placed on order, - // when it is executed. Each executed order invokes a - // deal, that opens new or changes existing - // position. Id of that position is placed on - // executed order in this moment. - long pocitionID; - - // - // Initial volume on order placement ... - double initialVolume; - - // - // Unfilled volume ... - double currentVolume; - - // - // Price, specified in the order ... - double openPrice; - - // - // Current price by order symbol ... - double currentPrice; - - // - // Price of placing Limit order when StopLimit order is triggered ... - double stopLimitPrice; - - // - // Take Profit level ... - double tp; - - // - // Stop Loss level ... - double sl; - - // - // Trading Symbol ... - string smybol; - - // - // Order Comment ... - string comment; -}; - -// -// Model a Deal ... -struct XDeal -{ - // - // the ID of the Expert Advisor, that executed the deal ... - ulong magic; - - // - // the ID of position, in which the deal was involved ... - ulong positionId; - - // - // Ticket ... - ulong ticket; - - // - // the name of the deal symbol ... - string symbol; - - // - // order by which the deal is executed ... - ulong order; - - // - // the time of deal execution ... - datetime time; - - // - // Deal price ... - double price; - - // - // the financial result of the deal (in deposit currency) ... - double profit; - - // - // the amount of swap when position is closed ... - double swap; - - // - // the amount of commission of the deal ... - double commission; - - // - // the volume of deal ... - double volume; - - // - // the deal comment ... - string comment; - - // - // the deal type ... - // ------------------------------------------------------------------ - // DEAL_TYPE_BUY => Buy ... - // DEAL_TYPE_SELL => Sell ... - // DEAL_TYPE_BUY_CANCELED => Canceled buy deal ... - // There can be a situation when a previously executed buy deal is canceled. In this case, - // the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED, - // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ... - // - // DEAL_TYPE_SELL_CANCELED => Canceled sell deal ... - // There can be a situation when a previously executed sell deal is canceled. In this case, - // the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED, - // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation - // - // DEAL_TYPE_BALANCE => Balance ... - // DEAL_TYPE_CREDIT => Credit ... - // DEAL_TYPE_CHARGE => Additional charge ... - // DEAL_TYPE_CORRECTION => Correction ... - // DEAL_TAX => Tax charges ... - // DEAL_TYPE_BONUS => Bonus ... - // DEAL_TYPE_INTEREST => Interest rate ... - // DEAL_DIVIDEND => Dividend operations... - // DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ... - // DEAL_TYPE_COMMISSION => Additional commission ... - // DEAL_TYPE_COMMISSION_DAILY => Daily commission ... - // DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ... - // DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ... - // DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission - ENUM_DEAL_TYPE type; - - // - // the deal direction ... - // ---------------------------------- - // DEAL_ENTRY_IN => Entry in ... - // DEAL_ENTRY_OUT => Entry out ... - // DEAL_ENTRY_INOUT => Reverse ... - // DEAL_ENTRY_OUT_BY => Close a position by an opposite one ... - ENUM_DEAL_ENTRY entry; - - // - // deal reson ... - // --------------------- - // DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ... - // DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ... - // DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ... - // DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ... - // DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ... - // DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ... - // DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ... - // DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ... - // DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ... - // DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ... - ENUM_DEAL_REASON reason; -}; - -// -// Model OnTrade Event Handler Result on XCTrade Class ... -struct XOnTradeHandlerState -{ - // - bool hasNewDeal; - int newDeals; - - // - bool hasNewOrder; - int newOrders; - - // - bool hasNewPosition; - int newPositions; - - // - bool hasNewHistoryOrder; - int newHistoryOrders; -}; - -// -typedef void (*OnDealsChanged)(int count); - -// -typedef void (*OnOrdersChanged)(int count); - -// -typedef void (*OnPositionsChanged)(int count); - -// -typedef void (*OnStopLoss)(const XDeal &deal); -typedef void (*OnTakeProfit)(const XDeal &deal); - -// -typedef void (*OnTradeStateChanged)(const XOnTradeHandlerState &state); - -// -// END Definitions ... -// - -// -// START Import and Inclused requirements ... -// - -// -// Includes ... -#include -#include "../Libraries/x-saherelm.log.lib.mq5" -#include "../Libraries/x-saherelm.common.lib.mq5" -#include "../Libraries/x-saherelm.seriallizer.lib.mq5" - -// -// END Import and Inclused requirements ... -// - -// -// START Overrides ... -// +// Overrides ... // // XCTrade Base Class ... @@ -822,34 +510,35 @@ public: }; // -// END Overrides ... -// +// Implementation ... -// -// a Class for Manage Trades ... +// a Class For Manage Trades and Handle Trading Actions ... class XSCTrade { // // Public ... public: // - // Constructor ... + // Props ... + + // + // Constructors ... void XSCTrade( int slippage, // Specify Slippage ulong magicNumber // Specify Magic Number ) { // + // Setting Props ... mSlippage = slippage; mMagicNumber = magicNumber; // - mPeriodPrefix = "PR"; - - // + // Instance Base Trader Class ... mTrader = new XSCTradeBase(); // + // Configuring Base Trader Class ... mTrader.SetAsyncMode(false); mTrader.SetDeviationInPoints(mSlippage); mTrader.SetExpertMagicNumber(mMagicNumber); @@ -859,7 +548,8 @@ public: mTrader.LogLevel(LOG_LEVEL_ERRORS); // - // Prepare Trade Event Materials ... + // OnTrade Context ... + // mDaysForRead = 1; mScanStarted = false; @@ -875,21 +565,217 @@ public: // // Deconstructor ... - void ~XSCTrade() + ~XSCTrade() { + // + // Remove Pointer ... + delete mTrader; } // - // START Event Processing ... + // Props ... + // + // Retrieve Slippage ... + int GetSlippage() + { + return mSlippage; + } + + // + // Retrieve Magic Number ... + ulong GetMagicNumber() + { + return mMagicNumber; + } + + // + // Add Event Listeners ... + + // + // Add New Deals Changed Event Handler ... + void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) + { + // + Add( + handler, + mTradeStateChangedEventHandlers + // + ); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnDealsChangedEventHandler(TOnDealsChanged handler) + { + // + Add( + handler, + mDealsChangedEventHandlers + // + ); + } + + // + // Add New Orders Changed Event Handler ... + void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) + { + // + Add( + handler, + mOrdersChangedEventHandlers + // + ); + } + + // + // Add New Positions Changed Event Handler ... + void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) + { + // + Add( + handler, + mPositionsChangedEventHandlers + // + ); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + Add( + handler, + mStopLossEventHandlers + // + ); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + Add( + handler, + mTakeProfitEventHandlers + // + ); + } + + // + // Functions ... + + // + // Handlers ... + + // + // Process On Trade Requirement ... + // this Only Used when we Have to Proccess OnTrade Event in EA(s) ... + void HandleOnTradeEvent( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + result.Clean(); + + // + if (mScanStarted) + { + // + ProcessOnTradeContext(result); + } + else + { + // + // Init Trade Context ... + InitOnTradeContext(); + + // + return; + } + + // + // Here we Can Check the Start ... + bool isValid = + // + result.IsValid() && + // + !result.hasNewDeal && + !result.hasNewOrder && + !result.hasNewPosition && + !result.hasNewHistoryOrder + // + ; + if (!isValid) + { + return; + } + + // + // State ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(result); + + // + // Deals ... + if (result.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(result.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + int dealsCount = GetDeals(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // Orders ... + if (result.hasNewOrder || result.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(result.newOrders + result.newHistoryOrders); + } + + // + // Positions ... + if (result.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(result.newPositions); + } + } // // This Must be Called Every time OnTrade Event Happening ... + // this Used for Implementing Custom Senarios ... XOnTradeHandlerState HandleOnTrade() { // // Handle OnTrade Event ... - XOnTradeHandlerState state = {}; + XOnTradeHandlerState state; HandleOnTradeEvent(state); if ( !state.hasNewDeal && @@ -901,7 +787,7 @@ public: } // - // STATE ... + // State ... // // Notfy Trade State Changed Event ... @@ -960,339 +846,310 @@ public: } // - // Process On Trade Requirement - void HandleOnTradeEvent( - XOnTradeHandlerState &result // Hold's Result + // Trade Actions ... + + // + // Main ... + + // + // Manage ... + // this must be Call on OnTick for Manage + // Positions ... + void Manage() + { + // + // All required Position Managements Actions implemented here ... + + // + // - [] Partial Close; + // - [] Risk Free; + // - [] Trail Stop; + // - [] SLS; + // - [] TPS; + + // + // - [] Data Collector; + // - [] Profit Management; + } + + // + // Execute a Signal ... + bool ExecuteSignal( + XSignal &signal, // Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL // order expiration time ) { // - if (mScanStarted) + bool result = false; + state = X_SIGNAL_EXECUTION_UNKNOWN; + + // + double currentEntry = GetEntry( + signal.symbol, + signal.type + // + ); + bool isLong = IsLong(signal.type); + + // + // Select SL and TP ... + double selectedSL = 0; + double selectedTP = 0; + + // + if (!signal.IsValid()) { - ProcessOnTradeContext(result); + // + state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; + return result; } - else + + // + // Handle Market Execution ... + if (signal.mode == X_ORDER_MODE_MARKET) { - InitOnTradeContext(); + // + if (isLong) + { + // + result = Buy( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + signal.comment + // + ); + } + else + { + // + result = Sell( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + signal.comment + // + ); + } } + // + // Handle Stop Execution ... + else if (signal.mode == X_ORDER_MODE_STOP) + { + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? signal.entry > currentEntry + : signal.entry < currentEntry; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; + return result; + } + + // + // Execute Order ... + if (isLong) + { + // + result = BuyStop( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + lifetime, + expiration, + signal.comment + // + ); + } + else + { + // + result = SellStop( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + lifetime, + expiration, + signal.comment + // + ); + } + } + // + // Handle Limit Execution ... + else if (signal.mode == X_ORDER_MODE_LIMIT) + { + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? signal.entry < currentEntry + : signal.entry > currentEntry; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; + return result; + } + + // + // Execute Order ... + if (isLong) + { + // + result = BuyLimit( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + lifetime, + expiration, + signal.comment + // + ); + } + else + { + // + result = SellLimit( + signal.symbol, + signal.period, + signal.volume, + signal.entry, + selectedSL, + selectedTP, + lifetime, + expiration, + signal.comment + // + ); + } + } + + // + // Handle Ticket ... + if (result) + { + // + state = X_SIGNAL_EXECUTION_SUCCEED; + + // + ulong ticket; + if (signal.mode == X_ORDER_MODE_MARKET) + { + ticket = GetLastOpenPositionTicket(); + } + else + { + ticket = GetLastPlacedOrderTicket(); + } + + // + signal.positionId = ticket; + + // + // Handle Executing Support Signals ... + int supportsCount = ArraySize(signal.supports); + if (supportsCount > 0) + { + // + int executed = 0; + for (int i = 0; i < supportsCount; i++) + { + // + XSignal iSupport = signal.supports[i]; + + // + int supIndex = i + 1; + string iComment = GenerateSupportTag(ticket); + + // + bool isExecuted = ExecuteSignal( + iSupport, + state, + lifetime, + expiration + // + ); + if (isExecuted) + { + executed++; + } + } + + // + result = executed == supportsCount; + } + } + + // + return result; } // - // Event Emitters ... - - // - // STATE Changed ... - - // - // Clear Trade State Changed Event Handlers ... - void ClearOnTradeStateChangedEventHandlers() - { - // - ArrayFree(mTradeStateChangedEventHandlers); - - // - ArrayResize(mTradeStateChangedEventHandlers, 0); - } - - // - // Add New Deals Changed Event Handler ... - void AddOnTradeStateChangedEventHandler(OnTradeStateChanged handler) - { - // - ArrayResize( - mTradeStateChangedEventHandlers, - ArraySize(mTradeStateChangedEventHandlers) + 1); - - // - mTradeStateChangedEventHandlers[ArraySize(mTradeStateChangedEventHandlers) - 1] = handler; - } - - // - // DEALS ... - - // - // Clear Deals Changed Event Handlers ... - void ClearOnDealsChangedEventHandlers() - { - // - ArrayFree(mDealsChangedEventHandlers); - - // - ArrayResize(mDealsChangedEventHandlers, 0); - } - - // - // Add New Deals Changed Event Handler ... - void AddOnDealsChangedEventHandler(OnDealsChanged handler) - { - // - ArrayResize( - mDealsChangedEventHandlers, - ArraySize(mDealsChangedEventHandlers) + 1); - - // - mDealsChangedEventHandlers[ArraySize(mDealsChangedEventHandlers) - 1] = handler; - } - - // - // ORDERS ... - - // - // Clear Orders Changed Event Handlers ... - void ClearOnOrdersChangedEventHandlers() - { - // - ArrayFree(mOrdersChangedEventHandlers); - - // - ArrayResize(mOrdersChangedEventHandlers, 0); - } - - // - // Add New Orders Changed Event Handler ... - void AddOnOrdersChangedEventHandler(OnOrdersChanged handler) - { - // - ArrayResize( - mOrdersChangedEventHandlers, - ArraySize(mOrdersChangedEventHandlers) + 1); - - // - mOrdersChangedEventHandlers[ArraySize(mOrdersChangedEventHandlers) - 1] = handler; - } - - // - // POSITIONS ... - - // - // Clear Positions Changed Event Handlers ... - void ClearOnPositionsChangedEventHandlers() - { - // - ArrayFree(mPositionsChangedEventHandlers); - - // - ArrayResize(mPositionsChangedEventHandlers, 0); - } - - // - // Add New Positions Changed Event Handler ... - void AddOnPositionsChangedEventHandler(OnPositionsChanged handler) - { - // - ArrayResize( - mPositionsChangedEventHandlers, - ArraySize(mPositionsChangedEventHandlers) + 1); - - // - mPositionsChangedEventHandlers[ArraySize(mPositionsChangedEventHandlers) - 1] = handler; - } - - // - // TPSL ... - - // - // Clear Stop Loss Event Handlers ... - void ClearOnStopLossEventHandlers() - { - // - ArrayFree(mStopLossEventHandlers); - - // - ArrayResize(mStopLossEventHandlers, 0); - } - - // - // Add New Stop Loss Event Handler ... - void AddOnStopLossEventHandler(OnStopLoss handler) - { - // - ArrayResize( - mStopLossEventHandlers, - ArraySize(mStopLossEventHandlers) + 1); - - // - mStopLossEventHandlers[ArraySize(mStopLossEventHandlers) - 1] = handler; - } - - // - // Clear Take Profit Event Handlers ... - void ClearOnTakeProfitEventHandlers() - { - // - ArrayFree(mTakeProfitEventHandlers); - - // - ArrayResize(mTakeProfitEventHandlers, 0); - } - - // - // Add New Stop Loss Event Handler ... - void AddOnTakeProfitEventHandler(OnTakeProfit handler) - { - // - ArrayResize( - mTakeProfitEventHandlers, - ArraySize(mTakeProfitEventHandlers) + 1); - - // - mTakeProfitEventHandlers[ArraySize(mTakeProfitEventHandlers) - 1] = handler; - } - - // - // END Event Processing ... - // - - // - // START Provided Functions ... - // - - // - // Count Currently Open Positions ... - int PositionsCount( - string symbol = "", // Specified Symbol - ENUM_POSITION_TYPE type = NULL // Specified Type + // Execute a Collection Of Signals ... + int ExecuteSignals( + XSignal &signals[], // Collection of Signal for Execution + ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL // order expiration time ) { // int result = 0; // - int allPositions = 0; - int longPositions = 0; - int shortPositions = 0; + Clean(states); // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) { return result; } // - for (int i = 0; i < positionsCount; i++) + ArrayResize(states, signalsCount); + ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN); + for (int i = 0; i < signalsCount; i++) { // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - string positionSymbol = mPositionInfo.Symbol(); - - // - ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); - - // - if ( - type == NULL && - StringLen(symbol) <= 0) - { + bool isExecuted = ExecuteSignal( + signals[i], + states[i], + lifetime, + expiration // - allPositions++; + ); - // - continue; - } - else if ( - type != NULL && - StringLen(symbol) > 0) - { - // - if (type == positionType && - symbol == positionSymbol) - { - // - if (type == POSITION_TYPE_BUY) - { - longPositions++; - } - else - { - shortPositions++; - } - - // - continue; - } - } - else if (StringLen(symbol) > 0) - { - // - if (positionSymbol == symbol) - { - // - allPositions++; - - // - continue; - } - } - else if (type != NULL) - { - // - if (type == positionType) - { - // - if (type == POSITION_TYPE_BUY) - { - longPositions++; - } - else - { - shortPositions++; - } - - // - continue; - } - } - } - - // - // Specify Result ... - if ( - type == NULL && - StringLen(symbol) <= 0) - { // - result = allPositions; - } - else if ( - type != NULL && - StringLen(symbol) > 0) - { - // - if (type == POSITION_TYPE_BUY) + if (isExecuted) { - result = longPositions; - } - else - { - result = shortPositions++; - } - } - else if (StringLen(symbol) > 0) - { - // - result = allPositions; - } - else if (type != NULL) - { - // - if (type == POSITION_TYPE_BUY) - { - result = longPositions; - } - else - { - result = shortPositions; + result++; } } @@ -1301,745 +1158,10 @@ public: } // - // Retrieve Max In Profit Position Ticket ... - ulong GetMaxInProfitPosition( - string symbol = "", // Specified Symbol - ENUM_POSITION_TYPE type = NULL // Specified Type - ) - { - // - ulong result = -1; - - // - double profit = 0; - - // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return result; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - ulong positionTicket = mPositionInfo.Ticket(); - - // - string positionSymbol = mPositionInfo.Symbol(); - - // - double positionProfit = mPositionInfo.Profit(); - double positionAbsProfit = MathAbs(positionProfit); - if (positionProfit <= 0) - { - continue; - } - - // - ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); - - // - if ( - type == NULL && - StringLen(symbol) <= 0) - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - - // - continue; - } - else if ( - type != NULL && - StringLen(symbol) > 0) - { - // - if (type == positionType && - symbol == positionSymbol) - { - // - if (type == POSITION_TYPE_BUY) - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - } - else - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - } - - // - continue; - } - } - else if (StringLen(symbol) > 0) - { - // - if (positionSymbol == symbol) - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - - // - continue; - } - } - else if (type != NULL) - { - // - if (type == positionType) - { - // - if (type == POSITION_TYPE_BUY) - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - } - else - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - } - - // - continue; - } - } - } - - // - return result; - } + // Regular Trade Actions ... // - // Retrieve Max In DrawDown Position Ticket ... - ulong GetMaxInDrawDownPosition( - string symbol = "", // Specified Symbol - ENUM_POSITION_TYPE type = NULL // Specified Type - ) - { - // - ulong result = -1; - - // - double profit = 0; - - // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return result; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - ulong positionTicket = mPositionInfo.Ticket(); - - // - string positionSymbol = mPositionInfo.Symbol(); - - // - double positionProfit = mPositionInfo.Profit(); - double positionAbsProfit = MathAbs(positionProfit); - if (positionProfit >= 0) - { - continue; - } - - // - ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); - - // - if ( - type == NULL && - StringLen(symbol) <= 0) - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - - // - continue; - } - else if ( - type != NULL && - StringLen(symbol) > 0) - { - // - if (type == positionType && - symbol == positionSymbol) - { - // - if (type == POSITION_TYPE_BUY) - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - } - else - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - } - - // - continue; - } - } - else if (StringLen(symbol) > 0) - { - // - if (positionSymbol == symbol) - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - - // - continue; - } - } - else if (type != NULL) - { - // - if (type == positionType) - { - // - if (type == POSITION_TYPE_BUY) - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - } - else - { - // - if (profit < positionAbsProfit) - { - // - result = positionTicket; - profit = positionAbsProfit; - } - } - - // - continue; - } - } - } - - // - return result; - } - - // - // Retrieve Specific Position's Profit ... - double GetPositionProfit( - const ulong ticket // Specified Position Ticket - ) - { - // - double result = 0; - - // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return result; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - ulong positionTicket = mPositionInfo.Ticket(); - if (positionTicket != ticket) - { - continue; - } - - // - result = mPositionInfo.Profit(); - break; - } - - // - return result; - } - - // - // Retrieve Specific Position's OpenDate ... - datetime GetPositionOpenDate( - const ulong ticket // Specified Position Ticket - ) - { - // - datetime result = 0; - - // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return result; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - ulong positionTicket = mPositionInfo.Ticket(); - if (positionTicket != ticket) - { - continue; - } - - // - result = mPositionInfo.Time(); - break; - } - - // - return result; - } - - // - // Retrieve Specific Position's Comment ... - string GetPositionComment( - const ulong ticket // Specified Position Ticket - ) - { - // - string result = ""; - - // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return result; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - ulong positionTicket = mPositionInfo.Ticket(); - if (positionTicket != ticket) - { - continue; - } - - // - result = mPositionInfo.Comment(); - break; - } - - // - return result; - } - - // - // Retrieve All Open Positions Profit ... - double GetPositionsProfit( - string symbol = "", // Specified Symbol - ENUM_POSITION_TYPE type = NULL // Specified Type - ) - { - // - double result = 0; - - // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return result; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - ulong positionTicket = mPositionInfo.Ticket(); - - // - string positionSymbol = mPositionInfo.Symbol(); - - // - double positionProfit = mPositionInfo.Profit(); - - // - ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); - - // - if ( - type == NULL && - StringLen(symbol) <= 0) - { - // - result += positionProfit; - - // - continue; - } - else if ( - type != NULL && - StringLen(symbol) > 0) - { - // - if (type == positionType && - symbol == positionSymbol) - { - // - if (type == POSITION_TYPE_BUY) - { - result += positionProfit; - } - else - { - result += positionProfit; - } - - // - continue; - } - } - else if (StringLen(symbol) > 0) - { - // - if (positionSymbol == symbol) - { - result += positionProfit; - - // - continue; - } - } - else if (type != NULL) - { - // - if (type == positionType) - { - // - if (type == POSITION_TYPE_BUY) - { - result += positionProfit; - } - else - { - result += positionProfit; - } - - // - continue; - } - } - } - - // - return result; - } - - // - // Find Oldes Position ... - ulong GetOldestPosition( - string symbol = "", // Specified Symbol - ENUM_POSITION_TYPE type = NULL // Specified Type - ) - { - // - ulong result = 0; - - // - int age = 0; - - // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return result; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - ulong positionTicket = mPositionInfo.Ticket(); - - // - string positionSymbol = mPositionInfo.Symbol(); - - // - double positionProfit = mPositionInfo.Profit(); - double positionAbsProfit = MathAbs(positionProfit); - if (positionProfit >= 0) - { - continue; - } - - // - ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); - - // - string positionComment = mPositionInfo.Comment(); - ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(positionComment); - - // - // Calculate Position's Age ... - datetime positionOpenTime = mPositionInfo.Time(); - - // - // Retrieve Trade Open Bar Index based on Current Period ... - int positionOpenBarIndex = iBarShift( - positionSymbol, - positionPeriod, - positionOpenTime); - - // - // Calculate Trade Life ... - int positionAge = MathAbs(0 - positionOpenBarIndex); - - // - if ( - type == NULL && - StringLen(symbol) <= 0) - { - // - if (age < positionAge) - { - // - age = positionAge; - result = positionTicket; - } - - // - continue; - } - else if ( - type != NULL && - StringLen(symbol) > 0) - { - // - if (type == positionType && - symbol == positionSymbol) - { - // - if (type == POSITION_TYPE_BUY) - { - // - if (age < positionAge) - { - // - age = positionAge; - result = positionTicket; - } - } - else - { - // - if (age < positionAge) - { - // - age = positionAge; - result = positionTicket; - } - } - - // - continue; - } - } - else if (StringLen(symbol) > 0) - { - // - if (positionSymbol == symbol) - { - // - if (age < positionAge) - { - // - age = positionAge; - result = positionTicket; - } - - // - continue; - } - } - else if (type != NULL) - { - // - if (type == positionType) - { - // - if (type == POSITION_TYPE_BUY) - { - // - if (age < positionAge) - { - // - age = positionAge; - result = positionTicket; - } - } - else - { - // - if (age < positionAge) - { - // - age = positionAge; - result = positionTicket; - } - } - - // - continue; - } - } - } - - // - return result; - } + // Buy ... // // Force Open a Buy/Long Position ... @@ -2050,17 +1172,23 @@ public: double price, // execution price double sl = 0, // stop loss price double tp = 0, // take profit price - string comment = "" // comment + string comment = NULL // comment ) { // bool result = false; // - string mPeriodStr = GeneratePositionPeriodComment(period); + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); - // - comment += mPeriodStr; + // + comment += mPeriodStr; + } // result = mTrader.Buy( @@ -2069,7 +1197,9 @@ public: price, sl, tp, - comment); + comment + // + ); // return result; @@ -2086,17 +1216,23 @@ public: double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time - string comment = "" // comment + string comment = NULL // comment ) { // bool result = false; // - string mPeriodStr = GeneratePositionPeriodComment(period); + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); - // - comment += mPeriodStr; + // + comment += mPeriodStr; + } // result = mTrader.BuyLimit( @@ -2107,7 +1243,9 @@ public: tp, typeTime, expiration, - comment); + comment + // + ); // return result; @@ -2124,17 +1262,23 @@ public: double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time - string comment = "" // comment + string comment = NULL // comment ) { // bool result = false; // - string mPeriodStr = GeneratePositionPeriodComment(period); + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); - // - comment += mPeriodStr; + // + comment += mPeriodStr; + } // result = mTrader.BuyStop( @@ -2145,12 +1289,17 @@ public: tp, typeTime, expiration, - comment); + comment + // + ); // return result; } + // + // Sell ... + // // Force Open a Sell/Short Position ... bool Sell( @@ -2160,17 +1309,23 @@ public: double price, // execution price double sl = 0, // stop loss price double tp = 0, // take profit price - string comment = "" // comment + string comment = NULL // comment ) { // bool result = false; // - string mPeriodStr = GeneratePositionPeriodComment(period); + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); - // - comment += mPeriodStr; + // + comment += mPeriodStr; + } // result = mTrader.Sell( @@ -2179,7 +1334,9 @@ public: price, sl, tp, - comment); + comment + // + ); // return result; @@ -2196,17 +1353,23 @@ public: double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time - string comment = "" // comment + string comment = NULL // comment ) { // bool result = false; // - string mPeriodStr = GeneratePositionPeriodComment(period); + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); - // - comment += mPeriodStr; + // + comment += mPeriodStr; + } // result = mTrader.SellLimit( @@ -2217,7 +1380,9 @@ public: tp, typeTime, expiration, - comment); + comment + // + ); // return result; @@ -2234,17 +1399,23 @@ public: double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time - string comment = "" // comment + string comment = NULL // comment ) { // bool result = false; // - string mPeriodStr = GeneratePositionPeriodComment(period); + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); - // - comment += mPeriodStr; + // + comment += mPeriodStr; + } // result = mTrader.SellStop( @@ -2255,7 +1426,26 @@ public: tp, typeTime, expiration, - comment); + comment + // + ); + + // + return result; + } + + // + // Check a Position is Exists Open or not ... + bool IsOpen( + ulong ticket // Specified Position Ticket + ) + { + // + bool result = false; + + // + result = mPositionInfo + .SelectByTicket(ticket); // return result; @@ -2264,10 +1454,10 @@ public: // // Modify Position ... bool Modify( - const ulong ticket, // position ticket - double sl = 0, // stop loss price - double tp = 0, // take profit - string comment = "" // comment + const ulong ticket, // position ticket + double sl = 0, // stop loss price + double tp = 0, // take profit + string comment = NULL // comment ) { // @@ -2275,17 +1465,22 @@ public: // // Validate Args ... - if (tp <= 0 && sl <= 0) + result = + IsOpen(ticket) && + (tp >= 0 || sl >= 0); + if (!result) { - result = false; return result; } // // Use Position Comment when there isn't new One ... - if (StringLen(comment) == 0) + if (!IsValid(comment) == 0) { - comment = GetPositionComment(ticket); + // + // if there isn't provided Comment + // Use Position Comment for default ... + comment = "Modify " + GetPositionComment(ticket); } // @@ -2293,7 +1488,9 @@ public: ticket, sl, tp, - comment); + comment + // + ); // return result; @@ -2302,163 +1499,64 @@ public: // // Close Position By Ticket ... bool Close( - ulong ticket, // Position Ticket - string comment = "" // Close Position By Specific Comment + ulong ticket, // Position Ticket + string comment = NULL // Close Position By Specific Comment ) { // bool result = false; // - // Try to Select Position ... - if (!mPositionInfo.SelectByTicket(ticket)) + // Check Position Open ... + result = !IsOpen(ticket); + if (!result) { return result; } + // + // Use Default Position Comment if it's Not Provided ... + if (!IsValid(comment)) + { + comment = "Close " + GetPositionComment(ticket); + } + // // Close Position By Specific Comment ... result = mTrader.PositionClose( ticket, mSlippage, - comment); + comment + // + ); // return result; } // - // Close All Positions ... - void CloseAllPositions( - string comment = "" // Close Position By Specific Comment + // Close Specified Positions ... + int Close( + string comment = NULL, // Close Position By Specific Comment + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true // Get Only Self Open Positions ) { // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - ulong positionTicket = mPositionInfo.Ticket(); - Close( - positionTicket, - comment); - } - } - - // - // Close Partial By Ticket ... - bool ClosePartial( - ulong ticket, // Position Ticket - double volume, // Volume Size for Partial Closing - string comment = "" // Close Position By Specific Comment - ) - { - // - bool result = false; - - // - if (!mPositionInfo.SelectByTicket(ticket)) - { - return result; - } - - // - result = mTrader.PositionClosePartial( - ticket, - volume, - mSlippage, - comment); - - // - return result; - } - - // - // Find Position Open Bar Index ... - int GetPositionOpenBarIndex( - const ulong ticket // position ticket - ) - { - // - int result = -1; - - // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return result; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - ulong positionTicket = mPositionInfo.Ticket(); - if (positionTicket != ticket) - { - continue; - } - - // - string symbol = mPositionInfo.Symbol(); - datetime openAt = mPositionInfo.Time(); - string comment = mPositionInfo.Comment(); - ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment); - - // - result = iBarShift( - symbol, - period, - openAt); - } - - // - return result; - } - - // - bool GetPosition( - XPosition &position, // Holds result ... - ulong ticket // Required Position Ticket ... - ) - { - // - bool result = false; + int result = 0; // XPosition positions[]; - GetPositions(positions); - int positionsCount = ArraySize(positions); + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic); if (positionsCount <= 0) { return result; @@ -2471,357 +1569,12 @@ public: XPosition iPosition = positions[i]; // - result = iPosition.ticket == ticket; - if (!result) - { - continue; - } - - // - position = iPosition; - break; - } - - // - return result; - } - - // - // Retrieve Positions as an Array ... - void GetPositions( - XPosition &result[] // Hold Result ... - ) - { - // - Clean(result); - - // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - if (!mPositionInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mPositionInfo.Magic() != mMagicNumber) - { - continue; - } - - // - ulong magic = mPositionInfo.Magic(); - ulong ticket = mPositionInfo.Ticket(); - string symbol = mPositionInfo.Symbol(); - datetime openAt = mPositionInfo.Time(); - double swap = mPositionInfo.Swap(); - double sl = mPositionInfo.StopLoss(); - double tp = mPositionInfo.TakeProfit(); - double profit = mPositionInfo.Profit(); - double volume = mPositionInfo.Volume(); - string comment = mPositionInfo.Comment(); - double entry = mPositionInfo.PriceOpen(); - double price = mPositionInfo.PriceCurrent(); - double commission = mPositionInfo.Commission(); - ENUM_POSITION_TYPE type = mPositionInfo.PositionType(); - ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment); - - // - XPosition iPosition = {}; - - // - iPosition.tp = tp; - iPosition.sl = sl; - iPosition.swap = swap; - iPosition.type = type; - iPosition.magic = magic; - iPosition.entry = entry; - iPosition.price = price; - iPosition.ticket = ticket; - iPosition.symbol = symbol; - iPosition.period = period; - iPosition.volume = volume; - iPosition.openAt = openAt; - iPosition.profit = profit; - iPosition.comment = comment; - iPosition.commission = commission; - - // - Add( - iPosition, - result); - } - } - - // - void GetPositions( - XPosition &result[], // Hold Result ... - string symbol, // Trading Symbol ... - ENUM_TIMEFRAMES period // Trading Period ... - ) - { - // - Clean(result); - - // - int positionsCount = PositionsTotal(); - if (positionsCount <= 0) - { - return; - } - - // - XPosition allPositions[]; - GetPositions(allPositions); - - // - for (int i = 0; i < positionsCount; i++) - { - // - XPosition iPosition = allPositions[i]; - - // - if (symbol != iPosition.symbol) - { - continue; - } - - // - ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(iPosition.comment); - if (period != positionPeriod) - { - continue; - } - - // - Add( - iPosition, - result); - } - } - - // - // Execute a Signal ... - bool ExecuteSignal( - XSignal &signal, // Signal ... - string comment = "", // Position Comment ... - ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ... - datetime expiration = 0 // order expiration time - ) - - { - // - bool result = false; - - // - double currentEntry = GetEntry( - signal.symbol, - signal.type); - bool isLong = IsLong(signal.type); - - // - ResetLastError(); - - // - if (signal.mode == X_ORDER_MODE_MARKET) - { - // - // Execute MArket Orders ... - if (isLong) - { + bool isClosed = Close( + iPosition.ticket, + comment // - result = Buy( - signal.symbol, - signal.period, - signal.volume, - signal.entry, - signal.sl, - signal.tp, - comment); - } - else - { - // - result = Sell( - signal.symbol, - signal.period, - signal.volume, - signal.entry, - signal.sl, - signal.tp, - comment); - } - } - else if (signal.mode == X_ORDER_MODE_LIMIT) - { - // - // Execute Limit Orders ... - - // - // Check Conditions ... - - // - // Check Price ... - result = isLong - ? signal.entry < currentEntry - : signal.entry > currentEntry; - if (!result) - { - return result; - } - - // - // Check Expiration Date ... - result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY) - ? expiration > 0 - : true; - if (!result) - { - return result; - } - - // - if (isLong) - { - // - result = BuyLimit( - signal.symbol, - signal.period, - signal.volume, - signal.entry, - signal.sl, - signal.tp, - lifetime, - expiration, - comment); - } - else - { - // - result = SellLimit( - signal.symbol, - signal.period, - signal.volume, - signal.entry, - signal.sl, - signal.tp, - lifetime, - expiration, - comment); - } - } - else if (signal.mode == X_ORDER_MODE_STOP) - { - // - // Execute Stop Orders ... - - // - // Check Conditions ... - - // - // Check Price ... - result = isLong - ? signal.entry > currentEntry - : signal.entry < currentEntry; - if (!result) - { - return result; - } - - // - // Check Expiration Date ... - result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY) - ? expiration > 0 - : true; - if (!result) - { - return result; - } - - // - if (isLong) - { - // - result = BuyStop( - signal.symbol, - signal.period, - signal.volume, - signal.entry, - signal.sl, - signal.tp, - lifetime, - expiration, - comment); - } - else - { - // - result = SellStop( - signal.symbol, - signal.period, - signal.volume, - signal.entry, - signal.sl, - signal.tp, - lifetime, - expiration, - comment); - } - } - - // - if (!result) - { - // - LogMessage("Error: " + (string)GetLastError() + ", " + GetErrorDescription(GetLastError())); - } - - // - return result; - } - - // - // Execute a Collection of Signals ... - int ExecuteSignals( - const XSignal &signals[], // an Array of Signals ... - string comment = "", // Position Comment ... - ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ... - datetime expiration = 0 // order expiration time - ) - { - // - int result = 0; - - // - int signalsCount = ArraySize(signals); - if (signalsCount <= 0) - { - return result; - } - - // - for (int i = 0; i < signalsCount; i++) - { - // - XSignal iSignal = signals[i]; - - // - bool isExecuted = ExecuteSignal( - iSignal, - comment, - lifetime, - expiration); - - // - if (isExecuted) + ); + if (isClosed) { result++; } @@ -2832,85 +1585,20 @@ public: } // - // Retrieve in Profit Positions ... - void GetInProfitPositions( - XPosition &result[] // Hold Result ... + // Close a Collection of Positions ... + int Close( + XPosition &positions[], // Collection of Positions + string comment // Close Comment ) { // - Clean(result); + int result = 0; - // - XPosition allPositions[]; - GetPositions(allPositions); - int positionsCount = ArraySize(allPositions); - if (positionsCount <= 0) - { - return; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - XPosition iPosition = allPositions[i]; - - // - if (iPosition.profit > 0) - { - Add( - iPosition, - result); - } - } - } - - // - // Retrieve in Drawdown Positions ... - void GetInDrawdownPositions( - XPosition &result[] // Hold Result ... - ) - { - // - Clean(result); - - // - XPosition allPositions[]; - GetPositions(allPositions); - int positionsCount = ArraySize(allPositions); - if (positionsCount <= 0) - { - return; - } - - // - for (int i = 0; i < positionsCount; i++) - { - // - XPosition iPosition = allPositions[i]; - - // - if (iPosition.profit < 0) - { - Add( - iPosition, - result); - } - } - } - - // - // Close a Collection Of Positions ... - void ClosePositions( - XPosition &positions[], // Positions to Close ... - string comment = "" // Specified Comment ... - ) - { // int positionsCount = ArraySize(positions); if (positionsCount <= 0) { - return; + return result; } // @@ -2920,135 +1608,76 @@ public: XPosition iPosition = positions[i]; // - Close( + bool isClosed = Close( iPosition.ticket, - comment); + comment + // + ); + if (isClosed) + { + result++; + } } + + // + return result; } // - // Retrieve All Orders ... - void GetOrders( - XOrder &result[], // Holdes Result .... - string symbol, // Trading Symbol ... - ENUM_TIMEFRAMES period, // Trading TimeFrame ... - ENUM_ORDER_STATE state = NULL // Order State ... + // Close Partial By Ticket ... + bool ClosePartial( + ulong ticket, // Position Ticket + double volume, // Volume Size for Partial Closing + string comment = NULL // Close Position By Specific Comment ) { // - Clean(result); + bool result = false; // - int ordersCount = OrdersTotal(); - if (ordersCount <= 0) + result = IsOpen(ticket); + if (!result) { - return; + return result; } // - // Since Orders may be so more than positions ... - // start Orders Collectiong Loops reverse ... - for (int i = ordersCount - 1; i >= 0; i--) + // Use Default Partial Close Comment ... + if (!IsValid(comment)) { // - if (!mOrderInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mOrderInfo.Magic() != mMagicNumber) - { - continue; - } - - // - // Reading Order Info ... - long magic = mOrderInfo.Magic(); - double sl = mOrderInfo.StopLoss(); - ulong ticket = mOrderInfo.Ticket(); - double tp = mOrderInfo.TakeProfit(); - string oSymbol = mOrderInfo.Symbol(); - string comment = mOrderInfo.Comment(); - long pocitionID = mOrderInfo.PositionId(); - double openPrice = mOrderInfo.PriceOpen(); - datetime setupAt = mOrderInfo.TimeSetup(); - datetime executedAt = mOrderInfo.TimeDone(); - ENUM_ORDER_STATE oState = mOrderInfo.State(); - ENUM_ORDER_TYPE type = mOrderInfo.OrderType(); - double currentPrice = mOrderInfo.PriceCurrent(); - datetime expiredAt = mOrderInfo.TimeExpiration(); - double initialVolume = mOrderInfo.VolumeInitial(); - double currentVolume = mOrderInfo.VolumeCurrent(); - double stopLimitPrice = mOrderInfo.PriceStopLimit(); - ENUM_ORDER_TYPE_TIME lifetime = mOrderInfo.TypeTime(); - ENUM_ORDER_TYPE_FILLING filling = mOrderInfo.TypeFilling(); - - // - if (StringLen(symbol) > 0 && symbol != oSymbol) - { - continue; - } - - // - ENUM_TIMEFRAMES oPeriod = ExtractPositionPeriod(comment); - if (period != NULL && period != oPeriod) - { - continue; - } - - // - if (state != NULL && oState != state) - { - continue; - } - - // - // Now Create an instance of XOrder struct and fill it by - // retrieved data, and add it to results ... - XOrder iOrder = {}; - - // - iOrder.sl = sl; - iOrder.tp = tp; - iOrder.type = type; - iOrder.magic = magic; - iOrder.state = oState; - iOrder.ticket = ticket; - iOrder.smybol = oSymbol; - iOrder.setupAt = setupAt; - iOrder.comment = comment; - iOrder.filling = filling; - iOrder.lifetime = lifetime; - iOrder.expiredAt = expiredAt; - iOrder.openPrice = openPrice; - iOrder.pocitionID = pocitionID; - iOrder.executedAt = executedAt; - iOrder.currentPrice = currentPrice; - iOrder.initialVolume = initialVolume; - iOrder.currentVolume = currentVolume; - iOrder.stopLimitPrice = stopLimitPrice; - - // - Add( - iOrder, - result); + comment += "PClose " + GetPositionComment(ticket); } + + // + result = mTrader.PositionClosePartial( + ticket, + volume, + mSlippage, + comment + // + ); + + // + return result; } // - int OrdersCount() + // Cancel Specific Order ... + bool CancelOrder(ulong ticket) { - return OrdersTotal(); + return mTrader + .OrderDelete(ticket); } // // Cancel Specific Orders ... - bool CancelOrders( - XOrder &orders[]) + int CancelOrders( + XOrder &orders[] // Specified Orders ... + ) { // - bool result = false; + int result = 0; // int ordersCount = ArraySize(orders); @@ -3064,10 +1693,11 @@ public: XOrder iOrder = orders[i]; // - bool isDeleted = mTrader.OrderDelete(iOrder.ticket); + bool isDeleted = mTrader + .OrderDelete(iOrder.ticket); if (isDeleted && !result) { - result = isDeleted; + result++; } } @@ -3075,118 +1705,995 @@ public: return result; } + // + // Extractors ... + + // + // Positions ... + + // + // Calculate Positions Profit ... + double Profit( + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true // Get Only Self Open Positions + ) + { + // + double result = 0; + + // + // Retrieve Positions ... + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic + // + ); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + result += positions[i].profit; + } + + // + return result; + } + + // + // Retrieve Specific Position by Index ... + bool GetPosition( + int index, // Specified Index + XPosition &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + // Retrieve Specific Position by Ticket ... + bool GetPosition( + ulong ticket, // Specified Ticket + XPosition &result // Hold's Result + ) + { + // + return result + .ByTicket(ticket); + } + + // + // Retrieve Positions ... + int GetPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = PositionsTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XPosition iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Select In Profit Positions ... + int GetInProfitPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) + ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic, + forceClean); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition min; + XPosition max; + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit <= 0) + { + continue; + } + + // + // Calculate Min and Max ... + + // + // Min ... + if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) + { + min = iPosition; + } + + // + // Max ... + if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) + { + max = iPosition; + } + + // + bool isSelectionMethodFilterPassed = + // + (method == NULL || + method == X_POSITION_SELECT_ALL || + method == X_POSITION_SELECT_ALL) + ? true + : false; + // + ; + if (!isSelectionMethodFilterPassed) + { + continue; + } + + // + AddRef( + iPosition, + result + // + ); + } + + // + if (min.IsValid() && + (method == X_POSITION_SELECT_MIN || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + min, + result + // + ); + } + + // + if (max.IsValid() && + (method == X_POSITION_SELECT_MAX || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + max, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Select In Drawdown Positions ... + int GetInDrawdownPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) + ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic, + forceClean); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition min; + XPosition max; + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit >= 0) + { + continue; + } + + // + // Calculate Min and Max ... + + // + // Min ... + if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) + { + min = iPosition; + } + + // + // Max ... + if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) + { + max = iPosition; + } + + // + bool isSelectionMethodFilterPassed = + // + (method == NULL || + method == X_POSITION_SELECT_ALL || + method == X_POSITION_SELECT_ALL) + ? true + : false; + // + ; + if (!isSelectionMethodFilterPassed) + { + continue; + } + + // + AddRef( + iPosition, + result + // + ); + } + + // + if (min.IsValid() && + (method == X_POSITION_SELECT_MIN || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + min, + result + // + ); + } + + // + if (max.IsValid() && + (method == X_POSITION_SELECT_MAX || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + max, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Orders ... + + // + // Retrieve Specific Order by Index ... + bool GetOrder( + int index, // Specified Index + XOrder &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + // Retrieve Specific Positions Orders ... + int GetOrders( + ulong ticket, // Positions Ticket + XOrder &result[], // Hold's Result + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + // Select History by Specified Ticket ... + bool isHistorySelected = HistorySelectByPosition(ticket); + if (!isHistorySelected) + { + return mResult; + } + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder; + bool isLoaded = iOrder.HistoryByIndex(i); + if (!isLoaded) + { + continue; + } + + // + bool isTicketFilterPassed = + // + iOrder.ticket = ticket + // + ; + if (!isTicketFilterPassed) + { + continue; + } + + // + AddRef( + iOrder, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Retrieve All Orders ... + int GetOrders( + XOrder &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_ORDER_TYPE type = NULL, // Long (Buy) or Short (Sell) + ENUM_ORDER_STATE state = NULL, // Order State + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = OrdersTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XOrder iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + state, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Retrieve Historical Orders ... + int GetOrders( + XOrder &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_ORDER_TYPE type = NULL, // Long (Buy) or Short (Sell) + ENUM_ORDER_STATE state = NULL, // Order State + datetime startDate = NULL, // Specify Start Date + datetime endDate = NULL, // Specify End Date + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + endDate = NormalizeTime(endDate); + + // + if (!IsValid(startDate)) + { + startDate = endDate - PeriodSeconds(PERIOD_D1); + } + + // + bool isHistorySelected = HistorySelect( + startDate, + endDate); + if (!isHistorySelected) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = OrdersTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XOrder iItem; + bool isLoaded = iItem.HistoryByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + state, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Deals ... + + // + // Retrieve Specific Deal by Index ... + bool GetDeal( + int index, // Specified Index + XDeal &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + // Retrieve Specified Deal's History ... + int GetDealsHistory( + XDeal &deal, // Specified Deal + XOrder &history[], // Deals History + bool forceClean = true // Clean Result Array + ) + { + // + int result = 0; + + // + if (!deal.IsValid()) + { + return result; + } + + // + result = GetOrders( + deal.positionId, + history, + forceClean); + + // + return result; + } + // // Retrieve All Deals ... - void GetDeals(XDeal &result[]) + int GetDeals( + XDeal &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_DEAL_TYPE type = NULL, // Deal Type + ENUM_DEAL_ENTRY entry = NULL, // Deal Entry + ENUM_DEAL_REASON reason = NULL, // Deal Reason + datetime startDate = NULL, // Specify Start Date + datetime endDate = NULL, // Specify End Date + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) { // - Clean(result); + int mResult = 0; // - int dealsCount = HistoryDealsTotal(); - if (dealsCount <= 0) + endDate = NormalizeTime(endDate); + + // + if (!IsValid(startDate)) + { + startDate = endDate - PeriodSeconds(PERIOD_D1); + } + + // + bool isHistorySelected = HistorySelect( + startDate, + endDate); + if (!isHistorySelected) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = HistoryDealsTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XDeal iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + entry, + reason, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Protected ... +protected: + // + // Props ... + + // + // Event Listener Notifiers ... + + // + // State ... + void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) + { + // + int count = ArraySize(mTradeStateChangedEventHandlers); + if (count <= 0) { return; } // - for (int i = dealsCount - 1; i >= 0; i--) + for (int i = 0; i < count; i++) { // - if (!mDealInfo.SelectByIndex(i)) - { - continue; - } - - // - if (mDealInfo.Magic() != mMagicNumber) - { - continue; - } - - // - // Reading Order Info ... - double swap = mDealInfo.Swap(); - ulong magic = mDealInfo.Magic(); - ulong order = mDealInfo.Order(); - ulong ticket = mDealInfo.Ticket(); - datetime time = mDealInfo.Time(); - double price = mDealInfo.Price(); - string symbol = mDealInfo.Symbol(); - double profit = mDealInfo.Profit(); - double volume = mDealInfo.Volume(); - string comment = mDealInfo.Comment(); - ulong positionId = mDealInfo.PositionId(); - ENUM_DEAL_ENTRY entry = mDealInfo.Entry(); - double commission = mDealInfo.Commission(); - ENUM_DEAL_TYPE type = mDealInfo.DealType(); - ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( - ticket, - DEAL_REASON); - - // - XDeal iDeal = {}; - - // - iDeal.swap = swap; - iDeal.time = time; - iDeal.type = type; - iDeal.magic = magic; - iDeal.entry = entry; - iDeal.order = order; - iDeal.price = price; - iDeal.ticket = ticket; - iDeal.symbol = symbol; - iDeal.profit = profit; - iDeal.volume = volume; - iDeal.reason = reason; - iDeal.comment = comment; - iDeal.positionId = positionId; - iDeal.commission = commission; - - // - Add( - iDeal, - result); + TOnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i]; + iHandler(state); } } // - // Generate String Representation Of Position's Time Frame ... - string GeneratePositionPeriodComment(ENUM_TIMEFRAMES period) + // Deals ... + void NotifyDealsChangeEvent(int changes) { // - string result = mPeriodPrefix + "(" + ToString(period) + ")"; + int count = ArraySize(mDealsChangedEventHandlers); + if (count <= 0) + { + return; + } // - return result; + for (int i = 0; i < count; i++) + { + // + TOnDealsChanged iHandler = mDealsChangedEventHandlers[i]; + iHandler(changes); + } } // - // Extract Position Time Frame From it's Comment ... - ENUM_TIMEFRAMES ExtractPositionPeriod(string comment) + // Orders ... + void NotifyOrdersChangeEvent(int changes) { // - ENUM_TIMEFRAMES result = _Period; + int count = ArraySize(mOrdersChangedEventHandlers); + if (count <= 0) + { + return; + } // - if (StringLen(comment) <= 0) + for (int i = 0; i < count; i++) + { + // + TOnOrdersChanged iHandler = mOrdersChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // Positions ... + void NotifyPositionsChangeEvent(int changes) + { + // + int count = ArraySize(mPositionsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // StopLoss ... + void NotifyStopLossEvent(const XDeal &deal) + { + // + int count = ArraySize(mStopLossEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnStopLoss iHandler = mStopLossEventHandlers[i]; + iHandler(deal); + } + } + + // + // Take Profit ... + void NotifyTakeProfitEvent(const XDeal &deal) + { + // + int count = ArraySize(mTakeProfitEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTakeProfit iHandler = mTakeProfitEventHandlers[i]; + iHandler(deal); + } + } + + // + // Tools ... + + // + // Retrieve Specified Position Comment ... + string GetPositionComment(ulong ticket) + { + // + string result = NULL; + + // + if (!IsOpen(ticket)) { return result; } // - string periodStr = ExtractString( - comment, - mPeriodPrefix + "(", - ")"); - if (StringLen(periodStr) <= 0) + XPosition position; + bool isLoaded = position.ByTicket(ticket); + if (!isLoaded) { return result; } // - result = ToPeriod(periodStr); + result = position.comment; // return result; @@ -3236,167 +2743,188 @@ public: } // - // SUPPORT Signals ... + // XPosition Pack ... // - // Find an Specific Position Has Support Signal Or not ... - bool HasSupport(ulong ticket) + // Extract specific Positions Pack ... + // in this senario there is no need to Position exists itself ... + bool GetPositionPack( + ulong ticket, // Specified Positions Ticket + string symbol, // Specified Position Symbol + ENUM_TIMEFRAMES period, // Specified Position Period + XPositionPack &pack // Hold Result + ) { // bool result = false; // - int count = PositionsCount(); - if (count <= 1) - { - return result; - } + pack.Clean(); // XPosition position; - result = GetPosition( - position, - ticket); - if (!result) + bool hasPosition = GetPosition( + ticket, + position + // + ); + if (hasPosition) { - return result; + pack.position = position; } // - XPosition positions[]; - GetPositions(positions); - for (int i = 0; i < count; i++) - { - // - XPosition iPosition = positions[i]; - - // - string supportTicketStr = ExtractParentTicketOfSupport(iPosition.comment); - if (StringLen(supportTicketStr) == 0) - { - continue; - } - - // - ulong parentTicket = (ulong)supportTicketStr; - - // - result = - parentTicket == ticket && - iPosition.ticket != parentTicket; - if (result) - { - break; - } - } - - // - return result; - } - - // - // Get All Support Positions for Specific Position ... - bool GetSupportPositions( - ulong ticket, // Parent Position Ticket - XPosition &supports[] // Holds Result ... - ) - { - // - bool result = false; - - // - Clean(supports); - - // - int count = PositionsCount(); - if (count <= 0) - { - return result; - } - - // - XPosition parentPosition; - bool positionExist = GetPosition( - parentPosition, - ticket); - if (!positionExist) - { - return result; - } - - // - bool hasSupport = HasSupport(ticket); - if (!hasSupport) - { - return result; - } - - // - XPosition positions[]; - GetPositions(positions); - for (int i = 0; i < count; i++) - { - // - XPosition iPosition = positions[i]; - - // - if (iPosition.ticket == ticket) - { - continue; - } - - // - string pTicketStr = ExtractParentTicketOfSupport(iPosition.comment); - if (StringLen(pTicketStr) <= 0) - { - continue; - } - - // - ulong pTicket = (ulong)pTicketStr; - if (pTicket != ticket) - { - continue; - } - - // - Add( - iPosition, - supports); - } - - // - result = ArraySize(supports) > 0; - - // - return result; - } - - // - bool GetSupportOrders( - ulong ticket, // Parent Position Ticket - XOrder &supports[], // Holds Result ... - string symbol, // Trading Symbol ... - ENUM_TIMEFRAMES period, // Trading TimeFrame ... - ENUM_ORDER_STATE state = NULL // Order State ... - ) - { - // - bool result = false; - - // - Clean(supports); + XOrder supportOrders[]; + XPosition supportPositions[]; // XOrder orders[]; GetOrders( orders, - symbol, - period, - state); + symbol, // Specified Symbol + NULL, // All Providers + period, // Specified Period + NULL, // All Types + ORDER_STATE_PLACED, // Just UnTriggered Orders + true // Filter by Magic + ); int ordersCount = ArraySize(orders); - result = ordersCount > 0; - if (!result) + + // + // Select Orders ... + if (ordersCount > 0) + { + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + // Retrieve Order Supported Ticket ... + ulong parentTicket = ExtractSupportedTicket(iOrder.comment); + if (NotEmpty(parentTicket) && parentTicket == ticket) + { + // + AddRef( + iOrder, + supportOrders + // + ); + } + } + } + + // + int supportOrdersCount = ArraySize(supportOrders); + if (supportOrdersCount > 0) + { + // + pack.supportOrdersCount = supportOrdersCount; + + // + Copy( + supportOrders, + pack.supportOrders); + } + + // + XPosition positions[]; + GetPositions( + positions, + symbol, // Specified Symbol ... + NULL, // All Providers ... + period // Specified Period ... + ); + int positionsCount = ArraySize(positions); + + // + // Select Positions ... + if (positionsCount > 0) + { + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + ulong parentTicket = ExtractSupportedTicket(iPosition.comment); + if (NotEmpty(parentTicket) && parentTicket == ticket) + { + // + AddRef( + iPosition, + supportPositions + // + ); + } + } + } + + // + int supportPositionsCount = ArraySize(supportPositions); + if (supportPositionsCount > 0) + { + // + pack.supportPositionsCount = supportPositionsCount; + + // + Copy( + supportPositions, + pack.supportPositions); + } + + // + result = supportOrdersCount > 0 || supportPositionsCount > 0; + + // + return result; + } + + // + // Extract Specific Deals Position's Pack ... + // this used when a Position SL or TP triggered and we want to close + // all it's Supported Packs ... + bool GetDealPack( + XDeal &deal, + XPositionPack &pack // + ) + { + // + bool result = false; + + // + ulong ticket = deal.positionId; + ENUM_TIMEFRAMES dealPeriod = GetDealPeriod(deal); + string dealSymbol = deal.symbol; + + // + // So We Have to Get Positions Pack ... + result = GetPositionPack( + ticket, + dealSymbol, + dealPeriod, + pack + // + ); + + // + return result; + } + + // + ENUM_TIMEFRAMES GetDealPeriod(XDeal &deal) + { + // + ENUM_TIMEFRAMES result = NULL; + + // + XOrder orders[]; + int ordersCount = GetDealsHistory( + deal, + orders); + if (!ordersCount) { return result; } @@ -3408,422 +2936,121 @@ public: XOrder iOrder = orders[i]; // - string pTicketStr = ExtractParentTicketOfSupport(iOrder.comment); - if (StringLen(pTicketStr) == 0) + if (IsValid(iOrder.comment)) { - continue; + // + ENUM_TIMEFRAMES iPeriod = ExtractPeriod(iOrder.comment); + if (IsValid(iPeriod)) + { + result = iPeriod; + break; + } } - - // - ulong pTicket = (ulong)pTicketStr; - if (pTicket != ticket) - { - continue; - } - - // - Add( - iOrder, - supports); - } - - // - result = ArraySize(supports) > 0; - - // - return result; - } - - // - // Generate SL Support Signal ... - bool GenerateSLSupportSignal( - XSignal &signal, // Holds Result .... - ulong ticket, // Specific Position Ticket ... - double slGapPoint = 10, // Which Distance to SL for Enabling Signal ... - double volumeMultiplier = 2 // Support Signals Volume Multiplier ... - ) - { - // - bool result = false; - - // - int count = PositionsCount(); - if (count <= 0) - { - return result; - } - - // - bool hasSupport = HasSupport(ticket); - if (hasSupport) - { - return result; - } - - // - XPosition position; - result = GetPosition( - position, - ticket); - if (!result) - { - return result; - } - - // - bool isLong = - IsLong(position.type); - - // - string symbol = position.symbol; - ENUM_TIMEFRAMES period = ExtractPositionPeriod(position.comment); - double volume = position.volume * volumeMultiplier; - volume = NormalizeVolume( - volume, - symbol); - - ENUM_POSITION_TYPE type = isLong - ? POSITION_TYPE_SELL - : POSITION_TYPE_BUY; - ENUM_X_ORDER_MODES mode = X_ORDER_MODE_STOP; - - // - double slGapPrice = PointToPrice( - symbol, - slGapPoint); - double riskPrice = MathAbs(position.entry - position.sl); - - // - double entry = - isLong - ? position.sl + slGapPrice - : position.sl - slGapPrice; - entry = NormalizePrice(entry, symbol); - - // - double sl = - isLong - ? entry + riskPrice - : entry - riskPrice; - sl = NormalizePrice(sl, symbol); - - // - double tp = - isLong - ? entry - riskPrice - : entry + riskPrice; - tp = NormalizePrice(tp, symbol); - - // - signal.sl = sl; - signal.tp = tp; - signal.type = type; - signal.mode = mode; - signal.entry = entry; - signal.volume = volume; - signal.symbol = symbol; - signal.period = period; - - // - return result; - } - - // - // Close a Position and it's Supports on a Profit ... - bool ClosePositionAndSupports( - ulong ticket, // Position Ticket - double minProfit = 4 // Minimum Profit For Closing - ) - { - // - bool result = false; - - // - if (minProfit <= 0) - { - return result; - } - - // - int count = PositionsCount(); - if (count <= 0) - { - return result; - } - - // - XPosition position; - bool isExist = GetPosition( - position, - ticket); - if (!isExist) - { - return result; - } - - // - bool hasSupport = HasSupport(ticket); - if (!hasSupport) - { - return result; - } - - // - XPosition supports[]; - hasSupport = GetSupportPositions( - ticket, - supports); - int supportsCount = ArraySize(supports); - if (!hasSupport || supportsCount <= 0) - { - return result; - } - - // - double profitSummary = 0; - for (int i = 0; i < supportsCount; i++) - { - // - XPosition iSupport = supports[i]; - - // - profitSummary += iSupport.profit; - } - - // - result = profitSummary > 0 && profitSummary >= minProfit; - if (!result) - { - return result; - } - - // - Add( - position, - supports); - - // - string comment = "Close Position (" + (string)ticket + ") and it's Supports in Profit: " + (string)profitSummary + " ..."; - ClosePositions( - supports, - comment); - - // - if (result) - { - LogMessage(comment); } // return result; } - // - // END Provided Functions ... - // - - // - // Protected ... -protected: // // Private ... +private: + // + // Props ... // - // EVENTS Handlers Notifiers ... + int mSlippage; // Slippage ... + ulong mMagicNumber; // Magic Number (Unique Identifier) ... // - // STATE ... - void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) - { - // - int count = ArraySize(mTradeStateChangedEventHandlers); - if (count <= 0) - { - return; - } - - // - for (int i = 0; i < count; i++) - { - // - OnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i]; - iHandler(state); - } - } + XSCTradeBase *mTrader; // Base CTrade Manipulated Instance ... // - // DEALS ... - void NotifyDealsChangeEvent(int changes) - { - // - int count = ArraySize(mDealsChangedEventHandlers); - if (count <= 0) - { - return; - } - - // - for (int i = 0; i < count; i++) - { - // - OnDealsChanged iHandler = mDealsChangedEventHandlers[i]; - iHandler(changes); - } - } + CDealInfo mDealInfo; // Deals Info ... + COrderInfo mOrderInfo; // Order Info ... + CPositionInfo mPositionInfo; // Positions Info + CHistoryOrderInfo mHistoryOrderInfo; // History Orders Info ... // - // ORDERS ... - void NotifyOrdersChangeEvent(int changes) - { - // - int count = ArraySize(mOrdersChangedEventHandlers); - if (count <= 0) - { - return; - } - - // - for (int i = 0; i < count; i++) - { - // - OnOrdersChanged iHandler = mOrdersChangedEventHandlers[i]; - iHandler(changes); - } - } + // Tools ... // - // POSITIONS ... - void NotifyPositionsChangeEvent(int changes) - { - // - int count = ArraySize(mPositionsChangedEventHandlers); - if (count <= 0) - { - return; - } + // OnTrade Event Handlers Section ... - // - for (int i = 0; i < count; i++) - { - // - OnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; - iHandler(changes); - } - } + // + // Props ... + + // + int mDaysForRead; // Reading Dates for Trade History Checker ... + datetime mEndDate; // End Date for Trade history Checking ... + datetime mStartDate; // Start Date for Trade history Checking ... ... + int mOrdersCount; // Number of Active orders ... + int mPositionsCount; // Number of Open positions ... + int mDealsCount; // Number of Deals in the Trade History Checking ... + int mHistoryOrdersCount; // Number of Orders in the Trade History Checking ... + bool mScanStarted; // a Flag of counter relevance ... + + // + // Event Listeners ... + + // + // Deals Changed Event Handlers ... + TOnDealsChanged mDealsChangedEventHandlers[]; + + // + // Orders Changed Event Handlers ... + TOnOrdersChanged mOrdersChangedEventHandlers[]; + + // + // Positions Changed Event Handlers ... + TOnPositionsChanged mPositionsChangedEventHandlers[]; + + // + // Trade State Changed Event Handlers ... + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; // // TPSL ... + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; // - void NotifyStopLossEvent(const XDeal &deal) + // Reset On Trade Scanner Context ... + void ResetOnTradeContext() { // - int count = ArraySize(mStopLossEventHandlers); - if (count <= 0) + mEndDate = TimeCurrent(); + mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + } + + // + // Initial Context Of Trade Scanner ... + void InitOnTradeContext() + { + // + ResetLastError(); + + // + mOrdersCount = OrdersTotal(); + mPositionsCount = PositionsTotal(); + + // + // load history ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) { return; } // - for (int i = 0; i < count; i++) - { - // - OnStopLoss iHandler = mStopLossEventHandlers[i]; - iHandler(deal); - } - } - - // - void NotifyTakeProfitEvent(const XDeal &deal) - { - // - int count = ArraySize(mTakeProfitEventHandlers); - if (count <= 0) - { - return; - } + // get the current value ... + mDealsCount = HistoryDealsTotal(); + mHistoryOrdersCount = HistoryOrdersTotal(); // - for (int i = 0; i < count; i++) - { - // - OnTakeProfit iHandler = mTakeProfitEventHandlers[i]; - iHandler(deal); - } + mScanStarted = true; } -private: - // - // using deviation, it must be in Point ... - int mSlippage; - - // - // using magic number ... - ulong mMagicNumber; - - // - // using CTrade instance ... - XSCTradeBase mTrader; - - // - // Deals Info ... - CDealInfo mDealInfo; - - // - // Order Info ... - COrderInfo mOrderInfo; - - // - // using PositionInfo instance ... - CPositionInfo mPositionInfo; - - // - // ADDITIONAL Data ... - - // - string mPeriodPrefix; - - // - // START Trade Processing ... - // - - // - int mDaysForRead; - - // - // set the limits of the trade history on the global scope ... - - // - // // start date for trade history in cache ... - datetime mStartDate; - - // - // end date for trade history in cache ... - datetime mEndDate; - - // - // global OnTrade counters ... - - // - // number of active orders ... - int mOrdersCount; - - // - // number of open positions ... - int mPositionsCount; - - // - // number of deals in the trade history cache ... - int mDealsCount; - - // - // number of orders in the trade history cache ... - int mHistoryOrdersCount; - - // - // flag of counter relevance ... - bool mScanStarted; - // // Check Statrt Date In Trade History ... void CheckStartDateInTradeHistory() @@ -3943,169 +3170,6 @@ private: // checking if it is necessary to change the limits of the trade history to be requested in cache ... CheckStartDateInTradeHistory(); } - - // - // Reset On Trade Scanner Context ... - void ResetOnTradeContext() - { - // - mEndDate = TimeCurrent(); - mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); - } - - // - // Initial Context Of Trade Scanner ... - void InitOnTradeContext() - { - // - ResetLastError(); - - // - mOrdersCount = OrdersTotal(); - mPositionsCount = PositionsTotal(); - - // - // load history ... - bool selected = HistorySelect(mStartDate, mEndDate); - if (!selected) - { - return; - } - - // - // get the current value ... - mDealsCount = HistoryDealsTotal(); - mHistoryOrdersCount = HistoryOrdersTotal(); - - // - mScanStarted = true; - } - - // - // Deals Changed Event Handlers ... - OnDealsChanged mDealsChangedEventHandlers[]; - - // - // Orders Changed Event Handlers ... - OnOrdersChanged mOrdersChangedEventHandlers[]; - - // - // Positions Changed Event Handlers ... - OnPositionsChanged mPositionsChangedEventHandlers[]; - - // - // Trade State Changed Event Handlers ... - OnTradeStateChanged mTradeStateChangedEventHandlers[]; - - // - // TPSL ... - OnStopLoss mStopLossEventHandlers[]; - OnTakeProfit mTakeProfitEventHandlers[]; - - // - // END Trade Processing ... - // }; -// -// START Usefull Functions ... -// - -// -// Add Specific XPosition to Specified Array ... -void Add( - XDeal &item, - XDeal &buffer[]) -{ - // - ArrayResize( - buffer, - ArraySize(buffer) + 1); - - // - buffer[ArraySize(buffer) - 1] = item; -} -void Add( - XOrder &item, - XOrder &buffer[]) -{ - // - ArrayResize( - buffer, - ArraySize(buffer) + 1); - - // - buffer[ArraySize(buffer) - 1] = item; -} -void Add( - XPosition &item, - XPosition &buffer[]) -{ - // - ArrayResize( - buffer, - ArraySize(buffer) + 1); - - // - buffer[ArraySize(buffer) - 1] = item; -} - -// -// Clear All Items Inside Array ... -void Clean(XDeal &buffer[]) -{ - // - ArrayFree(buffer); - ArrayResize(buffer, 0); -} -void Clean(XOrder &buffer[]) -{ - // - ArrayFree(buffer); - ArrayResize(buffer, 0); -} -void Clean(XPosition &buffer[]) -{ - // - ArrayFree(buffer); - ArrayResize(buffer, 0); -} - -// -// Generate Identifier Tag ... -string GenerateTag(XSignal &info) -{ - // - string result = ""; - - // - result = info.symbol + "," + ToString(info.period); - - // - return result; -} - -// -// Convert Position to Signal ... -XSignal ToSignalInfo( - XPosition &position) -{ - // - XSignal result; - - // - result.tp = position.tp; - result.sl = position.sl; - result.type = position.type; - result.entry = position.entry; - result.symbol = position.symbol; - result.period = position.period; - result.volume = position.volume; - - // - return result; -} - -// -// END Usefull Functions ... -// +// \ No newline at end of file diff --git a/MQLTestWorkspace/Documents/.gitkeep b/MQLTestWorkspace/Documents/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/MQLTestWorkspace/Documents/JsModules/x-color.tools.js b/MQLTestWorkspace/Documents/JsModules/x-color.tools.js new file mode 100644 index 0000000..c3ac5f9 --- /dev/null +++ b/MQLTestWorkspace/Documents/JsModules/x-color.tools.js @@ -0,0 +1,506 @@ +/** + * XColor Tools Module ... + * a module for handle colorify text contents in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Module Imports ... +const XValueTools = require("./x-value.tools"); +//#endregion + +// +//#region Constants ... +/** + * these are available style which can applied to an string ... + */ +const AVAILABLE_STYLES = { + // + Bold: "\x1b[1m", + Dim: "\x1b[2m", + Underlined: "\x1b[4m", + Blink: "\x1b[5m", + ReverseFandB: "\x1b[7m", + Hidden: "\x1b[8m", + // + // Commonly used for reset all Styles ... + Reset: "\x1b[0m" +}; + +/** + * these are available foreground colors which can applied to an string ... + */ +const AVAILABLE_FOREGROUND_COLORS = { + Default: "\x1b[39m", + Black: "\x1b[30m", + Red: "\x1b[31m", + Green: "\x1b[32m", + Yellow: "\x1b[33m", + Blue: "\x1b[34m", + Magenta: "\x1b[35m", + Cyan: "\x1b[36m", + LightGray: "\x1b[37m", + DarkGray: "\x1b[90m", + LightRed: "\x1b[91m", + LightGreen: "\x1b[92m", + LightYellow: "\x1b[93m", + LightBlue: "\x1b[94m", + LightMagenta: "\x1b[95m", + LightCyan: "\x1b[96m", + White: "\x1b[97m", +}; + +/** + * these are available background colors which can applied to an string ... + */ +const AVAILABLE_BACKGROUND_COLORS = { + Default: "\x1b[49m", + Black: "\x1b[40m", + Red: "\x1b[41m", + Green: "\x1b[42m", + Yellow: "\x1b[43m", + Blue: "\x1b[44m", + Magenta: "\x1b[45m", + Cyan: "\x1b[46m", + LightGray: "\x1b[47m", + DarkGray: "\x1b[100m", + LightRed: "\x1b[101m", + LightGreen: "\x1b[102m", + LightYellow: "\x1b[103m", + LightBlue: "\x1b[104m", + LightMagenta: "\x1b[105m", + LightCyan: "\x1b[106m", + White: "\x1b[107m", +}; + +/** + * these are available style names, which exports from module and + * users can use them ... + */ +const STYLE_NAMES = { + Bold: "Bold", + Dim: "Dim", + Underlined: "Underlined", + Blink: "Blink", + ReverseFandB: "ReverseFandB", + Hidden: "Hidden", + Reset: "Reset", +}; + +/** + * these are available color names, which exports from module and + * users can use them ... + */ +const COLOR_NAMES = { + Default: "Default", + Black: "Black", + Red: "Red", + Green: "Green", + Yellow: "Yellow", + Blue: "Blue", + Magenta: "Magenta", + Cyan: "Cyan", + LightGray: "LightGray", + DarkGray: "DarkGray", + LightRed: "LightRed", + LightGreen: "LightGreen", + LightYellow: "LightYellow", + LightBlue: "LightBlue", + LightMagenta: "LightMagenta", + LightCyan: "LightCyan", + White: "White", +}; +//#endregion + +// +//#region Actions ... +/** + * apply specified style and color on a content ... + * + * @param {string} content specified content for styling ... + * @param {string} color specific color name for using to styling ... + * @param {string} style soecufic style name to use ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} styled content ... + */ +function apply( + content, + color, + style, + toForeground = true, + toBackground = false +) { + // + let result = content; + + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}${result}${AVAILABLE_STYLES.Reset}`; + } + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}${result}${AVAILABLE_STYLES.Reset}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}${result}${AVAILABLE_STYLES.Reset}`; + } + +} + +/** + * apply specific style on a content ... + * + * @param {string} content specific content which going to styled ... + * @param {string} style a member of STYLE_NAMES which specified that which style going to applied to content ... + * @returns {string} styled content ... + */ +function applyStyle(content, style) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eStyle = AVAILABLE_STYLES[style]; + if (eStyle === undefined) { + return content; + } + + // + return `${eStyle}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * apply specific foreground color on a content ... + * + * @param {string} content specific content which going to colorified ... + * @param {string} color a member of COLOR_NAMES which specified that which color going to applied to content ... + * @returns {string} colorified content ... + */ +function applyForegroundColor(content, color) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eColor = AVAILABLE_FOREGROUND_COLORS[color]; + if (eColor === undefined) { + return content; + } + + // + return `${eColor}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * apply specific background color on a content ... + * + * @param {string} content specific content which going to colorified ... + * @param {string} color a member of COLOR_NAMES which specified that which color going to applied to content ... + * @returns {string} colorified content ... + */ +function applyBackgroundColor(content, color) { + // + // Validate Arg ... + if (!XValueTools.isValidArg(content)) { + return content; + } + + // + let eColor = AVAILABLE_BACKGROUND_COLORS[color]; + if (eColor === undefined) { + return content; + } + + // + return `${eColor}${content}${AVAILABLE_STYLES.Reset}`; +} + +/** + * generate style and color applier expression ... + * + * @param {string} color specific color name for using to styling ... + * @param {string} style soecufic style name to use ... + * @param {boolean} reset close applier string by reset styles ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} style and color applier string ... + */ +function getApplier( + style = "", + color = "", + reset = false, + toForeground = true, + toBackground = false +) { + // + let result = ""; + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}`; + } + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * generate style applier expression ... + * + * @param {string} style soecufic style name to use ... + * @param {boolean} reset close applier string by reset styles ... + * @returns {string} style applier string ... + */ +function getStyleApplier( + style = "", + reset = false +) { + // + let result = ""; + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * generate color applier expression ... + * + * @param {string} color specific color name for using to styling ... + * @param {boolean} reset close applier string by reset styles ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} color applier string ... + */ +function getColorApplier( + color = "", + reset = false, + toForeground = true, + toBackground = false +) { + // + let result = ""; + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}`; + } + + // + if ( + !!reset && + result.length > 0 + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * colorified specific content ... + * + * @param {string} content specified content for styling ... + * @param {string} color specific color name for using to styling ... + * @param {boolean} toForeground apply specified color as foreground ... + * @param {boolean} toBackground apply specified color as background ... + * @returns {string} + */ +function colorifyContent( + content = "", + color = "", + toForeground = true, + toBackground = false +) { + // + let result = content; + + // + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Finde Colors ... + + // + // Detect and Validate Foreground Color and Apply it ... + let eFColor = AVAILABLE_FOREGROUND_COLORS[color]; + if ( + !!toForeground + && XValueTools.isValidArg(eFColor) + ) { + result = `${eFColor}${result}`; + } + + // + // Detect and Validate Background Color and Apply it ... + let eBColor = AVAILABLE_BACKGROUND_COLORS[color]; + if ( + !!toBackground + && XValueTools.isValidArg(eBColor) + ) { + result = `${eBColor}${result}`; + } + + // + if ( + result.length > 0 + && ( + XValueTools.isValidArg(eFColor) || + XValueTools.isValidArg(eBColor) + ) + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} + +/** + * apply style on specific content ... + * + * @param {string} content specified content for styling ... + * @param {string} style soecufic style name to use ... + * @returns {string} + */ +function stylifiyContent( + content = "", + style = "", +) { + // + let result = content; + + // + if (!XValueTools.isValidArg(content)) { + return result; + } + + // + // Detect and Validate Style and Apply it ... + let eStyle = AVAILABLE_STYLES[style]; + if (XValueTools.isValidArg(eStyle)) { + result = `${eStyle}${result}`; + } + + // + if ( + result.length > 0 + && XValueTools.isValidArg(eStyle) + ) { + result = `${result}${AVAILABLE_STYLES.Reset}`; + } + + // + return result; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + STYLE_NAMES, + COLOR_NAMES, + // + apply, + applyStyle, + getApplier, + getColorApplier, + getStyleApplier, + colorifyContent, + stylifiyContent, + applyForegroundColor, + applyBackgroundColor, +} +//#endregion \ No newline at end of file diff --git a/MQLTestWorkspace/Documents/JsModules/x-file.tools.js b/MQLTestWorkspace/Documents/JsModules/x-file.tools.js new file mode 100644 index 0000000..a1642a4 --- /dev/null +++ b/MQLTestWorkspace/Documents/JsModules/x-file.tools.js @@ -0,0 +1,830 @@ +/** + * XFile Tools Module ... + * a module for handle all file/folder manipulating task in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Module Imports ... +const fs = require('fs'); +const os = require('os'); +const Path = require('path'); +const http = require('http'); +const https = require('https'); +const XValueTools = require('./x-value.tools'); +//#endregion + +// +//#region Constants ... +/** + * current os path separators ... + */ +const PathSeparator = Path.sep; + +/** + * current directory ... + */ +const CurrentDir = __dirname; +//#endregion + +// +//#region Actions ... +// +//#region Global ... +/** + * retrieve a path status ... + * + * @param {string} path a path value to check ... + * @returns an stat object ... + */ +function getStatus(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return undefined; + } + + // + return fs.statSync(path); +} + +/** + * retrieve user's Home path ... + * + * @returns {string} a path ... + */ +function getHomePath() { + return os.homedir(); +} +//#endregion + +// +//#region Path ... +/** + * retrieve the base name of specific address path ... + * + * @param {string} path address of file or folder ... + * @returns string ... + */ +function basename(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return ''; + } + + // + const result = Path.basename(path); + return result; +} + +/** + * join several path segments together ... + * + * @param {...string} path path params ... + * @returns a joined paths ... + */ +function joinPath(...path) { + return Path.join(...path); +} + +/** + * resolve a relative path to absolute ... + * + * @param {string[]} path a path value to check ... + * @returns {string} + */ +function resolvePath(...path) { + return Path.resolve(...path); +} +//#endregion + +// +//#region File ... +/** + * determines a path destination is a file or not ... + * + * @param {string} path a path value to check ... + * @returns a boolean value ... + */ +function isFileExists(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return false; + } + + // + try { + const stat = getStatus(path); + if (!stat) { + return false; + } + + // + return stat.isFile(); + } catch { + return false; + } +} + +/** + * remove a file ... + * + * @param {string} path a file path ... + * @returns {Promise} action done or not ... + */ +function removeFile(path = '') { + return new Promise((resolve) => { + // + if (!isFileExists(path)) { + resolve(false); + } + + // + fs.unlink(path, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * copy a file to destination path ... + * + * @param {string} source source file path ... + * @param {string} dest dest folder path ... + * @returns {Promise} action done or not ... + */ +function copyFile( + source = '', + dest = '' +) { + return new Promise((resolve) => { + // + if ( + !isFileExists(source) || + !isDirectoryExists(dest) + ) { + resolve(false); + return; + } + + // + const destFilePath = Path.join(dest, Path.basename(source)); + fs.copyFile(source, destFilePath, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * reading specified file content ... + * + * @param {string} path a file path ... + * @returns {Promise} file content ... + */ +function readFile(path = '') { + return new Promise((resolve) => { + // + if (!isFileExists(path)) { + resolve(''); + return; + } + + // + fs.readFile(path, 'utf8', (err, content) => { + // + if (err) { + resolve(undefined); + return; + } + + // + resolve(content); + }); + }); +} + +/** + * write content to a file ... + * + * @param {string} path a file path ... + * @param {string} content the content which going to write to the file ... + * @param {bool} overwrite determines file overwrite if exists ... + * @returns {Promise} action done or not ... + */ +function writeFile( + path = '', + content = '', + overwrite = true +) { + return new Promise((resolve) => { + // + if (isFileExists(path) && !overwrite) { + // + resolve(false); + return; + } + + // + // Normalize Content ... + content = XValueTools.isValidArg(content) ? + content : + ''; + + // + fs.writeFile(path, content, (err) => { + // + if (err) { + // + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * create a file ... + * + * @param {string} path file path ... + * @param {string} fileName file name ... + * @returns {Promise} action done or not ... + */ +function createFile( + path = '', + fileName = '' +) { + return new Promise((resolve) => { + // + const filePath = Path.join(path, fileName); + if ( + isFileExists(filePath) || + !XValueTools.isValidArg(path) || + !XValueTools.isValidArg(fileName) + ) { + // + resolve(false); + return; + } + + // + fs.writeFile(filePath, '', (err) => { + // + if (err) { + // + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * remove a file name extension ... + * + * @param {string} name + * @returns {string} name without extension ... + */ +function removeFileExtension(name = '') { + return name.substring(0, name.lastIndexOf('.')) || name; +} + +/** + * retrieve a file extension ... + * + * @param {string} path a path which locate a file ... + * @returns {string} + */ +function getFileExtension(path = '') { + // + let result = ""; + + // + // Validate Arg ... + if ( + !XValueTools.isValidArg(path) + || !isFileExists(path) + ) { + return result; + } + + // + // Retrieve just file name ... + const fileName = basename(path); + result = fileName.replace( + removeFileExtension(fileName), + "" + ); + + // + return result; +} + +/** + * retrieve all files list recursively from specific path ... + * + * @param {string} path a source folder path ... + * @param {string[]} extensions which file extensions need to be listed, live empty for all files ... + * @returns {Promise} + */ +async function getRecursiveFilesList( + path = "", + extensions = [] +) { + // + let result = []; + + // + // Validate Args ... + if ( + !XValueTools.isValidArg(path) + || !isDirectoryExists(path) + ) { + return result; + } + + // + const contents = await getDirectoryContents(path); + for(const item of contents) { + // + const itemPath = joinPath( + path, + item + ); + + // + const isItemFile = isFileExists(itemPath); + if (isItemFile) { + // + const itemFileExtension = getFileExtension(itemPath); + const isFileInSupportedExtensions = + extensions === undefined || extensions.length === 0 + ? true + : extensions.includes(itemFileExtension) + ; + if (isFileInSupportedExtensions) { + result.push(itemPath); + } + } else if (isDirectoryExists(itemPath)) { + // + const itemPathFiles = await getRecursiveFilesList(itemPath, extensions); + result.push(...itemPathFiles); + } + } + + // + return result; +} +//#endregion + +// +//#region Directory ... +/** + * create a directory ... + * + * @param {string} path destination path including dir name ... + * @param {boolean} recursive create directories recursively ... + * @returns action done or not ... + */ +function createDirectory( + path = '', + recursive = true +) { + // + let result = false; + + // + if ( + isDirectoryExists(path) || + !XValueTools.isValidArg(path) + ) { + return false; + } + + // + try { + // + fs.mkdirSync(path, { recursive: recursive }); + result = true; + return result; + } catch { + return false; + } +} + +/** + * remove a directory ... + * + * @param {string} path destination path including dir name ... + * @param {boolean} recursive removes directories recursively ... + * @returns {Promise} action done or not ... + */ +function removeDirectory( + path = '', + recursive = false +) { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve(false); + return; + } + + // + fs.rm(path, { + recursive + }, (err) => { + // + if (err) { + resolve(false); + return; + } + + // + resolve(true); + }); + }); +} + +/** + * determines a path destination is a directory or not ... + * + * @param {string} path a folder path ... + * @returns represent destnation path is Directory or not ... + */ +function isDirectoryExists(path = '') { + // + if (!XValueTools.isValidArg(path)) { + return false; + } + + // + try { + // + const isExists = fs.existsSync(path); + if (!isExists) { + return false; + } + + // + const stat = getStatus(path); + if (!stat) { + return false; + } + + // + const result = stat.isDirectory(); + return result; + } catch { + return false; + } +} + +/** + * retrieve a directory content ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder files ... + */ +function getDirectoryContents(path = '') { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + resolve(content); + }); + }); +} + +/** + * retrieve a directory files ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder files ... + */ +function getDirectoryFiles( + path = '', + containsHiddenFiles = false +) { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + if (!containsHiddenFiles) { + content = content.filter(c => !c.startsWith('.')); + } + + // + const result = []; + content + .forEach(c => { + // + const cPath = Path.join(path, c); + if (isFileExists(cPath)) { + result.push(c); + } + }); + + // + resolve(result); + }); + }); +} + +/** + * retrieve a directory folders ... + * + * @param {string} path a folder path ... + * @returns {Promise} a collection of folder names ... + */ +function getDirectoryFolders(path = '') { + return new Promise((resolve) => { + // + if (!isDirectoryExists(path)) { + resolve([]); + return; + } + + // + fs.readdir(path, (err, content) => { + // + if (err) { + resolve([]); + return; + } + + // + const result = []; + content.forEach(c => { + // + const cPath = Path.join(path, c); + if (isDirectoryExists(cPath)) { + result.push(c); + } + }); + + // + resolve(result); + }); + }); +} + +/** + * copy a folder with all of it's content to dest ... + * + * @param {string} source source folder path ... + * @param {string} dest dest folder path ... + * @returns {Promise} action done or not ... + */ +async function copyFolder( + source = '', + dest = '' +) { + // + if ( + !isDirectoryExists(source) || + !XValueTools.isValidArg(dest) || + !XValueTools.isValidArg(source) + ) { + return false; + } + + // + const folderName = Path.basename(source); + const destPath = Path.join(dest, folderName); + + // + // Create Dest Path folder if not exists ... + if (!isDirectoryExists(destPath)) { + // + let result = createDirectory(destPath, true); + if (!result) { + return false; + } + } + + // + // Files ... + const files = await getDirectoryFiles(source); + if (files && files.constructor === Array && files.length > 0) { + // + const filesPromises = files.map(file => copyFile(Path.join(source, file), destPath)); + const filesResult = (await Promise.all(filesPromises)).every(r => !!r); + if (!filesResult) { + return false; + } + } + + // + // Folders ... + const folders = await getDirectoryFolders(source); + if (folders && folders.constructor === Array && folders.length > 0) { + // + const folderPromises = folders.map(folder => copyFolder(Path.join(source, folder), destPath)); + const filesResult = (await Promise.all(folderPromises)).every(r => !!r); + if (!filesResult) { + return false; + } + } + + // + return true; +} +//#endregion + +// +//#region Downloader ... +/** + * download a file from specific url and store it ... + * + * @param {string} filepath the file name and path which required to put download file on it ... + * @param {string} url the web url for downloading ... + */ +function download(filepath, url) { + // + // Validate Args ... + if ( + !XValueTools.isValidArg(url) + || !XValueTools.isValidURL(url) + || !XValueTools.isValidArg(filepath) + ) { + return; + } + + // + var file = fs.createWriteStream(filepath); + + // + if (url.startsWith('https:')) { + https.get(url, function (response) { + response.pipe(file); + }); + } else if (url.startsWith('http:')) { + http.get(url, function (response) { + response.pipe(file); + }); + } +} +//#endregion + +// +//#region JSON ... +/** + * read and parse a JSON content from a file ... + * + * @param {string} path source file path ... + * @returns {any} + */ +function readJSON(path = "") { + // + // Validate Args ... + if (!isFileExists(path)) { + return undefined; + } + + // + let result = undefined; + try { + result = require(path); + } catch { + result = undefined; + } + + // + return result; +} + +/** + * write a JSON Object content into a file ... + * + * @param {string} path dest file path ... + * @param {any} content an object which required to write to file ... + * @returns {Promise} + */ +async function writeJSON( + path = "", + content = undefined +) { + // + let result = false; + + // + // Validate Args ... + if (!XValueTools.isValidArg(path)) { + return result; + } + + // + // Normallize Content ... + if (content === undefined) { + content = {}; + } + + // + const contentString = XValueTools.beautifyJSON(content); + + // + result = await writeFile( + path, + contentString, + true + ); + + // + return result; +} +//#endregion +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + CurrentDir, + PathSeparator, + + // + getStatus, + getHomePath, + + // + basename, + joinPath, + resolvePath, + + // + download, + + // + readJSON, + writeJSON, + + // + copyFile, + readFile, + writeFile, + createFile, + removeFile, + isFileExists, + getFileExtension, + removeFileExtension, + getRecursiveFilesList, + + // + copyFolder, + createDirectory, + removeDirectory, + createDirectory, + removeDirectory, + isDirectoryExists, + isDirectoryExists, + getDirectoryFiles, + getDirectoryFolders, + getDirectoryContents, +} +//#endregion \ No newline at end of file diff --git a/MQLTestWorkspace/Documents/JsModules/x-shell.tools.js b/MQLTestWorkspace/Documents/JsModules/x-shell.tools.js new file mode 100644 index 0000000..0ee13de --- /dev/null +++ b/MQLTestWorkspace/Documents/JsModules/x-shell.tools.js @@ -0,0 +1,219 @@ +/** + * XShell Tools Module ... + * a module for handling shell actions and retrieve OS Info in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Imports ... +const os = require('os'); +const process = require('process'); +const { exec } = require("child_process"); +const XFileTools = require('./x-file.tools'); +//#endregion + +// +//#region Constants ... +// +const OS = { + Aix: 'aix', + Darwin: 'darwin', + FreeBSD: 'freebsd', + Linux: 'linux', + OpenBSD: 'openbsd', + SnOS: 'sunos', + Windows: 'win32' +}; + +// +const isWindows = process.platform === OS.Windows; +//#endregion + +// +//#region Actions ... +// +//#region Pure shell commands ... +/** + * execute a command using NodeJS on shell ... + * + * @param {string} cmd command to execute ... + * @param {string} cwd working directory ... + * + * @returns Promise instance ... + */ +function execute(cmd, cwd) { + return new Promise((resolve, reject) => { + // + if (!cmd || cmd.toString().length === 0 || (cwd && !XFileTools.isDirectoryExists(cwd))) { + reject('invalid args ...'); + return; + } + + // + exec(cmd, { cwd }, (err, result, stdError) => { + // + if (err) { + reject(err); + return; + } + + // + if (stdError) { + // + // reject(stdError); + // return; + } + + // + resolve(result); + }); + }); +}; + +/** + * determines a command exists on host or not ... + * + * @param {string} name specific command name ... + * + * @returns boolean Promise ... + */ +function checkCommandExists(name) { + return new Promise(resolve => { + // + if (!name) { + resolve(false); + return; + } + + // + const cmd = isWindows ? `${name} >nul 2>&1` : `type ${name} >/dev/null 2>&1`; + execute(cmd).then(result => { + resolve(true); + }) + .catch(err => { + resolve(false); + }); + }); +} +//#endregion + +// +//#region required commands state ... +/** + * check al required commands exists or not ... + * + * @returns + */ +async function isRequiredCommandsExists() { + // + let result = false; + + // + // const isTarExists = await isTarCommandExists(); + // const isCatExists = await isCatCommandExists(); + // const isGrepExists = await isGrepCommandExists(); + // const isSedExists = await isSedCommandExists(); + const isNpmExists = await isNpmCommandExists(); + const isNgExists = await isNgCommandExists(); + const isIonicExists = await isIonicCommandExists(); + const isCordovaExists = await isCordovaCommandExists(); + + // + result = isNpmExists + && isNgExists + && isIonicExists + && isCordovaExists + ; + + // + return result; +} + +/** + * retrieve required commands state object ... + * + * @returns + */ +async function getRequiredCommandsStates() { + // + const result = {}; + + // + // const isTarExists = await isTarCommandExists(); + // const isCatExists = await isCatCommandExists(); + // const isGrepExists = await isGrepCommandExists(); + // const isSedExists = await isSedCommandExists(); + const isNpmExists = await isNpmCommandExists(); + const isNgExists = await isNgCommandExists(); + const isIonicExists = await isIonicCommandExists(); + const isCordovaExists = await isCordovaCommandExists(); + + // + result['npm'] = isNpmExists; + result['ng'] = isNgExists; + result['ionic'] = isIonicExists; + result['cordova'] = isCordovaExists; + + // + return result; +} +//#endregion + +// +//#region Commonly used Command Checkers ... +/** + * determines npm command exists or not ... + * + * @returns + */ +function isNpmCommandExists() { + return checkCommandExists('npm'); +} + +/** + * determines ng command exists or not ... + * + * @returns + */ +function isNgCommandExists() { + return checkCommandExists('ng'); +} + +/** + * determines ionic command exists or not ... + * + * @returns + */ +function isIonicCommandExists() { + return checkCommandExists('ionic'); +} + +/** + * determines cordova command exists or not ... + * + * @returns + */ +function isCordovaCommandExists() { + return checkCommandExists('cordova'); +} +//#endregion +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + execute, + checkCommandExists, + isRequiredCommandsExists, + getRequiredCommandsStates, + + // + isNgCommandExists, + isIonicCommandExists, + isCordovaCommandExists, +} +//#endregion \ No newline at end of file diff --git a/MQLTestWorkspace/Documents/JsModules/x-type-detector.tools.js b/MQLTestWorkspace/Documents/JsModules/x-type-detector.tools.js new file mode 100644 index 0000000..86ed3d8 --- /dev/null +++ b/MQLTestWorkspace/Documents/JsModules/x-type-detector.tools.js @@ -0,0 +1,268 @@ +/** + * DataType Tools Module ... + * a module for manipulate and detect supported data types in node js ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Constants ... +/** + * all supported data types ... + */ +const DataTypes = { + Null: 'null', + Date: 'date', + Array: 'array', + Object: 'object', + String: 'string', + Number: 'number', + Unknown: 'unknown', + Boolean: 'boolean', + Function: 'function', + Undefined: 'undefined', +}; +//#endregion + +// +//#region Actions ... +/** + * detect type of a content ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getType(value) { + // + const type = typeof value; + + // + let result = DataTypes.Unknown; + let dateIdentifier = '[object Date]'; + let constructor = value && value.constructor ? + value.constructor.toString() : + ''; + + // + switch (type) { + // + case 'undefined': + result = DataTypes.Undefined; + break; + + // + case 'boolean': + result = DataTypes.Boolean; + break; + + // + case 'string': + result = DataTypes.String; + break; + + // + case 'number': + result = DataTypes.Number; + break; + + // + case 'function': + result = DataTypes.Function; + break; + + // + case 'object': + // + // Null ... + if (value === null) { + result = DataTypes.Null; + } else + // + // Array ... + if (Array.isArray(value)) { + result = DataTypes.Array; + } else + // + // Data ... + if ( + value instanceof Date || + isFunction(value.getMonth) || + constructor.includes(dateIdentifier) || + Object.prototype.toString.call(value) === dateIdentifier + ) { + result = DataTypes.Date; + } else + // + // Object ... + { + result = DataTypes.Object; + } + break; + + // + default: + result = DataTypes.Unknown; + break; + } + + // + return result; +} + +/** + * retrieve an object constructor ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getConstructor(value) { + // + const result = value && value.constructor ? + value.constructor.toString() : + ''; + + // + return result; +} + +/** + * retrieve an object prototype ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function getPrototype(value) { + // + const result = value ? + Object.prototype.toString.call(value) : + ''; + + // + return result; +} + +/** + * check an object is null or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNull(value) { + return getType(value) === DataTypes.Null; +} + +/** + * check an object is undefined or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isUndefined(value) { + return getType(value) === DataTypes.Undefined; +} + +/** + * check an object is null or undefined or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNullOrUndefined(value) { + return isNull(value) || isUndefined(value); +} + +/** + * check an object is a date or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isDate(value) { + return getType(value) === DataTypes.Date; +} + +/** + * check an object is number or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isNumber(value) { + return getType(value) === DataTypes.Number; +} + +/** + * check an object is string or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isString(value) { + return getType(value) === DataTypes.String; +} + +/** + * check an object is boolean or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isBoolean(value) { + return getType(value) === DataTypes.Boolean; +} + +/** + * check an object is an Array or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isArray(value) { + return getType(value) === DataTypes.Array; +} + +/** + * check an object is and Object or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isObject(value) { + return getType(value) === DataTypes.Object; +} + +/** + * check an object is a Function or not ... + * + * @param {any} value the content which going to check ... + * @returns + */ +function isFunction(value) { + return getType(value) === DataTypes.Function; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + DataTypes, + + // + getType, + getConstructor, + getPrototype, + isNull, + isUndefined, + isNullOrUndefined, + isDate, + isNumber, + isString, + isBoolean, + isArray, + isObject, + isFunction, +} +//#endregion \ No newline at end of file diff --git a/MQLTestWorkspace/Documents/JsModules/x-value.tools.js b/MQLTestWorkspace/Documents/JsModules/x-value.tools.js new file mode 100644 index 0000000..81cfcc4 --- /dev/null +++ b/MQLTestWorkspace/Documents/JsModules/x-value.tools.js @@ -0,0 +1,1528 @@ +/** + * Value Tools Module ... + * a module for Validate args and values ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) + */ + +// +//#region Imports ... +const XTypeTools = require('./x-type-detector.tools'); +//#endregion + +// +//#region Actions ... +/** +* validate a value as an argument ... +* +* @param {string} value the value which going to validate ... +* @returns +*/ +function isValidArg(value) { + // + let result = false; + + // + result = value && + value.length > 0; + + // + return result; +} + +/** + * validate a collection of valuea as an arguments ... + * + * @param {string|string[]} values the value collection which going to checked ... + * @returns + */ +function isValidArgs(values) { + // + // Normalize Values ... + const normalValues = toNormalArray(values); + if (!hasChildArray(normalValues)) { + return false; + } + + // + let result = normalValues.every(nv => isValidArg(nv)); + return result; +} + +/** + * converts content to an array object ... + * + * @param {string|string[]} content the content which required to normalized ... + * @returns {string[]} array object ... + */ +function toNormalArray(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + const result = Array.isArray(content) ? + [...content] : + content.includes(',') && + content !== ',' ? + [...content.split(',')] : + [content]; + + // + return result; +} + +/** + * determines value is array and has atleast one child ... + * + * @param {any} value the value which going to checked ... + * @returns {boolean} result of checking ... + */ +function hasChildArray(value) { + // + let result = false; + result = value && + Array.isArray(value) && + value.length > 0; + + // + return result; +} + +/** + * check an string is ends with specified symbol ... + * + * @param {string} symbol specified search symbol ... + * @param {string} value specified search content ... + * @param {boolean} ignoreCase specified search case sensitive or not ... + * @returns + */ +function endsWidth( + symbol = '', + value = '', + ignoreCase = true +) { + // + if (!isValidArg(value)) { + return false; + } + + // + if (!isValidArg(symbol)) { + return true; + } + + // + // TODO: uncomment it if necessary ... + // symbol = symbol.trim(); + + // + let result = false; + const subtractedContent = value.substring(value.length - symbol.length); + result = !!ignoreCase ? + subtractedContent + .toLowerCase() === symbol + .toLowerCase() : + subtractedContent === symbol; + + // + return result; +} + +/** + * surround specified content by provided symbol ... + * + * @param {string} symbol surround string ... + * @param {string} content used content to surrounded by symbol ... + * @returns surrounded content ... + */ +function surroundBy( + symbol = '', + content = '' +) { + // + // Validate Args ... + if (!isValidArg(content)) { + content = ''; + } + + // + if (!isValidArg(symbol)) { + symbol = ''; + } + + // + if (isSurrounded(symbol, content)) { + return content; + } + + // + const result = `${symbol}${content}${symbol}`; + return result; +} + +/** + * convert a parsed sign to clear string ... + * + * @param {string} value a parsed content ... + * @returns clear parsed signs ... + */ +function toStringExpression(value) { + // + let result = ''; + result = value; + + // + if ( + !value || + !isValidArg(value) || + !isSurroundedString(value) + ) { + return result; + } + + // + const startSymbol = value.charAt(0); + const endSymbol = value.charAt(value.length - 1); + + // + if (startSymbol !== endSymbol) { + return result; + } + + // + if ( + startSymbol === "\"" || + startSymbol === "\'" + ) { + result = clearSurround(startSymbol, value); + } + + // + return result; +} + + + +/** + * find and cleare proposed candidates from specified content ... + * + * @param {string|string[]} candidates the proposed string(s) whic going to cleared from content ... + * @param {string} content the destination content which used to find and replace candidates on it ... + * @returns cleared content ... + */ +function clearContent( + candidates, + content +) { + // + // Validate Args ... + if ( + !candidates || + !isValidArg(content) + ) { + return ''; + } + + // + // Normalize candidates ... + const normalCandidates = toNormalArray(candidates) + .filter(c => isValidArg(c)); + if (!hasChildArray(normalCandidates)) { + return content; + } + + // + // define regexp for content ... + const regExpExpression = normalCandidates.join('|'); + const regExp = new RegExp( + regExpExpression, + 'gi' + ); + + // + let result = ''; + result = content.replace(regExp, ''); + + // + return result; +} + +/** + * clear surrounded symbol from content ... + * + * @param {string} symbol specified search symbol ... + * @param {string} content specified content to clear ... + * @returns + */ +function clearSurround( + symbol = '', + content = '' +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + (isValidArg(symbol) && + symbol.length >= content.length - 1) + ) { + return ''; + } + + // + // Validate Surround ... + if (!isSurrounded(symbol, content)) { + return content; + } + + // + if (!isValidArg(symbol)) { + return content; + } + + // + let result = content.substring(symbol.length, content.length - symbol.length); + return result; +} + +/** + * clear object sign ... + * + * @param {string} content + * @returns cleared content ... + */ +function clearObjectSurround(content = '') { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isSurroundedObject(content) + ) { + return content; + } + + // + const endIndex = content.length - ( + endsWidth('}', content) ? + 1 : + endsWidth('},', content) || + endsWidth('};', content) || + endsWidth('}\n', content) ? + 2 : + 0 + ); + + // + const result = content.substring(1, endIndex); + return result; +} + +/** + * clear array sign ... + * + * @param {string} content + * @returns cleared content ... + */ +function clearArraySurround(content = '') { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isSurroundedArray(content) + ) { + return content; + } + + // + const endIndex = content.length - ( + endsWidth(']', content) ? + 1 : + endsWidth('],', content) || + endsWidth('];', content) || + endsWidth(']\n', content) ? + 2 : + 0 + ); + + // + const result = content.substring(1, endIndex); + return result; +} + +/** + * slice a content to individual parts ... + * + * @param {number|number[]} indexes which indexes used to slice ... + * @param {strng} content the content which going to sliced ... + * @returns sliced parts of content ... + */ +function sliceContent(indexes, content) { + // + // Validate Args ... + if ( + !isValidArg(indexes) || + !isValidArg(content) + ) { + return []; + } + + // + // Normalize indexes ... + const normalIndexes = toNormalArray(indexes) + .filter(index => index > -1 && index < content.length); + if (!hasChildArray(normalIndexes)) { + return []; + } + + // + let result = ['']; + result.pop(); + + // + let lastIndex = 0; + for (const index of normalIndexes) { + // + const part = content.substring(lastIndex, index); + if (isValidArg(part)) { + result.push(part.trim()); + } + + // + lastIndex = index + 1; + } + + // + // check remained parts ... + if (lastIndex < content.length) { + // + const part = content.substring(lastIndex); + if (isValidArg(part)) { + result.push(part.trim()); + } + } + + // + return result; +} + + + +/** + * check an string is starts and ends with specified symbol ... + * + * @param {string} symbol specified search symbol ... + * @param {string} content specified search content ... + * @param {boolean} ignoreCase specified search case sensitive or not ... + * @returns + */ +function isSurrounded( + symbol = '', + content = '', + ignoreCase = true +) { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + if (!isValidArg(symbol)) { + return true; + } + + // + symbol = symbol.trim(); + + // + let result = false; + result = (!!ignoreCase ? + content + .toLowerCase() + .startsWith(symbol.toLowerCase()) : + content.startsWith(symbol) + ) && + endsWidth(symbol, content, ignoreCase); + + // + return result; +} + +/** + * determines a content is an string surrounded value or not ... + * + * @param {string} content a content which going to check ... + * @returns + */ +function isSurroundedString(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = ( + content.startsWith('\'') && + ( + endsWidth('\'', content) || + endsWidth('\',', content) || + endsWidth('\';', content) || + endsWidth('\'\n', content) + ) || + content.startsWith('\"') && + ( + endsWidth('\"', content) || + endsWidth('\",', content) || + endsWidth('\";', content) || + endsWidth('\"\n', content) + ) || + content.startsWith('`') && + ( + endsWidth('\`', content) || + endsWidth('\`,', content) || + endsWidth('\`;', content) || + endsWidth('\`\n', content) + ) + ); + return result; +} + +/** + * check a content is an array content or not ... + * + * @param {string} content + * @returns + */ +function isSurroundedArray(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = content.startsWith('[') && + ( + endsWidth(']', content) || + endsWidth('],', content) || + endsWidth('];', content) || + endsWidth(']\n', content) + ); + return result; +} + +/** + * check a content is an object content or not ... + * + * @param {string} content + * @returns + */ +function isSurroundedObject(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return false; + } + + // + let result = false; + result = content.startsWith('{') && + ( + endsWidth('}', content) || + endsWidth('},', content) || + endsWidth('};', content) || + endsWidth('}\n', content) + ); + return result; +} + +/** + * check an index model is contains inside anothers or not ... + * + * @param {{ start: number, end: number}} source the source index model to check ... + * @param {...{ start: number, end: number}} dest the collection of index models which going to check ... + * @returns + */ +function isIndexInside(source, ...dest) { + // + let result = false; + + // + // Validate Args ... + if (!source || !dest) { + return result; + } + + // + // Check idx is standard ... + if ( + !source || + !source.end || + !source.start || + source.start > source.end + ) { + return false; + } + + // + // Check types of destinations ... + for (let index of dest) { + // + // Check idx is standard ... + if ( + !index || + !index.end || + !index.start || + index.start > index.end + ) { + return false; + } + } + + // + if (dest.includes(source)) { + dest = dest.filter(d => d !== source); + } + + // + const insideContentIndex = dest.find(dIndex => { + // + const result = source.start >= dIndex.start && + source.start <= dIndex.end && + source.end >= dIndex.start && + source.end <= dIndex.end; + return result; + }); + + // + result = insideContentIndex; + return result; +} + +/** + * check a number exists in + * @param {number} idx the number which going to check ... + * @param {{ start: number, end: number}} index the index model + * @returns + */ +function isInsideIndex(idx = -1, index) { + // + let result = false; + + // + // Validate Args ... + if ( + !index || + !index.hasOwnProperty('end') || + !index.hasOwnProperty('start') + ) { + return result; + } + + // + result = idx > index.start && idx < index.end; + return result; +} + +/** + * determines an object is key/value and type ... + * + * @param {any} content the object which we are going to check ... + * @returns + */ +function isKeyValueType(content) { + // + const result = content && + content.hasOwnProperty('key') && + content.hasOwnProperty('type') && + content.hasOwnProperty('value'); + + // + return result; +} + + + +/** + * find all indexes of token(s) in content ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns {number[]} all occured indexes ... + */ +function findAllIndexes( + tokens, + content +) { + // + // Validate Args ... + if ( + !isValidArg(tokens) || + !isValidArg(content) + ) { + return []; + } + + // + // normalize tokens ... + const normalTokens = toNormalArray(tokens); + if (!hasChildArray(normalTokens)) { + return []; + } + + // + // Parse contents ... + let match; + const result = []; + const regExp = new RegExp( + normalTokens.join('|'), + 'g' + ); + while ((match = regExp.exec(content)) !== null) { + result.push(match.index); + } + if (!hasChildArray(result)) { + return []; + } + + // + return result; +} + +/** + * find nearest symbol in a content from specified index ... + * + * @param {string|string[]} candidates specifies which symbols to find ... + * @param {string} content te content for seasrch ... + * @param {number} startFromIndex the index of start position ... + * @returns + */ +function findNearest( + candidates, + content = '', + startFromIndex = 0 +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(candidates) || + !isValidArg(content.trim()) + ) { + return ''; + } + + // + // Normalize Content ... + content = content.trim(); + + // + // Normalize Starts From ... + startFromIndex = startFromIndex < 0 || startFromIndex > content.length - 1 ? 0 : startFromIndex; + + // + // Normalize Symbols ... + const normalCandidates = toNormalArray(candidates); + if (!hasChildArray(normalCandidates)) { + return ''; + } + + // + let nearestIndex = findNearestIndex( + normalCandidates, + content, + startFromIndex + ); + if (nearestIndex < 0) { + return ''; + } + + // + let result = content.substring( + nearestIndex, + nearestIndex + Math.max(...normalCandidates.map(nc => nc.length)) + ).trim(); + return result; +} + +/** + * search candidates in content and find nearest one and return it ... + * + * @param {string|string[]} candidates which candidates required to check ... + * @param {string} content the content which required to search candidates ... + * @param {number} startFromIndex the proposed index to start searching content from on ... + * @returns + */ +function findNearestIndex( + candidates = [''], + content = '', + startFromIndex = 0, + ignoreClosedItems = false +) { + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(candidates) + ) { + return -1; + } + + // + // Mormalize startFromIndex value ... + startFromIndex = startFromIndex < 0 ? + 0 : + startFromIndex > content.length - 1 ? + content.length - 1 : + startFromIndex; + + // + // Normalize candidates ... + let normalCandidates = toNormalArray(candidates); + + // + if (!!ignoreClosedItems) { + normalCandidates = normalCandidates + .map(c => content.indexOf( + c, + startFromIndex + ) + ).map(c => +c) + .filter(c => +c > -1); + } else { + normalCandidates = findAllIndexesOutOfCloseds(normalCandidates, content) + .filter(c => c >= startFromIndex); + } + if (!hasChildArray(normalCandidates)) { + return -1; + } + + // + let result = -1; + result = Math.min(...normalCandidates); + + // + return result; +} + +/** + * find close index of specific sign in destination content ... + * + * @param {string} openSymbol open of area sign ... + * @param {string} closeSymbol close of area sign ... + * @param {string} content the destination content for parsing ... + * @param {number} startsFrom an start index of content for start parsing ... + * @returns + */ +function findCloseIndex( + openSymbol = '', + closeSymbol = '', + content = '', + startsFrom = -1 +) { + // + // Validate Args ... + if ( + startsFrom < 0 || + !isValidArg(content) || + !isValidArg(openSymbol) || + !isValidArg(closeSymbol) || + openSymbol === closeSymbol || + !content.includes(openSymbol) || + !content.includes(closeSymbol) || + startsFrom > content.length - 1 + ) { + return -1; + } + + // + let result = -1; + + // + let index = startsFrom; + const openSignStack = []; + while (index < content.length) { + // + const openCandidate = content.substring(index, index + openSymbol.length); + const closeCandidate = content.substring(index, index + closeSymbol.length); + + // + if (openCandidate === openSymbol) { + openSignStack.push(index); + } else if (closeCandidate === closeSymbol) { + // + if (openSignStack.length > 0) { + openSignStack.pop(); + } + + // + if (openSignStack.length === 0) { + result = index; + break; + } + } + + // + index++; + } + + // + return result; +} + +/** + * find closed contents of specific sign in destination content ... + * + * @param {string} openSymbol open of area sign ... + * @param {string} closeSymbol close of area sign ... + * @param {string} content the destination content for parsing ... + * @param {number} startsFrom an start index of content for start parsing ... + * @returns + */ +function findClosedContent( + openSymbol = '', + closeSymbol = '', + content = '', + startsFrom = 0, +) { + // + let result = [{ + start: -1, + end: -1, + content: '' + }]; + result.pop(); + + // + // Validate Args ... + if ( + !isValidArg(content) || + !isValidArg(openSymbol) || + !isValidArg(closeSymbol) || + !content.includes(openSymbol) || + !content.includes(closeSymbol) || + openSymbol.length >= content.length || + closeSymbol.length >= content.length + ) { + return result; + } + + // + // Normalize Start From ... + startsFrom = startsFrom < 0 || startsFrom >= content.length ? 0 : startsFrom; + + // + let canContinue = true; + while (!!canContinue) { + // + let openSymbolIndex = content.indexOf(openSymbol, startsFrom); + if (openSymbolIndex < 0) { + // + canContinue = false; + continue; + } + + // + let closeSymbolIndex = findCloseIndex( + openSymbol, + closeSymbol, + content, + openSymbolIndex + ); + if (closeSymbolIndex < 0) { + // + canContinue = false; + continue; + } + if (content.charAt(closeSymbolIndex) !== closeSymbol) { + closeSymbolIndex++; + } + + // + // Prevent ${} string interpolations ... + if ( + openSymbol === '{' && + openSymbolIndex - 1 >= 0 + ) { + // + const prevChar = content.charAt(openSymbolIndex - 1); + if (prevChar === '$') { + continue; + } + } + + // + const item = content + .substring(openSymbolIndex, closeSymbolIndex + 1) + .trim(); + startsFrom = closeSymbolIndex + 1; + result.push({ + start: openSymbolIndex, + end: closeSymbolIndex, + content: item + }); + } + + // + if (!hasChildArray(result)) { + return result; + } + + // + return result; +} + +/** + * extract a collection of closed contents exists in a content ... + * + * @param symbols a collection of open and close contents ... + * @param {string} content a content for searching inside it ... + * @returns a collection of closed content ... + */ +function findClosedContents( + symbols = [ + { + openSymbol: '', + closeSymbol: '' + } + ], + content = '' +) { + // + let result = [{ + start: -1, + end: -1, + content: '' + }]; + result.pop(); + + // + if ( + !isValidArg(content) || + !hasChildArray(symbols) + ) { + return []; + } + + // + symbols.forEach(symbol => { + // + const closedContent = findClosedContent( + symbol.openSymbol, + symbol.closeSymbol, + content + ); + + // + if (hasChildArray(closedContent)) { + result.push( + ...closedContent + ); + } + }); + + // + return result; +} + +/** + * find all string content closed items ... + * + * @param {string} content a content which going to search ... + * @returns a collection of index descriptors ... + */ +function findClosedStrings(content = '') { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // there are 3 types of strings ... + // ' " and ` + + // + const token1 = '\''; + const token1Stack = [0]; + token1Stack.pop(); + + // + const token2 = '"'; + const token2Stack = [0]; + token2Stack.pop(); + + // + const token3 = '`'; + const token3Stack = [0]; + token3Stack.pop(); + + // + const result = [ + { + start: -1, + end: -1, + content: '' + } + ]; + result.pop(); + + // + for (let i = 0; i < content.length; i++) { + // + const currentChart = content.charAt(i); + + // + //#region Token 1 ... + if (currentChart === token1) { + // + if (!hasChildArray(token1Stack)) { + token1Stack.push(i); + } else { + // + const start = token1Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + + // + //#region Token 2 ... + if (currentChart === token2) { + // + if (!hasChildArray(token2Stack)) { + token2Stack.push(i); + } else { + // + const start = token2Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + + // + //#region Token 3 ... + if (currentChart === token3) { + // + if (!hasChildArray(token3Stack)) { + token3Stack.push(i); + } else { + // + const start = token3Stack.pop(); + const end = i + 1; + const pContent = content.substring(start, end); + result.push({ + start, + end, + content: pContent + }); + } + } + //#endregion + } + + // + return result; +} + +/** + * find container indexes from within indexes ... + * + * @param {...{start: number, end: number}} index the collection of indexes to find beiggers inside ... + * @returns + */ +function findContainerIndexes(...index) { + // + let result = [ + { + start: -1, + end: -1, + content: '' + } + ]; + result.pop(); + + // + let concatedIndexes = []; + for (let idx of index) { + // + // Index Childs ... + for (let iix of idx) { + // + // Check idx is standard ... + if ( + !iix || + !iix.end || + !iix.start || + iix.start > iix.end + ) { + continue; + } + + // + // Check index inside another index ... + concatedIndexes.push(iix); + } + } + + // + if (!hasChildArray(concatedIndexes)) { + return result; + } + + // + for (let ccIdx of concatedIndexes) { + // + const isInside = isIndexInside(ccIdx, ...concatedIndexes); + if (isInside) { + continue; + } + + // + if (hasChildArray(result)) { + // + const isInsideResult = isIndexInside(ccIdx, ...result); + if (isInsideResult) { + continue; + } + } + + // + result.push(ccIdx); + } + + // + return result; +} + +/** + * find all tokens indexes inside a content which they are not inside closed items ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns + */ +function findAllIndexesOutOfCloseds1( + tokens, + content, +) { + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // Extract token Indexes ... + const tokensIndexes = findAllIndexes(tokens, content); + if (!hasChildArray(tokensIndexes)) { + return []; + } + + // + // Extract Closed Objects Indexes ... + const closedArrays = findClosedContent('[', ']', content); + const closedObjects = findClosedContent('{', '}', content); + const closedStrings = findClosedStrings(content); + if ( + !hasChildArray(closedObjects) && + !hasChildArray(closedArrays) && + !hasChildArray(closedStrings) + ) { + return tokensIndexes; + } + + // + // find bigger sloded ... + let containerClosedItems = findContainerIndexes( + closedArrays, + closedObjects, + closedStrings + ).filter(i => !isSurroundedString(i.content)); + + // + let result = [-1]; + result.pop(); + + // + for (let tIdx of tokensIndexes) { + // + let canAdd = true; + for (let ccIndex of containerClosedItems) { + // + canAdd = isInsideIndex(tIdx, ccIndex); + if (canAdd) { + break; + } + } + + // + if (!canAdd) { + result.push(tIdx); + } + } + + // + return result; +} + +/** + * find all tokens indexes inside a content which they are not inside closed items ... + * + * @param {string|string[]} tokens the tokens which require to search ... + * @param {string} content the content which using to search ... + * @returns + */ +function findAllIndexesOutOfCloseds( + tokens, + content, +) { + // + // Define Result ... + let result = [-1]; + result.pop(); + + // + // Validate Args ... + if (!isValidArg(content)) { + return []; + } + + // + // Normalize Tokens ... + const normalizeTokens = toNormalArray(tokens); + if (!hasChildArray(normalizeTokens)) { + return result; + } + + // + // Extract Closed Objects Indexes ... + let openSymbols = [ + '{', + '[', + '\'', + '"', + '`' + ]; + let closeSymbols = [ + '}', + ']', + '\'', + '"', + '`' + ]; + let openStack = []; + let lastOpenSymbol = ''; + let lastClosedIndex = -1; + for (let i = 0; i < content.length; i++) { + // + const prevChar = content.charAt(i - 1) || ''; + const char = content.charAt(i); + const nextChar = content.charAt(i + 1) || ''; + + // + const isToken = normalizeTokens.includes(char); + const isOpenSymbol = openSymbols.includes(char); + const isCloseSymbol = closeSymbols.includes(char); + + // + if (isOpenSymbol && lastOpenSymbol !== char) { + openStack.push(i); + lastOpenSymbol = char === '\'' || char === '"' || char === '`' ? char : lastOpenSymbol; + } else if (isCloseSymbol) { + // + lastOpenSymbol = char === '\'' || char === '"' || char === '`' ? '' : lastOpenSymbol; + let lastPop = openStack.pop(); + if (openStack.length === 0) { + lastClosedIndex = lastPop; + } + } else if (isToken) { + if ( + i > lastClosedIndex && + openStack.length === 0 + ) { + result.push(i); + } + } + } + + // + return result; +} +//#endregion + +// +//#region Validator Actions ... +/** + * check specified value is Valid URL Address or not ... + * + * @param {string} value specified string which required to check + * @returns {boolean} + */ +function isValidURL(value = "") { + // + if (!isValidArg(value)) { + return false; + } + + const pattern = new RegExp( + '^([a-zA-Z]+:\\/\\/)?' + // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR IP (v4) address + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path + '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string + '(\\#[-a-z\\d_]*)?$', // fragment locator + 'i' + ); + + // + const result = pattern.test(value); + return result; +} + +/** + * check specified value is Valid URL Address or not ... + * + * @param {string} value specified string which required to check + */ +function isValidEmail(value = "") { + // + if (!isValidArg(value)) { + return false; + } + + // + const pattern = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/gim; + + // + const result = pattern.test(value); + return result; +} +//#endregion + +// +//#region Normallizers ... +/** + * normallize an string ... + * + * @param {string} value specified value ... + * @returns {string} + */ +function toNormalString(value = "") { + // + if (!XTypeTools.isString(value)) { + value = ""; + } + + // + const result = value + .trim() + .toLowerCase(); + + // + return result; +} +//#endregion + +// +//#region Beautifiers ... +/** + * converts an object to string based on json and beautify result ... + * + * @param {any} object + * @returns {string} + */ +function beautifyJSON(object = undefined) { + // + // TODO: Complete this ... + let result = ""; + + // + // validate object ... + if (object === undefined) { + return result; + } + + // + // Convert result ... + result = JSON.stringify( + object, + null, + 4 + ); + + // + return result; +} +//#endregion + +// +//#region Module Exports ... +module.exports = { + // + endsWidth, + surroundBy, + isValidArg, + isValidArgs, + toNormalArray, + hasChildArray, + toStringExpression, + + // + sliceContent, + clearContent, + clearSurround, + clearArraySurround, + clearObjectSurround, + + // + isSurrounded, + isIndexInside, + isInsideIndex, + isKeyValueType, + isSurroundedArray, + isSurroundedString, + isSurroundedObject, + + // + findNearest, + findAllIndexes, + findCloseIndex, + findNearestIndex, + findClosedContent, + findClosedStrings, + findClosedContents, + findAllIndexesOutOfCloseds, + + // + // Validator Actions ... + isValidURL, + isValidEmail, + + // + // Normallizers ... + toNormalString, + + // + beautifyJSON, +} +//#endregion \ No newline at end of file diff --git a/MQLTestWorkspace/Experts/x-saherelm.xbe.ea.ex5 b/MQLTestWorkspace/Experts/x-saherelm.xbe.ea.ex5 new file mode 100644 index 0000000..8667591 Binary files /dev/null and b/MQLTestWorkspace/Experts/x-saherelm.xbe.ea.ex5 differ diff --git a/MQLTestWorkspace/Experts/x-saherelm.xbe.ea.mq5 b/MQLTestWorkspace/Experts/x-saherelm.xbe.ea.mq5 new file mode 100644 index 0000000..651546b --- /dev/null +++ b/MQLTestWorkspace/Experts/x-saherelm.xbe.ea.mq5 @@ -0,0 +1,3365 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XBEEA MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XBEEA +// Description: an Exper Advisor which used RSI and MA +// to Analyse Market ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XBEEA" +#property strict + +// +#define ShortName "XBEEA" + +// +enum ENUM_X_ZIGZAG_BUFFERS +{ + X_ZIGZAG_MAIN_LINE = 0, + X_ZIGZAG_PIVOTS_LINE = 1, +}; + +// +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.draw.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xtrade.class.mq5" + +// +#include "../Helpers/x-saherelm.xche.helper.mq5" + +// +// Inputs ... + +// +long xBEEAMagicNumber = 78692110; // Magic Number +int xBEEASlippage = 10; // Slippgae + +// +input double xBEEAVolume = 0.01; + +// +// Indicator Inputs ... + +// +// Maarket ... +input group "Cycles"; + +// +// Short ... +input group "Short"; +input ENUM_X_PERIOD_METHOD scMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES scPeriod = PERIOD_H4; // Period + +// +// Presentation ... +input bool xBEEADrawSCLabel = true; +input bool xBEEADrawSCCBar = true; +input bool xBEEADrawSCPBar = false; +input bool xBEEADrawSCCMid = true; +input bool xBEEADrawSCPMid = true; + +// +// Medium ... +input group "Medium"; +input ENUM_X_PERIOD_METHOD mcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES mcPeriod = PERIOD_H12; // Mid Period + +// +// Presentation ... +input bool xBEEADrawMCLabel = true; +input bool xBEEADrawMCCBar = true; +input bool xBEEADrawMCPBar = false; +input bool xBEEADrawMCCMid = true; +input bool xBEEADrawMCPMid = true; + +// +// Long ... +input group "Long"; +input ENUM_X_PERIOD_METHOD lcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES lcPeriod = PERIOD_D1; // Long Period + +// +// Presentation ... +input bool xBEEADrawLCLabel = true; +input bool xBEEADrawLCCBar = true; +input bool xBEEADrawLCPBar = false; +input bool xBEEADrawLCCMid = true; +input bool xBEEADrawLCPMid = true; + +// +// Hind ... +input group "Hind"; +input ENUM_X_PERIOD_METHOD hcMode = X_PERIOD_MANUALLY; // Method +input ENUM_TIMEFRAMES hcPeriod = PERIOD_W1; // Hind Period + +// +// Moving Averages ... +input group "Moving Average"; +input int xBEEAMaFastLength = 9; // Fast Length +input int xBEEAMaSlowLength = 18; // Slow Length +input int xBEEAMaShift = 0; // Shift +input ENUM_MA_METHOD xBEEAMaMethod = MODE_EMA; // Method +input ENUM_APPLIED_PRICE xBEEAMaAppliedTo = PRICE_CLOSE; // AppliedTo + +// +// Presentation ... +input bool xBEEADrawHCLabel = true; +input bool xBEEADrawHCCBar = true; +input bool xBEEADrawHCPBar = true; +input bool xBEEADrawHCCMid = true; +input bool xBEEADrawHCPMid = true; + +// +// Vars ... + +// +string xBEEASymbol; +ENUM_TIMEFRAMES xBEEAPeriod; + +// +int maxBuys = 1; +int maxSells = 1; +int buyCount = 0; +int sellCount = 0; + +// +double _tp = 0; +double _sl = 0; +double _entry = 0; +ENUM_POSITION_TYPE _type = NULL; + +// +MqlTick xBEEATick; +XSCTrade *xBEEATrader; + +// +// ZigZag ... +int zigZagHandler = INVALID_HANDLE; +double zigZagBuffer[]; +bool isZigZagInPeak; + +// +// Cycles Definitions ... + +// +XMarketCycle sc; +XDrawSpecifications scCMidSpecs; +XDrawSpecifications scPMidSpecs; +XOHCLDrawSpecification scCBSpecs; +XOHCLDrawSpecification scPBSpecs; +// +XOHCL scCBar; +double scCMidLine; +XOHCL scPBar; +double scPMidLine; +// +double scTrndBuffer[]; +double scFastBuffer[]; +double scSlowBuffer[]; +double scLongExit1[]; +double scLongExit2[]; +double scShortExit1[]; +double scShortExit2[]; +int scCheHandler = INVALID_HANDLE; +int scFastHandler = INVALID_HANDLE; +int scSlowHandler = INVALID_HANDLE; +int scTrndHandler = INVALID_HANDLE; + +// +bool isSCCBullish; +bool isSCPBullish; +bool isSCFastOverSlow; +bool isSCFastUnderSlow; + +// +XMarketCycle mc; +XDrawSpecifications mcCMidSpecs; +XDrawSpecifications mcPMidSpecs; +XOHCLDrawSpecification mcCBSpecs; +XOHCLDrawSpecification mcPBSpecs; +// +XOHCL mcCBar; +double mcCMidLine; +XOHCL mcPBar; +double mcPMidLine; +// +double mcTrndBuffer[]; +double mcFastBuffer[]; +double mcSlowBuffer[]; +double mcLongExit1[]; +double mcLongExit2[]; +double mcShortExit1[]; +double mcShortExit2[]; +int mcFastHandler = INVALID_HANDLE; +int mcSlowHandler = INVALID_HANDLE; +int mcTrndHandler = INVALID_HANDLE; +int mcCheHandler = INVALID_HANDLE; +// +bool isMCCBullish; +bool isMCPBullish; +bool isMCFastOverSlow; +bool isMCFastUnderSlow; + +// +XMarketCycle lc; +XDrawSpecifications lcCMidSpecs; +XDrawSpecifications lcPMidSpecs; +XOHCLDrawSpecification lcCBSpecs; +XOHCLDrawSpecification lcPBSpecs; +// +XOHCL lcCBar; +double lcCMidLine; +XOHCL lcPBar; +double lcPMidLine; +// +double lcTrndBuffer[]; +double lcFastBuffer[]; +double lcSlowBuffer[]; +double lcLongExit1[]; +double lcLongExit2[]; +double lcShortExit1[]; +double lcShortExit2[]; +int lcFastHandler = INVALID_HANDLE; +int lcSlowHandler = INVALID_HANDLE; +int lcTrndHandler = INVALID_HANDLE; +int lcCheHandler = INVALID_HANDLE; +// +bool isLCCBullish; +bool isLCPBullish; +bool isLCFastOverSlow; +bool isLCFastUnderSlow; + +// +XMarketCycle hc; +XDrawSpecifications hcCMidSpecs; +XDrawSpecifications hcPMidSpecs; +XOHCLDrawSpecification hcCBSpecs; +XOHCLDrawSpecification hcPBSpecs; +// +XOHCL hcCBar; +double hcCMidLine; +XOHCL hcPBar; +double hcPMidLine; +// +double hcTrndBuffer[]; +double hcFastBuffer[]; +double hcSlowBuffer[]; +double hcLongExit1[]; +double hcLongExit2[]; +double hcShortExit1[]; +double hcShortExit2[]; +int hcFastHandler = INVALID_HANDLE; +int hcSlowHandler = INVALID_HANDLE; +int hcTrndHandler = INVALID_HANDLE; +int hcCheHandler = INVALID_HANDLE; +// +bool isHCCBullish; +bool isHCPBullish; +bool isHCFastOverSlow; +bool isHCFastUnderSlow; + +// +int mBullishScore; +int mBearishScore; +bool xBEEAIsSummaryTrendBullish; +bool xBEEALastIsSummaryTrendBullish; +string mLastCommentHash; + +// +int mMaxBullishScore = 0; +int mMinBullishScore = 0; +int mMaxBearishScore = 0; +int mMinBearishScore = 0; + +// +double mPivots[]; +bool mPivotsScanStart; +int mPivotsLoopback = 52; +int mMinRequiredPivots = 400; +int mNumberPivotsSequential = 10; + +// +X121CHEInputs xBEEACheInputs; +XSCX121CHEHelper xBEEACheHelper; + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + if (xBEEASymbol == NULL || StringLen(xBEEASymbol) <= 0) + { + xBEEASymbol = _Symbol; + } + + // + if (xBEEAPeriod == NULL) + { + xBEEAPeriod = _Period; + } + + // + // Validate Inputs ... + if (!XBEEAValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + drawPrefix = ShortName; + + // + // Initialize XTrader ... + xBEEATrader = new XSCTrade( + xBEEASlippage, + xBEEAMagicNumber); + + // + // Init Indicators ... + if (!InitIndicators()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Prepare Style Specs ... + PrepareStyleSpecs(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 XBEEA Providers ... + delete xBEEATrader; + + // + // Short ... + IndicatorRelease(scCheHandler); + IndicatorRelease(scTrndHandler); + IndicatorRelease(scFastHandler); + IndicatorRelease(scSlowHandler); + + // + // Medium ... + IndicatorRelease(mcCheHandler); + IndicatorRelease(mcTrndHandler); + IndicatorRelease(mcFastHandler); + IndicatorRelease(mcSlowHandler); + + // + // Long ... + IndicatorRelease(lcCheHandler); + IndicatorRelease(lcTrndHandler); + IndicatorRelease(lcFastHandler); + IndicatorRelease(lcSlowHandler); + + // + // Hind ... + IndicatorRelease(hcCheHandler); + IndicatorRelease(hcTrndHandler); + IndicatorRelease(hcFastHandler); + IndicatorRelease(hcSlowHandler); + + // + IndicatorRelease(zigZagHandler); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + if (!HasEnoughPivots()) + { + // + if (!mPivotsScanStart) + { + ProcessPivots(); + } + + // + return; + } + + // + if (!IsNewCandle( + xBEEASymbol, + xBEEAPeriod)) + { + return; + } + + // + // Reading Tick ... + if (!SymbolInfoTick(xBEEASymbol, xBEEATick)) + { + return; + } + + // + // Reading Data From XDSR Indicator ... + ReadData(); + + // + // Counting Currently Open Positions ... + buyCount = xBEEATrader.CountPositions(xBEEASymbol, POSITION_TYPE_BUY); + sellCount = xBEEATrader.CountPositions(xBEEASymbol, POSITION_TYPE_SELL); + + // + if (buyCount < maxBuys) + { + // + // Check For Buy Signals ... + } + + // + if (sellCount < maxSells) + { + // + // Check for Sell Signals ... + } + + // + UpdatePivots(); + + // + string comment = XBEEAGenerateState(); + Comment(comment); +} + +// +// Custom Functions ... + +// +// Validate Variables nd Inputs ... +bool XBEEAValidateInputs() +{ + // + bool result = false; + + // + result = + // + xBEEASlippage > 0 && + xBEEAMagicNumber > 0 + // + && + // + // Short ... + IsValidCycle( + scMode, + scPeriod) + // + && + // + // Medium ... + IsValidCycle( + mcMode, + mcPeriod) + // + && + // + // Long ... + IsValidCycle( + lcMode, + lcPeriod) + // + && + // + // Hind ... + IsValidCycle( + hcMode, + hcPeriod) + // + ; + + // + return result; +} + +// +// Initial Indicators ... +bool InitIndicators() +{ + // + bool result = false; + + // + // Init XZG Indicator ... + zigZagHandler = iCustom( + xBEEASymbol, + xBEEAPeriod, + "x-saherelm.x121.xzg", + // + // Inputs ... + // TODO: + // add these inputs to TODO ... + 12, // Depth ... + 5, // Deviation ... + 3, // Back Step ... + 1 // MODE ENUM_X_ZG_PRICE_MODE (X_ZG_PRICE_HIGH_LOW_MODE) ... + // + ); + result = zigZagHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // Here we have to Init XMarketCycles also ... + result = InitMarketCycles(); + + // + xBEEACheInputs.Default(); + result = xBEEACheInputs.IsValid(); + if (!result) + { + return result; + } + + // + result = xBEEACheHelper.Init( + xBEEASymbol, + xBEEAPeriod, + xBEEACheInputs); + if (!result) + { + return result; + } + + // + return result; +} + +// +// Initial Market Cycles ... +bool InitMarketCycles() +{ + // + bool result = false; + + // + // Short ... + sc.method = scMode; + sc.period = scPeriod; + result = sc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_SHORT // + ); + if (!result) + { + return result; + } + + // + // Trend ... + ArraySetAsSeries(scTrndBuffer, true); + scTrndHandler = iCustom( + xBEEASymbol, + sc.period, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // ATR ... + "", + 14, // Length + 3.5, // Multiplier + PRICE_MEDIAN, // Applied To + // + // Presentation ... + "", + true, // Show Trends + false // Fill Trends + // + ); + + // + // Che ... + ArraySetAsSeries(scLongExit1, true); + ArraySetAsSeries(scLongExit2, true); + ArraySetAsSeries(scShortExit1, true); + ArraySetAsSeries(scShortExit2, true); + scCheHandler = iCustom( + xBEEASymbol, + sc.period, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + 35, + 26, + 3.0, + 3.5, + // + // Calculations ... + "", + PRICE_HIGH, + PRICE_LOW, + // + // Presentation ... + "", + true, + true, + true, + true + // + ); + + // + // MA's ... + ArraySetAsSeries(scFastBuffer, true); + scFastHandler = iMA( + xBEEASymbol, + sc.period, + xBEEAMaFastLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + ArraySetAsSeries(scSlowBuffer, true); + scSlowHandler = iMA( + xBEEASymbol, + sc.period, + xBEEAMaSlowLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + + // + result = + // + scCheHandler != INVALID_HANDLE && + scTrndHandler != INVALID_HANDLE && + scFastHandler != INVALID_HANDLE && + scSlowHandler != INVALID_HANDLE + // + ; + if (!result) + { + return result; + } + + // + // Medium ... + mc.method = mcMode; + mc.period = mcPeriod; + result = mc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_MEDIUM // + ); + if (!result) + { + return result; + } + + // + // Trend ... + ArraySetAsSeries(mcTrndBuffer, true); + mcTrndHandler = iCustom( + xBEEASymbol, + mc.period, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // ATR ... + "", + 14, // Length + 3.5, // Multiplier + PRICE_MEDIAN, // Applied To + // + // Presentation ... + "", + true, // Show Trends + false // Fill Trends + // + ); + + // + // Che ... + ArraySetAsSeries(mcLongExit1, true); + ArraySetAsSeries(mcLongExit2, true); + ArraySetAsSeries(mcShortExit1, true); + ArraySetAsSeries(mcShortExit2, true); + mcCheHandler = iCustom( + xBEEASymbol, + mc.period, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + 35, + 26, + 3.0, + 3.5, + // + // Calculations ... + "", + PRICE_HIGH, + PRICE_LOW, + // + // Presentation ... + "", + true, + true, + true, + true + // + ); + + // + // MA's ... + ArraySetAsSeries(mcFastBuffer, true); + mcFastHandler = iMA( + xBEEASymbol, + mc.period, + xBEEAMaFastLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + ArraySetAsSeries(mcSlowBuffer, true); + mcSlowHandler = iMA( + xBEEASymbol, + mc.period, + xBEEAMaSlowLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + + // + result = + // + mcTrndHandler != INVALID_HANDLE && + mcFastHandler != INVALID_HANDLE && + mcSlowHandler != INVALID_HANDLE + // + ; + if (!result) + { + return result; + } + + // + // Long ... + lc.method = lcMode; + lc.period = lcPeriod; + result = lc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_LONG // + ); + if (!result) + { + return result; + } + + // + // Trend ... + ArraySetAsSeries(lcTrndBuffer, true); + lcTrndHandler = iCustom( + xBEEASymbol, + lc.period, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // ATR ... + "", + 14, // Length + 3.5, // Multiplier + PRICE_MEDIAN, // Applied To + // + // Presentation ... + "", + true, // Show Trends + false // Fill Trends + // + ); + + // + // Che ... + ArraySetAsSeries(lcLongExit1, true); + ArraySetAsSeries(lcLongExit2, true); + ArraySetAsSeries(lcShortExit1, true); + ArraySetAsSeries(lcShortExit2, true); + lcCheHandler = iCustom( + xBEEASymbol, + lc.period, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + 35, + 26, + 3.0, + 3.5, + // + // Calculations ... + "", + PRICE_HIGH, + PRICE_LOW, + // + // Presentation ... + "", + true, + true, + true, + true + // + ); + + // + // MA's ... + ArraySetAsSeries(lcFastBuffer, true); + lcFastHandler = iMA( + xBEEASymbol, + lc.period, + xBEEAMaFastLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + ArraySetAsSeries(lcSlowBuffer, true); + lcSlowHandler = iMA( + xBEEASymbol, + lc.period, + xBEEAMaSlowLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + + // + result = + // + lcTrndHandler != INVALID_HANDLE && + lcFastHandler != INVALID_HANDLE && + lcSlowHandler != INVALID_HANDLE + // + ; + if (!result) + { + return result; + } + + // + // Hind ... + hc.method = hcMode; + hc.period = hcPeriod; + result = hc.Init( + xBEEASymbol, + xBEEAPeriod, + X_MARKET_CYCLE_HIND // + ); + if (!result) + { + return result; + } + + // + // Trend ... + ArraySetAsSeries(hcTrndBuffer, true); + hcTrndHandler = iCustom( + xBEEASymbol, + hc.period, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // ATR ... + "", + 14, // Length + 3.5, // Multiplier + PRICE_MEDIAN, // Applied To + // + // Presentation ... + "", + true, // Show Trends + false // Fill Trends + // + ); + + // + // Che ... + ArraySetAsSeries(hcLongExit1, true); + ArraySetAsSeries(hcLongExit2, true); + ArraySetAsSeries(hcShortExit1, true); + ArraySetAsSeries(hcShortExit2, true); + hcCheHandler = iCustom( + xBEEASymbol, + hc.period, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + 35, + 26, + 3.0, + 3.5, + // + // Calculations ... + "", + PRICE_HIGH, + PRICE_LOW, + // + // Presentation ... + "", + true, + true, + true, + true + // + ); + + // + // MA's ... + ArraySetAsSeries(hcFastBuffer, true); + hcFastHandler = iMA( + xBEEASymbol, + hc.period, + xBEEAMaFastLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + ArraySetAsSeries(hcSlowBuffer, true); + hcSlowHandler = iMA( + xBEEASymbol, + hc.period, + xBEEAMaSlowLength, + xBEEAMaShift, + xBEEAMaMethod, + xBEEAMaAppliedTo // + ); + + // + result = + // + hcTrndHandler != INVALID_HANDLE && + hcFastHandler != INVALID_HANDLE && + hcSlowHandler != INVALID_HANDLE + // + ; + if (!result) + { + return result; + } + + // + return result; +} + +// +// Prepare Style Specs for Drawings ... +void PrepareStyleSpecs() +{ + // + // Each Cycle has 2 Kind of Specs: + // 1- MidLines; + // 2- Candles; + // + // also for each Cycle we have 2 Series of Specs: + // 1- For Current Bar; + // 2- Prev Bar; + + // + // Short ... + + // + // Current ... + + // + // MidLine ... + scCMidSpecs.width = 1; + scCMidSpecs.style = STYLE_DOT; + scCMidSpecs.clr = clrSpringGreen; + scCMidSpecs.Label( + sc.prefix + "_C MID", + scCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + scCBSpecs.Default(); + scCBSpecs.Width(1); + scCBSpecs.Style(STYLE_DOT); + // + // scCBSpecs.openStyle.clr = clrDarkOliveGreen; + // scCBSpecs.closeStyle.clr = clrDarkOrchid; + // scCBSpecs.highStyle.clr = clrDarkSeaGreen; + // scCBSpecs.lowStyle.clr = clrPink; + // + scCBSpecs.openStyle.Label( + sc.prefix + "_C O", + scCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scCBSpecs.highStyle.Label( + sc.prefix + "_C H", + scCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scCBSpecs.closeStyle.Label( + sc.prefix + "_C C", + scCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scCBSpecs.lowStyle.Label( + sc.prefix + "_C L", + scCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + scPMidSpecs.width = 2; + scPMidSpecs.style = STYLE_SOLID; + scPMidSpecs.clr = clrLimeGreen; + scPMidSpecs.Label( + sc.prefix + "_P MID", + scPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + scPBSpecs.Default(); + scPBSpecs.Width(2); + // + // scPBSpecs.openStyle.clr = ; + // scPBSpecs.closeStyle.clr = ; + // scPBSpecs.highStyle.clr = ; + // scPBSpecs.lowStyle.clr = ; + // + scPBSpecs.openStyle.Label( + sc.prefix + "_P O", + scPBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scPBSpecs.highStyle.Label( + sc.prefix + "_P H", + scPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scPBSpecs.closeStyle.Label( + sc.prefix + "_P C", + scPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + scPBSpecs.lowStyle.Label( + sc.prefix + "_P L", + scPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Medium ... + + // + // Current ... + + // + // MidLine ... + mcCMidSpecs.width = 1; + mcCMidSpecs.style = STYLE_DOT; + mcCMidSpecs.clr = clrSteelBlue; + mcCMidSpecs.Label( + mc.prefix + "_C MID", + mcCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + mcCBSpecs.Default(); + mcCBSpecs.Width(1); + mcCBSpecs.Style(STYLE_DOT); + // + // mcCBSpecs.openStyle.clr = clrDarkOliveGreen; + // mcCBSpecs.closeStyle.clr = clrDarkOrchid; + // mcCBSpecs.highStyle.clr = clrDarkSeaGreen; + // mcCBSpecs.lowStyle.clr = clrPink; + // + mcCBSpecs.openStyle.Label( + mc.prefix + "_C O", + mcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcCBSpecs.highStyle.Label( + mc.prefix + "_C H", + mcCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcCBSpecs.closeStyle.Label( + mc.prefix + "_C C", + mcCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcCBSpecs.lowStyle.Label( + mc.prefix + "_C L", + mcCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + mcPMidSpecs.width = 2; + mcPMidSpecs.style = STYLE_SOLID; + mcPMidSpecs.clr = clrRoyalBlue; + mcPMidSpecs.Label( + mc.prefix + "_P MID", + mcPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + mcPBSpecs.Default(); + mcPBSpecs.Width(2); + // + // mcPBSpecs.openStyle.clr = ; + // mcPBSpecs.closeStyle.clr = ; + // mcPBSpecs.highStyle.clr = ; + // mcPBSpecs.lowStyle.clr = ; + // + mcPBSpecs.openStyle.Label( + mc.prefix + "_P O", + mcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcPBSpecs.highStyle.Label( + mc.prefix + "_P H", + mcPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcPBSpecs.closeStyle.Label( + mc.prefix + "_P C", + mcPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + mcPBSpecs.lowStyle.Label( + mc.prefix + "_P L", + mcPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Long ... + + // + // Current ... + + // + // MidLine ... + lcCMidSpecs.width = 1; + lcCMidSpecs.style = STYLE_DOT; + lcCMidSpecs.clr = clrYellow; + lcCMidSpecs.Label( + lc.prefix + "_C MID", + lcCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + lcCBSpecs.Default(); + lcCBSpecs.Width(1); + lcCBSpecs.Style(STYLE_DOT); + // + // lcCBSpecs.openStyle.clr = clrDarkOliveGreen; + // lcCBSpecs.closeStyle.clr = clrDarkOrchid; + // lcCBSpecs.highStyle.clr = clrDarkSeaGreen; + // lcCBSpecs.lowStyle.clr = clrPink; + // + lcCBSpecs.openStyle.Label( + lc.prefix + "_C O", + lcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcCBSpecs.highStyle.Label( + lc.prefix + "_C H", + lcCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcCBSpecs.closeStyle.Label( + lc.prefix + "_C C", + lcCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcCBSpecs.lowStyle.Label( + lc.prefix + "_C L", + lcCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + lcPMidSpecs.width = 2; + lcPMidSpecs.style = STYLE_SOLID; + lcPMidSpecs.clr = clrOrange; + lcPMidSpecs.Label( + lc.prefix + "_P MID", + lcPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + lcPBSpecs.Default(); + lcPBSpecs.Width(2); + // + // lcPBSpecs.openStyle.clr = ; + // lcPBSpecs.closeStyle.clr = ; + // lcPBSpecs.highStyle.clr = ; + // lcPBSpecs.lowStyle.clr = ; + // + lcPBSpecs.openStyle.Label( + lc.prefix + "_P O", + lcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcPBSpecs.highStyle.Label( + lc.prefix + "_P H", + lcPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcPBSpecs.closeStyle.Label( + lc.prefix + "_P C", + lcPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + lcPBSpecs.lowStyle.Label( + lc.prefix + "_P L", + lcPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Hind ... + + // + // Current ... + + // + // MidLine ... + hcCMidSpecs.width = 1; + hcCMidSpecs.style = STYLE_DOT; + hcCMidSpecs.clr = clrSandyBrown; + hcCMidSpecs.Label( + hc.prefix + "_C MID", + hcCMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + hcCBSpecs.Default(); + hcCBSpecs.Width(1); + hcCBSpecs.Style(STYLE_DOT); + // + // hcCBSpecs.openStyle.clr = clrDarkOliveGreen; + // hcCBSpecs.closeStyle.clr = clrDarkOrchid; + // hcCBSpecs.highStyle.clr = clrDarkSeaGreen; + // hcCBSpecs.lowStyle.clr = clrPink; + // + hcCBSpecs.openStyle.Label( + hc.prefix + "_C O", + hcCBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcCBSpecs.highStyle.Label( + hc.prefix + "_C H", + hcCBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcCBSpecs.closeStyle.Label( + hc.prefix + "_C C", + hcCBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcCBSpecs.lowStyle.Label( + hc.prefix + "_C L", + hcCBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + hcPMidSpecs.width = 2; + hcPMidSpecs.style = STYLE_SOLID; + hcPMidSpecs.clr = clrSaddleBrown; + hcPMidSpecs.Label( + hc.prefix + "_P MID", + hcPMidSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + hcPBSpecs.Default(); + hcPBSpecs.Width(2); + // + // hcPBSpecs.openStyle.clr = clrDarkOliveGreen; + // hcPBSpecs.closeStyle.clr = clrDarkOrchid; + // hcPBSpecs.highStyle.clr = clrDarkSeaGreen; + // hcPBSpecs.lowStyle.clr = clrPink; + // + hcPBSpecs.openStyle.Label( + hc.prefix + "_P O", + hcPBSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcPBSpecs.highStyle.Label( + hc.prefix + "_P H", + hcPBSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcPBSpecs.closeStyle.Label( + hc.prefix + "_P C", + hcPBSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + hcPBSpecs.lowStyle.Label( + hc.prefix + "_P L", + hcPBSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); +} + +// +// Reading Data From Indicators ... +void ReadData() +{ + // + int mLoopBack = 15; + + // + // Update Market Cycles ... + UpdateMarketCycles(0); + + // + // Short ... + CopyBuffer( + scFastHandler, + 0, + 0, + mLoopBack, + scFastBuffer + // + ); + CopyBuffer( + scSlowHandler, + 0, + 0, + mLoopBack, + scSlowBuffer + // + ); + isSCFastOverSlow = scFastBuffer[1] > scSlowBuffer[1]; + isSCFastUnderSlow = scFastBuffer[1] > scSlowBuffer[1]; + + // + // Medium ... + CopyBuffer( + mcFastHandler, + 0, + 0, + mLoopBack, + mcFastBuffer + // + ); + CopyBuffer( + mcSlowHandler, + 0, + 0, + mLoopBack, + mcSlowBuffer + // + ); + isMCFastOverSlow = mcFastBuffer[1] > mcSlowBuffer[1]; + isMCFastUnderSlow = mcFastBuffer[1] > mcSlowBuffer[1]; + + // + // Long ... + CopyBuffer( + lcFastHandler, + 0, + 0, + mLoopBack, + lcFastBuffer + // + ); + CopyBuffer( + lcSlowHandler, + 0, + 0, + mLoopBack, + lcSlowBuffer + // + ); + isLCFastOverSlow = lcFastBuffer[1] > lcSlowBuffer[1]; + isLCFastUnderSlow = lcFastBuffer[1] > lcSlowBuffer[1]; + + // + // Hind ... + CopyBuffer( + hcFastHandler, + 0, + 0, + mLoopBack, + hcFastBuffer + // + ); + CopyBuffer( + hcSlowHandler, + 0, + 0, + mLoopBack, + hcSlowBuffer + // + ); + isHCFastOverSlow = hcFastBuffer[1] > hcSlowBuffer[1]; + isHCFastUnderSlow = hcFastBuffer[1] > hcSlowBuffer[1]; + + // + // XZigZag ... + CopyBuffer( + zigZagHandler, + X_ZIGZAG_PIVOTS_LINE, + 0, + mLoopBack, + zigZagBuffer + // + ); + + // + isZigZagInPeak = zigZagBuffer[0] < MathMax(xBEEATick.ask, xBEEATick.bid); + + // + // Summary ... + CalculateSummary(); + + // + // Provide all Draws ... + XBEEAHandleDraws( + // + // Short ... + xBEEADrawSCLabel, + xBEEADrawSCCBar, + xBEEADrawSCPBar, + xBEEADrawSCCMid, + xBEEADrawSCPMid, + // + // Medium ... + xBEEADrawMCLabel, + xBEEADrawMCCBar, + xBEEADrawMCPBar, + xBEEADrawMCCMid, + xBEEADrawMCPMid, + // + // Long ... + xBEEADrawLCLabel, + xBEEADrawLCCBar, + xBEEADrawLCPBar, + xBEEADrawLCCMid, + xBEEADrawLCPMid, + // + // Hind ... + xBEEADrawHCLabel, + xBEEADrawHCCBar, + xBEEADrawHCPBar, + xBEEADrawHCCMid, + xBEEADrawHCPMid + // + ); +} + +// +// Update Market Cycles ... +bool UpdateMarketCycles(int barIndex) +{ + // + bool result = false; + + // + XOHCL cBar; + XOHCL pBar; + + // + // Short ... + result = sc.Update(barIndex); + if (!result) + { + return result; + } + // + cBar = sc.GetBar(0); + pBar = sc.GetBar(1); + scCBar = cBar; + scPBar = pBar; + scCMidLine = (cBar.high - cBar.low) / 2; + scPMidLine = (pBar.high - pBar.low) / 2; + isSCCBullish = cBar.close > cBar.open; + isSCPBullish = pBar.close > pBar.open; + + // + // Medium ... + result = mc.Update(barIndex); + if (!result) + { + return result; + } + // + cBar = mc.GetBar(0); + pBar = mc.GetBar(1); + mcCBar = cBar; + mcPBar = pBar; + mcCMidLine = (cBar.high - cBar.low) / 2; + mcPMidLine = (pBar.high - pBar.low) / 2; + isMCCBullish = cBar.close > cBar.open; + isMCPBullish = pBar.close > pBar.open; + + // + // Long ... + result = lc.Update(barIndex); + if (!result) + { + return result; + } + // + cBar = lc.GetBar(0); + pBar = lc.GetBar(1); + lcCBar = cBar; + lcPBar = pBar; + lcCMidLine = (cBar.high - cBar.low) / 2; + lcPMidLine = (pBar.high - pBar.low) / 2; + isLCCBullish = cBar.close > cBar.open; + isLCPBullish = pBar.close > pBar.open; + + // + // Hind ... + result = hc.Update(barIndex); + if (!result) + { + return result; + } + // + cBar = hc.GetBar(0); + pBar = hc.GetBar(1); + hcCBar = cBar; + hcPBar = pBar; + hcCMidLine = (cBar.high - cBar.low) / 2; + hcPMidLine = (pBar.high - pBar.low) / 2; + isHCCBullish = cBar.close > cBar.open; + isHCPBullish = pBar.close > pBar.open; + + // + return result; +} + +// +// Pivots ... + +// +int CountPivots() +{ + return ArraySize(mPivots); +} + +// +bool HasEnoughPivots() +{ + return CountPivots() >= mMinRequiredPivots; +} + +// +// First time Scan for Previous Pivots ... +void ProcessPivots() +{ + // + if (mPivotsScanStart) + { + return; + } + + // + mPivotsScanStart = true; + + // + ArraySetAsSeries(mPivots, true); + + // + double tmpPivots[]; + + // + int count = iBars( + xBEEASymbol, + xBEEAPeriod) - + mPivotsLoopback * 2; + + // + // Reading Pivots based on ZigZag ... + int bIdx = 0; + while (!HasEnoughPivots() && bIdx < count) + { + // + UpdatePivots(bIdx); + + // + bIdx++; + } +} + +// +// Update Pivots on Running ... +void UpdatePivots(int barIndex = 0) +{ + // + double tmpPivots[]; + + // + CopyBuffer( + zigZagHandler, + X_ZIGZAG_PIVOTS_LINE, + barIndex, + mPivotsLoopback, + tmpPivots); + + // + int valueVerifications = 0; + double selectedValue = tmpPivots[0]; + + // + int start = 1; + int end = ArraySize(tmpPivots) - 1; + for (int i = start; i < end; i++) + { + // + double iValue = tmpPivots[i]; + + // + if (iValue == selectedValue) + { + valueVerifications++; + } + } + + // + if (valueVerifications >= mNumberPivotsSequential) + { + // + AddIfNotExists( + selectedValue, + mPivots + // + ); + } + + // + ArrayFree(tmpPivots); +} + +// +// Other ... + +// +// Calculated Suggested States ... +void CalculateSummary() +{ + // + // Summary ... + + // + int bullishSigns = 0; + int bearishSigns = 0; + + // + // Short ... + + // + if (isSCCBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isSCPBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isSCFastOverSlow) + { + bullishSigns++; + } + else if (isSCFastUnderSlow) + { + bearishSigns++; + } + + // + if (scCMidLine < MathMin(scCBar.open, scCBar.close)) + { + bearishSigns++; + } + + if (scCMidLine < scCBar.low) + { + bearishSigns++; + } + + if (scPMidLine < MathMin(scPBar.open, scPBar.close)) + { + bearishSigns++; + } + + if (scPMidLine < scPBar.low) + { + bearishSigns++; + } + + if (scCMidLine < MathMin(scPBar.open, scPBar.close)) + { + bearishSigns++; + } + + if (scCMidLine < scPBar.low) + { + bearishSigns++; + } + + // + if (scCMidLine > MathMax(scCBar.open, scCBar.close)) + { + bullishSigns++; + } + + if (scCMidLine > scCBar.high) + { + bullishSigns++; + } + + if (scPMidLine > MathMax(scPBar.open, scPBar.close)) + { + bullishSigns++; + } + + if (scPMidLine > scPBar.high) + { + bullishSigns++; + } + + if (scCMidLine > MathMax(scPBar.open, scPBar.close)) + { + bullishSigns++; + } + + if (scCMidLine > scPBar.high) + { + bullishSigns++; + } + + // + // Medium ... + + // + if (isMCCBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isMCPBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isMCFastOverSlow) + { + bullishSigns++; + } + else if (isMCFastUnderSlow) + { + bearishSigns++; + } + + // + if (mcCMidLine < MathMin(mcCBar.open, mcCBar.close)) + { + bearishSigns++; + } + + if (mcCMidLine < mcCBar.low) + { + bearishSigns++; + } + + if (mcPMidLine < MathMin(mcPBar.open, mcPBar.close)) + { + bearishSigns++; + } + + if (mcPMidLine < mcPBar.low) + { + bearishSigns++; + } + + if (mcCMidLine < MathMin(mcPBar.open, mcPBar.close)) + { + bearishSigns++; + } + + if (mcCMidLine < mcPBar.low) + { + bearishSigns++; + } + + // + if (mcCMidLine > MathMax(mcCBar.open, mcCBar.close)) + { + bullishSigns++; + } + + if (mcCMidLine > mcCBar.high) + { + bullishSigns++; + } + + if (mcPMidLine > MathMax(mcPBar.open, mcPBar.close)) + { + bullishSigns++; + } + + if (mcPMidLine > mcPBar.high) + { + bullishSigns++; + } + + if (mcCMidLine > MathMax(mcPBar.open, mcPBar.close)) + { + bullishSigns++; + } + + if (mcCMidLine > mcPBar.high) + { + bullishSigns++; + } + + // + // Long ... + + // + if (isLCCBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isLCPBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isLCFastOverSlow) + { + bullishSigns++; + } + else if (isLCFastUnderSlow) + { + bearishSigns++; + } + + // + if (lcCMidLine < MathMin(lcCBar.open, lcCBar.close)) + { + bearishSigns++; + } + + if (lcCMidLine < lcCBar.low) + { + bearishSigns++; + } + + if (lcPMidLine < MathMin(lcPBar.open, lcPBar.close)) + { + bearishSigns++; + } + + if (lcPMidLine < lcPBar.low) + { + bearishSigns++; + } + + if (lcCMidLine < MathMin(lcPBar.open, lcPBar.close)) + { + bearishSigns++; + } + + if (lcCMidLine < lcPBar.low) + { + bearishSigns++; + } + + // + if (lcCMidLine > MathMax(lcCBar.open, lcCBar.close)) + { + bullishSigns++; + } + + if (lcCMidLine > lcCBar.high) + { + bullishSigns++; + } + + if (lcPMidLine > MathMax(lcPBar.open, lcPBar.close)) + { + bullishSigns++; + } + + if (lcPMidLine > lcPBar.high) + { + bullishSigns++; + } + + if (lcCMidLine > MathMax(lcPBar.open, lcPBar.close)) + { + bullishSigns++; + } + + if (lcCMidLine > lcPBar.high) + { + bullishSigns++; + } + + // + // Hind ... + + // + if (isHCCBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isHCPBullish) + { + bullishSigns++; + } + else + { + bearishSigns++; + } + + // + if (isHCFastOverSlow) + { + bullishSigns++; + } + else if (isHCFastUnderSlow) + { + bearishSigns++; + } + + // + if (hcCMidLine < MathMin(hcCBar.open, hcCBar.close)) + { + bearishSigns++; + } + + if (hcCMidLine < hcCBar.low) + { + bearishSigns++; + } + + if (hcPMidLine < MathMin(hcPBar.open, hcPBar.close)) + { + bearishSigns++; + } + + if (hcPMidLine < hcPBar.low) + { + bearishSigns++; + } + + if (hcCMidLine < MathMin(hcPBar.open, hcPBar.close)) + { + bearishSigns++; + } + + if (hcCMidLine < hcPBar.low) + { + bearishSigns++; + } + + // + if (hcCMidLine > MathMax(hcCBar.open, hcCBar.close)) + { + bullishSigns++; + } + + if (hcCMidLine > hcCBar.high) + { + bullishSigns++; + } + + if (hcPMidLine > MathMax(hcPBar.open, hcPBar.close)) + { + bullishSigns++; + } + + if (hcPMidLine > hcPBar.high) + { + bullishSigns++; + } + + if (hcCMidLine > MathMax(hcPBar.open, hcPBar.close)) + { + bullishSigns++; + } + + if (hcCMidLine > hcPBar.high) + { + bullishSigns++; + } + + // + // ZigZag ... + if (isZigZagInPeak) + { + bearishSigns++; + } + else + { + bullishSigns++; + } + + // + mBullishScore = bullishSigns; + mBearishScore = bearishSigns; + xBEEAIsSummaryTrendBullish = bullishSigns > bearishSigns; + + // + // Calculate Max an Min Scores ... + + // + mMinBullishScore = + // + mMinBullishScore == 0 || mMinBullishScore > mBullishScore + ? mBullishScore + : mMinBullishScore + // + ; + + // + mMinBearishScore = + // + mMinBearishScore == 0 || mMinBearishScore > mBearishScore + ? mBearishScore + : mMinBearishScore + // + ; + + // + mMaxBullishScore = + // + mMaxBullishScore == 0 || mMaxBullishScore < mBullishScore + ? mBullishScore + : mMaxBullishScore + // + ; + + // + mMaxBearishScore = + // + mMaxBearishScore == 0 || mMaxBearishScore < mBearishScore + ? mBearishScore + : mMaxBearishScore + // + ; + + // + if (xBEEAIsSummaryTrendBullish != xBEEALastIsSummaryTrendBullish) + { + // + // TODO: Summary Trend Change Alert ... + LogMessage("Majour Trend Changed Happens: " + (xBEEAIsSummaryTrendBullish ? "Bullish" : "Bearish")); + } + + // + xBEEALastIsSummaryTrendBullish = xBEEAIsSummaryTrendBullish; +} + +// +// Handle All Draws of Experts ... +void XBEEAHandleDraws( + // + // Short ... + bool drawSCLabel = true, + bool drawSCCBar = true, + bool drawSCPBar = true, + bool drawSCCMid = true, + bool drawSCPMid = true, + // + // Medium ... + bool drawMCLabel = true, + bool drawMCCBar = true, + bool drawMCPBar = true, + bool drawMCCMid = true, + bool drawMCPMid = true, + // + // Long ... + bool drawLCLabel = true, + bool drawLCCBar = true, + bool drawLCPBar = true, + bool drawLCCMid = true, + bool drawLCPMid = true, + // + // Hind ... + bool drawHCLabel = true, + bool drawHCCBar = true, + bool drawHCPBar = true, + bool drawHCCMid = true, + bool drawHCPMid = true // +) +{ + // + int offset = 0; + + // + // Short ... + + // + // Cycle ... + if (drawSCCBar || drawSCPBar) + { + // + XBEEADrawCycle( + sc.cycle, + drawSCLabel, + !drawSCCBar && drawSCPBar, + !drawSCPBar && drawSCCBar, + offset + // + ); + + // + if (drawSCLabel) + { + // + if (drawSCCBar) + { + offset += 3; + } + + // + if (drawSCPBar) + { + offset += 3; + } + + // + if (drawSCCMid) + { + offset++; + } + + // + if (drawSCPMid) + { + offset++; + } + } + } + + // + // MidLine ... + if (drawSCCMid || drawSCPMid) + { + // + XBEEADrawMidLine( + sc.cycle, + drawSCLabel, + !drawSCCMid && drawSCPMid, + !drawSCPMid && drawSCCMid, + offset + // + ); + + // + if (drawSCLabel) + { + // + if (drawSCCMid) + { + offset++; + } + + // + if (drawSCPMid) + { + offset++; + } + } + } + + // + // Medium ... + + // + // Cycle ... + if (drawMCCBar || drawMCPBar) + { + // + XBEEADrawCycle( + mc.cycle, + drawMCLabel, + !drawMCCBar && drawMCPBar, + !drawMCPBar && drawMCCBar, + offset + // + ); + + // + if (drawMCLabel) + { + // + if (drawMCCBar) + { + offset += 3; + } + + // + if (drawMCPBar) + { + offset += 3; + } + + // + if (drawMCCMid) + { + offset++; + } + + // + if (drawMCPMid) + { + offset++; + } + } + } + + // + // Mid Line ... + if (drawMCCMid || drawMCPMid) + { + // + XBEEADrawMidLine( + mc.cycle, + drawMCLabel, + !drawMCCMid && drawMCPMid, + !drawMCPMid && drawMCCMid, + offset + // + ); + + // + if (drawMCLabel) + { + // + if (drawMCCMid) + { + offset++; + } + + // + if (drawMCPMid) + { + offset++; + } + } + } + + // + // Long ... + + // + // Cycle ... + if (drawLCCBar || drawLCPBar) + { + // + XBEEADrawCycle( + lc.cycle, + drawLCLabel, + !drawLCCBar && drawLCPBar, + !drawLCPBar && drawLCCBar, + offset + // + ); + + // + if (drawLCLabel) + { + // + if (drawLCCBar) + { + offset += 3; + } + + // + if (drawLCPBar) + { + offset += 3; + } + + // + if (drawLCCMid) + { + offset++; + } + + // + if (drawLCPMid) + { + offset++; + } + } + } + + // + // MidLine ... + if (drawLCCMid || drawLCPMid) + { + // + XBEEADrawMidLine( + lc.cycle, + drawLCLabel, + !drawLCCMid && drawLCPMid, + !drawLCPMid && drawLCCMid, + offset + // + ); + + // + if (drawLCLabel) + { + // + if (drawLCCMid) + { + offset++; + } + + // + if (drawLCPMid) + { + offset++; + } + } + } + + // + // Hind ... + + // + // Cycle ... + if (drawHCCBar || drawHCPBar) + { + // + XBEEADrawCycle( + hc.cycle, + drawHCLabel, + !drawHCCBar && drawHCPBar, + !drawHCPBar && drawHCCBar, + offset + // + ); + + // + if (drawHCLabel) + { + // + if (drawHCCBar) + { + offset += 3; + } + + // + if (drawHCPBar) + { + offset += 3; + } + + // + if (drawHCCMid) + { + offset++; + } + + // + if (drawHCPMid) + { + offset++; + } + } + } + + // + // MidLine ... + if (drawHCCMid || drawHCPMid) + { + // + XBEEADrawMidLine( + hc.cycle, + drawHCLabel, + !drawHCCMid && drawHCPMid, + !drawHCPMid && drawHCCMid, + offset + // + ); + } +} + +// +// Draw Middle Line of Cycle ... +void XBEEADrawCycle( + ENUM_X_MARKET_CYCLES cycle, // Specify Which Cycle to Draw ... + bool drawLabel = false, // Specify Draw Label of Mid Line or not ... + bool drawOnlyPrev = false, // Specify Draw Only Prev Bar of Cycle ... + bool drawOnlyCurrent = false, // Specify Draw Only Current Bar of Cycle ... + int offset = 0 // Distance used for Labels ... +) +{ + // + if (offset < 0) + { + offset = 0; + } + + // + XMarketCycle cycleModel; + XOHCLDrawSpecification cycleCBarSpecs; + XOHCLDrawSpecification cyclePBarSpecs; + + // + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + // + cycleModel = sc; + cycleCBarSpecs = scCBSpecs; + cyclePBarSpecs = scPBSpecs; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + // + cycleModel = mc; + cycleCBarSpecs = mcCBSpecs; + cyclePBarSpecs = mcPBSpecs; + break; + + // + case X_MARKET_CYCLE_LONG: + // + cycleModel = lc; + cycleCBarSpecs = lcCBSpecs; + cyclePBarSpecs = lcPBSpecs; + break; + + // + case X_MARKET_CYCLE_HIND: + // + cycleModel = hc; + cycleCBarSpecs = hcCBSpecs; + cyclePBarSpecs = hcPBSpecs; + break; + } + + // + string baseTag = ToString(cycle); + + // + XOHCL cBar = cycleModel.GetBar(0); + XOHCL pBar = cycleModel.GetBar(1); + + // + datetime fromCDate = cycleModel.GetBarTime(0); + datetime fromPDate = cycleModel.GetBarTime(1); + + // + datetime cTime = TimeCurrent(); + + // + // Try to Draw ... + + // + bool canDrawPrev = !drawOnlyCurrent; + bool canDrawCurrent = !drawOnlyPrev; + + // + // Set Cycles Color based on Current Candle ... + + // + bool isCBarBullish = + cBar.open < cBar.close; + + // + bool isPBarBullish = + pBar.open < pBar.close; + + // + color clrTemoBullishColor = cycleCBarSpecs.openStyle.clr; + color clrTemoBearishColor = cycleCBarSpecs.closeStyle.clr; + + // + color cBarSelectedColor = isCBarBullish ? clrTemoBullishColor : clrTemoBearishColor; + color pBarSelectedColor = isPBarBullish ? clrTemoBullishColor : clrTemoBearishColor; + + // + cycleCBarSpecs.openStyle.clr = cBarSelectedColor; + cycleCBarSpecs.openStyle.labelColor = cBarSelectedColor; + + // + cycleCBarSpecs.closeStyle.clr = cBarSelectedColor; + cycleCBarSpecs.closeStyle.labelColor = cBarSelectedColor; + + // + cyclePBarSpecs.openStyle.clr = pBarSelectedColor; + cyclePBarSpecs.openStyle.labelColor = pBarSelectedColor; + + // + cyclePBarSpecs.closeStyle.clr = pBarSelectedColor; + cyclePBarSpecs.closeStyle.labelColor = pBarSelectedColor; + + // + if (canDrawPrev) + { + offset++; + } + + // + // Label ... + if (drawLabel) + { + // + if (canDrawPrev) + { + // + // Draw Prev Bar Lables ... + + // + XBEEADrawCycleXOHCLLabel( + cycleModel, + pBar, + cyclePBarSpecs, + "P", + cTime, + offset - 1 + // + ); + + // + offset += 3; + } + + // + if (canDrawCurrent) + { + // + // Draw Current Bar Lables ... + + // + XBEEADrawCycleXOHCLLabel( + cycleModel, + cBar, + cycleCBarSpecs, + "C", + cTime, + offset + // + ); + } + } + + // + // Line ... + + // + if (canDrawPrev) + { + // + // Draw Cycle Prev Bar ... + XBEEADrawCycleXOHCLContent( + cycleModel, + pBar, + cyclePBarSpecs, + "P", + fromPDate + // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Cycle Current Bar ... + XBEEADrawCycleXOHCLContent( + cycleModel, + cBar, + cycleCBarSpecs, + "C", + fromCDate + // + ); + } +} + +// +// Draw Middle Line of Cycle ... +void XBEEADrawMidLine( + ENUM_X_MARKET_CYCLES cycle, // Specify Which Cycle to Draw ... + bool drawLabel = false, // Specify Draw Label of Mid Line or not ... + bool drawOnlyPrev = false, // Specify Draw Only Prev Bar of Cycle ... + bool drawOnlyCurrent = false, // Specify Draw Only Current Bar of Cycle ... + int offset = 0 // Distance used for Labels ... +) +{ + // + if (offset < 0) + { + offset = 0; + } + + // + XMarketCycle cycleModel; + XDrawSpecifications cycleCMidSpecs; + XDrawSpecifications cyclePMidSpecs; + + // + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + // + cycleModel = sc; + cycleCMidSpecs = scCMidSpecs; + cyclePMidSpecs = scPMidSpecs; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + // + cycleModel = mc; + cycleCMidSpecs = mcCMidSpecs; + cyclePMidSpecs = mcPMidSpecs; + break; + + // + case X_MARKET_CYCLE_LONG: + // + cycleModel = lc; + cycleCMidSpecs = lcCMidSpecs; + cyclePMidSpecs = lcPMidSpecs; + break; + + // + case X_MARKET_CYCLE_HIND: + // + cycleModel = hc; + cycleCMidSpecs = hcCMidSpecs; + cyclePMidSpecs = hcPMidSpecs; + break; + } + + // + // Calculate Mid Line ... + double midLine = (cycleModel.bar.high + cycleModel.bar.low) / 2; + + // + XOHCL cyclePrevBar = cycleModel.GetBar(1); + double midLinePrev = (cyclePrevBar.high + cyclePrevBar.low) / 2; + + // + string baseTag = ToString(cycle); + + // + string midCTag = baseTag + "|MID|C|"; + string midPTag = baseTag + "|MID|P|"; + + // + string midCLblTag = midCTag + "lbl"; + string midPLblTag = midPTag + "lbl"; + + // + datetime fromCDate = cycleModel.GetBarTime(0); + datetime fromPDate = cycleModel.GetBarTime(1); + + // + datetime cTime = TimeCurrent(); + + // + // Try to Draw ... + + // + bool canDrawPrev = !drawOnlyCurrent; + bool canDrawCurrent = !drawOnlyPrev; + + // + if (canDrawPrev) + { + offset++; + } + + // + // Label ... + if (drawLabel) + { + // + if (canDrawPrev) + { + // + // Draw Prev Candle MidLine Lable ... + XBEEADrawLabel( + cyclePMidSpecs, + midPLblTag, + cTime, + midLinePrev, + offset // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Current Candle MidLine Label ... + XBEEADrawLabel( + cycleCMidSpecs, + midCLblTag, + cTime, + midLine, + offset - 1 // + ); + } + } + + // + // Line ... + + // + if (canDrawPrev) + { + // + // Draw Prev Candle MidLine ... + XBEEADrawTrendLine( + cyclePMidSpecs, + midPTag, + fromPDate, + midLinePrev // + ); + } + + // + if (canDrawCurrent) + { + // + // Draw Current Candle MidLine ... + XBEEADrawTrendLine( + cycleCMidSpecs, + midCTag, + fromCDate, + midLine // + ); + } +} + +// +// Generate Expert State ... +string XBEEAGenerateState() +{ + // + string result = ""; + + // + // Summary ... + result += + // + "Summary: \n" + + "------------------\n" + + "Pivots: " + ToString(CountPivots()) + "\n" + + "BullishScore: " + ToString(mBullishScore) + ", min: " + ToString(mMinBullishScore) + ", max: " + ToString(mMaxBullishScore) + "\n" + + "BearishScore: " + ToString(mBearishScore) + ", min: " + ToString(mMinBearishScore) + ", max: " + ToString(mMaxBearishScore) + "\n" + + "isSUmmaryBullish: " + ToString(xBEEAIsSummaryTrendBullish) + "\n" + + "\n" + // + ; + + // + // ZigZag ... + result += + // + "Peaks and Vales: \n" + + "------------------\n" + + "Looking for New: " + (isZigZagInPeak ? "Vale" : "Peak") + "\n" + + "\n" + // + ; + + // + // Short ... + result += + // + "Short: \n" + + "------------------\n" + + "Period: " + ToString(sc.period) + "\n" + + "Bar 0: " + (isSCCBullish ? "Bullish" : "Bearish") + "\n" + + "Bar 1: " + (isSCPBullish ? "Bullish" : "Bearish") + "\n" + + "Trend MA: " + (isSCFastOverSlow ? "Bullish" : "Bearish") + "\n" + + "\n" + // + ; + + // + // Long ... + result += + // + "Medium: \n" + + "------------------\n" + + "Period: " + ToString(mc.period) + "\n" + + "Bar 0: " + (isMCCBullish ? "Bullish" : "Bearish") + "\n" + + "Bar 1: " + (isMCPBullish ? "Bullish" : "Bearish") + "\n" + + "Trend MA: " + (isMCFastOverSlow ? "Bullish" : "Bearish") + "\n" + + "\n" + // + ; + + // + // Medium ... + result += + // + "Long: \n" + + "------------------\n" + + "Period: " + ToString(lc.period) + "\n" + + "Bar 0: " + (isLCCBullish ? "Bullish" : "Bearish") + "\n" + + "Bar 1: " + (isLCPBullish ? "Bullish" : "Bearish") + "\n" + + "Trend MA: " + (isLCFastOverSlow ? "Bullish" : "Bearish") + "\n" + + "\n" + // + ; + + // + // Hind ... + result += + // + "Hind: \n" + + "------------------\n" + + "Period: " + ToString(hc.period) + "\n" + + "Bar 0: " + (isHCCBullish ? "Bullish" : "Bearish") + "\n" + + "Bar 1: " + (isHCPBullish ? "Bullish" : "Bearish") + "\n" + + "Trend MA: " + (isHCFastOverSlow ? "Bullish" : "Bearish") + "\n" + + "\n" + // + ; + + // + // Test CHE ... + double shortExit1s[]; + xBEEACheHelper.CopyShortExit1( + 0, + 2, + shortExit1s // + ); + + // + string shortExit1sStr = + // + "[0] => " + (shortExit1s[0] != EMPTY_VALUE ? ToString(shortExit1s[0]) : "EMPTY") + "\n" + + "[1] => " + (shortExit1s[1] != EMPTY_VALUE ? ToString(shortExit1s[1]) : "EMPTY") + "\n" + + "\n" + // + ; + + // + result = shortExit1sStr; + + // + string hash = ToMD5(result); + if (hash != mLastCommentHash) + { + // + LogMessage(result); + + // + LogMessage(hash); + + // + mLastCommentHash = hash; + } + + // + return result; +} + +// +// Custom DRAW(s) ... + +// +// Draw OHCL Labels ... +void XBEEADrawCycleXOHCLLabel( + XMarketCycle &cycleModel, // Specify Which Cycle to Draw ... + XOHCL &bar, // Specify Cycle XOHCL Model to Draw ... + XOHCLDrawSpecification &specs, // Specify Cycle XOHCL Draw Specifications ... + string baseTag, // Specify a Unique Tag ... + datetime time, // Draw Time ... + int offset = 0 // +) +{ + // + // Open ... + string openTag = cycleModel.prefix + "_" + baseTag + "_O_lbl"; + XBEEADrawLabel( + specs.openStyle, + openTag, + time, + bar.open, + offset + // + ); + + // + // High ... + string highTag = cycleModel.prefix + "_" + baseTag + "_H_lbl"; + XBEEADrawLabel( + specs.highStyle, + highTag, + time, + bar.high, + offset + 1 + // + ); + + // + // Close ... + string closeTag = cycleModel.prefix + "_" + baseTag + "_C_lbl"; + XBEEADrawLabel( + specs.closeStyle, + closeTag, + time, + bar.close, + offset + 2 + // + ); + + // + // Low ... + string lowTag = cycleModel.prefix + "_" + baseTag + "_L_lbl"; + XBEEADrawLabel( + specs.lowStyle, + lowTag, + time, + bar.low, + offset + 3 + // + ); +} + +// +// Draw OHCL Content ... +void XBEEADrawCycleXOHCLContent( + XMarketCycle &cycleModel, // Specify Which Cycle to Draw ... + XOHCL &bar, // Specify Cycle XOHCL Model to Draw ... + XOHCLDrawSpecification &specs, // Specify Cycle XOHCL Draw Specifications ... + string baseTag, // Specify a Unique Tag ... + datetime time // Draw Time ... +) +{ + // + // Open ... + string openTag = cycleModel.prefix + "_" + baseTag + "_O"; + XBEEADrawTrendLine( + specs.openStyle, + openTag, + time, + bar.open + // + ); + + // + // High ... + string highTag = cycleModel.prefix + "_" + baseTag + "_H"; + XBEEADrawTrendLine( + specs.highStyle, + highTag, + time, + bar.high + // + ); + + // + // Close ... + string closeTag = cycleModel.prefix + "_" + baseTag + "_C"; + XBEEADrawTrendLine( + specs.closeStyle, + closeTag, + time, + bar.close + // + ); + + // + // Low ... + string lowTag = cycleModel.prefix + "_" + baseTag + "_L"; + XBEEADrawTrendLine( + specs.lowStyle, + lowTag, + time, + bar.low + // + ); +} + +// +// Draw Label Using Specifications ... +void XBEEADrawLabel( + XDrawSpecifications &specs, + string tag, + datetime time, + double price, + int offset = 0 // +) +{ + // + long chartId = ChartID(); + int subWindow = 0; + + // + if (offset < 0) + { + offset = 0; + } + + // + int offsetSeconds = PeriodSeconds(xBEEAPeriod) * offset; + + // + string value = specs.label; + + // + DrawText( + chartId, + tag, + subWindow, + time - offsetSeconds, + price, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); +} + +// +// Draw TrendLine Using Specifications ... +void XBEEADrawTrendLine( + XDrawSpecifications &specs, + string tag, + datetime fromDate, + double fromPrice, + datetime toDate = NULL, + double toPrice = 0 // +) +{ + // + long chartId = ChartID(); + int subWindow = 0; + + // + if (toPrice <= 0) + { + toPrice = fromPrice; + } + + // + if (toDate == 0 || toDate == NULL) + { + toDate = TimeCurrent(); + } + + // + DrawTrendLine( + chartId, + tag, + subWindow, + fromDate, + fromPrice, + toDate, + toPrice, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); +} diff --git a/MQLTestWorkspace/Experts/x-sample.ea.ex5 b/MQLTestWorkspace/Experts/x-sample.ea.ex5 new file mode 100644 index 0000000..b99e398 Binary files /dev/null and b/MQLTestWorkspace/Experts/x-sample.ea.ex5 differ diff --git a/MQLTestWorkspace/Experts/x-sample.ea.mq5 b/MQLTestWorkspace/Experts/x-sample.ea.mq5 new file mode 100644 index 0000000..85503e2 --- /dev/null +++ b/MQLTestWorkspace/Experts/x-sample.ea.mq5 @@ -0,0 +1,398 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XSAMPLE MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XSAMPLE +// Description: an Exper Advisor which used RSI and MA +// to Analyse Market ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XSAMPLE" +#property strict + +// +#define ShortName "XSAMPLE" + +// +#include "../Libraries/x-saherelm.log.lib.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +#include "../Helpers/x-saherelm.x121.xmc.helper.mq5" +#include "../Helpers/x-saherelm.x121.xstr.helper.mq5" +#include "../Helpers/x-saherelm.x121.xche.helper.mq5" +#include "../Helpers/x-saherelm.x121.xosc.helper.mq5" + +// +#include "../Classes/x-saherelm.xtrade.class.mq5" +#include "../Classes/x-saherelm.x121.xmcycle.class.mq5" + +// +// Inputs ... +long xSampleEAMagicNumber = 78692110; // Magic Number +int xSampleEASlippage = 10; // Slippgae + +// +double xSampleEAVolume = 0.01; + +// +// Vars ... +string xSampleEASymbol; +ENUM_TIMEFRAMES xSampleEAPeriod; + +// +int maxBuys = 1; +int maxSells = 1; +int buyCount = 0; +int sellCount = 0; + +// +double _tp = 0; +double _sl = 0; +double _entry = 0; +ENUM_POSITION_TYPE _type = NULL; + +// +MqlTick xSampleEATick; + +// +XBarTracker xSamplEABarTracker; + +// +// X121MCycle ... +X121MCycleInputs xSampleEA121MCInputs; +XSC121Market xSampleEA121MC; + +// +XSCSignalCollector signalCollector; + +// +// Event Handlers ... +// +// Initialization ... +int OnInit() +{ + // + if (xSampleEASymbol == NULL || StringLen(xSampleEASymbol) <= 0) + { + xSampleEASymbol = _Symbol; + } + + // + if (xSampleEAPeriod == NULL) + { + xSampleEAPeriod = _Period; + } + + // + // Validate Inputs ... + if (!XSampleEAValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + drawPrefix = ShortName; + + // + bool result = xSamplEABarTracker.Init( + xSampleEASymbol, + xSampleEAPeriod); + if (!result) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // X121Market Cycle ... + result = xSampleEA121MCInputs.Init( + xSampleEASymbol, + xSampleEAPeriod, + X_MARKET_CYCLE_SHORT, + PERIOD_H1, + X_PERIOD_MANUALLY // + ); + if (!result) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // after Inputs Initialize Successfully we must prepare Styling for Draw ... + ApplyMCDrawStyles(); + + // + result = xSampleEA121MC.Init( + xSampleEA121MCInputs + // + ); + if (!result) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 XSampleEA Providers ... +} + +// +// On Tick Handler ... +void OnTick() +{ + // + if (!xSamplEABarTracker.IsNewBar()) + { + return; + } + + // + // Reading Tick ... + if (!SymbolInfoTick(xSampleEASymbol, xSampleEATick)) + { + return; + } + + // + // Draw Market Cycle Bars On Chart ... + int offset = 0; + xSampleEA121MC.Draw( + ChartID(), + 0, + offset + // + ); + + // + // TestXSignalCollector(); +} + +// +// Custom Functions ... + +// +// Validate Variables nd Inputs ... +bool XSampleEAValidateInputs() +{ + // + bool result = false; + + // + result = + // + xSampleEASlippage > 0 && + xSampleEAMagicNumber > 0 + // + ; + + // + return result; +} + +// +// Tools ... + +// +void TestXSignalCollector() +{ + // + XSignal signal; + bool isPrepared = signal.Prepare( + xSampleEASymbol, + "XTest", + xSampleEAPeriod, + POSITION_TYPE_BUY, + X_ORDER_MODE_MARKET, + GetEntry( + xSampleEASymbol, + POSITION_TYPE_BUY), + 0.01, + 0, + 0 + // + ); + if (isPrepared) + { + // + bool isAdded = signalCollector + .Add(signal); + + // + if (isAdded) + { + LogMessage("Signal Added Successfully ..."); + } + } + + // + // Try to Reading Collection ... + XSignal collectedSignals[]; + int collectedSignalsCount = signalCollector.Collect(collectedSignals); + if (collectedSignalsCount > 0) + { + LogMessage("Number of Loaded Signals: " + ToString(collectedSignalsCount)); + } +} + +// +void ApplyMCDrawStyles() +{ + // + // Here we Apply All Draw Styles on Input of Market Cycle ... + xSampleEA121MCInputs.drawCBar = true; + xSampleEA121MCInputs.drawPBar = true; + xSampleEA121MCInputs.drawLabels = true; + xSampleEA121MCInputs.drawCBarMid = true; + xSampleEA121MCInputs.drawPBarMid = true; + + // + // Current ... + + // + // MidLine ... + xSampleEA121MCInputs.cBarMidDrawSpecs.width = 1; + xSampleEA121MCInputs.cBarMidDrawSpecs.style = STYLE_DOT; + xSampleEA121MCInputs.cBarMidDrawSpecs.clr = clrSpringGreen; + xSampleEA121MCInputs.cBarMidDrawSpecs.Label( + xSampleEA121MCInputs.cycle.prefix + "_C MID", + xSampleEA121MCInputs.cBarMidDrawSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + xSampleEA121MCInputs.cBarDrawSpecs.Default(); + xSampleEA121MCInputs.cBarDrawSpecs.Width(1); + xSampleEA121MCInputs.cBarDrawSpecs.Style(STYLE_DOT); + // + xSampleEA121MCInputs.cBarDrawSpecs.openStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C O", + xSampleEA121MCInputs.cBarDrawSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.cBarDrawSpecs.highStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C H", + xSampleEA121MCInputs.cBarDrawSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.cBarDrawSpecs.closeStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C C", + xSampleEA121MCInputs.cBarDrawSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.cBarDrawSpecs.lowStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_C L", + xSampleEA121MCInputs.cBarDrawSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // Prev ... + + // + // MidLine ... + xSampleEA121MCInputs.pBarMidDrawSpecs.width = 2; + xSampleEA121MCInputs.pBarMidDrawSpecs.style = STYLE_SOLID; + xSampleEA121MCInputs.pBarMidDrawSpecs.clr = clrLimeGreen; + xSampleEA121MCInputs.pBarMidDrawSpecs.Label( + xSampleEA121MCInputs.cycle.prefix + "_P MID", + xSampleEA121MCInputs.pBarMidDrawSpecs.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + + // + // XOHCL ... + xSampleEA121MCInputs.pBarDrawSpecs.Default(); + xSampleEA121MCInputs.pBarDrawSpecs.Width(2); + // + xSampleEA121MCInputs.pBarDrawSpecs.openStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P O", + xSampleEA121MCInputs.pBarDrawSpecs.openStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.pBarDrawSpecs.highStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P H", + xSampleEA121MCInputs.pBarDrawSpecs.highStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.pBarDrawSpecs.closeStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P C", + xSampleEA121MCInputs.pBarDrawSpecs.closeStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); + xSampleEA121MCInputs.pBarDrawSpecs.lowStyle.Label( + xSampleEA121MCInputs.cycle.prefix + "_P L", + xSampleEA121MCInputs.pBarDrawSpecs.lowStyle.clr, + "Arial", + 8, + ANCHOR_LEFT_UPPER, + 90 + // + ); +} diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xche.helper.mq5 b/MQLTestWorkspace/Helpers/x-saherelm.x121.xche.helper.mq5 new file mode 100644 index 0000000..73a2d3d --- /dev/null +++ b/MQLTestWorkspace/Helpers/x-saherelm.x121.xche.helper.mq5 @@ -0,0 +1,492 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121CHEHelper +// 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 + +// +#include "../Classes/x-saherelm.xhelper.class.mq5" + +// +// Definitions ... + +// +enum ENUM_XCHE_BUFFERS +{ + X_CHE_LONG_EXIT_1_LINE = 0, + X_CHE_SHORT_EXIT_1_LINE = 1, + X_CHE_LONG_EXIT_2_LINE = 2, + X_CHE_SHORT_EXIT_2_LINE = 3, +}; + +// +// Input Models ... +struct X121CHEInputs +{ + // + // Props ... + + // + // Market ... + int length; // Length + int loopback; // Loopback + double multiplier1; // 1st Multiplier + double multiplier2; // 2nd Multiplier + + // + // Calculation ... + ENUM_APPLIED_PRICE upAppliedTo; // Up Zone Applied To + ENUM_APPLIED_PRICE downAppliedTo; // Down Zone Applied To + + // + // Constructor(s) ... + X121CHEInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + length = 0; + loopback = 0; + multiplier1 = 0; + multiplier2 = 0; + + // + upAppliedTo = PRICE_HIGH; + downAppliedTo = PRICE_LOW; + } + + // + // Default ... + void Default() + { + // + length = 35; + loopback = 26; + multiplier1 = 3.0; + multiplier2 = 3.5; + + // + upAppliedTo = PRICE_HIGH; + downAppliedTo = PRICE_LOW; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + length > 0 && + loopback < length && + multiplier1 > 0 && + multiplier2 > multiplier1 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(length, loopback); + + // + return result; + } +}; + +// +// Class ... +class XSCX121CHEHelper : public XSCBaseHelper +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + XSCX121CHEHelper() : XSCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XSCX121CHEHelper() {} + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121CHEInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + ArraySetAsSeries(longExit1Buffer, true); + ArraySetAsSeries(longExit2Buffer, true); + ArraySetAsSeries(shortExit1Buffer, true); + ArraySetAsSeries(shortExit2Buffer, true); + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xche", + // + // Inputs ... + // + // Market ... + "", + mInputs.length, + mInputs.loopback, + mInputs.multiplier1, + mInputs.multiplier2, + // + // Calculations ... + "", + mInputs.upAppliedTo, + mInputs.downAppliedTo, + // + // Presentation ... + "", + false, + false, + false, + false + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121CHEInputs GetInputs() { + return mInputs; + } + + // + bool SetInputs( + X121CHEInputs &inputs // Configs + ) { + // + return Init( + mSymbol, + mPeriod, + inputs + ); + } + + // + // Buffers ... + + // + double GetLongExit1( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return longExit1Buffer[barIndex]; + } + + // + // Copy Required Long Exits 1 ... + int CopyLongExit1( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + longExit1Buffer, + buffer, + forceClean + // + ); + } + + // + double GetLongExit2( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return longExit2Buffer[barIndex]; + } + + // + // Copy Required Long Exits 2 ... + int CopyLongExit2( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + longExit2Buffer, + buffer, + forceClean + // + ); + } + + // + double GetShortExit1( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return shortExit1Buffer[barIndex]; + } + + // + // Copy Required Short Exits 1 ... + int CopyShortExit1( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + shortExit1Buffer, + buffer, + forceClean + // + ); + } + + // + double GetShortExit2( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return shortExit2Buffer[barIndex]; + } + + // + // Copy Required Short Exits 2 ... + int CopyShortExit2( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + shortExit2Buffer, + buffer, + forceClean + // + ); + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + X121CHEInputs mInputs; // Inputs ... + + // + // Buffers ... + // + double longExit1Buffer[]; + double longExit2Buffer[]; + double shortExit1Buffer[]; + double shortExit2Buffer[]; + + // + // Tools ... + + // + // Calculate Values Until Now ... + void Calculate() + { + // + int totalBars = CountBars(); + int calculatedBars = CountCalculatedBars(); + + // + // Long Exit 1 ... + CopyBuffer( + mHandler, + X_CHE_LONG_EXIT_1_LINE, + 0, + totalBars, + longExit1Buffer + // + ); + + // + // Long Exit 2 ... + CopyBuffer( + mHandler, + X_CHE_LONG_EXIT_2_LINE, + 0, + totalBars, + longExit2Buffer + // + ); + + // + // Short Exit 1 ... + CopyBuffer( + mHandler, + X_CHE_SHORT_EXIT_1_LINE, + 0, + totalBars, + shortExit1Buffer + // + ); + + // + // Short Exit 2 ... + CopyBuffer( + mHandler, + X_CHE_SHORT_EXIT_2_LINE, + 0, + totalBars, + shortExit2Buffer + // + ); + } +}; + +// +// Tools ... diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xich.helper.ex5 b/MQLTestWorkspace/Helpers/x-saherelm.x121.xich.helper.ex5 new file mode 100644 index 0000000..089e402 Binary files /dev/null and b/MQLTestWorkspace/Helpers/x-saherelm.x121.xich.helper.ex5 differ diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xich.helper.mq5 b/MQLTestWorkspace/Helpers/x-saherelm.x121.xich.helper.mq5 new file mode 100644 index 0000000..74957a4 --- /dev/null +++ b/MQLTestWorkspace/Helpers/x-saherelm.x121.xich.helper.mq5 @@ -0,0 +1,717 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121ICHHelper +// 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 + +// +#include "../Classes/x-saherelm.xhelper.class.mq5" + +// +// Definitions ... +// +// Ichimoku Lines Calculator Mode ... +enum ENUM_XICH_CALCULATION_MODE +{ + // + X_XICH_HH_LL_MODE = 1, // Highest High and Lowest Low + X_XICH_HO_LC_MODE = 2, // Highest Open and Lowest Close +}; + +// +enum ENUM_XICH_BUFFERS +{ + X_ICH_TEANKANSEN_LINE = 0, + X_ICH_KIJUNSEN_LINE = 1, + X_ICH_CHIKOUSPAN_LINE = 4, + X_ICH_SENKOUSPANA_LINE = 5, + X_ICH_SENKOUSPANB_LINE = 6, +}; + +// +// Input Models ... +struct X121ICHInputs +{ + // + // Props ... + + // + // Market ... + // + // Tenkan Sen ... + int tenkanSenLength; // Length + ENUM_XICH_CALCULATION_MODE tenkanSenMode; // Calculation Mode + + // + // Kijun Sen ... + int kijunSenLength; // Length + ENUM_XICH_CALCULATION_MODE kijunSenMode; // Calculation Mode + + // + // Senkou Span B ... + int senkouSpanBLength; // Length + ENUM_XICH_CALCULATION_MODE senkouSpanBMode; // Calculation Mode + + // + // Chikou Span ... + ENUM_APPLIED_PRICE chikuoSpanAppliedTo; // Price Type + + // + // Constructor(s) ... + X121ICHInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + kijunSenLength = 0; + tenkanSenLength = 0; + senkouSpanBLength = 0; + + // + kijunSenMode = X_XICH_HH_LL_MODE; + tenkanSenMode = X_XICH_HH_LL_MODE; + senkouSpanBMode = X_XICH_HH_LL_MODE; + + // + chikuoSpanAppliedTo = PRICE_CLOSE; + } + + // + // Default ... + void Default() + { + // + kijunSenLength = 26; + tenkanSenLength = 9; + senkouSpanBLength = 52; + + // + kijunSenMode = X_XICH_HH_LL_MODE; + tenkanSenMode = X_XICH_HH_LL_MODE; + senkouSpanBMode = X_XICH_HH_LL_MODE; + + // + chikuoSpanAppliedTo = PRICE_CLOSE; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + tenkanSenLength > 2 && + kijunSenLength > tenkanSenLength && + senkouSpanBLength > kijunSenLength + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(result, tenkanSenLength); + result = MathMax(result, kijunSenLength); + result = MathMax(result, senkouSpanBLength); + + // + return result; + } +}; + +// +// Class ... +class XSCX121ICHHelper : public XSCBaseHelper +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + XSCX121ICHHelper() : XSCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XSCX121ICHHelper() {} + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121ICHInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + ArraySetAsSeries(tenkanSenBuffer, true); + ArraySetAsSeries(kijunSenBuffer, true); + ArraySetAsSeries(chikouSpanBuffer, true); + ArraySetAsSeries(senkouSpanABuffer, true); + ArraySetAsSeries(senkouSpanBBuffer, true); + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xich", + // + // Inputs ... + // + // TenkanSen ... + "", + mInputs.tenkanSenLength, + mInputs.tenkanSenMode, + // + // KijunSen ... + "", + mInputs.kijunSenLength, + mInputs.kijunSenMode, + // + // SenkouSpan B ... + "", + mInputs.senkouSpanBLength, + mInputs.senkouSpanBMode, + // + // ChikouSpan ... + "", + mInputs.chikuoSpanAppliedTo, + // + // Presentation ... + "", + false, + false, + false, + false, + false, + false, + false, + false, + false, + true // Push Kumo to Future ... + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121ICHInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121ICHInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs); + } + + // + // Buffers ... + + // + // TenkanSen ... + + // + double GetTenkanSen( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return tenkanSenBuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopyTenkanSen( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + tenkanSenBuffer, + buffer, + forceClean + // + ); + } + + // + // KijunSen ... + + // + double GetKijunSen( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return kijunSenBuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopyKijunSen( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + kijunSenBuffer, + buffer, + forceClean + // + ); + } + + // + // ChikouSpan ... + + // + double GetChikouSpan( + int barIndex // Bar Index + ) + { + // + barIndex -= mInputs.kijunSenLength; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex > ArraySize(chikouSpanBuffer)) { + barIndex = ArraySize(chikouSpanBuffer) - 1; + } + + // + Calculate(); + + // + return chikouSpanBuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopyChikouSpan( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start - mInputs.kijunSenLength, + count, + chikouSpanBuffer, + buffer, + forceClean + // + ); + } + + // + // SenkouSpanA ... + + // + double GetSenkouSpanA( + int barIndex // Bar Index + ) + { + // + barIndex += mInputs.kijunSenLength; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex > ArraySize(senkouSpanABuffer)) { + barIndex = ArraySize(senkouSpanABuffer) - 1; + } + + // + Calculate(); + + // + return senkouSpanABuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopySenkouSpanA( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start + mInputs.kijunSenLength, + count, + senkouSpanABuffer, + buffer, + forceClean + // + ); + } + + // + // SenkouSpanB ... + + // + double GetSenkouSpanB( + int barIndex // Bar Index + ) + { + // + barIndex += mInputs.kijunSenLength; + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + if (barIndex > ArraySize(senkouSpanBBuffer)) { + barIndex = ArraySize(senkouSpanBBuffer) - 1; + } + + // + Calculate(); + + // + return senkouSpanBBuffer[barIndex + mInputs.kijunSenLength]; + } + + // + // Copy Required Items ... + int CopySenkouSpanB( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start + mInputs.kijunSenLength, + count, + senkouSpanBBuffer, + buffer, + forceClean + // + ); + } + + // + // Future SenkouSpanA ... + + // + double GetFutureSenkouSpanA( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return senkouSpanABuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopyFutureSenkouSpanA( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + senkouSpanABuffer, + buffer, + forceClean + // + ); + } + + // + // SenkouSpanB ... + + // + double GetFutureSenkouSpanB( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return senkouSpanBBuffer[barIndex]; + } + + // + // Copy Required Items ... + int CopyFutureSenkouSpanB( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + senkouSpanBBuffer, + buffer, + forceClean + // + ); + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + X121ICHInputs mInputs; // Inputs ... + + // + // Buffers ... + double tenkanSenBuffer[]; + double kijunSenBuffer[]; + double chikouSpanBuffer[]; + double senkouSpanABuffer[]; + double senkouSpanBBuffer[]; + + // + // Tools ... + + // + // Calculate Values Until Now ... + void Calculate() + { + // + int totalBars = CountBars(); + int calculatedBars = CountCalculatedBars(); + + // + // TenkanSen ... + CopyBuffer( + mHandler, + X_ICH_TEANKANSEN_LINE, + 0, + totalBars, + tenkanSenBuffer + // + ); + + // + // KijunSen ... + CopyBuffer( + mHandler, + X_ICH_KIJUNSEN_LINE, + 0, + totalBars, + kijunSenBuffer + // + ); + + // + // ChikouSpan ... + CopyBuffer( + mHandler, + X_ICH_CHIKOUSPAN_LINE, + 0, + totalBars, + chikouSpanBuffer + // + ); + + // + // SenkouSpan A ... + CopyBuffer( + mHandler, + X_ICH_SENKOUSPANA_LINE, + 0, + totalBars, + senkouSpanABuffer + // + ); + + // + // SenkouSpan B ... + CopyBuffer( + mHandler, + X_ICH_SENKOUSPANB_LINE, + 0, + totalBars, + senkouSpanBBuffer + // + ); + } +}; + +// +// Tools ... diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xmc.helper.mq5 b/MQLTestWorkspace/Helpers/x-saherelm.x121.xmc.helper.mq5 new file mode 100644 index 0000000..f8c48b2 --- /dev/null +++ b/MQLTestWorkspace/Helpers/x-saherelm.x121.xmc.helper.mq5 @@ -0,0 +1,481 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121MCHelper +// 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 + +// +#include "../Classes/x-saherelm.xhelper.class.mq5" + +// +// Definitions ... + +// +enum ENUM_XMC_BUFFERS +{ + X_MC_FAST_LINE = 0, + X_MC_SLOW_LINE = 1, + X_MC_VERIFIER_LINE = 2, +}; + +// +// Input Models ... +struct X121MCInputs +{ + // + // Props ... + + // + // Market ... + + // + // Fast ... + int fastLength; // Length + int fastShift; // Shift + ENUM_MA_METHOD fastMethod; // Method + ENUM_APPLIED_PRICE fastAppliedTo; // Applied To + + // + // Slow ... + int slowLength; // Length + int slowShift; // Shift + ENUM_MA_METHOD slowMethod; // Method + ENUM_APPLIED_PRICE slowAppliedTo; // Applied To + + // + // Verifier ... + int verifierLength; // Length + int verifierShift; // Shift + ENUM_MA_METHOD verifierMethod; // Method + ENUM_APPLIED_PRICE verifierAppliedTo; // Applied To + + // + // Constructor(s) ... + X121MCInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + fastLength = 0; + fastShift = 0; + fastMethod = 0; + fastAppliedTo = PRICE_CLOSE; + + // + slowLength = 0; + slowShift = 0; + slowMethod = 0; + slowAppliedTo = PRICE_CLOSE; + + // + verifierLength = 0; + verifierShift = 0; + verifierMethod = 0; + verifierAppliedTo = PRICE_CLOSE; + } + + // + // Default ... + void Default() + { + // + fastLength = 9; + fastShift = 0; + fastMethod = MODE_EMA; + fastAppliedTo = PRICE_CLOSE; + + // + slowLength = 18; + slowShift = 0; + slowMethod = MODE_EMA; + slowAppliedTo = PRICE_CLOSE; + + // + verifierLength = 200; + verifierShift = 0; + verifierMethod = MODE_EMA; + verifierAppliedTo = PRICE_CLOSE; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + fastLength > 1 && + slowLength > fastLength && + verifierLength > slowLength + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(fastLength, slowLength); + result = MathMax(result, verifierLength); + + // + return result; + } +}; + +// +// Class ... +class XSCX121MCHelper : public XSCBaseHelper +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + XSCX121MCHelper() : XSCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XSCX121MCHelper() {} + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121MCInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + ArraySetAsSeries(fastBuffer, true); + ArraySetAsSeries(slowBuffer, true); + ArraySetAsSeries(verifierBuffer, true); + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xmc", + // + // Inputs ... + // + // Fast ... + "", + mInputs.fastLength, + mInputs.fastShift, + mInputs.fastMethod, + mInputs.fastAppliedTo, + // + // Slow ... + "", + mInputs.slowLength, + mInputs.slowShift, + mInputs.slowMethod, + mInputs.slowAppliedTo, + // + // Verifier ... + "", + mInputs.verifierLength, + mInputs.verifierShift, + mInputs.verifierMethod, + mInputs.verifierAppliedTo, + // + // Presentation ... + "", + false, + false, + false + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121MCInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121MCInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs); + } + + // + // Buffers ... + + // + // Fast ... + + // + double GetFast( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return fastBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyFast( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + fastBuffer, + buffer, + forceClean + // + ); + } + + // + // Slow ... + + // + double GetSlow( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return slowBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopySlow( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + slowBuffer, + buffer, + forceClean + // + ); + } + + // + // Verifier ... + + // + double GetVerifier( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return verifierBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyVerifier( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + verifierBuffer, + buffer, + forceClean + // + ); + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + X121MCInputs mInputs; // Inputs ... + + // + // Buffers ... + // + double fastBuffer[]; + double slowBuffer[]; + double verifierBuffer[]; + + // + // Tools ... + + // + // Calculate Values Until Now ... + void Calculate() + { + // + int totalBars = CountBars(); + int calculatedBars = CountCalculatedBars(); + + // + // Fast ... + CopyBuffer( + mHandler, + X_MC_FAST_LINE, + 0, + totalBars, + fastBuffer + // + ); + + // + // Slow ... + CopyBuffer( + mHandler, + X_MC_SLOW_LINE, + 0, + totalBars, + slowBuffer + // + ); + + // + // Verifier ... + CopyBuffer( + mHandler, + X_MC_VERIFIER_LINE, + 0, + totalBars, + verifierBuffer + // + ); + } +}; + +// +// Tools ... diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xosc.helper.mq5 b/MQLTestWorkspace/Helpers/x-saherelm.x121.xosc.helper.mq5 new file mode 100644 index 0000000..3c33097 --- /dev/null +++ b/MQLTestWorkspace/Helpers/x-saherelm.x121.xosc.helper.mq5 @@ -0,0 +1,1319 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121OSCHelper +// 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 + +// +#include "../Classes/x-saherelm.xhelper.class.mq5" + +// +// Definitions ... + +// +enum ENUM_XOSC_BUFFERS +{ + X_OSC_ATR_LINE = 0, + X_OSC_RVI_MAIN_LINE = 1, + X_OSC_RVI_SIGNAL_LINE = 2, + X_OSC_BULL_POWER_LINE = 3, + X_OSC_BEAR_POWER_LINE = 4, + X_OSC_VOLUME_LINE = 5, + X_OSC_RSI_LINE = 6, + X_OSC_CCI_LINE = 7, + X_OSC_MOMENTUM_LINE = 8, + X_OSC_SAR_LINE = 9, + X_OSC_MACD_MAIN_LINE = 10, + X_OSC_MACD_SIGNAL_LINE = 11, + X_OSC_STOCH_MAIN_LINE = 12, + X_OSC_STOCH_SIGNAL_LINE = 13, + X_OSC_STDDEV_LINE = 14, +}; + +// +// Input Models ... +struct X121OSCInputs +{ + // + // Props ... + + // + // ATR ... + int atrLength; // Length + + // + // RVI ... + int rviLength; // Length + + // + // BULLPOWER ... + int bullpLength; // Length + + // + // BEARPOWER ... + int bearpLength; // Length + + // + // VOLUME ... + ENUM_APPLIED_VOLUME volumeAppliedTo; // Applied To + + // + // RSI ... + int rsiLength; // Length + ENUM_APPLIED_PRICE rsiAppliedTo; // Applied To + + // + // CCI ... + int cciLength; // Length + ENUM_APPLIED_PRICE cciAppliedTo; // Applied To + + // + // STDDEV ... + int stddevLength; // Length + int stddevShift; // Shift + ENUM_MA_METHOD stddevMethod; // Mode + ENUM_APPLIED_PRICE stddevAppliedTo; // AppliedTo + + // + // MOMENTUM ... + int momentumLength; // Length + ENUM_APPLIED_PRICE momentumAppliedTo; // Applied To + + // + // SAR ... + double sarStep; // Step + double sarMaximum; // Maximum + + // + // MACD ... + int macdFastLength; // Fast Length + int macdSlowLength; // Slow Length + int macdSignaLength; // Signal Length + ENUM_APPLIED_PRICE macdAppliedTo; // Applied To + + // + // STOCHASTIC ... + // The buffer numbers: 0 - MAIN_LINE, 1 - SIGNAL_LINE. + int stochKLength; // K Length + int stochDLength; // D Length + int stochSlowing; // Slowing + ENUM_MA_METHOD stochMaMethod; // Ma Method + ENUM_STO_PRICE stochMode; // Calculation Mode + + // + // Constructor(s) ... + X121OSCInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + atrLength = 0; // Length + rviLength = 0; // Length + bullpLength = 0; // Length + bearpLength = 0; // Length + volumeAppliedTo = VOLUME_TICK; // Applied To + rsiLength = 0; // Length + rsiAppliedTo = PRICE_CLOSE; // Applied To + cciLength = 0; // Length + cciAppliedTo = PRICE_TYPICAL; // Applied To + stddevLength = 0; // Length + stddevShift = 0; // Shift + stddevMethod = MODE_SMA; // Mode + stddevAppliedTo = PRICE_CLOSE; // AppliedTo + momentumLength = 0; // Length + momentumAppliedTo = PRICE_CLOSE; // Applied To + sarStep = 0; // Step + sarMaximum = 0; // Maximum + macdFastLength = 0; // Fast Length + macdSlowLength = 0; // Slow Length + macdSignaLength = 0; // Signal Length + macdAppliedTo = PRICE_CLOSE; // Applied To + stochKLength = 0; // K Length + stochDLength = 0; // D Length + stochSlowing = 0; // Slowing + stochMaMethod = MODE_SMA; // Ma Method + stochMode = STO_LOWHIGH; // Calculation Mode + } + + // + // Default ... + void Default() + { + // + atrLength = 14; // Length + rviLength = 10; // Length + bullpLength = 13; // Length + bearpLength = 13; // Length + volumeAppliedTo = VOLUME_TICK; // Applied To + rsiLength = 14; // Length + rsiAppliedTo = PRICE_CLOSE; // Applied To + cciLength = 14; // Length + cciAppliedTo = PRICE_TYPICAL; // Applied To + stddevLength = 20; // Length + stddevShift = 0; // Shift + stddevMethod = MODE_SMA; // Mode + stddevAppliedTo = PRICE_CLOSE; // AppliedTo + momentumLength = 14; // Length + momentumAppliedTo = PRICE_CLOSE; // Applied To + sarStep = 0.02; // Step + sarMaximum = 0.2; // Maximum + macdFastLength = 12; // Fast Length + macdSlowLength = 26; // Slow Length + macdSignaLength = 9; // Signal Length + macdAppliedTo = PRICE_CLOSE; // Applied To + stochKLength = 5; // K Length + stochDLength = 3; // D Length + stochSlowing = 3; // Slowing + stochMaMethod = MODE_SMA; // Ma Method + stochMode = STO_LOWHIGH; // Calculation Mode + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + atrLength >= 2 && + rviLength >= 2 && + bullpLength >= 2 && + bearpLength >= 2 && + rsiLength >= 2 && + cciLength >= 2 && + momentumLength >= 2 && + sarStep > 0 && + sarStep < sarMaximum && + macdFastLength >= 2 && + macdSlowLength > macdFastLength && + macdSignaLength >= 2 && + stochKLength >= 2 && + stochDLength >= 2 && + stochSlowing >= 2 && + stddevLength >= 2 && + stddevShift >= 0 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(atrLength, rviLength); + result = MathMax(result, bullpLength); + result = MathMax(result, bearpLength); + result = MathMax(result, rsiLength); + result = MathMax(result, cciLength); + result = MathMax(result, momentumLength); + result = MathMax(result, macdFastLength); + result = MathMax(result, macdSlowLength); + result = MathMax(result, macdSignaLength); + result = MathMax(result, stochKLength); + result = MathMax(result, stochDLength); + result = MathMax(result, stochSlowing); + result = MathMax(result, stddevLength); + + // + return result; + } +}; + +// +// Class ... +class XSCX121OSCHelper : public XSCBaseHelper +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + XSCX121OSCHelper() : XSCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XSCX121OSCHelper() {} + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121OSCInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + ArraySetAsSeries(atrBuffer, true); + ArraySetAsSeries(rviMainBuffer, true); + ArraySetAsSeries(rviSignalBuffer, true); + ArraySetAsSeries(bullPBuffer, true); + ArraySetAsSeries(bearPBuffer, true); + ArraySetAsSeries(volumeBuffer, true); + ArraySetAsSeries(rsiBuffer, true); + ArraySetAsSeries(cciBuffer, true); + ArraySetAsSeries(momentumBuffer, true); + ArraySetAsSeries(sarBuffer, true); + ArraySetAsSeries(macdMainBuffer, true); + ArraySetAsSeries(macdSignalBuffer, true); + ArraySetAsSeries(stochMainBuffer, true); + ArraySetAsSeries(stochSignalBuffer, true); + ArraySetAsSeries(stddevBuffer, true); + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xosc", + // + // Inputs ... + // + // ATR ... + "", + mInputs.atrLength, + // + // RVI ... + "", + mInputs.rviLength, + // + // Bulls Power ... + "", + mInputs.bullpLength, + // + // Bears Power ... + "", + mInputs.bearpLength, + // + // Voluem ... + "", + mInputs.volumeAppliedTo, + // + // RSI ... + "", + mInputs.rsiLength, + mInputs.rsiAppliedTo, + // + // CCI ... + "", + mInputs.cciLength, + mInputs.cciAppliedTo, + // + // STDDev ... + "", + mInputs.stddevLength, + mInputs.stddevShift, + mInputs.stddevMethod, + mInputs.stddevAppliedTo, + // + // Momentum ... + "", + mInputs.momentumLength, + mInputs.momentumAppliedTo, + // + // SAR ... + "", + mInputs.sarStep, + mInputs.sarMaximum, + // + // MACD ... + "", + mInputs.macdFastLength, + mInputs.macdSlowLength, + mInputs.macdSignaLength, + mInputs.macdAppliedTo, + // + // Stochastic ... + "", + mInputs.stochKLength, + mInputs.stochDLength, + mInputs.stochSlowing, + mInputs.stochMaMethod, + mInputs.stochMode + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121OSCInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121OSCInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs); + } + + // + // Buffers ... + + // + // ATR ... + + // + double GetATR( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return atrBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyATR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + atrBuffer, + buffer, + forceClean + // + ); + } + + // + // RVI ... + + // + double GetRVI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return rviMainBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyRVI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + rviMainBuffer, + buffer, + forceClean + // + ); + } + + // + double GetRVISignal( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return rviSignalBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyRVISignal( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + rviSignalBuffer, + buffer, + forceClean + // + ); + } + + // + // BULLP ... + + // + double GetBullPower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return bullPBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyBullPower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + bullPBuffer, + buffer, + forceClean + // + ); + } + + // + // BEARP ... + + // + double GetBearPower( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return bearPBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyBearPower( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + bearPBuffer, + buffer, + forceClean + // + ); + } + + // + // VOLUME ... + + // + double GetVolume( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return volumeBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyVolume( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + volumeBuffer, + buffer, + forceClean + // + ); + } + + // + // RSI ... + + // + double GetRSI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return rsiBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyRSI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + rsiBuffer, + buffer, + forceClean + // + ); + } + + // + // CCI ... + + // + double GetCCI( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return cciBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyCCI( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + cciBuffer, + buffer, + forceClean + // + ); + } + + // + // MOMENTUM ... + + // + double GetMomentum( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return momentumBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyMomentum( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + momentumBuffer, + buffer, + forceClean + // + ); + } + + // + // SAR ... + + // + double GetSAR( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return sarBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopySAR( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + sarBuffer, + buffer, + forceClean + // + ); + } + + // + // STDDEV ... + + // + double GetSTDDEV( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return stddevBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopySTDDEV( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + stddevBuffer, + buffer, + forceClean + // + ); + } + + // + // MACD ... + + // + double GetMACD( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return macdMainBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyMACD( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + macdMainBuffer, + buffer, + forceClean + // + ); + } + + // + double GetMACDSignal( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return macdSignalBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyMACDSignal( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + macdSignalBuffer, + buffer, + forceClean + // + ); + } + + // + // STOCH ... + + // + double GetSTOCH( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return stochMainBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopySTOCH( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + stochMainBuffer, + buffer, + forceClean + // + ); + } + + // + double GetSTOCHSignal( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return stochSignalBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopySTOCHSignal( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + stochSignalBuffer, + buffer, + forceClean + // + ); + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + X121OSCInputs mInputs; // Inputs ... + + // + // Buffers ... + double atrBuffer[]; + double rviMainBuffer[]; + double rviSignalBuffer[]; + double bullPBuffer[]; + double bearPBuffer[]; + double volumeBuffer[]; + double rsiBuffer[]; + double cciBuffer[]; + double momentumBuffer[]; + double sarBuffer[]; + double macdMainBuffer[]; + double macdSignalBuffer[]; + double stochMainBuffer[]; + double stochSignalBuffer[]; + double stddevBuffer[]; + + // + // Tools ... + + // + // Calculate Values Until Now ... + void Calculate() + { + // + int totalBars = CountBars(); + int calculatedBars = CountCalculatedBars(); + + // + // ATR ... + CopyBuffer( + mHandler, + X_OSC_ATR_LINE, + 0, + totalBars, + atrBuffer + // + ); + + // + // BULLP ... + CopyBuffer( + mHandler, + X_OSC_BULL_POWER_LINE, + 0, + totalBars, + bullPBuffer + // + ); + + // + // BEARP ... + CopyBuffer( + mHandler, + X_OSC_BEAR_POWER_LINE, + 0, + totalBars, + bearPBuffer + // + ); + + // + // VOLUME ... + CopyBuffer( + mHandler, + X_OSC_VOLUME_LINE, + 0, + totalBars, + volumeBuffer + // + ); + + // + // RSI ... + CopyBuffer( + mHandler, + X_OSC_RSI_LINE, + 0, + totalBars, + rsiBuffer + // + ); + + // + // CCI ... + CopyBuffer( + mHandler, + X_OSC_CCI_LINE, + 0, + totalBars, + cciBuffer + // + ); + + // + // MOMENTUM ... + CopyBuffer( + mHandler, + X_OSC_MOMENTUM_LINE, + 0, + totalBars, + momentumBuffer + // + ); + + // + // SAR ... + CopyBuffer( + mHandler, + X_OSC_SAR_LINE, + 0, + totalBars, + sarBuffer + // + ); + + // + // STDDEV ... + CopyBuffer( + mHandler, + X_OSC_STDDEV_LINE, + 0, + totalBars, + stddevBuffer + // + ); + + // + // RVI ... + + // + // RVI Main ... + CopyBuffer( + mHandler, + X_OSC_RVI_MAIN_LINE, + 0, + totalBars, + rviMainBuffer + // + ); + + // + // RVI Signal ... + CopyBuffer( + mHandler, + X_OSC_RVI_SIGNAL_LINE, + 0, + totalBars, + rviSignalBuffer + // + ); + + // + // MACD ... + + // + // MACD Main ... + CopyBuffer( + mHandler, + X_OSC_MACD_MAIN_LINE, + 0, + totalBars, + macdMainBuffer + // + ); + + // + // MACD Signal ... + CopyBuffer( + mHandler, + X_OSC_MACD_SIGNAL_LINE, + 0, + totalBars, + macdSignalBuffer + // + ); + + // + // STOCH ... + + // + // STOCH Main ... + CopyBuffer( + mHandler, + X_OSC_STOCH_MAIN_LINE, + 0, + totalBars, + stochMainBuffer + // + ); + + // + // STOCH Signal ... + CopyBuffer( + mHandler, + X_OSC_STOCH_SIGNAL_LINE, + 0, + totalBars, + stochSignalBuffer + // + ); + } +}; + +// +// Tools ... diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xstr.helper.ex5 b/MQLTestWorkspace/Helpers/x-saherelm.x121.xstr.helper.ex5 new file mode 100644 index 0000000..00b7cd2 Binary files /dev/null and b/MQLTestWorkspace/Helpers/x-saherelm.x121.xstr.helper.ex5 differ diff --git a/MQLTestWorkspace/Helpers/x-saherelm.x121.xstr.helper.mq5 b/MQLTestWorkspace/Helpers/x-saherelm.x121.xstr.helper.mq5 new file mode 100644 index 0000000..d1c5446 --- /dev/null +++ b/MQLTestWorkspace/Helpers/x-saherelm.x121.xstr.helper.mq5 @@ -0,0 +1,408 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121STRHelper +// 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 + +// +#include "../Classes/x-saherelm.xhelper.class.mq5" + +// +// Definitions ... + +// +enum ENUM_XSTR_BUFFERS +{ + X_STR_TREND_LINE = 0, + X_STR_STATE_LINE = 5, +}; + +// +enum ENUM_XSTR_TREND_STATES +{ + X_STR_BULLISH = 1, // Bullish + X_STR_BEARISH = -1, // Bearish +}; + +// +// Input Models ... +struct X121STRInputs +{ + // + // Props ... + + // + // ATR ... + int length; // Length + double multiplier; // Multiplier + ENUM_APPLIED_PRICE appliedTo; // Applied To + + // + // Constructor(s) ... + X121STRInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + length = 0; + multiplier = 0; + appliedTo = PRICE_CLOSE; + } + + // + // Default ... + void Default() + { + // + length = 14; + multiplier = 3.5; + appliedTo = PRICE_MEDIAN; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + length > 0 && + multiplier > 0 + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = length; + + // + return result; + } +}; + +// +// Class ... +class XSCX121STRHelper : public XSCBaseHelper +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructors ... + XSCX121STRHelper() : XSCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XSCX121STRHelper() {} + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121STRInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + ArraySetAsSeries(trendBuffer, true); + ArraySetAsSeries(stateBuffer, true); + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xstr", + // + // Inputs ... + // + // ATR ... + "", + mInputs.length, + mInputs.multiplier, + mInputs.appliedTo, + // + // Presentation ... + "", + false, + false + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121STRInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121STRInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs); + } + + // + // Buffers ... + + // + // Trend ... + + // + double GetTrend( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return trendBuffer[barIndex]; + } + + // + // Copy Required Buffer ... + int CopyTrend( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + trendBuffer, + buffer, + forceClean + // + ); + } + + // + // State ... + + // + ENUM_XSTR_TREND_STATES GetState( + int barIndex // Bar Index + ) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + Calculate(); + + // + return (ENUM_XSTR_TREND_STATES)((int)stateBuffer[barIndex]); + } + + // + // Copy Required Buffer ... + int CopyState( + int start, // Start + int count, // Number of Items for read + double &buffer[], // Dest Buffer + bool forceClean = true // Force To Clean buffer + ) + { + // + // Update Calculations ... + Calculate(); + + // + // Copy Items ... + return Copy( + start, + count, + stateBuffer, + buffer, + forceClean + // + ); + } + + // + // Tools ... + + // + ENUM_XSTR_TREND_STATES ToState(double state) + { + return (ENUM_XSTR_TREND_STATES)((int)state); + } + + // + bool IsBullish(double state) + { + // + bool result = false; + + // + result = + // + ToState(state) == X_STR_BULLISH; + // + ; + + // + return result; + } + + // + bool IsBearish(double state) + { + // + bool result = false; + + // + result = + // + ToState(state) == X_STR_BEARISH; + // + ; + + // + return result; + } + + // + // Protected ... +protected: + // + // Private ... +private: + // + // Props ... + X121STRInputs mInputs; // Inputs ... + + // + // Buffers ... + double trendBuffer[]; + double stateBuffer[]; + + // + // Tools ... + + // + // Calculate Values Until Now ... + void Calculate() + { + // + int totalBars = CountBars(); + int calculatedBars = CountCalculatedBars(); + + // + // Trend ... + CopyBuffer( + mHandler, + X_STR_TREND_LINE, + 0, + totalBars, + trendBuffer + // + ); + + // + // State ... + CopyBuffer( + mHandler, + X_STR_STATE_LINE, + 0, + totalBars, + stateBuffer + // + ); + } +}; + +// +// Tools ... diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xche.ex5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xche.ex5 index 3960a6f..e91cf47 100644 Binary files a/MQLTestWorkspace/Indicators/x-saherelm.x121.xche.ex5 and b/MQLTestWorkspace/Indicators/x-saherelm.x121.xche.ex5 differ diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xich.ex5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xich.ex5 index e0e91b2..79f9628 100644 Binary files a/MQLTestWorkspace/Indicators/x-saherelm.x121.xich.ex5 and b/MQLTestWorkspace/Indicators/x-saherelm.x121.xich.ex5 differ diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xich.mq5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xich.mq5 index 5493ba2..724aff6 100644 --- a/MQLTestWorkspace/Indicators/x-saherelm.x121.xich.mq5 +++ b/MQLTestWorkspace/Indicators/x-saherelm.x121.xich.mq5 @@ -118,7 +118,7 @@ input bool shiftKumo = true; // Shift Kumo to Future #property indicator_chart_window // -#property indicator_buffers 9 +#property indicator_buffers 15 #property indicator_plots 8 // @@ -243,6 +243,29 @@ double senkouSpanBBuffer[]; #property indicator_style8 STYLE_SOLID #property indicator_width8 1 +// +// DATA Buffers ... + +// +#define dTenkanBufferIndex 9 +double dTenkanBuffer[]; + +// +#define dKijunBufferIndex 10 +double dKijunBuffer[]; + +// +#define dChikouBufferIndex 11 +double dChikouBuffer[]; + +// +#define dSSABufferIndex 12 +double dSSABuffer[]; + +// +#define dSSBBufferIndex 13 +double dSSBBuffer[]; + // // END Buffers ... // @@ -253,6 +276,7 @@ double senkouSpanBBuffer[]; // int maxLength; +int mHandler; // ENUM_SERIESMODE mTenkanSenTopMode = NULL; @@ -296,6 +320,19 @@ int OnInit() // Define Index Buffers ... DefineBuffers(); + // + // Init Handler ... + mHandler = iIchimoku( + _Symbol, + _Period, + tenkanSenLength, + kijunSenLength, + senkouSpanBLength); + if (mHandler == INVALID_HANDLE) + { + return INIT_FAILED; + } + // // Set Indicator ShortName ... SetIndicatorName(); @@ -320,6 +357,9 @@ void OnDeinit(const int reason) // REASON_TEMPLATE 7 Another chart template applied // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value // REASON_CLOSE 9 Terminal closed + + // + IndicatorRelease(mHandler); } // @@ -371,9 +411,34 @@ int OnCalculate( // this counts Available Bars ... int limit; + // + // Check Calculated Bars ... + int ichCalculatedBars = BarsCalculated(mHandler); + if (ichCalculatedBars < maxLength) + { + return prev_calculated; + } + // limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + // + // Buffers Copy ... + int copiedTenkans = CopyBuffer(mHandler, TENKANSEN_LINE, 0, limit, dTenkanBuffer); + int copiedKijuns = CopyBuffer(mHandler, KIJUNSEN_LINE, 0, limit, dKijunBuffer); + int copiedChikous = CopyBuffer(mHandler, CHIKOUSPAN_LINE, 0, limit, dChikouBuffer); + int copiedSSAs = CopyBuffer(mHandler, SENKOUSPANA_LINE, 0, limit, dSSABuffer); + int copiedSSBs = CopyBuffer(mHandler, SENKOUSPANB_LINE, 0, limit, dSSBBuffer); + if ( + copiedSSAs < 0 || + copiedSSBs < 0 || + copiedKijuns < 0 || + copiedTenkans < 0 || + copiedChikous < 0) + { + return prev_calculated; + } + // // Main Loop ... for (int i = limit - 1; i >= 0 && !IsStopped(); i--) @@ -550,6 +615,34 @@ void DefineBuffers() PlotIndexSetInteger(kumoBufferIndex, PLOT_SHIFT, shiftSize); PlotIndexSetInteger(kumoBufferIndex, PLOT_SHOW_DATA, false); PlotIndexSetInteger(kumoBufferIndex, PLOT_DRAW_TYPE, kumoDrawType); + + // + // DATA Buffers ... + + // + // D Tenkan ... + ArraySetAsSeries(dTenkanBuffer, true); + SetIndexBuffer(dTenkanBufferIndex, dTenkanBuffer, INDICATOR_CALCULATIONS); + + // + // D Kijun ... + ArraySetAsSeries(dKijunBuffer, true); + SetIndexBuffer(dKijunBufferIndex, dKijunBuffer, INDICATOR_CALCULATIONS); + + // + // D Chikou ... + ArraySetAsSeries(dChikouBuffer, true); + SetIndexBuffer(dChikouBufferIndex, dChikouBuffer, INDICATOR_CALCULATIONS); + + // + // D SSA ... + ArraySetAsSeries(dSSABuffer, true); + SetIndexBuffer(dSSABufferIndex, dSSABuffer, INDICATOR_CALCULATIONS); + + // + // D SSB ... + ArraySetAsSeries(dSSBBuffer, true); + SetIndexBuffer(dSSBBufferIndex, dSSBBuffer, INDICATOR_CALCULATIONS); } // diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xmc.ex5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xmc.ex5 new file mode 100644 index 0000000..d63fc53 Binary files /dev/null and b/MQLTestWorkspace/Indicators/x-saherelm.x121.xmc.ex5 differ diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xmc.mq5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xmc.mq5 new file mode 100644 index 0000000..61dffd2 --- /dev/null +++ b/MQLTestWorkspace/Indicators/x-saherelm.x121.xmc.mq5 @@ -0,0 +1,469 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 X121_XMC MA Cross Indicator +// --------------------------------------------------- +// Name: X121_XMC +// Description: Moving Average Crosses +// Market Analysor ... +// +// +// 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_XMC Indicator" +#property strict + +// +// START Constants ... +// + +// +// Indicator Short Name ... +#define ShortName "X121_XMC" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input group "Fast"; +input int fastMaLength = 9; // Length +input int fastMaShift = 0; // Shift +input ENUM_MA_METHOD fastMaMethod = MODE_EMA; // Method +input ENUM_APPLIED_PRICE fastMaAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "Slow"; +input int slowMaLength = 18; // Length +input int slowMaShift = 0; // Shift +input ENUM_MA_METHOD slowMaMethod = MODE_EMA; // Method +input ENUM_APPLIED_PRICE slowMaAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "Verifier"; +input int verifierMaLength = 50; // Length +input int verifierMaShift = 0; // Shift +input ENUM_MA_METHOD verifierMaMethod = MODE_EMA; // Method +input ENUM_APPLIED_PRICE verifierMaAppliedTo = PRICE_CLOSE; // Applied To + +// +input group "Presentation"; +input bool showFastMa = true; // Show Fast +input bool showSlowMa = true; // Show Slow +input bool showVerifierMa = true; // Show Verifier + +// +// END Inputs ... +// + +// +// START Includes and Imports ... +// + +// +// Includes Logging Library ... +#include "../Libraries/x-saherelm.log.lib.mq5" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Includes and Imports ... +// + +// +// START Buffers ... +// +#property indicator_chart_window + +// +#property indicator_buffers 3 +#property indicator_plots 3 + +// +// PLOTTED Buffers ... + +// +// MA ... + +// +// FAST ... +#define fastMaBufferIndex 0 +double fastMaBuffer[]; + +// +#property indicator_label1 "X121_XMC MA F" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrYellow +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +// +// SLOW ... +#define slowMaBufferIndex 1 +double slowMaBuffer[]; + +// +#property indicator_label2 "X121_XMC MA S" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrDarkOrange +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +// +// VERIFIER ... +#define verifierMaBufferIndex 2 +double verifierMaBuffer[]; + +// +#property indicator_label3 "X121_XMC MA V" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrDarkBlue +#property indicator_style3 STYLE_SOLID +#property indicator_width3 2 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +int fastMaHandler = INVALID_HANDLE; +int slowMaHandler = INVALID_HANDLE; +int verifierMaHandler = INVALID_HANDLE; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + logTag = ShortName; + + // + // 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(); + + // + // MA Initialization ... + + // + // FAST ... + fastMaHandler = iMA( + _Symbol, + _Period, + fastMaLength, + fastMaShift, + fastMaMethod, + fastMaAppliedTo); + if (fastMaHandler == INVALID_HANDLE) + { + // + string msg = "Error in Initilizing Indicator ..."; + LogMessage(msg); + + // + return INIT_FAILED; + } + + // + // SLOW ... + slowMaHandler = iMA( + _Symbol, + _Period, + slowMaLength, + slowMaShift, + slowMaMethod, + slowMaAppliedTo); + if (slowMaHandler == INVALID_HANDLE) + { + // + string msg = "Error in Initilizing Indicator ..."; + LogMessage(msg); + + // + return INIT_FAILED; + } + + // + // VERIFIER ... + verifierMaHandler = iMA( + _Symbol, + _Period, + verifierMaLength, + verifierMaShift, + verifierMaMethod, + verifierMaAppliedTo); + if (verifierMaHandler == INVALID_HANDLE) + { + // + string msg = "Error in Initilizing Indicator ..."; + LogMessage(msg); + + // + return INIT_FAILED; + } + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 + + // + // Here we can handle De Initialization Reasons ... + IndicatorRelease(fastMaHandler); + IndicatorRelease(slowMaHandler); + IndicatorRelease(verifierMaHandler); +} + +// +// Calculations ... +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + 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); + + // + // this counts Available Bars ... + int limit; + + // + // Check Calculated Bars ... + int fastMaCalculatedBars = BarsCalculated(fastMaHandler); + int slowMaCalculatedBars = BarsCalculated(slowMaHandler); + int verifierMaCalculatedBars = BarsCalculated(verifierMaHandler); + if (fastMaCalculatedBars < maxLength || + slowMaCalculatedBars < maxLength || + verifierMaCalculatedBars < maxLength) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + int copiedFastMas = CopyBuffer(fastMaHandler, 0, 0, limit, fastMaBuffer); + int copiedSlowMas = CopyBuffer(slowMaHandler, 0, 0, limit, slowMaBuffer); + int copiedVerifierMas = CopyBuffer(verifierMaHandler, 0, 0, limit, verifierMaBuffer); + if (copiedFastMas <= 0 || + copiedSlowMas <= 0 || + copiedVerifierMas <= 0 + ) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + CalculateBuffers(i); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = + // + // Validate Ma ... + (fastMaLength > 2 && + slowMaLength > fastMaLength && + verifierMaLength > slowMaLength) + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + // Ma ... + result = MathMax(result, fastMaLength); + result = MathMax(result, slowMaLength); + result = MathMax(result, verifierMaLength); + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // MA ... + + // + // FAST ... + ENUM_DRAW_TYPE fastMaDrawType = showFastMa ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(fastMaBuffer, true); + SetIndexBuffer(fastMaBufferIndex, fastMaBuffer, INDICATOR_DATA); + PlotIndexSetInteger(fastMaBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(fastMaBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(fastMaBufferIndex, PLOT_DRAW_TYPE, fastMaDrawType); + + // + // SLOW ... + ENUM_DRAW_TYPE slowMaDrawType = showSlowMa ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(slowMaBuffer, true); + SetIndexBuffer(slowMaBufferIndex, slowMaBuffer, INDICATOR_DATA); + PlotIndexSetInteger(slowMaBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(slowMaBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(slowMaBufferIndex, PLOT_DRAW_TYPE, slowMaDrawType); + + // + // VERIFIER ... + ENUM_DRAW_TYPE verifierMaDrawType = showVerifierMa ? DRAW_LINE : DRAW_NONE; + ArraySetAsSeries(verifierMaBuffer, true); + SetIndexBuffer(verifierMaBufferIndex, verifierMaBuffer, INDICATOR_DATA); + PlotIndexSetInteger(verifierMaBufferIndex, PLOT_DRAW_BEGIN, maxLength); + PlotIndexSetInteger(verifierMaBufferIndex, PLOT_SHOW_DATA, false); + PlotIndexSetInteger(verifierMaBufferIndex, PLOT_DRAW_TYPE, verifierMaDrawType); +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + // + string indicatorShortName = ""; + StringConcatenate(indicatorShortName, ShortName, ""); + + // + IndicatorSetString(INDICATOR_SHORTNAME, indicatorShortName); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index // Selected Bar Index +) +{ +} + +// +// END Functions ... +// diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xosc.ex5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xosc.ex5 new file mode 100644 index 0000000..d71114c Binary files /dev/null and b/MQLTestWorkspace/Indicators/x-saherelm.x121.xosc.ex5 differ diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xosc.mq5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xosc.mq5 new file mode 100644 index 0000000..0f0f9ef --- /dev/null +++ b/MQLTestWorkspace/Indicators/x-saherelm.x121.xosc.mq5 @@ -0,0 +1,721 @@ +////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121_XOSC +// Description: provides some oscillator values +// as empty 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 X121_XAMA Indicator" +#property strict + +// +// START Constants ... +// + +#define ShortName "X121_XOSC" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +// ATR ... +input group "ATR"; +input int atrLength = 14; // Length + +// +// RVI ... +// The buffer numbers are the following: 0 - MAIN_LINE, 1 - SIGNAL_LINE. +input group "RVI"; +input int rviLength = 10; // Length + +// +// BULLPOWER ... +input group "Bulls Power"; +input int bullpLength = 13; // Length + +// +// BEARPOWER ... +input group "Bears Power"; +input int bearpLength = 13; // Length + +// +// VOLUME ... +input group "Volumes"; +input ENUM_APPLIED_VOLUME volumeAppliedTo = VOLUME_TICK; // Applied To + +// +// RSI ... +input group "RSI"; +input int rsiLength = 14; // Length +input ENUM_APPLIED_PRICE rsiAppliedTo = PRICE_CLOSE; // Applied To + +// +// CCI ... +input group "CCI"; +input int cciLength = 14; // Length +input ENUM_APPLIED_PRICE cciAppliedTo = PRICE_TYPICAL; // Applied To + +// +// STDDEV ... +input group "Standard Deviation"; +input int stddevLength = 20; // Length +input int stddevShift = 0; // Shift +input ENUM_MA_METHOD stddevMethod = MODE_SMA; // Mode +input ENUM_APPLIED_PRICE stddevAppliedTo = PRICE_CLOSE; // AppliedTo + +// +// MOMENTUM ... +input group "Momentum"; +input int momentumLength = 14; // Length +input ENUM_APPLIED_PRICE momentumAppliedTo = PRICE_CLOSE; // Applied To + +// +// SAR ... +input group "SAR"; +input double sarStep = 0.02; // Step +input double sarMaximum = 0.2; // Maximum + +// +// MACD ... +// The buffer numbers are the following: 0 - MAIN_LINE, 1 - SIGNAL_LINE. +input group "MACD"; +input int macdFastLength = 12; // Fast Length +input int macdSlowLength = 26; // Slow Length +input int macdSignaLength = 9; // Signal Length +input ENUM_APPLIED_PRICE macdAppliedTo = PRICE_CLOSE; // Applied To + +// +// STOCHASTIC ... +// The buffer numbers: 0 - MAIN_LINE, 1 - SIGNAL_LINE. +input group "Stochastic"; +input int stochKLength = 5; // K Length +input int stochDLength = 3; // D Length +input int stochSlowing = 3; // Slowing +input ENUM_MA_METHOD stochMaMethod = MODE_SMA; // Ma Method +input ENUM_STO_PRICE stochMode = STO_LOWHIGH; // Calculation Mode + +// +// END Inputs ... +// + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 15 +#property indicator_plots 0 + +// +// ATR ... +#define atrBufferIndex 0 +double atrBuffer[]; + +// +// RVI ... +#define rviMainBufferIndex 1 +#define rviSignalBufferIndex 2 +double rviMainBuffer[]; +double rviSignalBuffer[]; + +// +// BULLPOWER ... +#define bullPBufferIndex 3 +double bullPBuffer[]; + +// +// BEARPOWER ... +#define bearPBufferIndex 4 +double bearPBuffer[]; + +// +// VOLUME ... +#define volumeBufferIndex 5 +double volumeBuffer[]; + +// +// RSI ... +#define rsiBufferIndex 6 +double rsiBuffer[]; + +// +// CCI ... +#define cciBufferIndex 7 +double cciBuffer[]; + +// +// MOMENTUM ... +#define momentumBufferIndex 8 +double momentumBuffer[]; + +// +// SAR ... +#define sarBufferIndex 9 +double sarBuffer[]; + +// +// MACD ... +#define macdMainBufferIndex 10 +#define macdSignalBufferIndex 11 +double macdMainBuffer[]; +double macdSignalBuffer[]; + +// +// STOCHASTIC ... +#define stochMainBufferIndex 12 +#define stochSignalBufferIndex 13 +double stochMainBuffer[]; +double stochSignalBuffer[]; + +// +// STANDARDDEVIATION ... +#define stddevBufferIndex 14 +double stddevBuffer[]; + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +int atrHandler = INVALID_HANDLE; +int rviHandler = INVALID_HANDLE; +int bullPHandler = INVALID_HANDLE; +int bearPHandler = INVALID_HANDLE; +int volumeHandler = INVALID_HANDLE; +int rsiHandler = INVALID_HANDLE; +int cciHandler = INVALID_HANDLE; +int momentumHandler = INVALID_HANDLE; +int sarHandler = INVALID_HANDLE; +int macdHandler = INVALID_HANDLE; +int stochHandler = INVALID_HANDLE; +int stddevHandler = INVALID_HANDLE; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + 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(); + + // + // Initializing Handlers ... + + // + // ATR ... + atrHandler = iATR( + _Symbol, + _Period, + atrLength); + + // + // RVI ... + rviHandler = iRVI( + _Symbol, + _Period, + rviLength); + + // + // BULLSPOWER ... + bullPHandler = iBullsPower( + _Symbol, + _Period, + bullpLength); + + // + // BEARSPOWER ... + bearPHandler = iBearsPower( + _Symbol, + _Period, + bullpLength); + + // + // VOLUMES ... + volumeHandler = iVolumes( + _Symbol, + _Period, + volumeAppliedTo); + + // + // RSI ... + rsiHandler = iRSI( + _Symbol, + _Period, + rsiLength, + rsiAppliedTo); + + // + // CCI ... + cciHandler = iCCI( + _Symbol, + _Period, + cciLength, + cciAppliedTo); + + // + // MOMENTUM ... + momentumHandler = iMomentum( + _Symbol, + _Period, + momentumLength, + momentumAppliedTo); + + // + // SAR ... + sarHandler = iSAR( + _Symbol, + _Period, + sarStep, + sarMaximum); + + // + // MACD ... + macdHandler = iMACD( + _Symbol, + _Period, + macdFastLength, + macdSlowLength, + macdSignaLength, + macdAppliedTo); + + // + // STOCHASTIC ... + stochHandler = iStochastic( + _Symbol, + _Period, + stochKLength, + stochDLength, + stochSlowing, + stochMaMethod, + stochMode); + + // + // STANDARDDEVIATION ... + stddevHandler = iStdDev( + _Symbol, + _Period, + stddevLength, + stddevShift, + stddevMethod, + stddevAppliedTo); + + // + bool isAllHandlersInit = + // + atrHandler != INVALID_HANDLE && + rviHandler != INVALID_HANDLE && + bullPHandler != INVALID_HANDLE && + bearPHandler != INVALID_HANDLE && + volumeHandler != INVALID_HANDLE && + rsiHandler != INVALID_HANDLE && + cciHandler != INVALID_HANDLE && + momentumHandler != INVALID_HANDLE && + sarHandler != INVALID_HANDLE && + macdHandler != INVALID_HANDLE && + stochHandler != INVALID_HANDLE && + stddevHandler != INVALID_HANDLE + // + ; + if (!isAllHandlersInit) + { + return INIT_FAILED; + } + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 + + // + // Here we can handle De Initialization Reasons ... + IndicatorRelease(atrHandler); + IndicatorRelease(rviHandler); + IndicatorRelease(bullPHandler); + IndicatorRelease(bearPHandler); + IndicatorRelease(volumeHandler); + IndicatorRelease(rsiHandler); + IndicatorRelease(cciHandler); + IndicatorRelease(momentumHandler); + IndicatorRelease(sarHandler); + IndicatorRelease(macdHandler); + IndicatorRelease(stochHandler); + IndicatorRelease(stddevHandler); +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + 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); + + // + // this counts Available Bars ... + int limit; + + // + // Check Calculated Bars ... + int atrCalculatedBars = BarsCalculated(atrHandler); + int rviCalculatedBars = BarsCalculated(rviHandler); + int bullPCalculatedBars = BarsCalculated(bullPHandler); + int bearPCalculatedBars = BarsCalculated(bearPHandler); + int volumeCalculatedBars = BarsCalculated(volumeHandler); + int rsiCalculatedBars = BarsCalculated(rsiHandler); + int cciCalculatedBars = BarsCalculated(cciHandler); + int momentumCalculatedBars = BarsCalculated(momentumHandler); + int sarCalculatedBars = BarsCalculated(sarHandler); + int macdCalculatedBars = BarsCalculated(macdHandler); + int stochCalculatedBars = BarsCalculated(stochHandler); + int stddevCalculatedBars = BarsCalculated(stddevHandler); + + // + bool isCalculatedBarsPassed = + // + atrCalculatedBars >= maxLength && + rviCalculatedBars >= maxLength && + bullPCalculatedBars >= maxLength && + bearPCalculatedBars >= maxLength && + volumeCalculatedBars >= maxLength && + rsiCalculatedBars >= maxLength && + cciCalculatedBars >= maxLength && + momentumCalculatedBars >= maxLength && + sarCalculatedBars >= maxLength && + macdCalculatedBars >= maxLength && + stochCalculatedBars >= maxLength && + stddevCalculatedBars >= maxLength + // + ; + if (!isCalculatedBarsPassed) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + int atrCopiedItems = CopyBuffer(atrHandler, 0, 0, limit, atrBuffer); + int rviMainCopiedItems = CopyBuffer(rviHandler, MAIN_LINE, 0, limit, rviMainBuffer); + int rviSignalCopiedItems = CopyBuffer(rviHandler, SIGNAL_LINE, 0, limit, rviSignalBuffer); + int bullPCopiedItems = CopyBuffer(bullPHandler, 0, 0, limit, bullPBuffer); + int bearPCopiedItems = CopyBuffer(bearPHandler, 0, 0, limit, bearPBuffer); + int volumeCopiedItems = CopyBuffer(volumeHandler, 0, 0, limit, volumeBuffer); + int rsiCopiedItems = CopyBuffer(rsiHandler, 0, 0, limit, rsiBuffer); + int cciCopiedItems = CopyBuffer(cciHandler, 0, 0, limit, cciBuffer); + int momentumCopiedItems = CopyBuffer(momentumHandler, 0, 0, limit, momentumBuffer); + int sarCopiedItems = CopyBuffer(sarHandler, 0, 0, limit, sarBuffer); + int macdMainCopiedItems = CopyBuffer(macdHandler, MAIN_LINE, 0, limit, macdMainBuffer); + int macdSignalCopiedItems = CopyBuffer(macdHandler, SIGNAL_LINE, 0, limit, macdSignalBuffer); + int stochMainCopiedItems = CopyBuffer(stochHandler, MAIN_LINE, 0, limit, stochMainBuffer); + int stocSignalhCopiedItems = CopyBuffer(stochHandler, SIGNAL_LINE, 0, limit, stochSignalBuffer); + int stddevCopiedItems = CopyBuffer(stddevHandler, 0, 0, limit, stddevBuffer); + + // + bool isCopiedBarsPassed = + // + atrCopiedItems > 0 && + rviMainCopiedItems > 0 && + rviSignalCopiedItems > 0 && + bullPCopiedItems > 0 && + bearPCopiedItems > 0 && + volumeCopiedItems > 0 && + rsiCopiedItems > 0 && + cciCopiedItems > 0 && + momentumCopiedItems > 0 && + sarCopiedItems > 0 && + macdMainCopiedItems > 0 && + macdSignalCopiedItems > 0 && + stochMainCopiedItems > 0 && + stocSignalhCopiedItems > 0 && + stddevCopiedItems > 0 + // + ; + if (!isCopiedBarsPassed) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + // Do Buffers Calculation ... + // HERE We Do Not anything ... + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + // Validate Args ... + result = + // + atrLength >= 2 && + rviLength >= 2 && + bullpLength >= 2 && + bearpLength >= 2 && + rsiLength >= 2 && + cciLength >= 2 && + momentumLength >= 2 && + sarStep > 0 && + sarStep < sarMaximum && + macdFastLength >= 2 && + macdSlowLength > macdFastLength && + macdSignaLength >= 2 && + stochKLength >= 2 && + stochDLength >= 2 && + stochSlowing >= 2 && + stddevLength >= 2 && + stddevShift >= 0 + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(atrLength, rviLength); + result = MathMax(result, bullpLength); + result = MathMax(result, bearpLength); + result = MathMax(result, rsiLength); + result = MathMax(result, cciLength); + result = MathMax(result, momentumLength); + result = MathMax(result, macdFastLength); + result = MathMax(result, macdSlowLength); + result = MathMax(result, macdSignaLength); + result = MathMax(result, stochKLength); + result = MathMax(result, stochDLength); + result = MathMax(result, stochSlowing); + result = MathMax(result, stddevLength); + + // + return result; +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // DATA Buffers ... + + // + // ATR ... + ArraySetAsSeries(atrBuffer, true); + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + // RVI ... + + // + // Main ... + ArraySetAsSeries(rviMainBuffer, true); + SetIndexBuffer(rviMainBufferIndex, rviMainBuffer, INDICATOR_CALCULATIONS); + + // + // Signal ... + ArraySetAsSeries(rviSignalBuffer, true); + SetIndexBuffer(rviSignalBufferIndex, rviSignalBuffer, INDICATOR_CALCULATIONS); + + // + // BULLPOWER ... + ArraySetAsSeries(bullPBuffer, true); + SetIndexBuffer(bullPBufferIndex, bullPBuffer, INDICATOR_CALCULATIONS); + + // + // BEARPOWER ... + ArraySetAsSeries(bearPBuffer, true); + SetIndexBuffer(bearPBufferIndex, bearPBuffer, INDICATOR_CALCULATIONS); + + // + // VOLUME ... + ArraySetAsSeries(volumeBuffer, true); + SetIndexBuffer(volumeBufferIndex, volumeBuffer, INDICATOR_CALCULATIONS); + + // + // RSI ... + ArraySetAsSeries(rsiBuffer, true); + SetIndexBuffer(rsiBufferIndex, rsiBuffer, INDICATOR_CALCULATIONS); + + // + // CCI ... + ArraySetAsSeries(cciBuffer, true); + SetIndexBuffer(cciBufferIndex, cciBuffer, INDICATOR_CALCULATIONS); + + // + // MOMENTUM ... + ArraySetAsSeries(momentumBuffer, true); + SetIndexBuffer(momentumBufferIndex, momentumBuffer, INDICATOR_CALCULATIONS); + + // + // SAR ... + ArraySetAsSeries(sarBuffer, true); + SetIndexBuffer(sarBufferIndex, sarBuffer, INDICATOR_CALCULATIONS); + + // + // STANDARDDEVIATION ... + ArraySetAsSeries(stddevBuffer, true); + SetIndexBuffer(stddevBufferIndex, stddevBuffer, INDICATOR_CALCULATIONS); + + // + // MACD ... + + // + // Main ... + ArraySetAsSeries(macdMainBuffer, true); + SetIndexBuffer(macdMainBufferIndex, macdMainBuffer, INDICATOR_CALCULATIONS); + + // + // Signal ... + ArraySetAsSeries(macdSignalBuffer, true); + SetIndexBuffer(macdSignalBufferIndex, macdSignalBuffer, INDICATOR_CALCULATIONS); +} + +// +// END Functions ... +// diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xstr.ex5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xstr.ex5 new file mode 100644 index 0000000..eab2381 Binary files /dev/null and b/MQLTestWorkspace/Indicators/x-saherelm.x121.xstr.ex5 differ diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xstr.mq5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xstr.mq5 new file mode 100644 index 0000000..bca9597 --- /dev/null +++ b/MQLTestWorkspace/Indicators/x-saherelm.x121.xstr.mq5 @@ -0,0 +1,580 @@ +////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121_XSTR +// Description: Super Trend 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 X121_XAMA Indicator" +#property strict + +// +// START Constants ... +// + +#define ShortName "X121_XSTR" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +// Market ... +input group "ATR"; +input int atrLength = 14; // Length +input double atrMultiplier = 3.0; // Multiplier +input ENUM_APPLIED_PRICE atrAppliedTo = PRICE_MEDIAN; // Applied To + +// +// Presentation ... +input group "Presentation"; +input bool showTrends = true; // Show Trends +input bool fillTrends = true; // Fill Trends + +// +// END Inputs ... +// + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 9 +#property indicator_plots 2 + +// +#define fillUpBufferIndex 0 +double fillUpBuffer[]; + +#define fillDownBufferIndex 1 +double fillDownBuffer[]; + +// +#define fillingPlotBufferIndex 0 + +// +#property indicator_label1 "X121_XSTR Filling" +#property indicator_type1 DRAW_FILLING +#property indicator_color1 clrBisque, clrPaleGreen + +// +#define mainBufferIndex 2 +#define mainPlotBufferIndex 1 +double mainBuffer[]; + +// +#define mainColorBufferIndex 3 +double mainColorBuffer[]; + +// +#property indicator_label2 "X121_XSTR" +#property indicator_type2 DRAW_COLOR_LINE +#property indicator_color2 CLR_NONE, clrGreen, clrDarkRed +#property indicator_style2 STYLE_DOT + +// +// DATA Buffers ... + +// +#define atrBufferIndex 4 +double atrBuffer[]; + +// +#define trendBufferIndex 5 +double trendBuffer[]; + +// +#define upBufferIndex 6 +double upBuffer[]; + +// +#define downBufferIndex 7 +double downBuffer[]; + +// +#define priceBufferIndex 8 +double priceBuffer[]; + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +int atrHandler = INVALID_HANDLE; + +// +int changeOfTrend; +int startBearishTrend; +int startBullishTrend; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + 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(); + + // + atrHandler = iATR( + _Symbol, + _Period, + atrLength); + if (atrHandler == INVALID_HANDLE) + { + return INIT_FAILED; + } + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 + + // + // Here we can handle De Initialization Reasons ... + IndicatorRelease(atrHandler); +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + const int &spread[]) +{ + // + int numOfRequiredAtrs; + if (prev_calculated > rates_total || prev_calculated < 0) + { + numOfRequiredAtrs = rates_total; + } + else + { + // + numOfRequiredAtrs = rates_total - prev_calculated; + if (prev_calculated > 0) + { + numOfRequiredAtrs++; + } + } + + // + // Checking for stop ... + if (IsStopped()) + { + return 0; + } + + // + // Check Number of items Copy or not ... + int copiedATRs = CopyBuffer(atrHandler, 0, 0, numOfRequiredAtrs, atrBuffer); + if (copiedATRs <= 0) + { + return 0; + } + + // + int limit; + + // + // checking for the limit start of calculation of an indicator ... + if (prev_calculated > rates_total || prev_calculated <= 0) + { + // + // starting index for calculation of all bars ... + limit = maxLength; + } + else + { + // + // starting number for calculation of new bars + limit = prev_calculated - 1; + } + + // + // Main Loop ... + for (int i = limit; i < rates_total && !IsStopped(); i++) + { + // + // Calculated Price ... + double price = getPrice( + atrAppliedTo, + open, + high, + low, + close, + i); + // price = (high[i] + low[i]) / 2; + priceBuffer[i] = price; + + // + double atr = atrBuffer[i]; + + // + // Up ... + upBuffer[i] = price + (atrMultiplier * atr); + + // + // Down ... + downBuffer[i] = price - (atrMultiplier * atr); + + // + if (close[i] > upBuffer[i - 1]) + { + // + trendBuffer[i] = 1; + if (trendBuffer[i - 1] == -1) + { + changeOfTrend = 1; + } + } + else if (close[i] < downBuffer[i - 1]) + { + // + trendBuffer[i] = -1; + if (trendBuffer[i - 1] == 1) + { + changeOfTrend = 1; + } + } + else if (trendBuffer[i - 1] == 1) + { + // + trendBuffer[i] = 1; + changeOfTrend = 0; + } + else if (trendBuffer[i - 1] == -1) + { + // + trendBuffer[i] = -1; + changeOfTrend = 0; + } + + // + // Down Trend Starting ... + if (trendBuffer[i] < 0 && trendBuffer[i - 1] > 0) + { + startBearishTrend = 1; + } + else + { + startBearishTrend = 0; + } + + // + // Up Trend Starting ... + if (trendBuffer[i] > 0 && trendBuffer[i - 1] < 0) + { + startBullishTrend = 1; + } + else + { + startBullishTrend = 0; + } + + // + if (trendBuffer[i] > 0 && downBuffer[i] < downBuffer[i - 1]) + { + downBuffer[i] = downBuffer[i - 1]; + } + + // + if (trendBuffer[i] < 0 && upBuffer[i] > upBuffer[i - 1]) + { + upBuffer[i] = upBuffer[i - 1]; + } + + // + if (startBearishTrend == 1) + { + upBuffer[i] = priceBuffer[i] + (atrMultiplier * atr); + } + + // + if (startBullishTrend == 1) + { + downBuffer[i] = priceBuffer[i] - (atrMultiplier * atr); + } + + // + // Draw the indicator ... + + // + double colorIDX = 0; + mainColorBuffer[i] = colorIDX; + + // + if (trendBuffer[i] == 1) + { + // + mainBuffer[i] = downBuffer[i]; + if (changeOfTrend == 1) + { + mainBuffer[i - 1] = mainBuffer[i - 2]; + changeOfTrend = 0; + } + + // + colorIDX = 1; + } + else if (trendBuffer[i] == -1) + { + // + mainBuffer[i] = upBuffer[i]; + if (changeOfTrend == 1) + { + // + mainBuffer[i - 1] = mainBuffer[i - 2]; + changeOfTrend = 0; + } + + // + colorIDX = 2; + } + + // + if (showTrends) + { + mainColorBuffer[i] = colorIDX; + } + + // + // Filling ... + if (fillTrends) + { + // + fillUpBuffer[i] = mainBuffer[i]; + fillDownBuffer[i] = close[i]; + } + else + { + // + fillUpBuffer[i] = EMPTY_VALUE; + fillDownBuffer[i] = EMPTY_VALUE; + } + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + // Validate Args ... + result = + // + atrLength >= 2 + // + ; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = atrLength; + + // + return result; +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // PLOT Buffers ... + + // + // FILLINGS ... + SetIndexBuffer(fillUpBufferIndex, fillUpBuffer, INDICATOR_DATA); + SetIndexBuffer(fillDownBufferIndex, fillDownBuffer, INDICATOR_DATA); + PlotIndexSetInteger(fillingPlotBufferIndex, PLOT_SHOW_DATA, false); + + // + // MAIN ... + SetIndexBuffer(mainBufferIndex, mainBuffer, INDICATOR_DATA); + PlotIndexSetInteger(mainPlotBufferIndex, PLOT_SHOW_DATA, showTrends); + SetIndexBuffer(mainColorBufferIndex, mainColorBuffer, INDICATOR_COLOR_INDEX); + + // + // DATA Buffers ... + + // + // ATR ... + SetIndexBuffer(atrBufferIndex, atrBuffer, INDICATOR_CALCULATIONS); + + // + // TREND ... + SetIndexBuffer(trendBufferIndex, trendBuffer, INDICATOR_CALCULATIONS); + + // + // UP ... + SetIndexBuffer(upBufferIndex, upBuffer, INDICATOR_CALCULATIONS); + + // + // DOWN ... + SetIndexBuffer(downBufferIndex, downBuffer, INDICATOR_CALCULATIONS); + + // + // PRICE ... + SetIndexBuffer(priceBufferIndex, priceBuffer, INDICATOR_CALCULATIONS); +} + +// +// END Functions ... +// + +// +// TEMPLATE Function ... + +template +double getPrice(ENUM_APPLIED_PRICE tprice, T &open[], T &high[], T &low[], T &close[], int i) +{ + switch (tprice) + { + case PRICE_CLOSE: + return (close[i]); + case PRICE_OPEN: + return (open[i]); + case PRICE_HIGH: + return (high[i]); + case PRICE_LOW: + return (low[i]); + case PRICE_MEDIAN: + return ((high[i] + low[i]) / 2.0); + case PRICE_TYPICAL: + return ((high[i] + low[i] + close[i]) / 3.0); + case PRICE_WEIGHTED: + return ((high[i] + low[i] + close[i] + close[i]) / 4.0); + } + return (0); +} diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xzg.ex5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xzg.ex5 new file mode 100644 index 0000000..015d297 Binary files /dev/null and b/MQLTestWorkspace/Indicators/x-saherelm.x121.xzg.ex5 differ diff --git a/MQLTestWorkspace/Indicators/x-saherelm.x121.xzg.mq5 b/MQLTestWorkspace/Indicators/x-saherelm.x121.xzg.mq5 new file mode 100644 index 0000000..d7cde07 --- /dev/null +++ b/MQLTestWorkspace/Indicators/x-saherelm.x121.xzg.mq5 @@ -0,0 +1,757 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121_XZG +// Description: Zogzag Implementation ... +// +// +// 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_XZG Indicator" +#property strict + +// +#define ShortName "X121_XZG" + +// +// DEFINITIONS ... +enum ENUM_X_ZG_SEARCH_MODE +{ + X_ZG_SEARCH_EXTREMUM = 0, // searching for the first extremum + X_ZG_SEARCH_PEAK = 1, // searching for the next ZigZag peak + X_ZG_SEARCH_VALE = -1 // searching for the next ZigZag vale +}; + +// +// How to Calculate Up and Down Price ... +enum ENUM_X_ZG_PRICE_MODE +{ + // + X_ZG_PRICE_HIGH_LOW_MODE = 1, + X_ZG_PRICE_OPEN_CLOSE_MODE = 2, +}; + +// +// INPUT ... + +// +input int depth = 12; // Depth +input int deviation = 5; // Deviation +input int backStep = 3; // Back Step +input ENUM_X_ZG_PRICE_MODE mode = X_ZG_PRICE_HIGH_LOW_MODE; // Mode + +// +// BUFFERS ... + +// +#property indicator_chart_window + +// +#property indicator_buffers 5 +#property indicator_plots 3 + +// +// ZigZag ... + +// +#define mainBufferIndex 0 +#define mainBufferPlotIndex 0 +double mainBuffer[]; + +// +#property indicator_label1 "X121_XZG Main" +#property indicator_type1 DRAW_SECTION +#property indicator_color1 clrYellow +#property indicator_width1 2 + +// +// Highs ... + +// +// ZigZag Pointer or Line Indicator ... +#define arrowBufferIndex 1 +#define arrowBufferPlotIndex 1 +double arrowBuffer[]; + +// +#define arrowColorBufferIndex 2 +double arrowColorBuffer[]; + +// +#property indicator_label2 "X121_XZG PV" +#property indicator_type2 DRAW_COLOR_ARROW +#property indicator_color2 clrAqua, clrMagenta +#property indicator_width2 1 + +// +#define highsBufferIndex 3 +double highsBuffer[]; + +// +// Lows ... + +// +#define lowsBufferIndex 4 +double lowsBuffer[]; + +// +// VARIABLES ... + +// +int mRecalc = 3; // Number of last extremes for recalculation + +// +// EVENT Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // logTag = ShortName; + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +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 +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + const int &spread[] // +) +{ + // + double mZGHigh[]; + double mZGLow[]; + if (mode == X_ZG_PRICE_OPEN_CLOSE_MODE) + { + // + ArrayCopy( + mZGHigh, + open + // + ); + + // + ArrayCopy( + mZGLow, + close + // + ); + } + else + { + // + ArrayCopy( + mZGHigh, + high + // + ); + + // + ArrayCopy( + mZGLow, + low + // + ); + } + + // + int zigZagResult = CalcukateZigZag( + prev_calculated, + rates_total, + mZGHigh, + mZGLow + // + ); + + // + if (zigZagResult != rates_total) + { + return zigZagResult; + } + + // + return rates_total; +} + +// +// CUSTOM Functions ... + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + depth > 0 && + deviation > 0 && + backStep > 0 + // + ; + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // Main ... + + // + SetIndexBuffer(mainBufferIndex, mainBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(mainBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(mainBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(mainBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Arrow ... + + // + SetIndexBuffer(arrowBufferIndex, arrowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_ARROW, 159); + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_ARROW_SHIFT, 0); + PlotIndexSetDouble(arrowBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Arrow Color ... + SetIndexBuffer(arrowColorBufferIndex, arrowColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Highs ... + SetIndexBuffer(highsBufferIndex, highsBuffer, INDICATOR_CALCULATIONS); + + // + // Lows ... + SetIndexBuffer(lowsBufferIndex, lowsBuffer, INDICATOR_CALCULATIONS); +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Calculating Zig Zag ... +int CalcukateZigZag( + const int prev_calculated, + const int rates_total, + double &high[], + double &low[] + // +) +{ + // + if (rates_total < 100) + { + return 0; + } + + // + // Define Variables ... + int i = 0; + + // + int start = 0; + int extreme_counter = 0; + int extreme_search = X_ZG_SEARCH_EXTREMUM; + int shift = 0; + int back = 0; + int last_high_pos = 0; + int last_low_pos = 0; + + // + double val = 0; + double res = 0; + double curlow = 0; + double curhigh = 0; + double last_high = 0; + double last_low = 0; + + // + double colorIDX = 0; + double lastZigZagValue = 0; + + // + // Initializing ... + if (prev_calculated == 0) + { + // + ArrayInitialize(mainBuffer, 0); + ArrayInitialize(highsBuffer, 0); + ArrayInitialize(lowsBuffer, 0); + + // + start = depth; + } + + // + // Already Calculated Before ... + if (prev_calculated > 0) + { + // + i = rates_total - 1; + + // + // Searching for the third X_ZG_SEARCH_EXTREMUM from the last UnComplete Bar ... + while (extreme_counter < mRecalc && i > rates_total - 100) + { + // + res = mainBuffer[i]; + if (res != 0) + { + extreme_counter++; + } + + // + i--; + } + + // + i++; + start = i; + + // + // What type of X_ZG_SEARCH_EXTREMUM we Search for ... + if (lowsBuffer[i] != 0) + { + // + curlow = lowsBuffer[i]; + extreme_search = X_ZG_SEARCH_PEAK; + } + else + { + // + curhigh = highsBuffer[i]; + extreme_search = X_ZG_SEARCH_VALE; + } + + // + // Clear Values ... + for (i = start + 1; i < rates_total && !IsStopped(); i++) + { + // + mainBuffer[i] = 0; + lowsBuffer[i] = 0; + highsBuffer[i] = 0; + } + } + + // + // Search for High and Low Extremes ... + for (shift = start; shift < rates_total && !IsStopped(); shift++) + { + // + // Low ... + val = low[Lowest(low, depth, shift)]; + if (val == last_low) + { + val = 0; + } + else + { + // + last_low = val; + + // + if ((low[shift] - val) > deviation * _Point) + { + val = 0; + } + else + { + // + for (back = 1; back <= backStep; back++) + { + // + res = lowsBuffer[shift - back]; + if ((res != 0) && (res > val)) + { + lowsBuffer[shift - back] = 0; + } + } + } + } + + // + if (low[shift] == val) + { + lowsBuffer[shift] = val; + } + else + { + lowsBuffer[shift] = 0; + } + + // + // High ... + val = high[Highest(high, depth, shift)]; + if (val == last_high) + { + val = 0; + } + else + { + // + last_high = val; + + // + if ((val - high[shift]) > deviation * _Point) + { + val = 0; + } + else + { + // + for (back = 1; back <= backStep; back++) + { + // + res = highsBuffer[shift - back]; + if ((res != 0) && (res < val)) + { + highsBuffer[shift - back] = 0; + } + } + } + } + + // + if (high[shift] == val) + { + highsBuffer[shift] = val; + } + else + { + highsBuffer[shift] = 0; + } + } + + // + // Set Last Value ... + if (extreme_search == 0) // Undefined Values ... + { + // + last_low = 0; + last_high = 0; + } + else + { + // + last_low = curlow; + last_high = curhigh; + } + + // + // Final Selection of Extreme Points for ZigZag ... + for (shift = start; shift < rates_total && !IsStopped(); shift++) + { + // + res = 0; + + // + switch (extreme_search) + { + // + case X_ZG_SEARCH_EXTREMUM: + // + if (last_low == 0 && last_high == 0) + { + // + if (highsBuffer[shift] != 0) + { + // + last_high_pos = shift; + last_high = high[shift]; + + // + extreme_search = X_ZG_SEARCH_VALE; + + // + mainBuffer[shift] = last_high; + + // + res = 1; + } + + // + if (lowsBuffer[shift] != 0) + { + // + last_low_pos = shift; + last_low = low[shift]; + + // + extreme_search = X_ZG_SEARCH_PEAK; + + // + mainBuffer[shift] = last_low; + + // + res = 1; + } + } + break; + + // + case X_ZG_SEARCH_PEAK: + // + if (lowsBuffer[shift] != 0 && lowsBuffer[shift] < last_low && highsBuffer[shift] == 0) + { + // + mainBuffer[last_low_pos] = 0; + + // + last_low_pos = shift; + last_low = lowsBuffer[shift]; + + // + mainBuffer[shift] = last_low; + + // + res = 1; + } + + // + if (highsBuffer[shift] != 0 && lowsBuffer[shift] == 0) + { + // + last_high_pos = shift; + last_high = highsBuffer[shift]; + + // + mainBuffer[shift] = last_high; + + // + extreme_search = X_ZG_SEARCH_VALE; + + // + res = 1; + } + break; + + // + case X_ZG_SEARCH_VALE: + // + if (highsBuffer[shift] != 0 && highsBuffer[shift] > last_high && lowsBuffer[shift] == 0) + { + // + mainBuffer[last_high_pos] = 0; + + // + last_high_pos = shift; + last_high = highsBuffer[shift]; + + // + mainBuffer[shift] = last_high; + } + + // + if (lowsBuffer[shift] != 0 && highsBuffer[shift] == 0) + { + // + last_low_pos = shift; + last_low = lowsBuffer[shift]; + + // + mainBuffer[shift] = last_low; + + // + extreme_search = X_ZG_SEARCH_PEAK; + } + break; + } + + // + double iZigZagForColor = lastZigZagValue; + double iZigZag = mainBuffer[shift]; + if (iZigZag == 0 && lastZigZagValue != 0) + { + arrowBuffer[shift] = lastZigZagValue; + } + else if (iZigZag != 0) + { + // + lastZigZagValue = iZigZag; + arrowBuffer[shift] = lastZigZagValue; + } + + // + colorIDX = + lastZigZagValue > iZigZagForColor + ? 0 + : lastZigZagValue < iZigZagForColor + ? 1 + : colorIDX; + arrowColorBuffer[shift] = colorIDX; + } + + // + return rates_total; +} + +// +// TOOLS ... + +// +// Search for the index of the highest bar ... +int Highest( + const double &mArray[], + const int mDepth, + const int mStart // +) +{ + // + int result = 0; + + // + if (mStart < 0) + { + return result; + } + + // + double max = mArray[mStart]; + result = mStart; + + // + // Start searching ... + for (int i = mStart - 1; i > mStart - mDepth && i >= 0; i--) + { + // + if (mArray[i] > max) + { + // + result = i; + max = mArray[i]; + } + } + + // + // Return index of the highest bar + return result; +} + +// +// Search for the index of the lowest bar ... +int Lowest( + const double &mArray[], + const int mDepth, + const int mStart // +) +{ + // + int result = 0; + + // + if (mStart < 0) + { + return result; + } + + // + double min = mArray[mStart]; + result = mStart; + + // + // Start searching ... + for (int i = mStart - 1; i > mStart - mDepth && i >= 0; i--) + { + // + if (mArray[i] < min) + { + // + result = i; + min = mArray[i]; + } + } + + // + // Return index of the lowest bar + return result; +} diff --git a/MQLTestWorkspace/Libraries/x-saherelm.alert.lib.ex5 b/MQLTestWorkspace/Libraries/x-saherelm.alert.lib.ex5 index 0c761ae..daa322c 100644 Binary files a/MQLTestWorkspace/Libraries/x-saherelm.alert.lib.ex5 and b/MQLTestWorkspace/Libraries/x-saherelm.alert.lib.ex5 differ diff --git a/MQLTestWorkspace/Libraries/x-saherelm.common.lib.ex5 b/MQLTestWorkspace/Libraries/x-saherelm.common.lib.ex5 index b41cad3..7535376 100644 Binary files a/MQLTestWorkspace/Libraries/x-saherelm.common.lib.ex5 and b/MQLTestWorkspace/Libraries/x-saherelm.common.lib.ex5 differ diff --git a/MQLTestWorkspace/Libraries/x-saherelm.common.lib.mq5 b/MQLTestWorkspace/Libraries/x-saherelm.common.lib.mq5 index f9b09b3..96b33e6 100644 --- a/MQLTestWorkspace/Libraries/x-saherelm.common.lib.mq5 +++ b/MQLTestWorkspace/Libraries/x-saherelm.common.lib.mq5 @@ -2,7 +2,7 @@ // // SaherElm IT Center MQL5 Common Library // -------------------------------------- -// Name: XCommon +// Name: XCommonLib // Description: provide all commonly used functions ... // // @@ -20,314 +20,2299 @@ #property strict // -// START Inputs ... -// +// Imports ... // -// END Inputs ... -// +// Models ... // -// Include Models Library ... -#include "x-saherelm.models.lib.mq5" +// Specified Price Type ... +enum ENUM_X_PRICE +{ + X_PRICE_HIGH, + X_PRICE_OPEN, + X_PRICE_CLOSE, + X_PRICE_LOW +}; // -// START Global Definitions: Variables, Properties and etc ... -// -// -// END Global Definitions: Variables, Properties and etc ... -// +// Swing Types Enum ... +enum ENUM_X_SWING_TYPE +{ + X_NO_SWING = 0, + X_SWING_HIGH = 1, + X_SWING_LOW = -1, +}; // -// START Provided Functions ... -// - -// -// Detect is new Candle or not ... -bool IsNewCandle() +// XPERIOD Calculation Method ... +enum ENUM_X_PERIOD_METHOD { // - bool result = false; + X_PERIOD_NOTHING, // Nothing + X_PERIOD_AUTO, // Auto Select + X_PERIOD_MANUALLY // Manually +}; + +// +// Available Market Cycles ... +enum ENUM_X_MARKET_CYCLES +{ + // + X_MARKET_CYCLE_UNKNOWN, // Unknown Cycle + X_MARKET_CYCLE_SHORT, // Short Cycle + X_MARKET_CYCLE_MEDIUM, // Medium Cycle + X_MARKET_CYCLE_LONG, // Long Cycle + X_MARKET_CYCLE_HIND, // Hind Cycle +}; + +// +// Structs ... + +// +// Model a Bar Remains Time ... +struct XBarRemainsTime +{ + // + int days; + int hours; + int minutes; + int seconds; // - static int barsOnChart = 0; - int currentBarsOnChart = Bars(_Symbol, _Period); - result = currentBarsOnChart > barsOnChart; - if (!result) + // Constructor ... + XBarRemainsTime() { + Clean(); + } + + // + // Always Calculate Current 0 Bar Timing ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int minuteSecoonds = 60; + int hourSeconds = minuteSecoonds * 60; + int daySeconds = 24 * hourSeconds; + + // + int periodSeconds = PeriodSeconds( + mPeriod); + datetime startTime = GetBarTime( + mSymbol, + mPeriod, + 0 + // + ); + + // + int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent(); + + // + int mWorkingSecondsDiff = secondsDiff; + if (mWorkingSecondsDiff > daySeconds) + { + // + days = mWorkingSecondsDiff / daySeconds; + mWorkingSecondsDiff -= days * daySeconds; + } + if (mWorkingSecondsDiff > hourSeconds) + { + // + hours = mWorkingSecondsDiff / hourSeconds; + mWorkingSecondsDiff -= hours * hourSeconds; + } + if (mWorkingSecondsDiff > minuteSecoonds) + { + // + minutes = mWorkingSecondsDiff / minuteSecoonds; + mWorkingSecondsDiff -= minutes * minuteSecoonds; + } + seconds = mWorkingSecondsDiff; + + // + result = true; + + // return result; } // - barsOnChart = currentBarsOnChart; - result = true; + // Tools ... // - return result; -} -bool IsNewCandle( - string mSymbol, // Trading Symbol ... - ENUM_TIMEFRAMES mPeriod // Trading Time Frame ... -) -{ - // - bool result = false; + // Cleanup ... + void Clean() + { + days = 0; + hours = 0; + minutes = 0; + seconds = 0; + } // - static string mChartTags[]; - static int mChartBars[]; - - // - string chTag = mSymbol + "," + ToString(mPeriod); - - // - int currChTagIdx = -1; - int chCountedBars = 0; - int currentBars = Bars(mSymbol, mPeriod); - - // - if (ArraySize(mChartTags) > 0) + // To String Representation ... + string ToString( + string dayId = "d", + string hourId = "h", + string minuteId = "m", + string secondId = "s", + string idSeparator = ": ", + string separator = ", ", + bool ignoreZeroValues = true + // + ) { // - for (int i = 0; i < ArraySize(mChartTags); i++) + string result = ""; + + // + // Days ... + if (!ignoreZeroValues || days > 0) + { + result += dayId + idSeparator + (string)days + separator; + } + + // + // Hours ... + if (!ignoreZeroValues || hours > 0) { // - string iTag = mChartTags[i]; - if (iTag != chTag) + string strHour = ToString(hours); + if (StringLen(strHour) == 1) { - continue; + strHour = "0" + strHour; } // - currChTagIdx = i; + result += hourId + idSeparator + strHour + separator; + } + + // + // Minutes ... + if (!ignoreZeroValues || minutes > 0) + { + // + string strMinute = ToString(minutes); + if (StringLen(strMinute) == 1) + { + strMinute = "0" + strMinute; + } + + // + result += minuteId + idSeparator + strMinute + separator; + } + + // + // Seconds ... + if (!ignoreZeroValues || seconds > 0) + { + // + string strSec = ToString(seconds); + if (StringLen(strSec) == 1) + { + strSec = "0" + strSec; + } + + // + result += secondId + idSeparator + strSec; + } + + // + return result; + } +}; + +// +// Describe an Specific Candle ... +struct XOHCL +{ + // + // Props ... + + // + double high; + double open; + double close; + double low; + + // + string symbol; + datetime time; + ENUM_TIMEFRAMES period; + + // + // Constructor ... + XOHCL() + { + Clean(); + } + + // + // Init a Bar ... + // Using Bar Index ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + int barIndex = 0 // Bar Index + ) + { + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + symbol = mSymbol; + period = mPeriod; + + // + time = iTime( + mSymbol, + mPeriod, + barIndex + // + ); + + // + open = iOpen( + mSymbol, + mPeriod, + barIndex + // + ); + + // + close = iClose( + mSymbol, + mPeriod, + barIndex + // + ); + + // + high = iHigh( + mSymbol, + mPeriod, + barIndex); + + // + low = iLow( + mSymbol, + mPeriod, + barIndex + // + ); + + // + bool result = IsValid(); + + // + return result; + } + + // + // Init a Bar ... + // Using Bar Time ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + datetime mTime = NULL // Bar Time + ) + { + // + mTime = NormalizeTime(mTime); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false // + ); + + // + bool result = Init( + mSymbol, + mPeriod, + barIndex + // + ); + + // + return result; + } + + // + // Tools ... + + // + void Clean() + { + // + high = 0; + open = 0; + close = 0; + low = 0; + + // + time = NULL; + symbol = NULL; + period = NULL; + } + + // + // Validate Bar ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + high > 0 && + open > 0 && + close > 0 && + low > 0 + // + ; + + // + return result; + } + + // + // Calculate X_PRICE Specified Type ... + double GetPrice(ENUM_X_PRICE mPType) + { + // + double result = 0; + + // + if (mPType == NULL) + { + mPType = X_PRICE_CLOSE; + } + + // + if (!IsValid()) + { + return result; + } + + // + switch (mPType) + { + // + case X_PRICE_OPEN: + result = open; + break; + // + case X_PRICE_HIGH: + result = high; + break; + // + case X_PRICE_CLOSE: + result = close; + break; + // + case X_PRICE_LOW: + result = low; break; } // - if (currChTagIdx > -1) - { - chCountedBars = mChartBars[currChTagIdx]; - } + return result; } // - result = currentBars > chCountedBars; - if (result) + // Calculate Applied Price ... + double GetPrice( + ENUM_APPLIED_PRICE appliedTo // Select Application Method + ) { // - if (currChTagIdx > -1) + double result = 0; + + // + // Calculate Applied Price ... + switch (appliedTo) { // - mChartTags[currChTagIdx] = chTag; - mChartBars[currChTagIdx] = currentBars; + case PRICE_CLOSE: + result = close; + break; + + // + case PRICE_OPEN: + result = open; + break; + + // + case PRICE_HIGH: + result = high; + break; + + // + case PRICE_LOW: + result = low; + break; + + // + case PRICE_MEDIAN: + result = (high + low) / 2; + break; + + // + case PRICE_TYPICAL: + result = (high + low + close) / 3; + break; + + // + case PRICE_WEIGHTED: + result = (high + low + close + close) / 4; + break; } - else + + // + return result; + } + + // + // Calculate Bar Mid Line ... + double GetMid() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = (high + low) / 2; + + // + return result; + } + + // + // Calculate up Price ... + double GetUp() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathMax(open, close); + + // + return result; + } + + // + // Calculate Down Price ... + double GetDown() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathMin(open, close); + + // + return result; + } + + // + // Calculate Bar Body ... + double GetBody() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetUp() - GetDown(); + + // + return result; + } + + // + // Calculate Bar Range ... + double GetRange() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = high - low; + + // + return result; + } + + // + // Calculate Bar Shadows ... + double GetShadows() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetRange() - GetBody(); + + // + return result; + } + + // + // Calculate Bar High Shadow ... + double GetHighShadow() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + high - GetUp() + // + ; + + // + return result; + } + + // + // Calculate Bar Low Shadow ... + double GetLowShadow() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + GetDown() - low; + // + ; + + // + return result; + } + + // + // Check Bar is Bullish ... + bool IsBullish() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = open < close; + + // + return result; + } + + // + // Check Bar is Bearish ... + bool IsBearish() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = open > close; + + // + return result; + } + + // + // Find Next Bar Time ... + datetime NextAt() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int prSeconds = PeriodSeconds(period); + + // + result = time + prSeconds; + + // + return result; + } + + // + // Find Prev Bar Time ... + datetime BeforeOn() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int prSeconds = PeriodSeconds(period); + + // + result = time - prSeconds; + + // + return result; + } + + // + // Find Current Bar Index on Chart ... + int Index() + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + result = iBarShift( + symbol, + period, + time + // + ); + + // + return result; + } + + // + // Check Bar has Strong Body or Not ... + bool HasStrongBody() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + double body = GetBody(); + double shadow = GetShadows(); + + // + result = body > shadow * 1.5; + + // + return result; + } + + // + // Determines Swings based On this Bar ... + // Calculates Based on atleast 3 Bars Prev ... + ENUM_X_SWING_TYPE GetSwingType() + { + // + ENUM_X_SWING_TYPE result = X_NO_SWING; + + // + // Find Current Index of Bar ... + int barIndex = Index(); + if (barIndex <= -1) + { + return result; + } + + // + // First we have to Retrieve atleast 3 Bars before this bar ... + XOHCL bars[]; + int barsCount = GetBars( + bars, + symbol, + period, + barIndex + 1, + 3 + // + ); + if (barsCount < 3) + { + return result; + } + + // + // Check Swing Start Candle has Strong Body ... + bool isStrongBodyCandle = bars[2].HasStrongBody(); + if (!isStrongBodyCandle) + { + return result; + } + + // + // Check Swing Low Conditions ... + bool isSwingLowOrderBlock = + bars[2].low < bars[1].low && + bars[1].low < bars[0].low && + bars[2].low < bars[0].low; + if (isSwingLowOrderBlock) + { + result = X_SWING_LOW; + } + + // + // Check Swing High Conditions ... + bool isSwingHighOrderBlock = + bars[2].high > bars[1].high && + bars[1].high > bars[0].high && + bars[2].high > bars[0].high; + if (isSwingHighOrderBlock) + { + result = X_SWING_HIGH; + } + + // + return result; + } + + // + // Find Swings (Highs nd Lows) ... + int FindSwing( + ENUM_X_SWING_TYPE swing, // Swing Based On Price mode ... + int mLength // Loopback ... + ) + { + // + int result = -1; + + // + if (!IsValid() || + !IsValid(swing)) + { + return result; + } + + // + int current = Index(); + int founded = FindNextSwing( + swing, + (mLength * 2) + 1, + current - mLength + // + ); + + // + while (founded != current) { // - Add(chTag, mChartTags); - Add(currentBars, mChartBars); + current = FindNextSwing( + swing, + mLength, + current + 1 + // + ); + + // + founded = FindNextSwing( + swing, + (mLength * 2) + 1, + current - mLength + // + ); } - } - // - return result; -} + // + result = current; -// -double XNZ(double check, double val = 0) -{ - if (check == EMPTY_VALUE || check == 0) - { - return val; - } - else - { - return check; - } -} - -// -// Retrive Ask Price ... -double GetAsk() -{ - return SymbolInfoDouble(_Symbol, SYMBOL_ASK); -} -double GetAsk( - string symbol // selected symbol for calculations -) -{ - // - double result = SymbolInfoDouble(symbol, SYMBOL_ASK); - - // - return result; -} - -// -// Retrieve Bid Price ... -double GetBid() -{ - return SymbolInfoDouble(_Symbol, SYMBOL_BID); -} -double GetBid( - string symbol // selected symbol for calculations -) -{ - // - double result = SymbolInfoDouble(symbol, SYMBOL_BID); - - // - return result; -} - -// -// Calculate and Retrieve Spread Price ... -double GetSpread() -{ - // - double ask = GetAsk(); - double bid = GetBid(); - double result = MathAbs(ask - bid); - - // - return result; -} -double GetSpread( - string symbol // selected symbol for calculations -) -{ - // - double ask = GetAsk(symbol); - double bid = GetBid(symbol); - double result = MathAbs(ask - bid); - - // - return result; -} - -// -// Get Points ... -double GetPoints() -{ - return _Point; -} -double GetPoints( - string symbol // selected symbol for calculations -) -{ - // - double result = SymbolInfoDouble(symbol, SYMBOL_POINT); - - // - return result; -} - -// -// Get Digits ... -int GetDigits() -{ - return _Digits; -} -int GetDigits( - string symbol // selected symbol for calculations -) -{ - // - int result = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); - - // - return result; -} - -// -// Get Signal Entry ... -double GetEntry( - ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... -) -{ - // - double result = 0; - - // - // Validate Arg ... - if (type == NULL) - { + // return result; } // - bool isLong = type == POSITION_TYPE_BUY; - result = isLong ? GetAsk() : GetBid(); - result = NormalizePrice(result); + // Find Next Swing ... + int FindNextSwing( + ENUM_X_SWING_TYPE swing, // Swing Based On Price mode ... + int from, // from Bar Index + int mLength // Loopback ... + ) + { + // + int result = -1; + + // + if (!IsValid() || + !IsValid(swing)) + { + return result; + } + + // + if (from < 0) + { + mLength += from; + from = 0; + } + + // + ENUM_SERIESMODE mode = swing == X_SWING_HIGH + ? MODE_HIGH + : MODE_LOW; + + // + result = swing == X_SWING_HIGH + ? iHighest( + symbol, + period, + mode, + mLength, + from) + : iLowest( + symbol, + period, + mode, + mLength, + from); + + // + return result; + } // - return result; -} -double GetEntry( - string symbol, // Specified Symbol - ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... -) + // Find Lowest Bar Index ... + int FindHighestIndex( + int mLength, // Loopback ... + ENUM_SERIESMODE mode // Calculation mode + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (mLength < 2) + { + mLength = 2; + } + + // + result = iHighest( + symbol, + period, + mode, + mLength, + Index()); + + // + return result; + } + + // + // Find Lowest ... + double FindHighest( + int mLength, // Loopback ... + ENUM_SERIESMODE mode // Calculation mode + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + int idx = FindHighestIndex( + mLength, + mode); + if (idx <= -1) + { + return result; + } + + // + ENUM_X_PRICE pMode = ToPrice(mode); + + // + XOHCL iH; + result = iH.Init( + symbol, + period, + idx + // + ); + if (!result) + { + return result; + } + + // + result = iH.GetPrice(pMode); + + // + return result; + } + + // + // Find Lowest Bar Index ... + int FindLowestIndex( + int mLength, // Loopback ... + ENUM_SERIESMODE mode // Calculation mode + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (mLength < 2) + { + mLength = 2; + } + + // + result = iLowest( + symbol, + period, + mode, + mLength, + Index()); + + // + return result; + } + + // + // Find Lowest ... + double FindLowest( + int mLength, // Loopback ... + ENUM_SERIESMODE mode // Calculation mode + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + int idx = FindLowestIndex( + mLength, + mode); + if (idx <= -1) + { + return result; + } + + // + ENUM_X_PRICE pMode = ToPrice(mode); + + // + XOHCL iL; + result = iL.Init( + symbol, + period, + idx + // + ); + if (!result) + { + return result; + } + + // + result = iL.GetPrice(pMode); + + // + return result; + } + + // + // Convert to String Representation ... + string ToString() + { + // + string result = ""; + + // + result = GetTypeName(this) + + "(O(" + ToString(open) + "),H(" + ToString(high) + "),C(" + ToString(close) + "),L(" + ToString(low) + "))"; + + // + return result; + } +}; + +// +// Model Support and Resistance +// for Specific Bar ... +struct XOHCLSupRes { // - double result = 0; + // Props ... // - bool isLong = type == POSITION_TYPE_BUY; - result = isLong ? GetAsk(symbol) : GetBid(symbol); - result = NormalizePrice(result, symbol); + /// Resistances ... + double res[]; + + // + // Supports ... + double sup[]; + + // + // Constructor ... + XOHCLSupRes() + { + Clean(); + } + + // + // Init ... + bool Init( + double price, // Price ... + const double &pivots[], // Provided Pivot Points ... + int count = 3, // Number of Requireds ... + double step = 0 // Distance between each item with it's Last Side ... + ) + { + // + bool result = false; + + // + Clean(); + + // + if (price <= 0) + { + return result; + } + + // + int pivotsCount = ArraySize(pivots); + if (pivotsCount <= 0) + { + return result; + } + + // + if (count <= 0 || + count > pivotsCount - 1) + { + return result; + } + + // + double lastR = 0; + double tmpR[]; + + // + double lastS = 0; + double tmpS[]; + + // + // Extract Supports ... + // which prices is under low of candle ... + // + // Extract Resistance ... + // which prices is over high of candle ... + for (int i = 0; i < pivotsCount; i++) + { + // + double iFlat = pivots[i]; + + // + if (iFlat > price) + { + // + bool canAdd = + step <= 0 + ? true + : lastR == 0 || MathAbs(iFlat - lastR) >= step; + if (canAdd) + { + // + Add( + iFlat, + tmpR); + + // + lastR = iFlat; + } + } + else if (iFlat < price) + { + // + bool canAdd = + step <= 0 + ? true + : lastS == 0 || MathAbs(iFlat - lastS) >= step; + if (canAdd) + { + // + Add( + iFlat, + tmpS); + + // + lastS = iFlat; + } + } + } + + // + // Sorting Founded Resistance and Supports ... + + // + // Since Resistance Levels must be Increasing ... + ArraySort(tmpR); + + // + // Since Support Levels must be Decreasing ... + ArraySort(tmpS); + ArrayReverse(tmpS); + + // + // Fill Resistance ... + int tmpRCount = ArraySize(tmpR); + if (tmpRCount > 0) + { + // + if (tmpRCount < count) + { + // + ArrayCopy( + res, + tmpR); + } + else + { + // + ArrayCopy( + res, + tmpR, + 0, + 0, + count); + } + } + + // + // Fill Supports ... + int tmpSCount = ArraySize(tmpS); + if (tmpSCount > 0) + { + // + if (tmpSCount < count) + { + // + ArrayCopy( + sup, + tmpS); + } + else + { + // + ArrayCopy( + sup, + tmpS, + 0, + 0, + count); + } + } + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + Clean(sup); + Clean(res); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + CountSupports() > 0 || + CountResistances() > 0 + // + ; + + // + return result; + } + + // + int CountSupports() + { + return ArraySize(sup); + } + + // + int CountResistances() + { + return ArraySize(res); + } +}; + +// +// Tracking Times ... +struct XTimeTracker +{ + // + // Props ... + int xMonth; + int xDayOfWeek; + int xForWeekDay; + int xDay; + int xHour; + + // + // Constructor ... + XTimeTracker() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + xDay = -1; + xHour = -1; + xMonth = -1; + xDayOfWeek = -1; + xForWeekDay = -1; + } + + // + // Detecting New Houre ... + bool IsNewHour() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.hour != xHour; + if (result) + { + xHour = timeStruct.hour; + } + + // + return result; + } + + // + // Detecting New Day ... + bool IsNewDay() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.day_of_year != xDay; + if (result) + { + xDay = timeStruct.day_of_year; + } + + // + return result; + } + + // + // Detecting New Week ... + bool IsNewWeek() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Week ... + // Since Week Starts From Monday in Forex World ... + // we Calculate Start of Week by 1-Monday ... + result = + xDayOfWeek == -1 && + xForWeekDay == -1 + ? true + : timeStruct.day_of_week == 1 && + timeStruct.day_of_year > xForWeekDay; + + // + xForWeekDay = timeStruct.day_of_year; + xDayOfWeek = timeStruct.day_of_week; + + // + return result; + } + + // + // Detecting End Of Week ... + bool IsWeekEnd() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check WeekEnd ... + // Since Week Starts From Monday in Forex World ... + // we Calculate End of Week by 5-Friday ... + result = + xDayOfWeek != -1 && + timeStruct.day_of_week == 5 && + timeStruct.hour == 23 && + timeStruct.min == 59 && + timeStruct.sec == 59; + + // + return result; + } + + // + // Detecting New Month ... + bool IsNewMonth() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.mon != xMonth; + if (result) + { + xMonth = timeStruct.mon; + } + + // + return result; + } +}; + +// +// Tracking Bars on Specified Environment ... +struct XBarTracker +{ + // + string symbol; // Tracking Symbol + ENUM_TIMEFRAMES period; // Tracking Time Frame + + // + int lastTrackedBar; // Last Tracked Bar ... + + // + // Constructor ... + XBarTracker() + { + Clean(); + } + + // + // Initializer ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + this.symbol = mSymbol; + this.period = mPeriod; + + // + this.lastTrackedBar = 0; + + // + result = true; + + // + return result; + } + + // + // Retrieve all Bars ... + int CountBars() + { + // + return Bars( + symbol, + period + // + ); + } + + // + // Check if it's New Bar ... + bool IsNewBar() + { + // + bool result = false; + + // + int currentBars = CountBars(); + + // + result = currentBars > lastTrackedBar; + if (result) + { + lastTrackedBar = currentBars; + } + + // + return result; + } + + // + // Tools ... + void Clean() + { + // + symbol = NormalizeSymbol(NULL); + period = NormalizePeriod(NULL); + } +}; + +// +// Track Value Changes ... +template +struct XValueTracker +{ + // + // Definitions ... + + // + // Model a Value Change ... + struct XValueChange + { + // + // Props ... + datetime at; // Change Time + T from; // Before Change Value + T to; // After Change Value + + // + // Constructor ... + XValueChange() + { + Clean(); + } + + // + // Cleanup ... + void Clean() + { + // + at = NULL; + from = NULL; + to = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = IsValid(at); + if (!result) + { + return result; + } + + // + result = NotEmpty(from) && + NotEmpty(to); + + // + return result; + } + }; + + // + // Props ... + XValueChange changes[]; // Hold Changes + + // + // Constructor ... + XValueTracker() + { + Clean(); + } + + // + // Track a Change Happens Or Not ... + bool Track( + const T &source[] // Data Source for Track Changes + ) + { + // + bool result = false; + + // + if (ArraySize(source) <= 1) + { + return result; + } + + // + datetime time = TimeCurrent(); + + // + double from = source[1]; + double to = source[0]; + + // + result = to != from; + if (result) + { + return result; + } + + // + XValueChange lastChange; + bool hasLastChange = + GetLastItem( + lastChange, + changes + // + ); + result = + !hasLastChange + ? true + : lastChange.at < time && + lastChange.to != to && + lastChange.from != from; + if (!result) + { + return result; + } + + // + lastChange.Clean(); + + // + lastChange.to = to; + lastChange.at = time; + lastChange.from = from; + + // + AddRef( + lastChange, + changes + // + ); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + Clean(changes); + } +}; + +// +// Model a Market Cycle ... +struct XMarketCycle +{ + // + // Props ... + + // + string prefix; // Prefix Trag ... + + // + string symbol; // Market Symbol ... + + // + ENUM_TIMEFRAMES period; // Period of Cycle ... + ENUM_X_PERIOD_METHOD method; // Period Selection Method ... + ENUM_X_MARKET_CYCLES cycle; // Cycles of MArket ... + + // + int length; // Number Of Candles per Current Time Frame ... + ENUM_TIMEFRAMES hostPeriod; // Current Time Frame ... + + // + datetime lastStart; // Last Candle Bar Time ... + + // + XBarTracker barTracker; // Bar Tracker ... + XBarRemainsTime remains; // Current Bar Remains Model ... + + // + // Constructor ... + XMarketCycle() + { + Clean(); + } + + // + // Init Cycle ... + bool Init( + string mSymbol, // Trading Symbol + ENUM_TIMEFRAMES mHostPeriod, // Host Period + ENUM_X_MARKET_CYCLES mCycle, // Init Cycle + string mPrefix = "" // Prefix + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mHostPeriod = NormalizePeriod(mHostPeriod); + + // + result = IsValid(mCycle); + if (!result) + { + return result; + } + + // + this.cycle = mCycle; + + // + // Set Automatically Prefix ... + if (StringLen(mPrefix) == 0) + { + this.prefix = ToString(cycle); + } + + // + result = IsValid( + method, + period // + ); + if (!result) + { + return result; + } + + // + this.symbol = mSymbol; + this.hostPeriod = mHostPeriod; + + // + // Find Cycle Period ... + if (method == X_PERIOD_AUTO) + { + // + // Select Period ... + this.period = GetCyclePeriod( + this.cycle, + this.hostPeriod); + } + + // + // Set Prefix if Provided ... + if (StringLen(mPrefix) > 0) + { + this.prefix = mPrefix; + } + + // + // Calculate Required Info ... + + // + // Length ... + this.length = PeriodSeconds(this.period) / PeriodSeconds(this.hostPeriod); + + // + // Update Additional Data ... + result = this.Update(0); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + length = 0; + lastStart = 0; + + // + cycle = NULL; + prefix = NULL; + symbol = NULL; + period = NULL; + method = NULL; + hostPeriod = NULL; + + // + remains.Clean(); + barTracker.Clean(); + } + + // + // Check Structure Valid ... + bool IsValid() + { + // + bool result = false; + + // + result = IsValid( + method, + period); + if (!result) + { + return result; + } + + // + result = + // + length > 0 && + symbol != NULL && + period != NULL && + method != NULL && + hostPeriod != NULL && + method != X_PERIOD_NOTHING + // + ; + + // + return result; + } + + // + // Update Market Cycle Additional Info ... + bool Update(int hostBarIndex) + { + // + bool result = false; + + // + result = this.IsValid(); + if (!result) + { + return result; + } + + // + // Init Remains ... + result = remains.Init( + this.symbol, + this.period); + if (!result) + { + return result; + } + + // + // Init Bar Tracker ... + result = barTracker.Init( + this.symbol, + this.period); + if (!result) + { + return result; + } + + // + return result; + } + + // + // Count Bars ... + int CountBars() + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = barTracker.CountBars(); + + // + return result; + } + + // + // Check New Bar ... + bool IsNewBar() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = barTracker.IsNewBar(); + + // + return result; + } + + // + // Retrieve Current Bar Index based on Host Period bar Index ... + int GetBarIndex(int barIndex) + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + if (barIndex < 0) + { + return result; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + // + result = totalBars - 1; + return result; + } + + // + datetime hostBarTime = iTime( + this.symbol, + this.hostPeriod, + barIndex + // + ); + + // + result = iBarShift( + this.symbol, + this.period, + hostBarTime + // + ); + + // + return result; + } + + // + // Retrieve Current Cycles Specific Bar ... + XOHCL GetBar(int barIndex) + { + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + barIndex = totalBars - 1; + } + + // + XOHCL result; + result.Init( + this.symbol, + this.period, + barIndex + // + ); + + // + return result; + } + + // + // Retrieve Bar Time ... + datetime GetBarTime(int barIndex) + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + if (barIndex < 0) + { + barIndex = 0; + } + + // + int totalBars = CountBars(); + if (barIndex >= totalBars) + { + barIndex = totalBars - 1; + } + + // + result = iTime( + this.symbol, + this.period, + barIndex + // + ); + + // + return result; + } + + // + // Create and String Representation for Unique Taging ... + string ToString() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = + GetTypeName(this) + "(" + + "PRFX(" + this.prefix + ")" + + "SMBL(" + this.symbol + ")" + + "CYC(" + ToString(this.cycle) + ")" + + "PRD(" + ToString(this.period) + ")" + + "PRDHST(" + ToString(this.hostPeriod) + ")" + + "MTH(" + EnumToString(this.method) + ")" + + ")"; + + // + return result; + } + + // + // Here we Produce a Summary brief of + // state of Cycle ... + string GenerateSummary() + { + // + string result = ""; + + // + bool hasPrefix = + StringLen(this.prefix) > 0 && + this.prefix != ToString(this.cycle); + result += (hasPrefix ? this.prefix + "[" : "") + + ToString(this.cycle) + + (hasPrefix ? "]" : "") + "\n"; + + // + result += " - PR: " + ToString(this.period) + "\n"; + + // + XOHCL cBar = GetBar(0); + + // + result += " - State: " + (cBar.IsBullish() ? "Bullish" : cBar.IsBearish() ? "Bearish" + : "Neutural"); + + // + return result; + } +}; + +// +// Functions ... + +// +// Validators ... + +// +// Validate an String has length and not NULL ... +bool IsValid(string value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + StringLen(value) > 0 + // + ; // return result; } // -// Get Signal Exit ... -double GetExit( - ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... -) +// Validate a Date ... +bool IsValid(datetime value) { // - double result = 0; + bool result = false; // - // Validate Arg ... - if (type == NULL) - { - return result; - } - - // - bool isLong = type == POSITION_TYPE_BUY; - result = isLong ? GetBid() : GetAsk(); - result = NormalizePrice(result); + result = NotEmpty(value) && value != NULL; // return result; } -double GetExit( - string symbol, // Specified Symbol - ENUM_POSITION_TYPE type // Get entry price for Which direction trade ... -) + +// +// Validate a Period Param ... +bool IsValid(ENUM_TIMEFRAMES value) { // - double result = 0; + bool result = false; // - // Validate Arg ... - if (type == NULL) - { - return result; - } - - // - bool isLong = type == POSITION_TYPE_BUY; - result = isLong ? GetBid(symbol) : GetAsk(symbol); - result = NormalizePrice(result, symbol); + result = + // + value != NULL + // + ; // return result; } +// +// Validate Specified Cycle ... +bool IsValid(ENUM_X_MARKET_CYCLES value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + value != X_MARKET_CYCLE_UNKNOWN + // + ; + + // + return result; +} + +// +// Validate Specific Period Mode ... +bool IsValid( + ENUM_X_PERIOD_METHOD mMethod, // Period Select Method + ENUM_TIMEFRAMES mPeriod // Selected Period +) +{ + // + bool result = false; + + // + result = + // + mMethod == X_PERIOD_NOTHING + ? false + : mMethod == X_PERIOD_MANUALLY + ? mPeriod != NULL + : mMethod == X_PERIOD_AUTO + ? true + : false + // + ; + + // + return result; +} + +// +// Validate Swing Mode ... +bool IsValid(ENUM_X_SWING_TYPE value) +{ + // + bool result = false; + + // + result = + // + value == X_SWING_HIGH || + value == X_SWING_LOW + // + ; + + // + return result; +} + +// +// As IS ... + // // Determine a Position type is Long or not ... bool IsLong(ENUM_POSITION_TYPE type) @@ -367,754 +2352,35 @@ bool IsShort(ENUM_ORDER_TYPE type) } // -// Get 1 Pip in Price Value ... -double GetPipPrice() -{ - // - double result = _Point; - if (_Digits == 3 || _Digits == 5) - { - result *= 10; - } - - // - return result; -} -double GetPipPrice( - string symbol // selected symbol for calculations -) -{ - // - double symbolPoint = GetPoints(symbol); - int symbolDigits = GetDigits(symbol); - - // - double result = symbolPoint; - if (symbolDigits == 3 || symbolDigits == 5) - { - result *= 10; - } - - // - return result; -} - -// -// Converts Pips To Price ... -double PipsToPrice( - int pips // pips amount -) -{ - // - int digits = GetDigits(); - double pipValue = GetPipPrice(); - double result = pips * pipValue; - - // - result = NormalizeDouble(result, digits); - - // - return result; -} -double PipsToPrice( - double pips // pips amount -) -{ - // - int digits = GetDigits(); - double pipValue = GetPipPrice(); - double result = pips * pipValue; - - // - result = NormalizeDouble(result, digits); - - // - return result; -} -double PipsToPrice( - string symbol, // selected symbol for calculation - int pips // pips amount -) -{ - // - int digits = GetDigits(symbol); - double pipValue = GetPipPrice(symbol); - double result = pips * pipValue; - - // - result = NormalizeDouble(result, digits); - - // - return result; -} -double PipsToPrice( - string symbol, // selected symbol for calculation - double pips // pips amount -) -{ - // - int digits = GetDigits(symbol); - double pipValue = GetPipPrice(symbol); - double result = pips * pipValue; - - // - result = NormalizeDouble(result, digits); - - // - return result; -} - -// -// Converts Price to Pips ... -double PriceToPips( - double price // the price amount which required to calculate -) -{ - // - int digits = GetDigits(); - double pipPrice = GetPipPrice(); - - // - double result = price / pipPrice; - - // - result = NormalizeDouble(result, digits); - - // - return result; -} -double PriceToPips( - string symbol, // Selected Symbol - double price // the price amount which required to calculate -) -{ - // - int digits = GetDigits(symbol); - double pipPrice = GetPipPrice(symbol); - - // - double result = price / pipPrice; - - // - result = NormalizeDouble(result, digits); - - // - return result; -} - -// -// Convert Price to Point ... -double PriceToPoint( - double price // the price amount which required to calculate -) -{ - return PriceToPoint(_Symbol, price); -} -double PriceToPoint( - string symbol, // Selected Symbol - double price // the price amount which required to calculate -) -{ - // - double result = 0; - - // - double point = GetPoints(symbol); - result = price / point; - - // - return result; -} - -// -// Converts Point to Price ... -double PointToPrice( - double points // Points Size -) -{ - return PointToPrice(_Symbol, points); -} -double PointToPrice( - string symbol, // Selected Symbol - double points // Points Size -) -{ - // - double result = 0; - - // - double point = GetPoints(symbol); - result = points * point; - - // - return result; -} - -// -// Get a Candle Body ... -double GetCandleBody( - XOHCL &candle // specified candle -) -{ - // - double result = MathAbs(candle.open - candle.close); - - // - return result; -} - -// -// Get a Candle Range ... -double GetCandleRange( - XOHCL &candle // specified candle -) -{ - // - double result = MathAbs(candle.high - candle.low); - - // - return result; -} - -// -// Get a Candle Shadow ... -double GetCandleShadow( - XOHCL &candle // specified candle -) -{ - // - double range = GetCandleRange(candle); - double body = GetCandleBody(candle); - - // - double result = MathAbs(range - body); - - // - return result; -} - -// -// Check a Candle is Base Candle for RTM or not ... -bool IsBaseCandle( - XOHCL &candle // specified candle -) -{ - // - double range = GetCandleRange(candle); - double body = GetCandleBody(candle); - - // - bool result = body > range; - - // - return result; -} - -// -// Retrieve Applied Price at Specific Candle ... -double GetAppliedPrice( - XOHCL &candle, // specified candle - ENUM_APPLIED_PRICE source = PRICE_CLOSE // specified Applied To -) -{ - // - double result = EMPTY_VALUE; - - // - switch (source) - { - // - // Open ... - case PRICE_OPEN: - result = candle.open; - break; - - // - // High ... - case PRICE_HIGH: - result = candle.high; - break; - - // - // Low ... - case PRICE_LOW: - result = candle.low; - break; - - // - // Median ((High + Low) / 2) ... - case PRICE_MEDIAN: - result = (candle.high + candle.low) / 2; - break; - - // - // Typical ((High + Low + Close)/3) ... - case PRICE_TYPICAL: - result = (candle.high + candle.low + candle.close) / 3; - break; - - // - // Weighted ((High + Low + Close + Close)/4) ... - case PRICE_WEIGHTED: - result = (candle.high + candle.low + (candle.close * 2)) / 4; - break; - - // - // Close ... - default: - case PRICE_CLOSE: - result = candle.close; - break; - } - - // - return result; -} -double GetAppliedPrice( - int bar_index, // specify candle index - ENUM_APPLIED_PRICE source = PRICE_CLOSE // specified Applied To -) -{ - // - double result = EMPTY_VALUE; - - // - XOHCL candle = GetCandle(bar_index); - result = GetAppliedPrice(candle, source); - - // - return result; -} -double GetAppliedPrice( - int bar_index, // specify candle index - ENUM_SERIESMODE mode // converts Series Mode to Applied Price ... -) -{ - // - double result = 0; - - // - ENUM_APPLIED_PRICE mAppliedTo = To(mode); - result = GetAppliedPrice( - bar_index, - mAppliedTo); - - // - return result; -} - -// -// Converts ... -ENUM_APPLIED_PRICE To( - ENUM_SERIESMODE mode // converts Series Mode to Applied Price ... -) -{ - // - ENUM_APPLIED_PRICE result = PRICE_CLOSE; - - // - switch (mode) - { - // - // High ... - case MODE_HIGH: - result = PRICE_HIGH; - break; - - // - // Open ... - case MODE_OPEN: - result = PRICE_OPEN; - break; - - // - // Low ... - case MODE_LOW: - result = PRICE_LOW; - break; - - // - // Close ... - // Default ... - case MODE_CLOSE: - default: - result = PRICE_CLOSE; - break; - } - - // - return result; -} - -// -// Retrieve a Candel Data ... -XOHCL GetCandle(int bar_index) -{ - // - XOHCL result = {}; - - // - double open = iOpen(_Symbol, _Period, bar_index); - double high = iHigh(_Symbol, _Period, bar_index); - double close = iClose(_Symbol, _Period, bar_index); - double low = iLow(_Symbol, _Period, bar_index); - - // - result.low = low; - result.open = open; - result.high = high; - result.close = close; - - // - return result; -} -XOHCL GetCandle( - ENUM_TIMEFRAMES mPeriod, // specify timeframe - int bar_index // specify candle index -) -{ - // - XOHCL result = {}; - - // - double open = iOpen(_Symbol, mPeriod, bar_index); - double high = iHigh(_Symbol, mPeriod, bar_index); - double close = iClose(_Symbol, mPeriod, bar_index); - double low = iLow(_Symbol, mPeriod, bar_index); - - // - result.low = low; - result.open = open; - result.high = high; - result.close = close; - - // - return result; -} -XOHCL GetCandle( - string symbol, // specify symbol - ENUM_TIMEFRAMES mPeriod, // specify timeframe - int bar_index // specify candle index -) -{ - // - XOHCL result = {}; - - // - double open = iOpen(symbol, mPeriod, bar_index); - double high = iHigh(symbol, mPeriod, bar_index); - double close = iClose(symbol, mPeriod, bar_index); - double low = iLow(symbol, mPeriod, bar_index); - - // - result.low = low; - result.open = open; - result.high = high; - result.close = close; - - // - return result; -} - -// -// Retrieve a candle index in current timeframe inside another timeframe ... -int GetCandleBarIndex( - int bar_index, // Specify Candle index in current timeframe - ENUM_TIMEFRAMES destPeriod // Specify destination timeframe -) -{ - // - int result = -1; - - // - datetime barTime = iTime(_Symbol, _Period, bar_index); - result = iBarShift(_Symbol, destPeriod, barTime); - - // - return result; -} - -// -// Retrieve a symbol candle index in source time frame inside dest timeframe ... -int GetCandleBarIndex( - int bar_index, // Specify Candle index in current timeframe - string symbol, // Specify desired Symbol - ENUM_TIMEFRAMES sourcePeriod, // Specify bar_index timeframe - ENUM_TIMEFRAMES destPeriod // Specify destination timeframe -) -{ - // - int result = -1; - - // - datetime barTime = iTime(symbol, sourcePeriod, bar_index); - result = iBarShift(symbol, destPeriod, barTime); - - // - return result; -} - -// -// Check a Candle is Bullish or not ... -bool IsBullishCandle( - XOHCL &candle // specified candle -) +// Check Expert Running in Testing Mode or not ... +bool IsRunningOnTestMode() { // bool result = false; // - result = candle.open < candle.close; - - // - return result; -} -bool IsBullishCandle( - int bar_index // candle index -) -{ - // - bool result = false; - - // - XOHCL candle = GetCandle(bar_index); - - // - result = IsBullishCandle(candle); - - // - return result; -} -bool IsBullishCandle( - string symbol, // specify symbol - ENUM_TIMEFRAMES mPeriod, // specify timeframe - int bar_index // candle index -) -{ - // - bool result = false; - - // - XOHCL candle = GetCandle( - symbol, - mPeriod, - bar_index); - - // - result = IsBullishCandle(candle); + // check programm mode ... + result = MQL5InfoInteger(MQL5_TESTING); // return result; } // -// Check a Candle is Bullish or not ... -bool IsBearishCandle( - XOHCL &candle // specified candle -) -{ - // - bool result = false; - - // - result = candle.open > candle.close; - - // - return result; -} -bool IsBearishCandle( - int bar_index // candle index -) -{ - // - bool result = false; - - // - XOHCL candle = GetCandle(bar_index); - - // - result = IsBearishCandle(candle); - - // - return result; -} -bool IsBearishCandle( - string symbol, // specify symbol - ENUM_TIMEFRAMES mPeriod, // specify timeframe - int bar_index // candle index -) -{ - // - bool result = false; - - // - XOHCL candle = GetCandle( - symbol, - mPeriod, - bar_index); - - // - result = IsBearishCandle(candle); - - // - return result; -} +// Normalizers ... // -// Check Candle Body Bigger Than it's Shadow ... -bool CandleHasStrongBody(XOHCL &candle) +// Check a Symbol provided or not ... +// if not use Default ... +string NormalizeSymbol(string value) { // - double bodySize = MathAbs(candle.open - candle.close); - double shadowSize = MathAbs(candle.high - candle.low) - bodySize; + string result = value; // - bool result = bodySize > (shadowSize * 1.5); - - // - return result; -} - -// -// Determines a cnadle is Swing High -// or Swing Low order block ... -ENUM_X_SWING_TYPE GetCandleSwing(int bar_index) -{ - // - ENUM_X_SWING_TYPE result = X_NO_SWING; - - // - // Reading Candle Models ... - XOHCL candles[3]; - candles[0] = GetCandle(bar_index + 1); - candles[1] = GetCandle(bar_index + 2); - candles[2] = GetCandle(bar_index + 3); - - // - // Check Swing Start Candle has Strong Body ... - bool isStrongBodyCandle = CandleHasStrongBody(candles[2]); - if (!isStrongBodyCandle) + if (!IsValid(result)) { - return result; - } - - // - // Check Swing Low Conditions ... - bool isSwingLowOrderBlock = - candles[2].low < candles[1].low && - candles[1].low < candles[0].low && - candles[2].low < candles[0].low; - if (isSwingLowOrderBlock) - { - result = X_SWING_LOW; - } - - // - // Check Swing High Conditions ... - bool isSwingHighOrderBlock = - candles[2].high > candles[1].high && - candles[1].high > candles[0].high && - candles[2].high > candles[0].high; - if (isSwingHighOrderBlock) - { - result = X_SWING_HIGH; - } - - // - return result; -} -ENUM_X_SWING_TYPE GetCandleSwing( - ENUM_TIMEFRAMES mPeriod, // specify timeframe - int bar_index // specify candle index -) -{ - // - ENUM_X_SWING_TYPE result = X_NO_SWING; - - // - // Reading Candle Models ... - XOHCL candles[3]; - candles[0] = GetCandle(mPeriod, bar_index + 1); - candles[1] = GetCandle(mPeriod, bar_index + 2); - candles[2] = GetCandle(mPeriod, bar_index + 3); - - // - // Check Swing Start Candle has Strong Body ... - bool isStrongBodyCandle = CandleHasStrongBody(candles[2]); - if (!isStrongBodyCandle) - { - return result; - } - - // - // Check Swing Low Conditions ... - bool isSwingLowOrderBlock = - candles[2].low < candles[1].low && - candles[1].low < candles[0].low && - candles[2].low < candles[0].low; - if (isSwingLowOrderBlock) - { - result = X_SWING_LOW; - } - - // - // Check Swing High Conditions ... - bool isSwingHighOrderBlock = - candles[2].high > candles[1].high && - candles[1].high > candles[0].high && - candles[2].high > candles[0].high; - if (isSwingHighOrderBlock) - { - result = X_SWING_HIGH; - } - - // - return result; -} -ENUM_X_SWING_TYPE GetCandleSwing( - string symbol, // specify symbol - ENUM_TIMEFRAMES mPeriod, // specify timeframe - int bar_index // specify candle index -) -{ - // - ENUM_X_SWING_TYPE result = X_NO_SWING; - - // - // Reading Candle Models ... - XOHCL candles[3]; - candles[0] = GetCandle(symbol, mPeriod, bar_index + 1); - candles[1] = GetCandle(symbol, mPeriod, bar_index + 2); - candles[2] = GetCandle(symbol, mPeriod, bar_index + 3); - - // - // Check Swing Start Candle has Strong Body ... - bool isStrongBodyCandle = CandleHasStrongBody(candles[2]); - if (!isStrongBodyCandle) - { - return result; - } - - // - // Check Swing Low Conditions ... - bool isSwingLowOrderBlock = - candles[2].low < candles[1].low && - candles[1].low < candles[0].low && - candles[2].low < candles[0].low; - if (isSwingLowOrderBlock) - { - result = X_SWING_LOW; - } - - // - // Check Swing High Conditions ... - bool isSwingHighOrderBlock = - candles[2].high > candles[1].high && - candles[1].high > candles[0].high && - candles[2].high > candles[0].high; - if (isSwingHighOrderBlock) - { - result = X_SWING_HIGH; + result = _Symbol; } // @@ -1122,462 +2388,17 @@ ENUM_X_SWING_TYPE GetCandleSwing( } // -// Find Swing Points ... -int FindSwing( - string mSymbol, // Trading Symbol ... - ENUM_TIMEFRAMES mPeriod, // Trading Period ... - ENUM_SERIESMODE mode, // Swing Based On Price mode ... - int mLength, // Loopback ... - int bar_index // BarIndex ... -) +// Check a Datetime provided or not ... +// if not use Current ... +datetime NormalizeTime(datetime value) { // - int result = -1; + datetime result = value; // - if (StringLen(mSymbol) == 0 || (mode != MODE_HIGH && mode != MODE_LOW)) + if (!IsValid(result)) { - return result; - } - - // - int current = bar_index; - int founded = FindNextSwing( - mSymbol, - mPeriod, - mode, - (mLength * 2) + 1, - current - mLength); - - // - while (founded != current) - { - // - current = FindNextSwing( - mSymbol, - mPeriod, - mode, - mLength, - current + 1); - - // - founded = FindNextSwing( - mSymbol, - mPeriod, - mode, - (mLength * 2) + 1, - current - mLength); - } - - // - result = current; - - // - return result; -} - -// -// Find Next Swing ... -int FindNextSwing( - string mSymbol, // Trading Symbol ... - ENUM_TIMEFRAMES mPeriod, // Trading Period ... - ENUM_SERIESMODE mode, // Swing Based On Price mode ... - int mLength, // Loopback ... - int bar_index // BarIndex ... -) -{ - // - int result = -1; - - // - if (bar_index < 0) - { - mLength += bar_index; - bar_index = 0; - } - - // - result = mode == MODE_HIGH - ? iHighest( - mSymbol, - mPeriod, - mode, - mLength, - bar_index) - : iLowest( - mSymbol, - mPeriod, - mode, - mLength, - bar_index); - - // - return result; -} - -// -// Retrieve Market Highest High ... -double GetHighestHigh( - int mLength, // Which market Length use - int bar_index // bar index -) -{ - // - double result = -1; - - // - int rIdx = iHighest( - _Symbol, - _Period, - MODE_HIGH, - mLength, - bar_index); - - // - result = iHigh( - _Symbol, - _Period, - rIdx); - - // - return result; -} -double GetHighestHigh( - int mLength, // Which market Length use - int bar_index, // bar index - ENUM_SERIESMODE mode // Calculation mode -) -{ - // - double result = -1; - - // - int rIdx = iHighest( - _Symbol, - _Period, - mode, - mLength, - bar_index); - - // - result = iHigh( - _Symbol, - _Period, - rIdx); - - // - return result; -} -double GetHighestHigh( - string symbol, // Specified Symbol - ENUM_TIMEFRAMES mPeriod, // Specified Period - int mLength, // Which market Length use - int bar_index // bar index -) -{ - // - double result = -1; - - // - int rIdx = iHighest( - symbol, - mPeriod, - MODE_HIGH, - mLength, - bar_index); - - // - result = iHigh( - symbol, - mPeriod, - rIdx); - - // - return result; -} -double GetHighestHigh( - string symbol, // Specified Symbol - ENUM_TIMEFRAMES mPeriod, // Specified Period - ENUM_SERIESMODE mode, // Calculation mode - int mLength, // Which market Length use - int bar_index // bar index -) -{ - // - double result = -1; - - // - int rIdx = iHighest( - symbol, - mPeriod, - mode, - mLength, - bar_index); - - // - result = iHigh( - symbol, - mPeriod, - rIdx); - - // - return result; -} - -// -// Retrieve Market Lowest Low ... -double GetLowestLow( - int mLength, // Which market Length use - int bar_index // bar index -) -{ - // - double result = -1; - - // - int rIdx = iLowest( - _Symbol, - _Period, - MODE_LOW, - mLength, - bar_index); - - // - result = iLow( - _Symbol, - _Period, - rIdx); - - // - return result; -} -double GetLowestLow( - int mLength, // Which market Length use - int bar_index, // bar index - ENUM_SERIESMODE mode // Calculation mode -) -{ - // - double result = -1; - - // - int rIdx = iLowest( - _Symbol, - _Period, - mode, - mLength, - bar_index); - - // - result = iLow( - _Symbol, - _Period, - rIdx); - - // - return result; -} -double GetLowestLow( - string symbol, // Specified Symbol - ENUM_TIMEFRAMES mPeriod, // Specified Period - int mLength, // Which market Length use - int bar_index // bar index -) -{ - // - double result = -1; - - // - int rIdx = iLowest( - symbol, - mPeriod, - MODE_LOW, - mLength, - bar_index); - - // - result = iLow( - symbol, - mPeriod, - rIdx); - - // - return result; -} -double GetLowestLow( - string symbol, // Specified Symbol - ENUM_TIMEFRAMES mPeriod, // Specified Period - ENUM_SERIESMODE mode, // Calculation mode - int mLength, // Which market Length use - int bar_index // bar index -) -{ - // - double result = -1; - - // - int rIdx = iLowest( - symbol, - mPeriod, - mode, - mLength, - bar_index); - - // - result = iLow( - symbol, - mPeriod, - rIdx); - - // - return result; -} - -// -// Find Support and Resistance for Specific Bar based on provided Buffer ... -XOHCLSupRes ExtractSupportAndResistance( - int barIndex, // Bar Index ... - const double &pivots[], // Provided Pivot Points ... - int count = 3, // Number of Requireds ... - string mSymbol = NULL, // Trading Symbol ... - ENUM_TIMEFRAMES mPeriod = NULL // Trading Period ... -) -{ - // - if (StringLen(mSymbol) == 0 || mSymbol == NULL) - { - mSymbol = _Symbol; - } - - // - if (mPeriod == NULL) - { - mPeriod = _Period; - } - - // - if (barIndex < 0) - { - barIndex = 0; - } - - // - XOHCLSupRes result; - Clean(result.res); - Clean(result.sup); - - // - int pivotsCount = ArraySize(pivots); - if (pivotsCount <= 0) - { - return result; - } - - // - if (count <= 0 || - count > pivotsCount - 1) - { - return result; - } - - // - XOHCL cBar = GetCandle( - mSymbol, - mPeriod, - barIndex); - - // - double tmpR[]; - - // - double tmpS[]; - - // - // Extract Supports ... - // which prices is under low of candle ... - // - // Extract Resistance ... - // which prices is over high of candle ... - for (int i = 0; i < pivotsCount; i++) - { - // - double iFlat = pivots[i]; - - // - if (iFlat > cBar.high) - { - Add( - iFlat, - tmpR); - } - else if (iFlat < cBar.low) - { - Add( - iFlat, - tmpS); - } - } - - // - // Sorting Founded Resistance and Supports ... - - // - // Since Resistance Levels must be Increasing ... - ArraySort(tmpR); - - // - // Since Support Levels must be Decreasing ... - ArraySort(tmpS); - ArrayReverse(tmpS); - - // - // Fill Resistance ... - int tmpRCount = ArraySize(tmpR); - if (tmpRCount > 0) - { - // - if (tmpRCount < count) - { - // - ArrayCopy( - result.res, - tmpR); - } - else - { - // - ArrayCopy( - result.res, - tmpR, - 0, - 0, - count); - } - } - - // - // Fill Supports ... - int tmpSCount = ArraySize(tmpS); - if (tmpSCount > 0) - { - // - if (tmpSCount < count) - { - // - ArrayCopy( - result.sup, - tmpS); - } - else - { - // - ArrayCopy( - result.sup, - tmpS, - 0, - 0, - count); - } + result = TimeCurrent(); } // @@ -1585,59 +2406,17 @@ XOHCLSupRes ExtractSupportAndResistance( } // -// Find a Value less than Specified ... -double FindLesserThanValue( - double value, // Specified Value ... - const double &source[], // Source ... - bool isDescend = false // Find Biggest Lesser Value ... -) +// Check a Period provided or not ... +// if not use Default ... +ENUM_TIMEFRAMES NormalizePeriod(ENUM_TIMEFRAMES value) { // - double result = -1; + ENUM_TIMEFRAMES result = value; // - int itemsCount = ArraySize(source); - if (itemsCount <= 0) + if (!IsValid(value)) { - return result; - } - - // - // Make a Copy of source ... - double tmp[]; - - // - ArrayResize( - tmp, - ArraySize(source)); - - // - ArrayCopy( - tmp, - source); - - // - // Sort Temp Buffer ... - ArraySort(tmp); - if (isDescend) - { - ArrayReverse(tmp); - } - - // - int tmpCount = ArraySize(tmp); - for (int i = 0; i < tmpCount; i++) - { - // - double iValue = tmp[i]; - - // - if (iValue < value) - { - // - result = iValue; - break; - } + result = _Period; } // @@ -1645,1476 +2424,41 @@ double FindLesserThanValue( } // -// Find a Value less than Specified ... -double FindBiggerThanValue( - double value, // Specified Value ... - const double &source[], // Source ... - bool isDescend = false // Find Smallest Bigger Value ... -) +// Normalize Cycle ... +ENUM_X_MARKET_CYCLES NormalizeCycle(ENUM_X_MARKET_CYCLES value) { // - double result = -1; + ENUM_X_MARKET_CYCLES result = value; // - int itemsCount = ArraySize(source); - if (itemsCount <= 0) + if (!IsValid(result)) { - return result; + result = X_MARKET_CYCLE_SHORT; } // - // Make a Copy of source ... - double tmp[]; - - // - ArrayResize( - tmp, - ArraySize(source)); - - // - ArrayCopy( - tmp, - source); - - // - // Sort Temp Buffer ... - ArraySort(tmp); - if (!isDescend) - { - ArrayReverse(tmp); - } - - // - int tmpCount = ArraySize(tmp); - for (int i = 0; i < tmpCount; i++) - { - // - double iValue = tmp[i]; - - // - if (iValue > value) - { - // - result = iValue; - break; - } - } - - // - return result; -} - -// -// Calculate Fib Level ... -double GetFibonacciLevel( - double upPrice, - double downPrice, - double level, - int direction) -{ - // - double ling = upPrice - downPrice; - double pLevel = (ling / 100) * (level * 100); - - // - double result = direction > 0 ? upPrice - pLevel : downPrice + pLevel; - result = NormalizeDouble(result, _Digits); - - // - return result; -} - -// -// Check first Cross Over second at bar_index ... -bool IsCrossOver( - const double &first[], // the buffer which check crossing over second buffer - const double &second[], // first buffer checks based on this buffer - const int bar_index // check crosses in specific index -) -{ - // - bool result = false; - - // - ArraySetAsSeries(first, true); - ArraySetAsSeries(second, true); - - // - // Validate Args ... - if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) - { - return result; - } - - // - result = first[bar_index] > second[bar_index] && - !(first[bar_index + 1] > second[bar_index + 1]); - - // - return result; -} - -// -// Check first is Over second at bar_index ... -bool IsOver( - const double &first[], // the buffer which check over second buffer - const double &second[], // first buffer checks based on this buffer - const int bar_index // check crosses in specific index -) -{ - // - bool result = false; - - // - ArraySetAsSeries(first, true); - ArraySetAsSeries(second, true); - - // - // Validate Args ... - if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) - { - return result; - } - - // - result = first[bar_index] > second[bar_index] && - first[bar_index + 1] > second[bar_index + 1]; - - // - return result; -} - -// -// Check first Cross Under second at bar_index ... -bool IsCrossUnder( - const double &first[], // the buffer which check crossing under second buffer - const double &second[], // first buffer checks based on this buffer - const int bar_index // check crosses in specific index -) -{ - // - bool result = false; - - // - ArraySetAsSeries(first, true); - ArraySetAsSeries(second, true); - - // - // Validate Args ... - if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) - { - return result; - } - - // - result = first[bar_index] < second[bar_index] && - !(first[bar_index + 1] < second[bar_index + 1]); - - // - return result; -} - -// -// Check first is Under second at bar_index ... -bool IsUnder( - const double &first[], // the buffer which check under second buffer - const double &second[], // first buffer checks based on this buffer - const int bar_index // check crosses in specific index -) -{ - // - bool result = false; - - // - ArraySetAsSeries(first, true); - ArraySetAsSeries(second, true); - - // - // Validate Args ... - if (ArraySize(first) < bar_index + 1 || ArraySize(second) < bar_index + 1) - { - return result; - } - - // - result = first[bar_index] < second[bar_index] && - first[bar_index + 1] < second[bar_index + 1]; - - // - return result; -} - -// -// Calculate Slope of Specified Buffer at Specified Index ... -double GetSlope( - int from, // In Past Index ... - int to, // In Past Index ... - double &buffer[]) -{ - // - double result = 0; - - // - double toValue = buffer[to]; - double fromValue = buffer[from]; - double deltaValue = toValue - fromValue; - double deltaTime = from - to; - - // - result = deltaValue / deltaTime; - - // - return result; -} - -// -// Check if a Value Increasing in Loopback ... -bool IsIncreasing( - int from, // Last Time Index - int to, // Fisr Tima Index - double &buffer[] // the Buffer which required to search -) -{ - // - bool result = false; - - // - // Validate Args ... - if ( - from <= to || - ArraySize(buffer) < from + 1) - { - return result; - } - - // - // Loop through Items ... - double toValue = buffer[to]; - double fromValue = buffer[from]; - result = toValue > fromValue; - for (int i = to + 1; i <= from - 1; i++) - { - // - double iValue = buffer[i]; - bool isPassed = toValue >= iValue; - - // - bool isIIncreasing = IsIncreasing( - from, - i, - buffer); - - // - // Check Result ... - result = result && isPassed && isIIncreasing; - if (!result) - { - break; - } - } - - // - return result; -} - -// -// Check if a Value Decreasing in Loopback ... -bool IsDecreasing( - int from, // Last Time Index - int to, // Fisr Tima Index - double &buffer[] // the Buffer which required to search -) -{ - // - bool result = false; - - // - // Validate Args ... - if ( - from <= to || - ArraySize(buffer) < from + 1) - { - return result; - } - - // - // Loop through Items ... - double toValue = buffer[to]; - double fromValue = buffer[from]; - result = toValue < fromValue; - for (int i = to + 1; i <= from - 1; i++) - { - // - double iValue = buffer[i]; - bool isPassed = toValue <= iValue; - - // - bool isIDecreasing = IsDecreasing( - from, - i, - buffer); - - // - // Check Result ... - result = result && isPassed && isIDecreasing; - if (!result) - { - break; - } - } - - // - return result; -} - -// -// Get Max Value of Specific Loopback of a Buffer ... -double GetMaxValue( - int mLoopback, // loopback length - double &buffer[] // the Buffer which required to search -) -{ - // - double result = 0; - - // - // Validate Args ... - if ( - mLoopback < 2 || - ArraySize(buffer) < mLoopback) - { - return result; - } - - // - // Loop Through LoopBack ... - for (int i = 0; i < mLoopback; i++) - { - // - double iValue = buffer[i]; - - // - result = - // - result == 0 || result < iValue - // - ? iValue - // - : result - // - ; - } - - // - return result; -} - -// -// Get Min Value of Specific Loopback of a Buffer ... -double GetMinValue( - int mLoopback, // loopback length - double &buffer[] // the Buffer which required to search -) -{ - // - double result = 0; - - // - // Validate Args ... - if ( - mLoopback < 2 || - ArraySize(buffer) < mLoopback) - { - return result; - } - - // - // Loop Through LoopBack ... - for (int i = 0; i < mLoopback; i++) - { - // - double iValue = buffer[i]; - - // - result = - // - result == 0 || result > iValue - // - ? iValue - // - : result - // - ; - } - - // - return result; -} - -// -// Find Same Values in Array ... -void FindSameValueInBuffer( - double &result[], // Holds Result ... - double &source[], // Source ... - int verifications = 3 // Number of Consequence Repeat ... -) -{ - // - Clean(result); - - // - // TenkanSen Flats ... - int sourceCount = ArraySize(source); - if (sourceCount > verifications) - { - // - double mLast = 0; - int mVerified = 0; - for (int i = 0; i < sourceCount; i++) - { - // - double iVal = source[i]; - if (mLast == 0) - { - mLast = iVal; - } - else if (mLast == iVal) - { - mVerified++; - } - else - { - mLast = iVal; - mVerified = 0; - } - - // - if (iVal == mLast && mVerified >= verifications) - { - // - Add( - iVal, - result); - - // - mLast = 0; - mVerified = 0; - } - } - } -} - -// -bool IsInPeak( - int mLoopback, // loopback length - double &buffer[] // the Buffer which required to search -) -{ - // - bool result = false; - - // - // Validate Args ... - if ( - mLoopback < 2 || - ArraySize(buffer) < mLoopback + 1) - { - return result; - } - - // - int q1Length = mLoopback / 4; - int halfLength = mLoopback / 2; - int q2Length = halfLength + q1Length; - - // - double firstValue = buffer[1]; - double q1Value = buffer[q1Length]; - double q2Value = buffer[q2Length]; - double halfValue = buffer[halfLength]; - double lastValue = buffer[ArraySize(buffer) - 1]; - - // - // Peak ... - result = - // - firstValue > lastValue - // - && - // - ( - firstValue > q1Value && - firstValue > halfValue) - // - ; - - // - return result; -} - -// -bool IsInVale( - int mLoopback, // loopback length - double &buffer[] // the Buffer which required to search -) -{ - // - bool result = false; - - // - // Validate Args ... - if ( - mLoopback < 2 || - ArraySize(buffer) < mLoopback + 1) - { - return result; - } - - // - int q1Length = mLoopback / 4; - int halfLength = mLoopback / 2; - int q2Length = halfLength + q1Length; - - // - double firstValue = buffer[1]; - double q1Value = buffer[q1Length]; - double q2Value = buffer[q2Length]; - double halfValue = buffer[halfLength]; - double lastValue = buffer[ArraySize(buffer) - 1]; - - // - // Peak ... - result = - // - firstValue < lastValue - // - && - // - ( - firstValue < q1Value && - firstValue < halfValue) - // - ; - - // - return result; -} - -// -// Check Sharp Happens or not ... -bool IsSharpChanged( - double fromValue, // Past Value - double toValue, // Present Value - double maxValue, // Max in Range Value - double minValue // Min in Range Value -) -{ - // - bool result = false; - - // - // This Used In Increased or Decreased Sharp Detection ... - bool isIncreased = toValue > fromValue; - - // - double toFromDelta = MathAbs(toValue - fromValue); - double minMaxDelta = maxValue - minValue; - - // - result = toFromDelta >= (minMaxDelta / 3); - - // - return result; -} -bool IsSharpChanged( - int from, // Past Index in Series - int to, // Present Index in Series - double &buffer[] // the Buffer which required to search -) -{ - // - bool result = false; - - // - // Validate Args ... - if ( - from <= to || - ArraySize(buffer) < from + 1) - { - return result; - } - - // - // Loop through Items ... - double toValue = buffer[to]; - double fromValue = buffer[from]; - - // - // This Used In Increased or Decreased Sharp Detection ... - bool isIncreased = toValue > fromValue; - - // - double minValue = GetMinValue( - ArraySize(buffer) - 1, - buffer); - double maxValue = GetMaxValue( - ArraySize(buffer) - 1, - buffer); - double minMaxDelta = maxValue - minValue; - - // - // Sharp Detection ... - result = IsSharpChanged( - fromValue, - toValue, - maxValue, - minValue); - - // - return result; -} -bool IsSharpChanged( - int from, // Past Bar Index - int to, // Present Bar Index - ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To -) -{ - // - bool result = false; - - // - double toValue = GetAppliedPrice( - to, - appliedPrice); - double fromValue = GetAppliedPrice( - from, - appliedPrice); - - // - int hIdx = iHighest( - _Symbol, - _Period, - MODE_HIGH, - from, - to); - double maxValue = iHigh( - _Symbol, - _Period, - hIdx); - - // - int lIdx = iLowest( - _Symbol, - _Period, - MODE_LOW, - from, - to); - double minValue = iLow( - _Symbol, - _Period, - lIdx); - - // - result = IsSharpChanged( - fromValue, - toValue, - maxValue, - minValue); - - // - return result; -} - -// -// Check InCreased Sharp Happens or not ... -bool IsSharpIncreasedChanged( - double fromValue, // Past Value - double toValue, // Present Value - double maxValue, // Max in Range Value - double minValue // Min in Range Value -) -{ - // - bool result = false; - - // - // This Used In Increased or Decreased Sharp Detection ... - bool isIncreased = toValue > fromValue; - - // - double toFromDelta = MathAbs(toValue - fromValue); - double minMaxDelta = maxValue - minValue; - - // - result = - isIncreased && - toFromDelta >= (minMaxDelta / 3); - - // - return result; -} -bool IsSharpIncreasedChanged( - int from, // Past Index in Series - int to, // Present Index in Series - double &buffer[] // the Buffer which required to search -) -{ - // - bool result = false; - - // - // Validate Args ... - if ( - from <= to || - ArraySize(buffer) < from + 1) - { - return result; - } - - // - // Loop through Items ... - double toValue = buffer[to]; - double fromValue = buffer[from]; - - // - double minValue = GetMinValue( - ArraySize(buffer) - 1, - buffer); - double maxValue = GetMaxValue( - ArraySize(buffer) - 1, - buffer); - double minMaxDelta = maxValue - minValue; - - // - // Sharp Detection ... - result = IsSharpIncreasedChanged( - fromValue, - toValue, - maxValue, - minValue); - - // - return result; -} -bool IsSharpIncreasedChanged( - int from, // Past Bar Index - int to, // Present Bar Index - ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To -) -{ - // - bool result = false; - - // - double toValue = GetAppliedPrice( - to, - appliedPrice); - double fromValue = GetAppliedPrice( - from, - appliedPrice); - - // - int hIdx = iHighest( - _Symbol, - _Period, - MODE_HIGH, - from, - to); - double maxValue = iHigh( - _Symbol, - _Period, - hIdx); - - // - int lIdx = iLowest( - _Symbol, - _Period, - MODE_LOW, - from, - to); - double minValue = iLow( - _Symbol, - _Period, - lIdx); - - // - result = IsSharpIncreasedChanged( - fromValue, - toValue, - maxValue, - minValue); - - // - return result; -} - -// -// Check Decreased Sharp Happens or not ... -bool IsSharpDecreasedChanged( - double fromValue, // Past Value - double toValue, // Present Value - double maxValue, // Max in Range Value - double minValue // Min in Range Value -) -{ - // - bool result = false; - - // - // This Used In Increased or Decreased Sharp Detection ... - bool isIncreased = toValue > fromValue; - - // - double toFromDelta = MathAbs(toValue - fromValue); - double minMaxDelta = maxValue - minValue; - - // - result = - !isIncreased && - toFromDelta >= (minMaxDelta / 3); - - // - return result; -} -bool IsSharpDecreasedChanged( - int from, // Past Index in Series - int to, // Present Index in Series - double &buffer[] // the Buffer which required to search -) -{ - // - bool result = false; - - // - // Validate Args ... - if ( - from <= to || - ArraySize(buffer) < from + 1) - { - return result; - } - - // - // Loop through Items ... - double toValue = buffer[to]; - double fromValue = buffer[from]; - - // - double minValue = GetMinValue( - ArraySize(buffer) - 1, - buffer); - double maxValue = GetMaxValue( - ArraySize(buffer) - 1, - buffer); - double minMaxDelta = maxValue - minValue; - - // - // Sharp Detection ... - result = IsSharpDecreasedChanged( - fromValue, - toValue, - maxValue, - minValue); - - // - return result; -} -bool IsSharpDecreasedChanged( - int from, // Past Bar Index - int to, // Present Bar Index - ENUM_APPLIED_PRICE appliedPrice // Which Price Choose in From or To -) -{ - // - bool result = false; - - // - double toValue = GetAppliedPrice( - to, - appliedPrice); - double fromValue = GetAppliedPrice( - from, - appliedPrice); - - // - int hIdx = iHighest( - _Symbol, - _Period, - MODE_HIGH, - from, - to); - double maxValue = iHigh( - _Symbol, - _Period, - hIdx); - - // - int lIdx = iLowest( - _Symbol, - _Period, - MODE_LOW, - from, - to); - double minValue = iLow( - _Symbol, - _Period, - lIdx); - - // - result = IsSharpDecreasedChanged( - fromValue, - toValue, - maxValue, - minValue); - - // - return result; -} - -// -void Clean(int &buffer[]) -{ - // - ArrayFree(buffer); - ArrayResize(buffer, 0); -} -void Clean(ulong &buffer[]) -{ - // - ArrayFree(buffer); - ArrayResize(buffer, 0); -} -void Clean(string &buffer[]) -{ - // - ArrayFree(buffer); - ArrayResize(buffer, 0); -} -void Clean(double &buffer[]) -{ - // - ArrayFree(buffer); - ArrayResize(buffer, 0); -} - -// -bool GetLastItem( - double &item, // Holds Result - double &buffer[] // Specified Buffer -) -{ - // - bool result = false; - - // - int bufferSize = ArraySize(buffer); - if (bufferSize <= 0) - { - return result; - } - - // - item = buffer[bufferSize - 1]; - - // - result = true; - return result; -} -bool GetLastItem( - datetime &item, // Holds Result - datetime &buffer[] // Specified Buffer -) -{ - // - bool result = false; - - // - int bufferSize = ArraySize(buffer); - if (bufferSize <= 0) - { - return result; - } - - // - item = buffer[bufferSize - 1]; - - // - result = true; - return result; -} - -// -void Add( - int item, // item want to add - int &buffer[] // Destination buffer -) -{ - // - ArrayResize( - buffer, - ArraySize(buffer) + 1); - - // - buffer[ArraySize(buffer) - 1] = item; -} -void Add( - ulong item, // item want to add - ulong &buffer[] // Destination buffer -) -{ - // - ArrayResize( - buffer, - ArraySize(buffer) + 1); - - // - buffer[ArraySize(buffer) - 1] = item; -} -void Add( - string item, // item want to add - string &buffer[] // Destination buffer -) -{ - // - ArrayResize( - buffer, - ArraySize(buffer) + 1); - - // - buffer[ArraySize(buffer) - 1] = item; -} -void Add( - double item, // item want to add - double &buffer[] // Destination buffer -) -{ - // - ArrayResize( - buffer, - ArraySize(buffer) + 1); - - // - buffer[ArraySize(buffer) - 1] = item; -} -void Add( - XOHCL &item, // item want to add - XOHCL &buffer[] // Destination buffer -) -{ - // - ArrayResize( - buffer, - ArraySize(buffer) + 1); - - // - buffer[ArraySize(buffer) - 1] = item; -} -void Add( - datetime &item, // item want to add - datetime &buffer[] // Destination buffer -) -{ - // - ArrayResize( - buffer, - ArraySize(buffer) + 1); - - // - buffer[ArraySize(buffer) - 1] = item; -} - -// -// Add an Item to a Buffer if not Exists ... -void AddIfNotExists( - double value, - double &values[], - double smoothingPoint = 3) -{ - // - double smoothingValue = smoothingPoint * GetPoints(_Symbol); - - // - int valuesCount = ArraySize(values); - if (valuesCount <= 0) - { - // - Add(value, - values); - } - else - { - // - bool isExists = false; - for (int i = 0; i < valuesCount; i++) - { - // - double iVal = values[i]; - - // - double diff = MathAbs(iVal - value); - - // - if (iVal == value || diff < smoothingValue) - { - // - isExists = true; - break; - } - } - - // - if (!isExists) - { - // - Add(value, - values); - } - } -} - -// -// Add a Buffers Child to another Buffer -// if it's not Contains them ... -void AddsIfNotExists( - double &source[], - double &dest[], - double smoothingPoint = 3) -{ - // - double smoothingValue = smoothingPoint * GetPoints(_Symbol); - - // - int sourceCount = ArraySize(source); - if (sourceCount <= 0) - { - return; - } - - // - for (int i = 0; i < sourceCount; i++) - { - // - double iSource = source[i]; - - // - AddIfNotExists( - iSource, - dest, - smoothingPoint); - } -} - -// -// Converts a Buffer to String Representation ... -string ToString( - const int &buffer[], // Specified Buffer - string separator = ",", // Specified Separator - bool addIndex = false, // Specified Add Items Indexes or Not - string indexLabel = "i:", // Specified Index Label - string indexSeparator = ">" // Specified Index Separator - -) -{ - // - string result = ""; - - // - int bufferSize = ArraySize(buffer); - if (bufferSize <= 0) - { - return result; - } - - // - for (int i = 0; i < bufferSize; i++) - { - // - if (addIndex) - { - // - if (StringLen(indexLabel) > 0) - { - result += indexLabel + " "; - } - - // - result += (string)i + " "; - - // - if (StringLen(indexSeparator) > 0) - { - result += indexSeparator + " "; - } - } - - // - string iItemString = (string)buffer[i]; - - // - result += iItemString; - - // - if (i < bufferSize - 1) - { - result += separator; - } - } - - // - return result; -} -string ToString( - const double &buffer[], // Specified Buffer - string separator = ",", // Specified Separator - bool addIndex = false, // Specified Add Items Indexes or Not - string indexLabel = "i:", // Specified Index Label - string indexSeparator = ">" // Specified Index Separator - -) -{ - // - string result = ""; - - // - int bufferSize = ArraySize(buffer); - if (bufferSize <= 0) - { - return result; - } - - // - for (int i = 0; i < bufferSize; i++) - { - // - if (addIndex) - { - // - if (StringLen(indexLabel) > 0) - { - result += indexLabel + " "; - } - - // - result += (string)i + " "; - - // - if (StringLen(indexSeparator) > 0) - { - result += indexSeparator + " "; - } - } - - // - string iItemString = (string)buffer[i]; - - // - result += iItemString; - - // - if (i < bufferSize - 1) - { - result += separator; - } - } - - // - return result; -} -string ToString( - const string &buffer[], // Specified Buffer - string separator = ",", // Specified Separator - bool addIndex = false, // Specified Add Items Indexes or Not - string indexLabel = "i:", // Specified Index Label - string indexSeparator = ">" // Specified Index Separator - -) -{ - // - string result = ""; - - // - int bufferSize = ArraySize(buffer); - if (bufferSize <= 0) - { - return result; - } - - // - for (int i = 0; i < bufferSize; i++) - { - // - if (addIndex) - { - // - if (StringLen(indexLabel) > 0) - { - result += indexLabel + " "; - } - - // - result += (string)i + " "; - - // - if (StringLen(indexSeparator) > 0) - { - result += indexSeparator + " "; - } - } - - // - string iItemString = (string)buffer[i]; - - // - result += iItemString; - - // - if (i < bufferSize - 1) - { - result += separator; - } - } - - // - return result; -} -string ToString( - const datetime &buffer[], // Specified Buffer - string separator = ",", // Specified Separator - bool addIndex = false, // Specified Add Items Indexes or Not - string indexLabel = "i:", // Specified Index Label - string indexSeparator = ">" // Specified Index Separator -) -{ - // - string result = ""; - - // - int bufferSize = ArraySize(buffer); - if (bufferSize <= 0) - { - return result; - } - - // - for (int i = 0; i < bufferSize; i++) - { - // - if (addIndex) - { - // - if (StringLen(indexLabel) > 0) - { - result += indexLabel + " "; - } - - // - result += (string)i + " "; - - // - if (StringLen(indexSeparator) > 0) - { - result += indexSeparator + " "; - } - } - - // - string iItemString = (string)buffer[i]; - - // - result += iItemString; - - // - if (i < bufferSize - 1) - { - result += separator; - } - } - - // - return result; -} -template -string ToString(T value) -{ - return (string)value; -} - -// -// Extract Data from String ... -string ExtractString( - const string source, // Source String used for Extracting - const string startString, // Expression Start String must be Unique - const string endString // Where to End Extraction, usually a Sign -) -{ - // - string result = ""; - - // - // Validate String ... - if ( - StringLen(source) == 0 || - StringLen(endString) == 0 || - StringLen(startString) == 0) - { - return result; - } - - // - // Find Start String Position ... - int sPos = StringFind( - source, - startString); - if (sPos < 0) - { - return result; - } - - // - // Find End String Position after Start String ... - int searchEndFromPos = sPos + StringLen(startString); - int ePos = StringFind( - source, - endString, - searchEndFromPos); - if (ePos < 0) - { - return result; - } - - // - // Extract Data from Source ... - int dLength = ePos - searchEndFromPos; - result = StringSubstr( - source, - searchEndFromPos, - dLength); - - // - return result; + return value; } // // Normalize a give Volume ... double NormalizeVolume( - double volume, // desired volume to normalize - string symbol = NULL, // Specified Symbol for Normalization - int mLength = 2 // Length of Digits + double mVolume, // desired volume to normalize + string mSymbol = NULL, // Trading Symbol + int mLength = 2 // Length of Digits ) { // - double result = volume; + double result = mVolume; // - // Normalize Symbol ... - if (StringLen(symbol) == 0) - { - symbol = _Symbol; - } + mSymbol = NormalizeSymbol(mSymbol); // // Normalize Digits ... - int digits = GetDigits(symbol); + int digits = GetDigits(mSymbol); + + // mLength = mLength == 0 || mLength > digits ? digits @@ -3125,8 +2469,8 @@ double NormalizeVolume( result = NormalizeDouble(result, mLength); // - double maxAvailableVolume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); - double minAvailableVolume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); + double maxAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MAX); + double minAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MIN); // // Validate Result ... @@ -3146,804 +2490,316 @@ double NormalizeVolume( // // Normallize Price ... double NormalizePrice( - double price, // desired Price for normalization - string symbol = NULL // Specified Symbol for Normalization + double mPrice, // desired Price for normalization + string mSymbol = NULL // Trading Symbol ) { // double result = 0; // - // Mormalize Symbol ... - if (StringLen(symbol) == 0) - { - symbol = _Symbol; - } + mSymbol = NormalizeSymbol(mSymbol); // - int digits = GetDigits(symbol); - result = NormalizeDouble(price, digits); + double tickSize = 0; + result = SymbolInfoDouble(mSymbol, SYMBOL_TRADE_TICK_SIZE, tickSize); + + // + int digits = GetDigits(mSymbol); + result = NormalizeDouble(MathRound(mPrice / tickSize) * tickSize, digits); // return result; } // -// Error Descriptions Functions ... -// +// Prices ... // -// Retrieve Specified Error Code Description ... -string GetErrorDescription(int err_code) +// Retrieve Ask Price ... +double GetAsk( + string mSymbol = NULL // Trading Symbol +) { // - string result = ""; + mSymbol = NormalizeSymbol(mSymbol); // - switch (err_code) + double result = SymbolInfoDouble(mSymbol, SYMBOL_ASK); + + // + return result; +} + +// +// Retrieve Bid Price ... +double GetBid( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_BID); + + // + return result; +} + +// +// Retrieve Spread Price ... +double GetSpread( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double ask = GetAsk(mSymbol); + double bid = GetBid(mSymbol); + + // + double result = MathAbs(ask - bid); + + // + return result; +} + +// +// Retrieve Point Value ... +double GetPoints( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_POINT); + + // + return result; +} + +// +// Retrieve Point Digits ... +int GetDigits( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + int result = (int)SymbolInfoInteger(mSymbol, SYMBOL_DIGITS); + + // + return result; +} + +// +// Retrieve Entry Price ... +double GetEntry( + string mSymbol = NULL, // Trading Symbol + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? GetAsk(mSymbol) + : GetBid(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Retrieve Exit Price ... +double GetExit( + string mSymbol = NULL, // Trading Symbol + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // Get entry price for Which direction trade ... +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? GetBid(mSymbol) + : GetAsk(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Get 1 Pip in Price Value ... +double GetPipPrice( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double symbolPoint = GetPoints(mSymbol); + int symbolDigits = GetDigits(mSymbol); + + // + double result = symbolPoint; + if (symbolDigits == 3 || symbolDigits == 5) { - // - //--- Constant Description - - // - case ERR_SUCCESS: - result = "The operation completed successfully"; - break; - - // - case ERR_INTERNAL_ERROR: - result = "Unexpected internal error"; - break; - - // - case ERR_WRONG_INTERNAL_PARAMETER: - result = "Wrong parameter in the inner call of the client terminal function"; - break; - - // - case ERR_INVALID_PARAMETER: - result = "Wrong parameter when calling the system function"; - break; - - // - case ERR_NOT_ENOUGH_MEMORY: - result = "Not enough memory to perform the system function"; - break; - - // - case ERR_STRUCT_WITHOBJECTS_ORCLASS: - result = "The structure contains objects of strings and/or dynamic arrays and/or structure of such objects and/or classes"; - break; - - // - case ERR_INVALID_ARRAY: - result = "Array of a wrong type, wrong size, or a damaged object of a dynamic array"; - break; - - // - case ERR_ARRAY_RESIZE_ERROR: - result = "Not enough memory for the relocation of an array, or an attempt to change the size of a static array"; - break; - - // - case ERR_STRING_RESIZE_ERROR: - result = "Not enough memory for the relocation of string"; - break; - - // - case ERR_NOTINITIALIZED_STRING: - result = "Not initialized string"; - break; - - // - case ERR_INVALID_DATETIME: - result = "Invalid date and/or time"; - break; - - // - case ERR_ARRAY_BAD_SIZE: - result = "Requested array size exceeds 2 GB"; - break; - - // - case ERR_INVALID_POINTER: - result = "Wrong pointer"; - break; - - // - case ERR_INVALID_POINTER_TYPE: - result = "Wrong type of pointer"; - break; - - // - case ERR_FUNCTION_NOT_ALLOWED: - result = "System function is not allowed to call"; - break; - - // - //--- Charts - - // - case ERR_CHART_WRONG_ID: - result = "Wrong chart ID"; - break; - - // - case ERR_CHART_NO_REPLY: - result = "Chart does not respond"; - break; - - // - case ERR_CHART_NOT_FOUND: - result = "Chart not found"; - break; - - // - case ERR_CHART_NO_EXPERT: - result = "No Expert Advisor in the chart that could handle the event"; - break; - - // - case ERR_CHART_CANNOT_OPEN: - result = "Chart opening error"; - break; - - // - case ERR_CHART_CANNOT_CHANGE: - result = "Failed to change chart symbol and period"; - break; - - // - case ERR_CHART_CANNOT_CREATE_TIMER: - result = "Failed to create timer"; - break; - - // - case ERR_CHART_WRONG_PROPERTY: - result = "Wrong chart property ID"; - break; - - // - case ERR_CHART_SCREENSHOT_FAILED: - result = "Error creating screenshots"; - break; - - // - case ERR_CHART_NAVIGATE_FAILED: - result = "Error navigating through chart"; - break; - - // - case ERR_CHART_TEMPLATE_FAILED: - result = "Error applying template"; - break; - - // - case ERR_CHART_WINDOW_NOT_FOUND: - result = "Subwindow containing the indicator was not found"; - break; - - // - case ERR_CHART_INDICATOR_CANNOT_ADD: - result = "Error adding an indicator to chart"; - break; - - // - case ERR_CHART_INDICATOR_CANNOT_DEL: - result = "Error deleting an indicator from the chart"; - break; - - // - case ERR_CHART_INDICATOR_NOT_FOUND: - result = "Indicator not found on the specified chart"; - break; - - // - //--- Graphical Objects - case ERR_OBJECT_ERROR: - result = "Error working with a graphical object"; - break; - - // - case ERR_OBJECT_NOT_FOUND: - result = "Graphical object was not found"; - break; - - // - case ERR_OBJECT_WRONG_PROPERTY: - result = "Wrong ID of a graphical object property"; - break; - - // - case ERR_OBJECT_GETDATE_FAILED: - result = "Unable to get date corresponding to the value"; - break; - - // - case ERR_OBJECT_GETVALUE_FAILED: - result = "Unable to get value corresponding to the date"; - break; - - // - //--- MarketInfo - - // - case ERR_MARKET_UNKNOWN_SYMBOL: - result = "Unknown symbol"; - break; - - // - case ERR_MARKET_NOT_SELECTED: - result = "Symbol is not selected in MarketWatch"; - break; - - // - case ERR_MARKET_WRONG_PROPERTY: - result = "Wrong identifier of a symbol property"; - break; - - // - case ERR_MARKET_LASTTIME_UNKNOWN: - result = "Time of the last tick is not known (no ticks)"; - break; - - // - case ERR_MARKET_SELECT_ERROR: - result = "Error adding or deleting a symbol in MarketWatch"; - break; - - // - //--- History Access - - // - case ERR_HISTORY_NOT_FOUND: - result = "Requested history not found"; - break; - - // - case ERR_HISTORY_WRONG_PROPERTY: - result = "Wrong ID of the history property"; - break; - - // - //--- Global_Variables - - // - case ERR_GLOBALVARIABLE_NOT_FOUND: - result = "Global variable of the client terminal is not found"; - break; - - // - case ERR_GLOBALVARIABLE_EXISTS: - result = "Global variable of the client terminal with the same name already exists"; - break; - - // - case ERR_MAIL_SEND_FAILED: - result = "Email sending failed"; - break; - - // - case ERR_PLAY_SOUND_FAILED: - result = "Sound playing failed"; - break; - - // - case ERR_MQL5_WRONG_PROPERTY: - result = "Wrong identifier of the program property"; - break; - - // - case ERR_TERMINAL_WRONG_PROPERTY: - result = "Wrong identifier of the terminal property"; - break; - - // - case ERR_FTP_SEND_FAILED: - result = "File sending via ftp failed"; - break; - - // - case ERR_NOTIFICATION_SEND_FAILED: - result = "Error in sending notification"; - break; - - // - //--- Custom Indicator Buffers - - // - case ERR_BUFFERS_NO_MEMORY: - result = "Not enough memory for the distribution of indicator buffers"; - break; - - // - case ERR_BUFFERS_WRONG_INDEX: - result = "Wrong indicator buffer index"; - break; - - // - //--- Custom Indicator Properties - - // - case ERR_CUSTOM_WRONG_PROPERTY: - result = "Wrong ID of the custom indicator property"; - break; - - // - //--- Account - - // - case ERR_ACCOUNT_WRONG_PROPERTY: - result = "Wrong account property ID"; - break; - - // - case ERR_TRADE_WRONG_PROPERTY: - result = "Wrong trade property ID"; - break; - - // - case ERR_TRADE_DISABLED: - result = "Trading by Expert Advisors prohibited"; - break; - - // - case ERR_TRADE_POSITION_NOT_FOUND: - result = "Position not found"; - break; - - // - case ERR_TRADE_ORDER_NOT_FOUND: - result = "Order not found"; - break; - - // - case ERR_TRADE_DEAL_NOT_FOUND: - result = "Deal not found"; - break; - - // - case ERR_TRADE_SEND_FAILED: - result = "Trade request sending failed"; - break; - - // - //--- Indicators - - // - case ERR_INDICATOR_UNKNOWN_SYMBOL: - result = "Unknown symbol"; - break; - - // - case ERR_INDICATOR_CANNOT_CREATE: - result = "Indicator cannot be created"; - break; - - // - case ERR_INDICATOR_NO_MEMORY: - result = "Not enough memory to add the indicator"; - break; - - // - case ERR_INDICATOR_CANNOT_APPLY: - result = "The indicator cannot be applied to another indicator"; - break; - - // - case ERR_INDICATOR_CANNOT_ADD: - result = "Error applying an indicator to chart"; - break; - - // - case ERR_INDICATOR_DATA_NOT_FOUND: - result = "Requested data not found"; - break; - - // - case ERR_INDICATOR_WRONG_HANDLE: - result = "Wrong indicator handle"; - break; - - // - case ERR_INDICATOR_WRONG_PARAMETERS: - result = "Wrong number of parameters when creating an indicator"; - break; - - // - case ERR_INDICATOR_PARAMETERS_MISSING: - result = "No parameters when creating an indicator"; - break; - - // - case ERR_INDICATOR_CUSTOM_NAME: - result = "The first parameter in the array must be the name of the custom indicator"; - break; - - // - case ERR_INDICATOR_PARAMETER_TYPE: - result = "Invalid parameter type in the array when creating an indicator"; - break; - - // - case ERR_INDICATOR_WRONG_INDEX: - result = "Wrong index of the requested indicator buffer"; - break; - - // - //--- Depth of Market - - // - case ERR_BOOKS_CANNOT_ADD: - result = "Depth Of Market can not be added"; - break; - - // - case ERR_BOOKS_CANNOT_DELETE: - result = "Depth Of Market can not be removed"; - break; - - // - case ERR_BOOKS_CANNOT_GET: - result = "The data from Depth Of Market can not be obtained"; - break; - - // - case ERR_BOOKS_CANNOT_SUBSCRIBE: - result = "Error in subscribing to receive new data from Depth Of Market"; - break; - - // - //--- File Operations - - // - case ERR_TOO_MANY_FILES: - result = "More than 64 files cannot be opened at the same time"; - break; - - // - case ERR_WRONG_FILENAME: - result = "Invalid file name"; - break; - - // - case ERR_TOO_LONG_FILENAME: - result = "Too long file name"; - break; - - // - case ERR_CANNOT_OPEN_FILE: - result = "File opening error"; - break; - - // - case ERR_FILE_CACHEBUFFER_ERROR: - result = "Not enough memory for cache to read"; - break; - - // - case ERR_CANNOT_DELETE_FILE: - result = "File deleting error"; - break; - - // - case ERR_INVALID_FILEHANDLE: - result = "A file with this handle was closed, or was not opening at all"; - break; - - // - case ERR_WRONG_FILEHANDLE: - result = "Wrong file handle"; - break; - - // - case ERR_FILE_NOTTOWRITE: - result = "The file must be opened for writing"; - break; - - // - case ERR_FILE_NOTTOREAD: - result = "The file must be opened for reading"; - break; - - // - case ERR_FILE_NOTBIN: - result = "The file must be opened as a binary one"; - break; - - // - case ERR_FILE_NOTTXT: - result = "The file must be opened as a text"; - break; - - // - case ERR_FILE_NOTTXTORCSV: - result = "The file must be opened as a text or CSV"; - break; - - // - case ERR_FILE_NOTCSV: - result = "The file must be opened as CSV"; - break; - - // - case ERR_FILE_READERROR: - result = "File reading error"; - break; - - // - case ERR_FILE_BINSTRINGSIZE: - result = "String size must be specified, because the file is opened as binary"; - break; - - // - case ERR_INCOMPATIBLE_FILE: - result = "A text file must be for string arrays, for other arrays - binary"; - break; - - // - case ERR_FILE_IS_DIRECTORY: - result = "This is not a file, this is a directory"; - break; - - // - case ERR_FILE_NOT_EXIST: - result = "File does not exist"; - break; - - // - case ERR_FILE_CANNOT_REWRITE: - result = "File can not be rewritten"; - break; - - // - case ERR_WRONG_DIRECTORYNAME: - result = "Wrong directory name"; - break; - - // - case ERR_DIRECTORY_NOT_EXIST: - result = "Directory does not exist"; - break; - - // - case ERR_FILE_ISNOT_DIRECTORY: - result = "This is a file, not a directory"; - break; - - // - case ERR_CANNOT_DELETE_DIRECTORY: - result = "The directory cannot be removed"; - break; - - // - case ERR_CANNOT_CLEAN_DIRECTORY: - result = "Failed to clear the directory (probably one or more files are blocked and removal operation failed)"; - break; - - // - case ERR_FILE_WRITEERROR: - result = "Failed to write a resource to a file"; - break; - - // - //--- String Casting - - // - case ERR_NO_STRING_DATE: - result = "No date in the string"; - break; - - // - case ERR_WRONG_STRING_DATE: - result = "Wrong date in the string"; - break; - - // - case ERR_WRONG_STRING_TIME: - result = "Wrong time in the string"; - break; - - // - case ERR_STRING_TIME_ERROR: - result = "Error converting string to date"; - break; - - // - case ERR_STRING_OUT_OF_MEMORY: - result = "Not enough memory for the string"; - break; - - // - case ERR_STRING_SMALL_LEN: - result = "The string length is less than expected"; - break; - - // - case ERR_STRING_TOO_BIGNUMBER: - result = "Too large number, more than ULONG_MAX"; - break; - - // - case ERR_WRONG_FORMATSTRING: - result = "Invalid format string"; - break; - - // - case ERR_TOO_MANY_FORMATTERS: - result = "Amount of format specifiers more than the parameters"; - break; - - // - case ERR_TOO_MANY_PARAMETERS: - result = "Amount of parameters more than the format specifiers"; - break; - - // - case ERR_WRONG_STRING_PARAMETER: - result = "Damaged parameter of string type"; - break; - - // - case ERR_STRINGPOS_OUTOFRANGE: - result = "Position outside the string"; - break; - - // - case ERR_STRING_ZEROADDED: - result = "0 added to the string end, a useless operation"; - break; - - // - case ERR_STRING_UNKNOWNTYPE: - result = "Unknown data type when converting to a string"; - break; - - // - case ERR_WRONG_STRING_OBJECT: - result = "Damaged string object"; - break; - - // - //--- Operations with Arrays - - // - case ERR_INCOMPATIBLE_ARRAYS: - result = "Copying incompatible arrays. String array can be copied only to a string array, and a numeric array - in numeric array only"; - break; - - // - case ERR_SMALL_ASSERIES_ARRAY: - result = "The receiving array is declared as AS_SERIES, and it is of insufficient size"; - break; - - // - case ERR_SMALL_ARRAY: - result = "Too small array, the starting position is outside the array"; - break; - - // - case ERR_ZEROSIZE_ARRAY: - result = "An array of zero length"; - break; - - // - case ERR_NUMBER_ARRAYS_ONLY: - result = "Must be a numeric array"; - break; - - // - case ERR_ONEDIM_ARRAYS_ONLY: - result = "Must be a one-dimensional array"; - break; - - // - case ERR_SERIES_ARRAY: - result = "Timeseries cannot be used"; - break; - - // - case ERR_DOUBLE_ARRAY_ONLY: - result = "Must be an array of type double"; - break; - - // - case ERR_FLOAT_ARRAY_ONLY: - result = "Must be an array of type float"; - break; - - // - case ERR_LONG_ARRAY_ONLY: - result = "Must be an array of type long"; - break; - - // - case ERR_INT_ARRAY_ONLY: - result = "Must be an array of type int"; - break; - - // - case ERR_SHORT_ARRAY_ONLY: - result = "Must be an array of type short"; - break; - - // - case ERR_CHAR_ARRAY_ONLY: - result = "Must be an array of type char"; - break; - - // - //--- Operations with OpenCL - - // - case ERR_OPENCL_NOT_SUPPORTED: - result = "OpenCL functions are not supported on this computer"; - break; - - // - case ERR_OPENCL_INTERNAL: - result = "Internal error occurred when running OpenCL"; - break; - - // - case ERR_OPENCL_INVALID_HANDLE: - result = "Invalid OpenCL handle"; - break; - - // - case ERR_OPENCL_CONTEXT_CREATE: - result = "Error creating the OpenCL context"; - break; - - // - case ERR_OPENCL_QUEUE_CREATE: - result = "Failed to create a run queue in OpenCL"; - break; - - // - case ERR_OPENCL_PROGRAM_CREATE: - result = "Error occurred when compiling an OpenCL program"; - break; - - // - case ERR_OPENCL_TOO_LONG_KERNEL_NAME: - result = "Too long kernel name (OpenCL kernel)"; - break; - - // - case ERR_OPENCL_KERNEL_CREATE: - result = "Error creating an OpenCL kernel"; - break; - - // - case ERR_OPENCL_SET_KERNEL_PARAMETER: - result = "Error occurred when setting parameters for the OpenCL kernel"; - break; - - // - case ERR_OPENCL_EXECUTE: - result = "OpenCL program runtime error"; - break; - - // - case ERR_OPENCL_WRONG_BUFFER_SIZE: - result = "Invalid size of the OpenCL buffer"; - break; - - // - case ERR_OPENCL_WRONG_BUFFER_OFFSET: - result = "Invalid offset in the OpenCL buffer"; - break; - - // - case ERR_OPENCL_BUFFER_CREATE: - result = "Failed to create and OpenCL buffer"; - break; - - // - //--- User-Defined Errors + result *= 10; + } + + // + return result; +} + +// +// Converts Pips To Price ... +double PipsToPrice( + double mPips, // pips amount + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + int digits = GetDigits(mSymbol); + double pipValue = GetPipPrice(mSymbol); + double result = mPips * pipValue; + + // + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Converts Price to Pips ... +double PriceToPips( + double mPrice, // the price amount which required to calculate + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + mPrice = NormalizePrice(mPrice, mSymbol); + + // + int digits = GetDigits(mSymbol); + double pipPrice = GetPipPrice(mSymbol); + + // + double result = mPrice / pipPrice; + + // + result = NormalizeDouble(result, digits); + + // + return result; +} + +// +// Convert Price to Point ... +double PriceToPoint( + double price, // the price amount which required to calculate + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + price = NormalizePrice(price, mSymbol); + + // + double point = GetPoints(mSymbol); + result = price / point; + + // + return result; +} + +// +// Converts Point to Price ... +double PointToPrice( + double points, // Points Amount + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double point = GetPoints(mSymbol); + result = points * point; + + // + result = NormalizePrice(result, mSymbol); + + // + return result; +} + +// +// Converts Series Mode to XPRICE ... +ENUM_X_PRICE ToPrice( + ENUM_SERIESMODE mode // Specified Series Mode ... +) +{ + // + ENUM_X_PRICE result = X_PRICE_CLOSE; + + // + switch (mode) + { + // + // High ... + case MODE_HIGH: + result = X_PRICE_HIGH; + break; + + // + // Open ... + case MODE_OPEN: + result = X_PRICE_OPEN; + break; + + // + // Low ... + case MODE_LOW: + result = X_PRICE_LOW; + break; + + // + // Close ... + // Default ... + case MODE_CLOSE: default: - result = "UNKNOWN Erro ..."; + result = X_PRICE_CLOSE; break; } @@ -3952,193 +2808,39 @@ string GetErrorDescription(int err_code) } // -// Retrieve Specified Error Code Description ... -string GetTradeServerReturnCodeDescription(int return_code) +// Retrieve Applied Price ... +template +double GetAppliedPrice( + ENUM_APPLIED_PRICE tprice, // Type of Price Selection + T &open[], // Open Prices + T &high[], // High Preices + T &low[], // Low Prices + T &close[], // Close Prices + int i // Bar Index +) { - // - string result = ""; - - // - switch (return_code) + switch (tprice) { - // - case TRADE_RETCODE_REQUOTE: - result = "Requote"; - break; - - // - case TRADE_RETCODE_REJECT: - result = "Request rejected"; - break; - - // - case TRADE_RETCODE_CANCEL: - result = "Request canceled by trader"; - break; - - // - case TRADE_RETCODE_PLACED: - result = "Order placed"; - break; - - // - case TRADE_RETCODE_DONE: - result = "Request completed"; - break; - - // - case TRADE_RETCODE_DONE_PARTIAL: - result = "Only part of the request was completed"; - break; - - // - case TRADE_RETCODE_ERROR: - result = "Request processing error"; - break; - - // - case TRADE_RETCODE_TIMEOUT: - result = "Request canceled by timeout"; - break; - - // - case TRADE_RETCODE_INVALID: - result = "Invalid request"; - break; - - // - case TRADE_RETCODE_INVALID_VOLUME: - result = "Invalid volume in the request"; - break; - - // - case TRADE_RETCODE_INVALID_PRICE: - result = "Invalid price in the request"; - break; - - // - case TRADE_RETCODE_INVALID_STOPS: - result = "Invalid stops in the request"; - break; - - // - case TRADE_RETCODE_TRADE_DISABLED: - result = "Trade is disabled"; - break; - - // - case TRADE_RETCODE_MARKET_CLOSED: - result = "Market is closed"; - break; - - // - case TRADE_RETCODE_NO_MONEY: - result = "There is not enough money to complete the request"; - break; - - // - case TRADE_RETCODE_PRICE_CHANGED: - result = "Prices changed"; - break; - - // - case TRADE_RETCODE_PRICE_OFF: - result = "There are no quotes to process the request"; - break; - - // - case TRADE_RETCODE_INVALID_EXPIRATION: - result = "Invalid order expiration date in the request"; - break; - - // - case TRADE_RETCODE_ORDER_CHANGED: - result = "Order state changed"; - break; - - // - case TRADE_RETCODE_TOO_MANY_REQUESTS: - result = "Too frequent requests"; - break; - - // - case TRADE_RETCODE_NO_CHANGES: - result = "No changes in request"; - break; - - // - case TRADE_RETCODE_SERVER_DISABLES_AT: - result = "Autotrading disabled by server"; - break; - - // - case TRADE_RETCODE_CLIENT_DISABLES_AT: - result = "Autotrading disabled by client terminal"; - break; - - // - case TRADE_RETCODE_LOCKED: - result = "Request locked for processing"; - break; - - // - case TRADE_RETCODE_FROZEN: - result = "Order or position frozen"; - break; - - // - case TRADE_RETCODE_INVALID_FILL: - result = "Invalid order filling type"; - break; - - // - case TRADE_RETCODE_CONNECTION: - result = "No connection with the trade server"; - break; - - // - case TRADE_RETCODE_ONLY_REAL: - result = "Operation is allowed only for live accounts"; - break; - - // - case TRADE_RETCODE_LIMIT_ORDERS: - result = "The number of pending orders has reached the limit"; - break; - - // - case TRADE_RETCODE_LIMIT_VOLUME: - result = "The volume of orders and positions for the symbol has reached the limit"; - break; - - // - default: - result = "Invalid return code of the trade server"; - break; + case PRICE_CLOSE: + return (close[i]); + case PRICE_OPEN: + return (open[i]); + case PRICE_HIGH: + return (high[i]); + case PRICE_LOW: + return (low[i]); + case PRICE_MEDIAN: + return ((high[i] + low[i]) / 2.0); + case PRICE_TYPICAL: + return ((high[i] + low[i] + close[i]) / 3.0); + case PRICE_WEIGHTED: + return ((high[i] + low[i] + close[i] + close[i]) / 4.0); } - - // - return result; + return (0); } // -// Check Expert Running in Testing Mode or not ... -bool IsRunningOnTestMode() -{ - // - bool result = false; - - // - // check programm mode ... - result = MQL5InfoInteger(MQL5_TESTING); - - // - return result; -} - -// -// Date Time Manipulation Functions ... -// +// Time / Date ... // // Representation of Time Struct ... @@ -4310,625 +3012,25 @@ ulong GetCurrentTimeAsMilliSeconds() } // -// Retrieve Specified Candle Time ... -datetime GetCandleTime( - string symbol = "", // Specify Symbol - ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame - int bar_index = 0 // Specify Bar Index +// Bar Times ... + +// +// Retrieve Specified Bar Time ... +datetime GetBarTime( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index ) { // // Validate and Normalize Args ... // - // Normalize Symbol ... - symbol = StringLen(symbol) == 0 - ? _Symbol - : symbol; - - // - // Normalize Period ... - period = period == NULL - ? _Period - : period; + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); // // Retrieve Bar Time ... - datetime result = iTime( - symbol, - period, - bar_index); - - // - return result; -} - -// -// Retrieve Specified Candle Time ... -ulong GetCandleTimeAsSeconds( - string symbol = "", // Specify Symbol - ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame - int bar_index = 0 // Specify Bar Index -) -{ - // - // Retrieve Bar Time ... - datetime time = GetCandleTime( - symbol, - period, - bar_index); - - // - ulong result = TimeToSeconds(time); - - // - return result; -} - -// -// Retrieve Specified Candle Time ... -ulong GetCandleTimeAsMilliSeconds( - string symbol = "", // Specify Symbol - ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame - int bar_index = 0 // Specify Bar Index -) -{ - // - // Retrieve Bar Time ... - datetime time = GetCandleTime( - symbol, - period, - bar_index); - - // - ulong result = TimeToMilliSeconds(time); - - // - return result; -} - -// -// Retrieve a Candle Time Structure ... -MqlDateTime GetCandleTimeStruct( - string symbol = "", // Specify Symbol - ENUM_TIMEFRAMES period = NULL, // Specify TimeFrame - int bar_index = 0 // Specify Bar Index -) -{ - // - MqlDateTime result = {}; - - // - // Retrieve Bar Time ... - datetime barTime = GetCandleTime( - symbol, - period, - bar_index); - - // - // Convert to Structure ... - TimeToStruct(barTime, result); - - // - return result; -} - -// -// Retrieve Number of Candles in a Day ... -int GetDailyCandleCount(ENUM_TIMEFRAMES mPeriod) -{ - // - int seconds = PeriodSeconds(mPeriod); - - // - int daySeconds = 24 * 60 * 60; - - // - int result = daySeconds / seconds; - - // - return result; -} - -int GetDailyCandleCount() -{ - // - int result = GetDailyCandleCount(_Period); - - // - return result; -} - -// -// -// - -// -// Holds Month ... -static int xMonth = -1; - -// -// Holds Day Of Week ... -static int xDayOfWeek = -1; -static int xForWeekDay = -1; - -// -// Holds Day ... -static int xDay = -1; - -// -// Holds Hour ... -static int xHour = -1; - -// -// Reset Timing Variables ... -void ResetTiming() -{ - // - xHour = -1; - xDay = -1; - xDayOfWeek = -1; - xMonth = -1; -} - -// -// Detecting New Houre ... -bool IsNewHour() -{ - // - bool result = false; - - // - // Retrieve Current Time as Struct ... - MqlDateTime timeStruct = GetCurrentTime(); - - // - // Check Houre ... - result = timeStruct.hour != xHour; - if (result) - { - xHour = timeStruct.hour; - } - - // - return result; -} - -// -// Detecting New Day ... -bool IsNewDay() -{ - // - bool result = false; - - // - // Retrieve Current Time as Struct ... - MqlDateTime timeStruct = GetCurrentTime(); - - // - // Check Houre ... - result = timeStruct.day_of_year != xDay; - if (result) - { - xDay = timeStruct.day_of_year; - } - - // - return result; -} - -// -// Detecting New Week ... -bool IsNewWeek() -{ - // - bool result = false; - - // - // Retrieve Current Time as Struct ... - MqlDateTime timeStruct = GetCurrentTime(); - - // - // Check Week ... - // Since Week Starts From Monday in Forex World ... - // we Calculate Start of Week by 1-Monday ... - result = - xDayOfWeek == -1 && - xForWeekDay == -1 - ? true - : timeStruct.day_of_week == 1 && - timeStruct.day_of_year > xForWeekDay; - - // - xForWeekDay = timeStruct.day_of_year; - xDayOfWeek = timeStruct.day_of_week; - - // - return result; -} - -// -// Detecting End Of Week ... -bool IsWeekEnd() -{ - // - bool result = false; - - // - // Retrieve Current Time as Struct ... - MqlDateTime timeStruct = GetCurrentTime(); - - // - // Check WeekEnd ... - // Since Week Starts From Monday in Forex World ... - // we Calculate End of Week by 5-Friday ... - result = - xDayOfWeek != -1 && - timeStruct.day_of_week == 5 && - timeStruct.hour == 23 && - timeStruct.min == 59 && - timeStruct.sec == 59; - - // - return result; -} - -// -// Detecting New Month ... -bool IsNewMonth() -{ - // - bool result = false; - - // - // Retrieve Current Time as Struct ... - MqlDateTime timeStruct = GetCurrentTime(); - - // - // Check Houre ... - result = timeStruct.mon != xMonth; - if (result) - { - xMonth = timeStruct.mon; - } - - // - return result; -} - -// -// Find Hindmost Time Frame ... -ENUM_TIMEFRAMES GetHindmostTimeFrame( - ENUM_TIMEFRAMES mPeriod // Specified Period -) -{ - // - ENUM_TIMEFRAMES result = NULL; - - // - // Normalize Period ... - if ( - mPeriod < 0 || - mPeriod == NULL) - { - mPeriod = _Period; - } - - // - switch (mPeriod) - { - // - case PERIOD_M1: - case PERIOD_M2: - case PERIOD_M3: - case PERIOD_M4: - case PERIOD_M5: - case PERIOD_M6: - case PERIOD_M10: - case PERIOD_M12: - case PERIOD_M15: - result = PERIOD_H12; - break; - - // - case PERIOD_M20: - case PERIOD_M30: - case PERIOD_H1: - case PERIOD_H2: - case PERIOD_H3: - case PERIOD_H4: - result = PERIOD_D1; - break; - - // - case PERIOD_H6: - case PERIOD_H8: - case PERIOD_H12: - case PERIOD_D1: - result = PERIOD_W1; - break; - - // - default: - result = PERIOD_MN1; - break; - } - - // - return result; -} - -// -// Find Farest Time Frame ... -ENUM_TIMEFRAMES GetFarestTimeFrame( - ENUM_TIMEFRAMES mPeriod // Specified Period -) -{ - // - ENUM_TIMEFRAMES result = NULL; - - // - // Normalize Period ... - if ( - mPeriod < 0 || - mPeriod == NULL) - { - mPeriod = _Period; - } - - // - switch (mPeriod) - { - // - case PERIOD_M1: - case PERIOD_M2: - case PERIOD_M3: - case PERIOD_M4: - case PERIOD_M5: - case PERIOD_M6: - case PERIOD_M10: - case PERIOD_M12: - case PERIOD_M15: - case PERIOD_M20: - case PERIOD_M30: - result = PERIOD_H4; - break; - - // - case PERIOD_H1: - case PERIOD_H2: - case PERIOD_H3: - case PERIOD_H4: - result = PERIOD_H12; - break; - - // - case PERIOD_H6: - case PERIOD_H8: - case PERIOD_H12: - case PERIOD_D1: - result = PERIOD_W1; - break; - - // - default: - result = PERIOD_MN1; - break; - } - - // - return result; -} - -// -// Find Medium Time Frame ... -ENUM_TIMEFRAMES GetMediestTimeFrame( - ENUM_TIMEFRAMES mPeriod // Specified Period -) -{ - // - ENUM_TIMEFRAMES result = NULL; - - // - // Normalize Period ... - if ( - mPeriod < 0 || - mPeriod == NULL) - { - mPeriod = _Period; - } - - // - switch (mPeriod) - { - // - case PERIOD_M1: - case PERIOD_M2: - case PERIOD_M3: - case PERIOD_M4: - case PERIOD_M5: - case PERIOD_M6: - case PERIOD_M10: - case PERIOD_M12: - case PERIOD_M15: - case PERIOD_M20: - result = PERIOD_H1; - break; - - // - case PERIOD_M30: - result = PERIOD_H2; - break; - - // - case PERIOD_H1: - case PERIOD_H2: - case PERIOD_H3: - result = PERIOD_H4; - break; - - // - case PERIOD_H4: - case PERIOD_H6: - case PERIOD_H8: - result = PERIOD_H12; - break; - - // - case PERIOD_H12: - result = PERIOD_D1; - break; - - // - case PERIOD_D1: - result = PERIOD_W1; - break; - - // - case PERIOD_W1: - result = PERIOD_MN1; - break; - - // - default: - result = PERIOD_MN1; - break; - } - - // - return result; -} - -// -// Find Nearest Time Frame ... -ENUM_TIMEFRAMES GetNearestTimeFrame( - ENUM_TIMEFRAMES mPeriod // Specified Period -) -{ - // - ENUM_TIMEFRAMES result = NULL; - - // - // Normalize Period ... - if ( - mPeriod < 0 || - mPeriod == NULL) - { - mPeriod = _Period; - } - - // - switch (mPeriod) - { - // - case PERIOD_M1: - case PERIOD_M2: - case PERIOD_M3: - case PERIOD_M4: - result = PERIOD_M5; - break; - - // - case PERIOD_M5: - case PERIOD_M6: - case PERIOD_M10: - case PERIOD_M12: - result = PERIOD_M15; - break; - - // - case PERIOD_M15: - case PERIOD_M20: - result = PERIOD_M30; - break; - - // - case PERIOD_M30: - result = PERIOD_H1; - break; - - // - case PERIOD_H1: - case PERIOD_H2: - case PERIOD_H3: - result = PERIOD_H4; - break; - - // - case PERIOD_H4: - case PERIOD_H6: - case PERIOD_H8: - result = PERIOD_H12; - break; - - // - case PERIOD_H12: - result = PERIOD_D1; - break; - - // - case PERIOD_D1: - result = PERIOD_W1; - break; - - // - case PERIOD_W1: - result = PERIOD_MN1; - break; - - // - default: - result = PERIOD_MN1; - break; - } - - // - return result; -} - -// -// Get Specific Time Frame Start Candle Time ... -datetime GetPeriodStartTime( - string mSymbol = NULL, // Specified Symbol ... - ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... - datetime mTime = NULL // Specified Bar Time ... -) -{ - // - // Normalize Arg ... - - // - if ( - mSymbol == NULL || - StringLen(mSymbol) == 0) - { - mSymbol = _Symbol; - } - - // - if ( - mPeriod < 0 || - mPeriod == NULL) - { - mPeriod = _Period; - } - - // - if ( - mTime < 0 || - mTime == NULL) - { - mTime = TimeCurrent(); - } - - // - int barIndex = iBarShift( - mSymbol, - mPeriod, - mTime, - false); - - // datetime result = iTime( mSymbol, mPeriod, @@ -4939,55 +3041,549 @@ datetime GetPeriodStartTime( } // -struct XCandleRemains +// Retrieve Specified Bar Time ... +ulong GetBarTimeAsSeconds( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) { // - int days; - int hours; - int minutes; - int seconds; -}; + // Retrieve Bar Time ... + datetime time = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} // -string ToString( - XCandleRemains &item, - string dayId = "d", - string hourId = "h", - string minuteId = "m", - string secondId = "s", - string idSeparator = ": ", - string separator = ", ", - bool ignoreZeroValues = true) +// Retrieve Specified Bar Time ... +ulong GetBarTimeAsMilliSeconds( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Retrieve Bar Time ... + datetime time = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +// Retrieve a Bar Time Structure ... +MqlDateTime GetBarTimeStruct( + string mSymbol = "", // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + MqlDateTime result = {}; + + // + // Retrieve Bar Time ... + datetime barTime = GetBarTime( + mSymbol, + mPeriod, + barIndex); + + // + // Convert to Structure ... + TimeToStruct(barTime, result); + + // + return result; +} + +// +// Other Tools ... + +// +// Check first Cross Over second at index ... +bool IsCrossedOver( + const double &first[], // the buffer which check crossing over second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] > second[index] && + !(first[index + 1] > second[index + 1]); + + // + return result; +} + +// +// Check first is Over second at index ... +bool IsOver( + const double &first[], // the buffer which check over second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] > second[index] && + first[index + 1] > second[index + 1]; + + // + return result; +} + +// +// Check first Cross Under second at index ... +bool IsCrossedUnder( + const double &first[], // the buffer which check crossing under second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] < second[index] && + !(first[index + 1] < second[index + 1]); + + // + return result; +} + +// +// Check first is Under second at index ... +bool IsUnder( + const double &first[], // the buffer which check under second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] < second[index] && + first[index + 1] < second[index + 1]; + + // + return result; +} + +// +// Calculate Slope of Specified Buffer at Specified Index ... +double GetSlope( + const double &buffer[], // Buffer + int from, // In Past Index ... + int to // In Past Index ... +) +{ + // + double result = 0; + + // + if (from > ArraySize(buffer) || to > ArraySize(buffer)) + { + return result; + } + + // + double toValue = buffer[to]; + double fromValue = buffer[from]; + double deltaValue = toValue - fromValue; + double deltaTime = from - to; + + // + result = deltaValue / deltaTime; + + // + return result; +} + +// +// Calculate Fib Level ... +double GetFibonacciLevel( + double upPrice, // Upper Bound + double downPrice, // Downer Bound + double level, // Level Multiplier Factor + int direction // From Down to Up < 0, other wise Vice Versa + // +) +{ + // + double ling = upPrice - downPrice; + double pLevel = (ling / 100) * (level * 100); + + // + double result = direction > 0 ? upPrice - pLevel : downPrice + pLevel; + + // + return result; +} + +// +// Templates ... + +// +// Retrieve Specific Object Types Name ... +template +string GetTypeName(const T &t) +{ + return typename(T); +} + +// +// Generate Unique Tags ... +template +string GenerateTag(T &model) { // string result = ""; // - // Days ... - if (!ignoreZeroValues || item.days > 0) + string tag = model.ToString(); + if (StringLen(tag) == 0) { - result += dayId + idSeparator + (string)item.days + separator; + return result; } // - // Hours ... - if (!ignoreZeroValues || item.hours > 0) + static XSCMD5 md5; + + // + result = md5.Hash(tag); + + // + return result; +} + +// +// Hash Specified Content ... +template +string ToMD5(T content) +{ + // + string result = ""; + + // + string strContent = ToString(content); + if (StringLen(strContent) == 0) { - result += hourId + idSeparator + (string)item.hours + separator; + return result; } // - // Minutes ... - if (!ignoreZeroValues || item.minutes > 0) + static XSCMD5 md5; + + // + result = md5.Hash(strContent); + + // + return result; +} + +// +// Check a Value Not Empty ... +template +bool NotEmpty(T value) +{ + return value != EMPTY_VALUE; +} + +// +// Add Specified Item to Array ... +template +int Add( + T item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + int result = 0; + + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; + + // + result = ArraySize(buffer); + + // + return result; +} +template +int AddRef( + T &item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + int result = 0; + + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; + + // + result = ArraySize(buffer); + + // + return result; +} + +// +// Remove Specified Item from an Array ... +template +bool Remove( + T item, + T &buffer[]) +{ + // + bool result = false; + + // + int itemIndex = FindIndex( + item, + buffer); + if (itemIndex < 0) { - result += minuteId + idSeparator + (string)item.minutes + separator; + return result; } // - // Seconds ... - if (!ignoreZeroValues || item.seconds > 0) + result = ArrayRemove( + buffer, + itemIndex, + 1); + + // + return result; +} + +// +// Clean Specified Array ... +template +void Clean(T &buffer[]) +{ + // + ArrayFree(buffer); + ArrayResize(buffer, 0); +} + +// +// Copy Whole Content of Source to Dest array ... +template +void Copy( + T &source[], // Source Buffer ... + T &dest[], // Dest Buffer ... + bool cleanDest = true // Force Clen Dest Buffer ... +) +{ + // + if (cleanDest) { - result += secondId + idSeparator + (string)item.seconds; + Clean(dest); + } + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + AddRef( + iSource, + dest); + } +} + +// +// Copy Items from a Buffer ... +template +int Copy( + int start, // Start + int count, // Number of Items for read + T &source[], // Source Buffer + T &dest[], // Dest Buffer + bool forceClean = true // Force To Clean buffer +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(dest); + } + + // + if (start < 0) + { + start = 0; + } + + // + if (start >= ArraySize(source)) + { + start = ArraySize(source) - 1; + } + + // + int beforeSize = ArraySize(dest); + + // + bool asSeriesDest = ArrayGetAsSeries(dest); + bool asSeriesSource = ArrayGetAsSeries(source); + + // + ArraySetAsSeries(dest, true); + ArraySetAsSeries(source, true); + + // + ArrayCopy( + dest, + source, + 0, + start, + count + // + ); + + // + int afterSize = ArraySize(dest); + + // + result = afterSize - beforeSize; + + // + ArraySetAsSeries(dest, asSeriesDest); + ArraySetAsSeries(source, asSeriesSource); + + // + return result; +} + +// +// Retrive Last Item of Specified Buffer ... +template +bool GetLastItem( + T &item, // Holds Result + T &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + item = buffer[bufferSize - 1]; + + // + result = true; + return result; +} + +// +// Search Array For Specific Item ... +template +int FindIndex( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + int result = -1; + + // + int count = ArraySize(buffer); + if (count <= 0) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + T iT = buffer[i]; + + // + if (iT == item) + { + // + result = i; + break; + } } // @@ -4995,65 +3591,1277 @@ string ToString( } // -// Retrieve Specific Candles Ramained Time ... -void GetCandleRemainsTime( - XCandleRemains &result, // Holds Result ... - string mSymbol = NULL, // Specified Symbol ... - ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... - int mBarIndex = 0 // Specified Bar Index ... +// Check an Array Contains Specified Value ... +template +bool Contains( + T item, // What is Search ... + T &buffer[] // Search in ... ) { // - int minuteSecoonds = 60; - int hourSeconds = minuteSecoonds * 60; - int daySeconds = 24 * hourSeconds; + bool result = false; // - int periodSeconds = PeriodSeconds( + int idx = FindIndex( + item, + buffer); + result = idx > -1; + + // + return result; +} + +// +// Calculate a Buffer's Average ... +template +double GetAverage( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Calculate Summary ... + for (int i = 0; i < tmpCount; i++) + { + result += buffer[i]; + } + + // + // Calculate Average ... + result = result / tmpCount; + + // + return result; +} + +// +// Get Max of Specific Loopback of a Buffer ... +template +double GetMax( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + double iValue = tmp[i]; + + // + result = + // + result == 0 || result < iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} + +// +// Get Min of Specific Loopback of a Buffer ... +template +double GetMinValue( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + double iValue = tmp[i]; + + // + result = + // + result == 0 || result > iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} + +// +// Find a Value less than Specified ... +template +T FindLesserThanValue( + T value, // Specified Value ... + const T &source[], // Source ... + bool isDescend = false // Find Biggest Lesser Value ... +) +{ + // + T result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source)); + + // + ArrayCopy( + tmp, + source); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue < value) + { + // + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find a Value less than Specified ... +template +T FindBiggerThanValue( + T value, // Specified Value ... + const T &source[], // Source ... + bool isDescend = false // Find Smallest Bigger Value ... +) +{ + // + T result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source)); + + // + ArrayCopy( + tmp, + source); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (!isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue > value) + { + // + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find Same Values in Array ... +template +void FindSameValues( + T &result[], // Holds Result ... + T &source[], // Source ... + int verifications = 3 // Number of Consequence Repeat ... +) +{ + // + Clean(result); + + // + // TenkanSen Flats ... + int sourceCount = ArraySize(source); + if (sourceCount > verifications) + { + // + T mLast = 0; + int mVerified = 0; + for (int i = 0; i < sourceCount; i++) + { + // + T iVal = source[i]; + if (mLast == 0) + { + mLast = iVal; + } + else if (mLast == iVal) + { + mVerified++; + } + else + { + mLast = iVal; + mVerified = 0; + } + + // + if (iVal == mLast && mVerified >= verifications) + { + // + Add( + iVal, + result); + + // + mLast = 0; + mVerified = 0; + } + } + } +} + +// +// Add an Item to a Buffer if not Exists ... +void AddIfNotExists( + double value, + double &values[], + double smoothingPoint = 3) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int valuesCount = ArraySize(values); + if (valuesCount <= 0) + { + // + Add(value, + values); + } + else + { + // + bool isExists = false; + for (int i = 0; i < valuesCount; i++) + { + // + double iVal = values[i]; + + // + double diff = MathAbs(iVal - value); + + // + if (iVal == value || diff < smoothingValue) + { + // + isExists = true; + break; + } + } + + // + if (!isExists) + { + // + Add(value, + values); + } + } +} + +// +// Add a Buffers Child to another Buffer +// if it's not Contains them ... +void AddsIfNotExists( + double &source[], + double &dest[], + double smoothingPoint = 3) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + double iSource = source[i]; + + // + AddIfNotExists( + iSource, + dest, + smoothingPoint); + } +} + +// +// Bar XOHCL ... + +// +// Extract Specific Range of Bars ... +// using Start Bar Index ... +int GetBars( + XOHCL &result[], // Hold Result + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame + int from = 0, // Start Bar Index + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array +) +{ + // + int mResult = 0; + + // + if (from < 0) + { + from = 0; + } + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int total = Bars( + mSymbol, mPeriod); - datetime startTime = GetCandleTime( + if (from > total - 2) + { + from = total - 2; + } + + // + if (count < 0) + { + count = 1; + } + + // + int start = from; + int end = start + count; + if (end > total - 1) + { + end = total - 1; + } + + // + if (forceClean) + { + Clean(result); + } + + // + int beforeSize = ArraySize(result); + + // + for (int i = start; i < end; i++) + { + // + XOHCL iBar; + bool isValid = iBar.Init( + mSymbol, + mPeriod, + i + // + ); + + // + if (isValid) + { + // + AddRef( + iBar, + result + // + ); + } + } + + // + int afterSize = ArraySize(result); + + // + mResult = afterSize - beforeSize; + + // + return mResult; +} + +// +// Extract Specific Range of Bars ... +// using Start Bar Time ... +int GetBars( + XOHCL &result[], // Hold Result + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame + datetime from = NULL, // Start Bar Time + int count = 1, // Number of Bars + bool forceClean = true // Clean Result Array +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + from = NormalizeTime(from); + + // + int barIndex = iBarShift( mSymbol, mPeriod, - mBarIndex); - - // - int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent(); - - // - int days = 0; - int hours = 0; - int minutes = 0; - int seconds = 0; - - // - int mWorkingSecondsDiff = secondsDiff; - if (mWorkingSecondsDiff > daySeconds) - { + from, + false // - days = mWorkingSecondsDiff / daySeconds; - mWorkingSecondsDiff -= days * daySeconds; - } - if (mWorkingSecondsDiff > hourSeconds) - { - // - hours = mWorkingSecondsDiff / hourSeconds; - mWorkingSecondsDiff -= hours * hourSeconds; - } - if (mWorkingSecondsDiff > minuteSecoonds) - { - // - minutes = mWorkingSecondsDiff / minuteSecoonds; - mWorkingSecondsDiff -= minutes * minuteSecoonds; - } - seconds = mWorkingSecondsDiff; + ); // - result.days = days; - result.hours = hours; - result.minutes = minutes; - result.seconds = seconds; + return GetBars( + result, + mSymbol, + mPeriod, + barIndex, + count, + forceClean + // + ); } +// +// String ... + +// +// Convert From String ... +template +T FromString(string value) +{ + // + T result = NULL; + + // + if (!IsValid(value)) + { + return result; + } + + // + result = (T)value; + + // + return result; +} + +// +// Converts an item to String ... +template +string ToString(T value) +{ + return (string)value; +} + +// +// Converts a Buffer to String Representation ... +template +string ToString( + const T &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} + +// +// Converts String to boolean ... +bool ToBoolean(string value) +{ + // + bool result = false; + + // + if (StringLen(value) <= 0) + { + return result; + } + + // + StringToLower(value); + result = value == "true"; + + // + return result; +} + +// +// Split an String Representation of an Array ... +int SplitContent( + string &result[], // Hold Result ... + string content, // Source ... + string separator = ",", // Separator ... + bool forceCleanResult = true // Clean Result ... +) +{ + // + int mResult = 0; + + // + if (forceCleanResult) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + if (separator == NULL || StringLen(separator) == 0) + { + separator = ","; + } + + // + if (StringLen(content) == 0) + { + return mResult; + } + + // + StringSplit( + content, + StringGetCharacter( + separator, + 0), + result); + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; +} + +// +// Extract Data from String ... +string ExtractString( + const string source, // Source String used for Extracting + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + string result = ""; + + // + // Validate String ... + if ( + StringLen(source) == 0 || + StringLen(endString) == 0 || + StringLen(startString) == 0) + { + return result; + } + + // + // Find Start String Position ... + int sPos = StringFind( + source, + startString); + if (sPos < 0) + { + return result; + } + + // + // Find End String Position after Start String ... + int searchEndFromPos = sPos + StringLen(startString); + int ePos = StringFind( + source, + endString, + searchEndFromPos); + if (ePos < 0) + { + return result; + } + + // + // Extract Data from Source ... + int dLength = ePos - searchEndFromPos; + result = StringSubstr( + source, + searchEndFromPos, + dLength); + + // + return result; +} + +// +// Extract an Array of Contents ... +int ExtractStrings( + string &result[], // Hold Result + const string source, // Source String used for Extracting + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + int mResult = 0; + + // + Clean(result); + + // + // Validate Args ... + int sourceLength = StringLen(source); + int startLength = StringLen(startString); + int endLength = StringLen(endString); + + // + int minRequiredLength = startLength + endLength; + + // + if ( + endLength <= 0 || + startLength <= 0 || + sourceLength <= 0 || + sourceLength < minRequiredLength) + { + return mResult; + } + + // + // Make a Copy of Source for Manipulating ... + string workStr = source; + + // + // Define a Loop ... + while (StringLen(workStr) > minRequiredLength) + { + // + // Find Item ... + string item = ExtractString( + workStr, + startString, + endString); + + // + // Breakout when couldn't find anymore item ... + int itemLength = StringLen(item); + if (itemLength <= 0) + { + break; + } + + // + // Prepare Item Source String for Replacing in Work String ... + string itemSource = startString + item + endString; + + // + // Add Item to Result Array ... + Add( + item, + result); + + // + // Replace Item Soure in Work String ... + StringReplace( + workStr, + itemSource, + ""); + } + + // + // Calculate Size of Array ... + mResult = ArraySize(result); + + // + return mResult; +} + +// +string ExtractSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + return ExtractString( + surrounded, + mToken + startString, + endString + // + ); +} + +// +int ParseIntSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + int result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (int)strContent; + + // + return result; +} +long ParseLongSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + long result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (long)strContent; + + // + return result; +} +string ParseStringSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + string result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (string)strContent; + + // + return result; +} +double ParseDoubleSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + double result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (double)strContent; + + // + return result; +} +datetime ParseTimeSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + datetime result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (datetime)strContent; + + // + return result; +} + +// +int ParseIntArraySurrounded( + int &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + int iValue = (int)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} +int ParseLongArraySurrounded( + long &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + long iValue = (long)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} +int ParseDoubleArraySurrounded( + double &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + double iValue = (double)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} + +// +// Surround an String by Specific Token ... +template +string Surround( + string mToken, // an String which used to Tokenize + T &value, // a Value for Tokenize it + string startString = "(", // Token Start Content + string endString = ")" // Token End Content +) +{ + // + string result = NULL; + + // + string strValue = ToString(value); + if (!IsValid(strValue)) + { + return result; + } + + // + result = + // + (IsValid(mToken) + ? mToken + : "") + + // + startString + + strValue + + endString + // + ; + + // + return result; +} + +// +// Periods / Cycles ... + // // Converts an String to TimeFrame ... ENUM_TIMEFRAMES ToPeriod(string value) @@ -5163,13 +4971,13 @@ ENUM_TIMEFRAMES ToPeriod(string value) // // Converts Period to String ... -string ToString(ENUM_TIMEFRAMES period) +string ToString(ENUM_TIMEFRAMES mPeriod) { // string result = ""; // - string mPStr = EnumToString(period); + string mPStr = EnumToString(mPeriod); string mPStrParts[]; int partsCount = StringSplit( @@ -5189,5 +4997,622 @@ string ToString(ENUM_TIMEFRAMES period) } // -// END Provided Functions ... +// Retrieve All Available Period as an Array ...s +int GetAllAvailablePeriods( + ENUM_TIMEFRAMES &result[] // Holds Result ... +) +{ + // + Clean(result); + + // + Add( + PERIOD_M1, + result + // + ); + + // + Add( + PERIOD_M2, + result + // + ); + + // + Add( + PERIOD_M3, + result + // + ); + + // + Add( + PERIOD_M4, + result + // + ); + + // + Add( + PERIOD_M5, + result + // + ); + + // + Add( + PERIOD_M6, + result + // + ); + + // + Add( + PERIOD_M10, + result + // + ); + + // + Add( + PERIOD_M12, + result + // + ); + + // + Add( + PERIOD_M15, + result + // + ); + + // + Add( + PERIOD_M20, + result + // + ); + + // + Add( + PERIOD_M30, + result + // + ); + + // + Add( + PERIOD_H1, + result + // + ); + + // + Add( + PERIOD_H2, + result + // + ); + + // + Add( + PERIOD_H3, + result + // + ); + + // + Add( + PERIOD_H4, + result + // + ); + + // + Add( + PERIOD_H6, + result + // + ); + + // + Add( + PERIOD_H8, + result + // + ); + + // + Add( + PERIOD_H12, + result + // + ); + + // + Add( + PERIOD_D1, + result + // + ); + + // + Add( + PERIOD_W1, + result + // + ); + + // + Add( + PERIOD_MN1, + result + // + ); + + // + int mResult = ArraySize(result); + + // + return mResult; +} + // +// Get Specific Time Frame Start Candle Time ... +datetime GetPeriodStartTime( + string mSymbol = NULL, // Specified Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... + datetime mTime = NULL // Specified Bar Time of Host Period ... +) +{ + // + // Normalize Arg ... + mTime = NormalizeTime(mTime); + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false + // + ); + + // + datetime result = GetBarTime( + mSymbol, + mPeriod, + barIndex + // + ); + + // + return result; +} + +// +// Converts an String to it's related Market Cycle ... +ENUM_X_MARKET_CYCLES ToCycle(string value) +{ + // + ENUM_X_MARKET_CYCLES result = X_MARKET_CYCLE_UNKNOWN; + + // + ENUM_X_MARKET_CYCLES cycles[]; + int count = GetAllMarketCycles(cycles); + for (int i = 0; i < count; i++) + { + // + ENUM_X_MARKET_CYCLES iCycle = cycles[i]; + string iStr = ToString(iCycle); + + // + if (value == iStr) + { + // + result = iCycle; + break; + } + } + + // + return result; +} + +// +// Converts a Cycle to it's String Representation ... +string ToString(ENUM_X_MARKET_CYCLES cycle) +{ + // + string result = ""; + + // + string mPStr = EnumToString(cycle); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[3]; + + // + return result; +} + +// +// Retrieve all Available Cycles ... +int GetAllMarketCycles(ENUM_X_MARKET_CYCLES &result[]) +{ + // + int mResult = 0; + + // + Clean(result); + + // + ENUM_X_MARKET_CYCLES tmp[] = { + X_MARKET_CYCLE_UNKNOWN, + X_MARKET_CYCLE_SHORT, + X_MARKET_CYCLE_MEDIUM, + X_MARKET_CYCLE_LONG, + X_MARKET_CYCLE_HIND}; + + // + Copy( + tmp, + result); + + // + Clean(tmp); + + // + mResult = ArraySize(result); + + // + return mResult; +} + +// +// Retrieve Nearest Period base on Given Period ... +ENUM_TIMEFRAMES GetNearestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + result = PERIOD_M4; + break; + + // + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_M6; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_M15; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_M30; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H4; + break; + + // + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_H12; + break; + + // + case PERIOD_H12: + result = PERIOD_D1; + break; + + // + case PERIOD_D1: + result = PERIOD_W1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Retrieve Mediest Period base on Given Period ... +ENUM_TIMEFRAMES GetMediestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + result = PERIOD_M15; + break; + + // + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_M30; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_H1; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_H2; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H8; + break; + + // + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_D1; + break; + + // + case PERIOD_H12: + result = PERIOD_W1; + break; + + // + case PERIOD_D1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Retrieve Longest Period base on Given Period ... +ENUM_TIMEFRAMES GetLongestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + result = PERIOD_M30; + break; + + // + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_H1; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_H2; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_H4; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_H12; + break; + + // + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_W1; + break; + + // + case PERIOD_H12: + result = PERIOD_MN1; + break; + + // + case PERIOD_D1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Retrieve Hindmost Period base on Given Period ... +ENUM_TIMEFRAMES GetHindMostPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + result = PERIOD_H1; + break; + + // + case PERIOD_M3: + case PERIOD_M4: + result = PERIOD_H2; + break; + + // + case PERIOD_M5: + case PERIOD_M6: + case PERIOD_M10: + case PERIOD_M12: + result = PERIOD_H4; + break; + + // + case PERIOD_M15: + case PERIOD_M20: + result = PERIOD_H8; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + case PERIOD_H3: + result = PERIOD_D1; + break; + + // + case PERIOD_H6: + case PERIOD_H8: + result = PERIOD_MN1; + break; + + // + case PERIOD_H12: + result = PERIOD_MN1; + break; + + // + case PERIOD_D1: + result = PERIOD_MN1; + break; + + // + default: + result = PERIOD_MN1; + break; + } + + // + return result; +} + +// +// Retrieve Specified Cycles Period related to Host Period ... +ENUM_TIMEFRAMES GetCyclePeriod( + ENUM_X_MARKET_CYCLES mCycle = NULL, // Specified Cycle + ENUM_TIMEFRAMES mPeriod = NULL // Host Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + mPeriod = NormalizePeriod(mPeriod); + mCycle = NormalizeCycle(mCycle); + + // + switch (mCycle) + { + // + // Short ... + case X_MARKET_CYCLE_SHORT: + result = GetNearestPeriod(mPeriod); + break; + + // + // Medium ... + case X_MARKET_CYCLE_MEDIUM: + result = GetMediestPeriod(mPeriod); + break; + + // + // Long ... + case X_MARKET_CYCLE_LONG: + result = GetLongestPeriod(mPeriod); + break; + + // + // Hind ... + case X_MARKET_CYCLE_HIND: + result = GetHindMostPeriod(mPeriod); + break; + } + + // + return result; +} \ No newline at end of file diff --git a/MQLTestWorkspace/Libraries/x-saherelm.draw.lib.ex5 b/MQLTestWorkspace/Libraries/x-saherelm.draw.lib.ex5 index 4f61b18..663a701 100644 Binary files a/MQLTestWorkspace/Libraries/x-saherelm.draw.lib.ex5 and b/MQLTestWorkspace/Libraries/x-saherelm.draw.lib.ex5 differ diff --git a/MQLTestWorkspace/Libraries/x-saherelm.draw.lib.mq5 b/MQLTestWorkspace/Libraries/x-saherelm.draw.lib.mq5 index 7771f54..b714aba 100644 --- a/MQLTestWorkspace/Libraries/x-saherelm.draw.lib.mq5 +++ b/MQLTestWorkspace/Libraries/x-saherelm.draw.lib.mq5 @@ -30,11 +30,15 @@ // Include Logger Library ... #include "x-saherelm.log.lib.mq5" #include "x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xmd5.class.mq5" // // START Global Definitions: Variables, Properties and etc ... +// + // string drawPrefix = "X-OBJ"; + // // END Global Definitions: Variables, Properties and etc ... // @@ -42,6 +46,7 @@ string drawPrefix = "X-OBJ"; // // START Provided Functions ... // + // // DeInitial Library if required ... void OnDeinitDrawLibrary() @@ -53,7 +58,7 @@ void OnDeinitDrawLibrary() // remove drawn objects ... void RemoveDraws( string tag = NULL, - int chartId = -1, + long chartId = -1, int subWindow = -1) { // @@ -95,7 +100,7 @@ void RemoveDraws( // bool RemoveDraw( string name, - int chartId = -1, + long chartId = -1, int subWindow = -1) { // @@ -156,7 +161,7 @@ void DeselectAllDraws() // Check Object Exists ... bool IsDrawExists( string name, - int chartId = -1, + long chartId = -1, int subWindow = -1) { // @@ -189,6 +194,7 @@ bool IsDrawExists( // return result; } + // // END Provided Functions ... // @@ -200,6 +206,7 @@ bool IsDrawExists( // // START Arrow Functions ... // + // // Draw an Arrow Object on Chart ... bool DrawArrow( @@ -464,6 +471,7 @@ void ChangeArrowEmptyPoint( price = SymbolInfoDouble(_Symbol, SYMBOL_BID); } } + // // END Arrow Functions ... // @@ -471,6 +479,7 @@ void ChangeArrowEmptyPoint( // // START Horizontal Line Functions ... // + // // Create, Draw the horizontal line ... bool DrawHorizontalLine( @@ -629,6 +638,7 @@ bool DeleteHorizontalLine( // successful execution ... return true; } + // // END Horizontal Line Functions ... // @@ -636,6 +646,7 @@ bool DeleteHorizontalLine( // // START Vertical Line Functions ... // + // // Create the vertical line ... bool DrawVerticalLine( @@ -794,13 +805,200 @@ bool DeleteVerticalLine( // successful execution ... return true; } + // // END Vertical Line Functions ... // +// +// START Rectangle Functions ... +// + +// +// Create rectangle by the given coordinates ... +bool DrawRectangle( + const long chartID = 0, // chart's ID + const string name = "Rectangle", // rectangle name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrRed, // rectangle color + const ENUM_LINE_STYLE style = STYLE_SOLID, // style of rectangle lines + const int width = 1, // width of rectangle lines + const bool fill = false, // filling rectangle with color + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Set anchor points' coordinates if they are not set ... + ChangeRectangleEmptyPoints(time1, price1, time2, price2); + + // + // Create a rectangle by the given coordinates ... + result = ObjectCreate(chartID, name, OBJ_RECTANGLE, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // Set rectangle color ... + ObjectSetInteger(chartID, name, OBJPROP_COLOR, clr); + + // + // Set the style of rectangle lines + ObjectSetInteger(chartID, name, OBJPROP_STYLE, style); + + // + // Set width of the rectangle lines ... + ObjectSetInteger(chartID, name, OBJPROP_WIDTH, width); + + // + // Enable (true) or disable (false) the mode of filling the rectangle ... + ObjectSetInteger(chartID, name, OBJPROP_FILL, fill); + + // + // Display in the foreground (false) or background (true) ... + ObjectSetInteger(chartID, name, OBJPROP_BACK, back); + + // + // Enable (true) or disable (false) the mode of highlighting the rectangle for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object + ObjectSetInteger(chartID, name, OBJPROP_SELECTABLE, selection); + + // + ObjectSetInteger(chartID, name, OBJPROP_SELECTED, selection); + + // + // Hide (true) or display (false) graphical object name in the object list ... + ObjectSetInteger(chartID, name, OBJPROP_HIDDEN, hidden); + + // + // Set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, name, OBJPROP_ZORDER, zOrder); + + // + // Successful execution + return result; +} + +// +// Move the rectangle anchor point ...s +bool RectanglePointChange( + const long chartID = 0, // chart's ID + const string name = "Rectangle", // rectangle name + const int pointIndex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // Move the anchor point ... + result = ObjectMove(chartID, name, pointIndex, time, price); + if (!result) + { + return result; + } + + // + // Successful execution + return result; +} + +// +// Delete the rectangle ... +bool DeleteRectangle( + const long chartID = 0, // chart's ID + const string name = "Rectangle" // rectangle name +) +{ + // + bool result = false; + + // + result = ObjectDelete(chartID, name); + + // + return result; +} + +// +// Check the values of rectangle's anchor points and set default +// values for empty ones +void ChangeRectangleEmptyPoints( + datetime &time1, double &price1, + datetime &time2, double &price2) +{ + // + // if the first point's time is not set, it will be on the current bar ... + if (!time1) + { + time1 = TimeCurrent(); + } + + // + // if the first point's price is not set, it will have Bid value ... + if (!price1) + { + price1 = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // if the second point's time is not set, it is located 9 bars left from the second one ... + if (!time2) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time1, 10, temp); + + // + // set the second point 9 bars left from the first one ... + time2 = temp[0]; + } + + // + // if the second point's price is not set, move it 300 points lower than the first one ... + if (!price2) + { + price2 = price1 - 300 * SymbolInfoDouble(Symbol(), SYMBOL_POINT); + } +} + +// +// END Rectangle Functions ... +// + // // START RectangleLabel Functions ... // + // // Create Rectangle Label Object ... bool DrawRectangleLabel( @@ -1070,12 +1268,15 @@ bool RectLabelChangeBorderType( // successful execution ... return true; } + // // END RectangleLabel Functions ... // // // START TrendLine Funcions ... +// + // // Create a trend line by the given coordinates ... bool DrawTrendLine( @@ -1296,12 +1497,15 @@ void ChangeTrendLineEmptyPoints( price2 = price1; } } + // // END TrendLine Functions ... // // // START Text Functions ... +// + // // Create and Draw a Text Object ... bool DrawText( @@ -1535,6 +1739,7 @@ void ChangeTextEmptyPoint( price = SymbolInfoDouble(_Symbol, SYMBOL_BID); } } + // // END Text Functions ... // @@ -1542,6 +1747,7 @@ void ChangeTextEmptyPoint( // // START Fibonacchi Functions ... // + // // Create Fibonacci Retracement by the given coordinates ... bool DrawFibonacci( @@ -1936,6 +2142,7 @@ void ChangeFibonacciEmptyPoints( price1 = price2 - 200 * SymbolInfoDouble(_Symbol, SYMBOL_POINT); } } + // // END Fibonacci Functions ... // @@ -2348,6 +2555,7 @@ bool ButtonDelete( // return result; } + // // END Button Functions ... // @@ -2359,6 +2567,7 @@ bool ButtonDelete( // // START Chart Style Drawers ... // + // // Apply Styles On Chart ... void ApplyChartStyle( @@ -2459,4 +2668,941 @@ bool GetChartSize( // // END Chart Style Drawers ... -// \ No newline at end of file +// + +// +// START Custom Drawings ... +// + +// +// Define a Draw Specifications ... +struct XDrawSpecifications +{ + // + // Props ... + + // + bool draw; // Draw or Not ... + + // + int width; // Draw Witdth ... + color clr; // Draw Color ... + ENUM_LINE_STYLE style; // Draw Style ... + + // + bool back; // in the background + bool fill; // fill object if supported + bool selection; // highlight to move + bool rayRight; // line's continuation to the right + bool hidden; // hidden in the object list + long zOrder; // priority for mouse click + + // + string label; // Label ... + color labelColor; // Label Color ... + double labelAngel; // Label Angle ... + string labelFont; // Label Font ... + int labelFontSize; // Label Font Size ... + ENUM_ANCHOR_POINT labelAnchor; // Label Anchor Point ... + + // + // Constructor ... + XDrawSpecifications() + { + Clean(); + } + + // + // Operator ... + void operator=(const XDrawSpecifications &value) + { + // + clr = value.clr; + draw = value.draw; + width = value.width; + style = value.style; + + // + back = value.back; + hidden = value.hidden; + zOrder = value.zOrder; + rayRight = value.rayRight; + selection = value.selection; + + // + fill = value.fill; + + // + label = value.label; + labelColor = value.labelColor; + labelAngel = value.labelAngel; + labelFont = value.labelFont; + labelFontSize = value.labelFontSize; + labelAnchor = value.labelAnchor; + } + + // + // Functions ... + + // + void Clean() + { + // + draw = false; + width = 1; + clr = CLR_NONE; + style = STYLE_SOLID; + + // + back = false; + hidden = false; + rayRight = false; + selection = false; + fill = false; + + // + zOrder = 0; + + // + label = ""; + labelColor = CLR_NONE; + labelAngel = 0; + labelFont = "Arial"; + labelFontSize = 20; + labelAnchor = ANCHOR_LEFT_UPPER; + } + + // + void Label( + string mLabel = "", // Label ... + color mLabelColor = CLR_NONE, // Label Color ... + string mLabelFont = "Arial", // Label Font ... + int mLabelFontSize = 20, // Label Font Size ... + ENUM_ANCHOR_POINT mLabelAnchor = ANCHOR_LEFT_UPPER, // Label Anchor Point ... + double mLabelAngel = 0 // Label Angle ... + ) + { + // + label = mLabel; + labelFont = mLabelFont; + labelColor = mLabelColor; + labelAngel = mLabelAngel; + labelAnchor = mLabelAnchor; + labelFontSize = mLabelFontSize; + } +}; + +// +// Candle Draw Specifications ... +struct XOHCLDrawSpecification +{ + // + // Props ... + XDrawSpecifications openStyle; + XDrawSpecifications highStyle; + XDrawSpecifications closeStyle; + XDrawSpecifications lowStyle; + + // + // Constructors ... + XOHCLDrawSpecification() + { + Clean(); + } + + // + // Operators ... + void operator=(const XOHCLDrawSpecification &value) + { + // + lowStyle = value.lowStyle; + openStyle = value.openStyle; + highStyle = value.highStyle; + closeStyle = value.closeStyle; + } + + // + // Functions ... + + // + void Clean() + { + // + lowStyle.Clean(); + openStyle.Clean(); + highStyle.Clean(); + closeStyle.Clean(); + } + + // + void Default() + { + // + // Open ... + openStyle.width = 1; + openStyle.draw = true; + openStyle.clr = clrLime; + openStyle.style = STYLE_SOLID; + openStyle.Label( + "O", + openStyle.clr); + + // + // High ... + highStyle.width = 1; + highStyle.draw = true; + highStyle.clr = clrAqua; + highStyle.style = STYLE_SOLID; + highStyle.Label( + "H", + highStyle.clr); + + // + // Close ... + closeStyle.width = 1; + closeStyle.draw = true; + closeStyle.clr = clrRed; + closeStyle.style = STYLE_SOLID; + closeStyle.Label( + "C", + closeStyle.clr); + + // + // Low ... + lowStyle.width = 1; + lowStyle.draw = true; + lowStyle.clr = clrMagenta; + lowStyle.style = STYLE_SOLID; + lowStyle.Label( + "L", + lowStyle.clr); + } + + // + void Width(int value) + { + // + lowStyle.width = value; + openStyle.width = value; + highStyle.width = value; + closeStyle.width = value; + } + + // + void Style(ENUM_LINE_STYLE value) + { + // + lowStyle.style = value; + openStyle.style = value; + highStyle.style = value; + closeStyle.style = value; + } + + // + void Color(color value) + { + // + lowStyle.clr = value; + openStyle.clr = value; + highStyle.clr = value; + closeStyle.clr = value; + } + + // + void RayRight(bool value) + { + // + lowStyle.rayRight = value; + openStyle.rayRight = value; + highStyle.rayRight = value; + closeStyle.rayRight = value; + } + + // + void Draw(bool value) + { + // + lowStyle.draw = value; + openStyle.draw = value; + highStyle.draw = value; + closeStyle.draw = value; + } + + // + void Back(bool value) + { + // + lowStyle.back = value; + openStyle.back = value; + highStyle.back = value; + closeStyle.back = value; + } + + // + void Fill(bool value) + { + // + lowStyle.fill = value; + openStyle.fill = value; + highStyle.fill = value; + closeStyle.fill = value; + } + + // + void Label(string value) + { + // + lowStyle.Label(value); + openStyle.Label(value); + highStyle.Label(value); + closeStyle.Label(value); + } + + // + void SetLabelPrefix(string value) + { + // + lowStyle.label = value + " " + lowStyle.label; + openStyle.label = value + " " + openStyle.label; + highStyle.label = value + " " + highStyle.label; + closeStyle.label = value + " " + closeStyle.label; + } +}; + +// +bool RemoveCandle( + XOHCL &c, + long chartId = 0, + int subWindow = 0 // +) +{ + // + bool result = false; + + // + string cTag = GenerateTag(c); + + // + result = IsDrawExists( + cTag, + chartId, + subWindow); + if (!result) + { + return result; + } + + // + RemoveDraws( + cTag, + chartId, + subWindow); + + // + return result; +} + +// +// XOHCL ... +void DrawCandleAsLine( + long chartId, // Chart ID ... + int subWindow, // SubWindow ... + XOHCL &c, // the Candle Which required to Draw ... + const datetime time, // Candle Time ... + XOHCLDrawSpecification &config, // Draw Specifications ... + string tag = "", // Draw Tag ... + bool update = true, // Update Draw if Exists ... + bool drawMidLine = true // Draw Open Close Middle Line ... +) +{ + // + datetime cTime = TimeCurrent(); + XDrawSpecifications specs; + + // + string baseTag = tag + GenerateTag(c); + + // + // Open ... + specs = config.openStyle; + if (specs.draw) + { + // + double value = c.open; + string valueTag = "|O|"; + + // + string mTag = baseTag + valueTag + ToString(value); + string mLblTag = baseTag + valueTag + "_lbl"; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + mTag, + chartId, + subWindow // + ); + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteText( + chartId, + mLblTag // + ); + + // + DeleteTrendLine( + chartId, + mTag // + ); + } + + // + if (canDraw) + { + // + // Draw Label ... + if (StringLen(specs.label) > 0) + { + DrawText( + chartId, + mLblTag, + subWindow, + cTime, + value, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw ... + DrawTrendLine( + chartId, + mTag, + subWindow, + time, + value, + cTime, + value, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); + } + } + + // + // High ... + specs = config.highStyle; + if (specs.draw) + { + // + double value = c.high; + string valueTag = "|H|"; + + // + string mTag = baseTag + valueTag + ToString(value); + string mLblTag = baseTag + valueTag + "_lbl"; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + mTag, + chartId, + subWindow // + ); + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteText( + chartId, + mLblTag // + ); + + // + DeleteTrendLine( + chartId, + mTag // + ); + } + + // + if (canDraw) + { + // + // Draw Label ... + if (StringLen(specs.label) > 0) + { + DrawText( + chartId, + mLblTag, + subWindow, + cTime, + value, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw ... + DrawTrendLine( + chartId, + mTag, + subWindow, + time, + value, + cTime, + value, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); + } + } + + // + // Close ... + specs = config.closeStyle; + if (specs.draw) + { + // + double value = c.close; + string valueTag = "|C|"; + + // + string mTag = baseTag + valueTag + ToString(value); + string mLblTag = baseTag + valueTag + "_lbl"; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + mTag, + chartId, + subWindow // + ); + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteText( + chartId, + mLblTag // + ); + + // + DeleteTrendLine( + chartId, + mTag); + } + + // + if (canDraw) + { + // + // Draw Label ... + if (StringLen(specs.label) > 0) + { + DrawText( + chartId, + mLblTag, + subWindow, + cTime, + value, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw ... + DrawTrendLine( + chartId, + mTag, + subWindow, + time, + value, + cTime, + value, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); + } + } + + // + // Low ... + specs = config.lowStyle; + if (specs.draw) + { + // + double value = c.low; + string valueTag = "|L|"; + + // + string mTag = baseTag + valueTag + ToString(value); + string mLblTag = baseTag + valueTag + "_lbl"; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + mTag, + chartId, + subWindow // + ); + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteText( + chartId, + mLblTag // + ); + + // + DeleteTrendLine( + chartId, + mTag); + } + + // + if (canDraw) + { + // + // Draw Label ... + if (StringLen(specs.label) > 0) + { + DrawText( + chartId, + mLblTag, + subWindow, + cTime, + value, + specs.label, + specs.labelFont, + specs.labelFontSize, + specs.labelColor, + specs.labelAngel, + specs.labelAnchor, + specs.back, + specs.selection, + specs.hidden, + specs.zOrder // + ); + } + + // + // Draw ... + DrawTrendLine( + chartId, + mTag, + subWindow, + time, + value, + cTime, + value, + specs.clr, + specs.style, + specs.width, + specs.back, + specs.selection, + specs.rayRight, + specs.hidden, + specs.zOrder // + ); + } + } +} + +// +void DrawCandleAsBox( + long chartId, // Chart ID ... + int subWindow, // SubWindow ... + XOHCL &c, // the Candle Which required to Draw ... + const datetime time, // Candle Time ... + XOHCLDrawSpecification &config, // Draw Specifications ... + string tag = "", // Draw Tag ... + bool drawBody = true, // Draw Body ... + bool drawShadows = true, // Draw Shadows ... + bool update = true // Update Draw if Exists ... +) +{ + // + datetime cTime = TimeCurrent(); + + // + // First Check all Styles Must Be Draw true ... + bool canDraw = + // + config.openStyle.draw && + config.highStyle.draw && + config.closeStyle.draw && + config.lowStyle.draw + // + ; + + // + if (!canDraw) + { + return; + } + + // + // Next we have to determine Candle is Bullish or Bearish ... + // + bool isBullish = + c.open < c.close; + + // + bool isBearish = + c.open > c.close; + + // + XDrawSpecifications bodySpec; + if (isBullish) + { + bodySpec = config.openStyle; + } + else if (isBearish) + { + bodySpec = config.closeStyle; + } + else + { + // + bodySpec.clr = clrGray; + } + + // + // Now We have to Draw 3 Rectangle ... + // 1- Up Shadow + // 2- Candle Body + // 3- Down Shadow + + // + double upPrice = MathMax(c.open, c.close); + double downPrice = MathMin(c.open, c.close); + double upShadowSize = c.high - upPrice; + double downShadowSize = downPrice - c.low; + + // + string mTag = GenerateTag(c); + + // + // Draw Up Shadow ... + if (drawShadows) + { + // + string upShadowTag = mTag + "|US|"; + + XDrawSpecifications spec = config.highStyle; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + upShadowTag, + chartId, + subWindow // + ); + + // + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteRectangle( + chartId, + upShadowTag // + ); + } + + // + if (canDraw) + { + // + // New ... + DrawRectangle( + chartId, + upShadowTag, + subWindow, + time, + c.high, + cTime, + upPrice, + spec.clr, + spec.style, + spec.width, + spec.fill, + spec.back, + spec.selection, + spec.hidden, + spec.zOrder // + ); + } + } + + // + // Draw Body ... + if (drawBody) + { + // + string bodyTag = mTag + "|BDY|"; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + bodyTag, + chartId, + subWindow // + ); + + // + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteRectangle( + chartId, + bodyTag // + ); + } + + // + if (canDraw) + { + // + // New ... + DrawRectangle( + chartId, + bodyTag, + subWindow, + time, + upPrice, + cTime, + downPrice, + bodySpec.clr, + bodySpec.style, + bodySpec.width, + bodySpec.fill, + bodySpec.back, + bodySpec.selection, + bodySpec.hidden, + bodySpec.zOrder // + ); + } + } + + // + // Draw Down Shadow ... + if (drawShadows) + { + // + string downShadowTag = mTag + "|DS|"; + + XDrawSpecifications spec = config.lowStyle; + + // + // Check if Object Exists Delete it ... + bool isExists = IsDrawExists( + downShadowTag, + chartId, + subWindow // + ); + + // + bool canDraw = !isExists || (isExists && update); + + // + if (isExists && canDraw) + { + // + DeleteRectangle( + chartId, + downShadowTag // + ); + } + + // + if (canDraw) + { + // + // New ... + DrawRectangle( + chartId, + downShadowTag, + subWindow, + time, + downPrice, + cTime, + downPrice + downShadowSize, + spec.clr, + spec.style, + spec.width, + spec.fill, + spec.back, + spec.selection, + spec.hidden, + spec.zOrder // + ); + } + } +} + +// +// END Custom Drawings ... +// diff --git a/MQLTestWorkspace/Libraries/x-saherelm.http.lib.ex5 b/MQLTestWorkspace/Libraries/x-saherelm.http.lib.ex5 index 134ec79..60ca77d 100644 Binary files a/MQLTestWorkspace/Libraries/x-saherelm.http.lib.ex5 and b/MQLTestWorkspace/Libraries/x-saherelm.http.lib.ex5 differ diff --git a/MQLTestWorkspace/Libraries/x-saherelm.log.lib.ex5 b/MQLTestWorkspace/Libraries/x-saherelm.log.lib.ex5 index ef1ae04..60429e2 100644 Binary files a/MQLTestWorkspace/Libraries/x-saherelm.log.lib.ex5 and b/MQLTestWorkspace/Libraries/x-saherelm.log.lib.ex5 differ diff --git a/MQLTestWorkspace/Libraries/x-saherelm.log.lib.mq5 b/MQLTestWorkspace/Libraries/x-saherelm.log.lib.mq5 index 3235c63..ad34125 100644 --- a/MQLTestWorkspace/Libraries/x-saherelm.log.lib.mq5 +++ b/MQLTestWorkspace/Libraries/x-saherelm.log.lib.mq5 @@ -22,16 +22,13 @@ // // START Inputs ... // -input group "Logging"; -input bool enableLogging = true; // Enable Logging +// input group "Logging"; +// input bool enableLogging = true; // Enable Logging +bool enableLogging = true; // Enable Logging // // END Inputs ... // -// -// Including Models ... -#include "x-saherelm.models.lib.mq5" - // // START Global Definitions: Variables, Properties and etc ... // @@ -74,6 +71,22 @@ void LogEmptyLine() LogMessage(" "); } +// +void LogError( + int error = -1 // Specific Error +) { + // + if (error <= -1) { + error = GetLastError(); + } + + // + string errorMsg = GetErrorDescription(error); + + // + LogMessage("Error: " + errorMsg); +} + // // Logging an Array ... void LogArray(int &array[]) @@ -115,3 +128,957 @@ void LogArray(string &array[]) // // END Provided Functions ... // + + +// +// Error Descriptions Functions ... +// + +// +// Retrieve Specified Error Code Description ... +string GetErrorDescription(int err_code) +{ + // + string result = ""; + + // + switch (err_code) + { + // + //--- Constant Description + + // + case ERR_SUCCESS: + result = "The operation completed successfully"; + break; + + // + case ERR_INTERNAL_ERROR: + result = "Unexpected internal error"; + break; + + // + case ERR_WRONG_INTERNAL_PARAMETER: + result = "Wrong parameter in the inner call of the client terminal function"; + break; + + // + case ERR_INVALID_PARAMETER: + result = "Wrong parameter when calling the system function"; + break; + + // + case ERR_NOT_ENOUGH_MEMORY: + result = "Not enough memory to perform the system function"; + break; + + // + case ERR_STRUCT_WITHOBJECTS_ORCLASS: + result = "The structure contains objects of strings and/or dynamic arrays and/or structure of such objects and/or classes"; + break; + + // + case ERR_INVALID_ARRAY: + result = "Array of a wrong type, wrong size, or a damaged object of a dynamic array"; + break; + + // + case ERR_ARRAY_RESIZE_ERROR: + result = "Not enough memory for the relocation of an array, or an attempt to change the size of a static array"; + break; + + // + case ERR_STRING_RESIZE_ERROR: + result = "Not enough memory for the relocation of string"; + break; + + // + case ERR_NOTINITIALIZED_STRING: + result = "Not initialized string"; + break; + + // + case ERR_INVALID_DATETIME: + result = "Invalid date and/or time"; + break; + + // + case ERR_ARRAY_BAD_SIZE: + result = "Requested array size exceeds 2 GB"; + break; + + // + case ERR_INVALID_POINTER: + result = "Wrong pointer"; + break; + + // + case ERR_INVALID_POINTER_TYPE: + result = "Wrong type of pointer"; + break; + + // + case ERR_FUNCTION_NOT_ALLOWED: + result = "System function is not allowed to call"; + break; + + // + //--- Charts + + // + case ERR_CHART_WRONG_ID: + result = "Wrong chart ID"; + break; + + // + case ERR_CHART_NO_REPLY: + result = "Chart does not respond"; + break; + + // + case ERR_CHART_NOT_FOUND: + result = "Chart not found"; + break; + + // + case ERR_CHART_NO_EXPERT: + result = "No Expert Advisor in the chart that could handle the event"; + break; + + // + case ERR_CHART_CANNOT_OPEN: + result = "Chart opening error"; + break; + + // + case ERR_CHART_CANNOT_CHANGE: + result = "Failed to change chart symbol and period"; + break; + + // + case ERR_CHART_CANNOT_CREATE_TIMER: + result = "Failed to create timer"; + break; + + // + case ERR_CHART_WRONG_PROPERTY: + result = "Wrong chart property ID"; + break; + + // + case ERR_CHART_SCREENSHOT_FAILED: + result = "Error creating screenshots"; + break; + + // + case ERR_CHART_NAVIGATE_FAILED: + result = "Error navigating through chart"; + break; + + // + case ERR_CHART_TEMPLATE_FAILED: + result = "Error applying template"; + break; + + // + case ERR_CHART_WINDOW_NOT_FOUND: + result = "Subwindow containing the indicator was not found"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_ADD: + result = "Error adding an indicator to chart"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_DEL: + result = "Error deleting an indicator from the chart"; + break; + + // + case ERR_CHART_INDICATOR_NOT_FOUND: + result = "Indicator not found on the specified chart"; + break; + + // + //--- Graphical Objects + case ERR_OBJECT_ERROR: + result = "Error working with a graphical object"; + break; + + // + case ERR_OBJECT_NOT_FOUND: + result = "Graphical object was not found"; + break; + + // + case ERR_OBJECT_WRONG_PROPERTY: + result = "Wrong ID of a graphical object property"; + break; + + // + case ERR_OBJECT_GETDATE_FAILED: + result = "Unable to get date corresponding to the value"; + break; + + // + case ERR_OBJECT_GETVALUE_FAILED: + result = "Unable to get value corresponding to the date"; + break; + + // + //--- MarketInfo + + // + case ERR_MARKET_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_MARKET_NOT_SELECTED: + result = "Symbol is not selected in MarketWatch"; + break; + + // + case ERR_MARKET_WRONG_PROPERTY: + result = "Wrong identifier of a symbol property"; + break; + + // + case ERR_MARKET_LASTTIME_UNKNOWN: + result = "Time of the last tick is not known (no ticks)"; + break; + + // + case ERR_MARKET_SELECT_ERROR: + result = "Error adding or deleting a symbol in MarketWatch"; + break; + + // + //--- History Access + + // + case ERR_HISTORY_NOT_FOUND: + result = "Requested history not found"; + break; + + // + case ERR_HISTORY_WRONG_PROPERTY: + result = "Wrong ID of the history property"; + break; + + // + //--- Global_Variables + + // + case ERR_GLOBALVARIABLE_NOT_FOUND: + result = "Global variable of the client terminal is not found"; + break; + + // + case ERR_GLOBALVARIABLE_EXISTS: + result = "Global variable of the client terminal with the same name already exists"; + break; + + // + case ERR_MAIL_SEND_FAILED: + result = "Email sending failed"; + break; + + // + case ERR_PLAY_SOUND_FAILED: + result = "Sound playing failed"; + break; + + // + case ERR_MQL5_WRONG_PROPERTY: + result = "Wrong identifier of the program property"; + break; + + // + case ERR_TERMINAL_WRONG_PROPERTY: + result = "Wrong identifier of the terminal property"; + break; + + // + case ERR_FTP_SEND_FAILED: + result = "File sending via ftp failed"; + break; + + // + case ERR_NOTIFICATION_SEND_FAILED: + result = "Error in sending notification"; + break; + + // + //--- Custom Indicator Buffers + + // + case ERR_BUFFERS_NO_MEMORY: + result = "Not enough memory for the distribution of indicator buffers"; + break; + + // + case ERR_BUFFERS_WRONG_INDEX: + result = "Wrong indicator buffer index"; + break; + + // + //--- Custom Indicator Properties + + // + case ERR_CUSTOM_WRONG_PROPERTY: + result = "Wrong ID of the custom indicator property"; + break; + + // + //--- Account + + // + case ERR_ACCOUNT_WRONG_PROPERTY: + result = "Wrong account property ID"; + break; + + // + case ERR_TRADE_WRONG_PROPERTY: + result = "Wrong trade property ID"; + break; + + // + case ERR_TRADE_DISABLED: + result = "Trading by Expert Advisors prohibited"; + break; + + // + case ERR_TRADE_POSITION_NOT_FOUND: + result = "Position not found"; + break; + + // + case ERR_TRADE_ORDER_NOT_FOUND: + result = "Order not found"; + break; + + // + case ERR_TRADE_DEAL_NOT_FOUND: + result = "Deal not found"; + break; + + // + case ERR_TRADE_SEND_FAILED: + result = "Trade request sending failed"; + break; + + // + //--- Indicators + + // + case ERR_INDICATOR_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_INDICATOR_CANNOT_CREATE: + result = "Indicator cannot be created"; + break; + + // + case ERR_INDICATOR_NO_MEMORY: + result = "Not enough memory to add the indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_APPLY: + result = "The indicator cannot be applied to another indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_ADD: + result = "Error applying an indicator to chart"; + break; + + // + case ERR_INDICATOR_DATA_NOT_FOUND: + result = "Requested data not found"; + break; + + // + case ERR_INDICATOR_WRONG_HANDLE: + result = "Wrong indicator handle"; + break; + + // + case ERR_INDICATOR_WRONG_PARAMETERS: + result = "Wrong number of parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_PARAMETERS_MISSING: + result = "No parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_CUSTOM_NAME: + result = "The first parameter in the array must be the name of the custom indicator"; + break; + + // + case ERR_INDICATOR_PARAMETER_TYPE: + result = "Invalid parameter type in the array when creating an indicator"; + break; + + // + case ERR_INDICATOR_WRONG_INDEX: + result = "Wrong index of the requested indicator buffer"; + break; + + // + //--- Depth of Market + + // + case ERR_BOOKS_CANNOT_ADD: + result = "Depth Of Market can not be added"; + break; + + // + case ERR_BOOKS_CANNOT_DELETE: + result = "Depth Of Market can not be removed"; + break; + + // + case ERR_BOOKS_CANNOT_GET: + result = "The data from Depth Of Market can not be obtained"; + break; + + // + case ERR_BOOKS_CANNOT_SUBSCRIBE: + result = "Error in subscribing to receive new data from Depth Of Market"; + break; + + // + //--- File Operations + + // + case ERR_TOO_MANY_FILES: + result = "More than 64 files cannot be opened at the same time"; + break; + + // + case ERR_WRONG_FILENAME: + result = "Invalid file name"; + break; + + // + case ERR_TOO_LONG_FILENAME: + result = "Too long file name"; + break; + + // + case ERR_CANNOT_OPEN_FILE: + result = "File opening error"; + break; + + // + case ERR_FILE_CACHEBUFFER_ERROR: + result = "Not enough memory for cache to read"; + break; + + // + case ERR_CANNOT_DELETE_FILE: + result = "File deleting error"; + break; + + // + case ERR_INVALID_FILEHANDLE: + result = "A file with this handle was closed, or was not opening at all"; + break; + + // + case ERR_WRONG_FILEHANDLE: + result = "Wrong file handle"; + break; + + // + case ERR_FILE_NOTTOWRITE: + result = "The file must be opened for writing"; + break; + + // + case ERR_FILE_NOTTOREAD: + result = "The file must be opened for reading"; + break; + + // + case ERR_FILE_NOTBIN: + result = "The file must be opened as a binary one"; + break; + + // + case ERR_FILE_NOTTXT: + result = "The file must be opened as a text"; + break; + + // + case ERR_FILE_NOTTXTORCSV: + result = "The file must be opened as a text or CSV"; + break; + + // + case ERR_FILE_NOTCSV: + result = "The file must be opened as CSV"; + break; + + // + case ERR_FILE_READERROR: + result = "File reading error"; + break; + + // + case ERR_FILE_BINSTRINGSIZE: + result = "String size must be specified, because the file is opened as binary"; + break; + + // + case ERR_INCOMPATIBLE_FILE: + result = "A text file must be for string arrays, for other arrays - binary"; + break; + + // + case ERR_FILE_IS_DIRECTORY: + result = "This is not a file, this is a directory"; + break; + + // + case ERR_FILE_NOT_EXIST: + result = "File does not exist"; + break; + + // + case ERR_FILE_CANNOT_REWRITE: + result = "File can not be rewritten"; + break; + + // + case ERR_WRONG_DIRECTORYNAME: + result = "Wrong directory name"; + break; + + // + case ERR_DIRECTORY_NOT_EXIST: + result = "Directory does not exist"; + break; + + // + case ERR_FILE_ISNOT_DIRECTORY: + result = "This is a file, not a directory"; + break; + + // + case ERR_CANNOT_DELETE_DIRECTORY: + result = "The directory cannot be removed"; + break; + + // + case ERR_CANNOT_CLEAN_DIRECTORY: + result = "Failed to clear the directory (probably one or more files are blocked and removal operation failed)"; + break; + + // + case ERR_FILE_WRITEERROR: + result = "Failed to write a resource to a file"; + break; + + // + //--- String Casting + + // + case ERR_NO_STRING_DATE: + result = "No date in the string"; + break; + + // + case ERR_WRONG_STRING_DATE: + result = "Wrong date in the string"; + break; + + // + case ERR_WRONG_STRING_TIME: + result = "Wrong time in the string"; + break; + + // + case ERR_STRING_TIME_ERROR: + result = "Error converting string to date"; + break; + + // + case ERR_STRING_OUT_OF_MEMORY: + result = "Not enough memory for the string"; + break; + + // + case ERR_STRING_SMALL_LEN: + result = "The string length is less than expected"; + break; + + // + case ERR_STRING_TOO_BIGNUMBER: + result = "Too large number, more than ULONG_MAX"; + break; + + // + case ERR_WRONG_FORMATSTRING: + result = "Invalid format string"; + break; + + // + case ERR_TOO_MANY_FORMATTERS: + result = "Amount of format specifiers more than the parameters"; + break; + + // + case ERR_TOO_MANY_PARAMETERS: + result = "Amount of parameters more than the format specifiers"; + break; + + // + case ERR_WRONG_STRING_PARAMETER: + result = "Damaged parameter of string type"; + break; + + // + case ERR_STRINGPOS_OUTOFRANGE: + result = "Position outside the string"; + break; + + // + case ERR_STRING_ZEROADDED: + result = "0 added to the string end, a useless operation"; + break; + + // + case ERR_STRING_UNKNOWNTYPE: + result = "Unknown data type when converting to a string"; + break; + + // + case ERR_WRONG_STRING_OBJECT: + result = "Damaged string object"; + break; + + // + //--- Operations with Arrays + + // + case ERR_INCOMPATIBLE_ARRAYS: + result = "Copying incompatible arrays. String array can be copied only to a string array, and a numeric array - in numeric array only"; + break; + + // + case ERR_SMALL_ASSERIES_ARRAY: + result = "The receiving array is declared as AS_SERIES, and it is of insufficient size"; + break; + + // + case ERR_SMALL_ARRAY: + result = "Too small array, the starting position is outside the array"; + break; + + // + case ERR_ZEROSIZE_ARRAY: + result = "An array of zero length"; + break; + + // + case ERR_NUMBER_ARRAYS_ONLY: + result = "Must be a numeric array"; + break; + + // + case ERR_ONEDIM_ARRAYS_ONLY: + result = "Must be a one-dimensional array"; + break; + + // + case ERR_SERIES_ARRAY: + result = "Timeseries cannot be used"; + break; + + // + case ERR_DOUBLE_ARRAY_ONLY: + result = "Must be an array of type double"; + break; + + // + case ERR_FLOAT_ARRAY_ONLY: + result = "Must be an array of type float"; + break; + + // + case ERR_LONG_ARRAY_ONLY: + result = "Must be an array of type long"; + break; + + // + case ERR_INT_ARRAY_ONLY: + result = "Must be an array of type int"; + break; + + // + case ERR_SHORT_ARRAY_ONLY: + result = "Must be an array of type short"; + break; + + // + case ERR_CHAR_ARRAY_ONLY: + result = "Must be an array of type char"; + break; + + // + //--- Operations with OpenCL + + // + case ERR_OPENCL_NOT_SUPPORTED: + result = "OpenCL functions are not supported on this computer"; + break; + + // + case ERR_OPENCL_INTERNAL: + result = "Internal error occurred when running OpenCL"; + break; + + // + case ERR_OPENCL_INVALID_HANDLE: + result = "Invalid OpenCL handle"; + break; + + // + case ERR_OPENCL_CONTEXT_CREATE: + result = "Error creating the OpenCL context"; + break; + + // + case ERR_OPENCL_QUEUE_CREATE: + result = "Failed to create a run queue in OpenCL"; + break; + + // + case ERR_OPENCL_PROGRAM_CREATE: + result = "Error occurred when compiling an OpenCL program"; + break; + + // + case ERR_OPENCL_TOO_LONG_KERNEL_NAME: + result = "Too long kernel name (OpenCL kernel)"; + break; + + // + case ERR_OPENCL_KERNEL_CREATE: + result = "Error creating an OpenCL kernel"; + break; + + // + case ERR_OPENCL_SET_KERNEL_PARAMETER: + result = "Error occurred when setting parameters for the OpenCL kernel"; + break; + + // + case ERR_OPENCL_EXECUTE: + result = "OpenCL program runtime error"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_SIZE: + result = "Invalid size of the OpenCL buffer"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_OFFSET: + result = "Invalid offset in the OpenCL buffer"; + break; + + // + case ERR_OPENCL_BUFFER_CREATE: + result = "Failed to create and OpenCL buffer"; + break; + + // + //--- User-Defined Errors + default: + result = "UNKNOWN Erro ..."; + break; + } + + // + return result; +} + +// +// Retrieve Specified Error Code Description ... +string GetTradeServerReturnCodeDescription(int return_code) +{ + // + string result = ""; + + // + switch (return_code) + { + // + case TRADE_RETCODE_REQUOTE: + result = "Requote"; + break; + + // + case TRADE_RETCODE_REJECT: + result = "Request rejected"; + break; + + // + case TRADE_RETCODE_CANCEL: + result = "Request canceled by trader"; + break; + + // + case TRADE_RETCODE_PLACED: + result = "Order placed"; + break; + + // + case TRADE_RETCODE_DONE: + result = "Request completed"; + break; + + // + case TRADE_RETCODE_DONE_PARTIAL: + result = "Only part of the request was completed"; + break; + + // + case TRADE_RETCODE_ERROR: + result = "Request processing error"; + break; + + // + case TRADE_RETCODE_TIMEOUT: + result = "Request canceled by timeout"; + break; + + // + case TRADE_RETCODE_INVALID: + result = "Invalid request"; + break; + + // + case TRADE_RETCODE_INVALID_VOLUME: + result = "Invalid volume in the request"; + break; + + // + case TRADE_RETCODE_INVALID_PRICE: + result = "Invalid price in the request"; + break; + + // + case TRADE_RETCODE_INVALID_STOPS: + result = "Invalid stops in the request"; + break; + + // + case TRADE_RETCODE_TRADE_DISABLED: + result = "Trade is disabled"; + break; + + // + case TRADE_RETCODE_MARKET_CLOSED: + result = "Market is closed"; + break; + + // + case TRADE_RETCODE_NO_MONEY: + result = "There is not enough money to complete the request"; + break; + + // + case TRADE_RETCODE_PRICE_CHANGED: + result = "Prices changed"; + break; + + // + case TRADE_RETCODE_PRICE_OFF: + result = "There are no quotes to process the request"; + break; + + // + case TRADE_RETCODE_INVALID_EXPIRATION: + result = "Invalid order expiration date in the request"; + break; + + // + case TRADE_RETCODE_ORDER_CHANGED: + result = "Order state changed"; + break; + + // + case TRADE_RETCODE_TOO_MANY_REQUESTS: + result = "Too frequent requests"; + break; + + // + case TRADE_RETCODE_NO_CHANGES: + result = "No changes in request"; + break; + + // + case TRADE_RETCODE_SERVER_DISABLES_AT: + result = "Autotrading disabled by server"; + break; + + // + case TRADE_RETCODE_CLIENT_DISABLES_AT: + result = "Autotrading disabled by client terminal"; + break; + + // + case TRADE_RETCODE_LOCKED: + result = "Request locked for processing"; + break; + + // + case TRADE_RETCODE_FROZEN: + result = "Order or position frozen"; + break; + + // + case TRADE_RETCODE_INVALID_FILL: + result = "Invalid order filling type"; + break; + + // + case TRADE_RETCODE_CONNECTION: + result = "No connection with the trade server"; + break; + + // + case TRADE_RETCODE_ONLY_REAL: + result = "Operation is allowed only for live accounts"; + break; + + // + case TRADE_RETCODE_LIMIT_ORDERS: + result = "The number of pending orders has reached the limit"; + break; + + // + case TRADE_RETCODE_LIMIT_VOLUME: + result = "The volume of orders and positions for the symbol has reached the limit"; + break; + + // + default: + result = "Invalid return code of the trade server"; + break; + } + + // + return result; +} diff --git a/MQLTestWorkspace/Libraries/x-saherelm.models.lib.ex5 b/MQLTestWorkspace/Libraries/x-saherelm.models.lib.ex5 index 6fce75c..cc0ed41 100644 Binary files a/MQLTestWorkspace/Libraries/x-saherelm.models.lib.ex5 and b/MQLTestWorkspace/Libraries/x-saherelm.models.lib.ex5 differ diff --git a/MQLTestWorkspace/Libraries/x-saherelm.seriallizer.lib.ex5 b/MQLTestWorkspace/Libraries/x-saherelm.seriallizer.lib.ex5 index 71e9aa6..f3f3686 100644 Binary files a/MQLTestWorkspace/Libraries/x-saherelm.seriallizer.lib.ex5 and b/MQLTestWorkspace/Libraries/x-saherelm.seriallizer.lib.ex5 differ diff --git a/MQLTestWorkspace/Libraries/x-saherelm.xtrade.lib.mq5 b/MQLTestWorkspace/Libraries/x-saherelm.xtrade.lib.mq5 new file mode 100644 index 0000000..c52370b --- /dev/null +++ b/MQLTestWorkspace/Libraries/x-saherelm.xtrade.lib.mq5 @@ -0,0 +1,3018 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XTradeLib +// Description: All models related to Trade ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Classes/x-saherelm.xdata-collector.mq5" + +// +// Definitions ... + +// +// a List of Used Tokens ... + +// +// Common ... +string XIDToken = "ID"; +string XModeToken = "MD"; +string XTypeToken = "TY"; +string XPeriodToken = "PR"; +string XProviderToken = "PRV"; + +// +string XTPToken = "TP"; +string XSLToken = "SL"; +string XTimeToken = "TM"; +string XEntryToken = "EN"; +string XVolumeToken = "VL"; +string XSymbolToken = "SMBL"; + +// +string XSupportToken = "SP"; +string XEQMSupportToken = "EQM"; + +// +// Available Order Modes ... +enum ENUM_X_ORDER_MODES +{ + X_ORDER_MODE_NOTHING, // Nothing + X_ORDER_MODE_MARKET, // Market Order + X_ORDER_MODE_STOP, // Pending Stop Order + X_ORDER_MODE_LIMIT, // Pending Limit Order + X_ORDER_MODE_STOP_LIMIT, // Pending Stop Limit Order +}; + +// +// Select Positions Type ... +enum ENUM_X_POSITION_SELECT_METHODS +{ + X_POSITION_SELECT_NONE, // None + X_POSITION_SELECT_MAX, // Max + X_POSITION_SELECT_MIN, // Min + X_POSITION_SELECT_BOTH, // Min and Max + X_POSITION_SELECT_ALL, // All +}; + +// +// Signal Execution Result ... +// note that some of them must be handles in +// EA's ... +enum ENUM_X_SIGNAL_EXECUTION_RESULT +{ + // + X_SIGNAL_EXECUTION_UNKNOWN, // Unknown + X_SIGNAL_EXECUTION_SUCCEED, // Succed + X_SIGNAL_EXECUTION_FAILED_NO_EQUITY, // No Equity for Trade + X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR, // Price Error + X_SIGNAL_EXECUTION_FAILED_MAX_REACHED, // Max Allowed Positions Reached + X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS, // Invalid Params +}; + +// +// Structs ... + +// +// Model a Signal ... +struct XSignal +{ + // + // Props ... + + // + ulong positionId; // if Executed this filled ... + double entry; // Exntry or Execution Price ... + double volume; // Position Volume ... + + // + datetime time; // Issue Time ... + + // + double tps[]; // a Collection of TP(s) ... + double sls[]; // a Collection of SL(s) ... + + // + string symbol; // Trading Symbol ... + string provider; // Signaller ... + string comment; // Comment ... + + // + ENUM_TIMEFRAMES period; // Trading TimeFrame ... + ENUM_POSITION_TYPE type; // Long (Buy) or Short (Sell) ... + ENUM_X_ORDER_MODES mode; // Execution Mode ... + + // + XSignal supports[]; // a Collecion of Support Signals ... + XOHCLSupRes supportResistances; // Support and Resistances ... + + // + // Constructor ... + XSignal() + { + Clean(); + } + + // + bool Prepare( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_POSITION_TYPE mType, // Long (Buy) or Short (Sell) + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + bool result = false; + + // + result = + // + IsValid(mMode) && + IsValid(mSymbol) && + IsValid(mPeriod) && + NotEmpty(mEntry) && + NotEmpty(mVolume) && + IsValid(mProvider) + // + ; + if (!result) + { + return result; + } + + // + type = mType; + mode = mMode; + symbol = mSymbol; + period = mPeriod; + provider = mProvider; + + // + // Normalization Values ... + sl = NormalizePrice(sl, mSymbol); + tp = NormalizePrice(tp, mSymbol); + mEntry = NormalizePrice(mEntry, mSymbol); + mVolume = NormalizeVolume(mVolume, mSymbol); + + // + entry = mEntry; + volume = mVolume; + + // + Add( + sl, + sls + // + ); + + // + Add( + tp, + tps + // + ); + + // + time = TimeCurrent(); + + // + result = IsValid(); + + // + return result; + } + + // + bool PrepareLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_BUY, + mMode, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + bool PrepareShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + ENUM_X_ORDER_MODES mMode, // Execution Mode + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_SELL, + mMode, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + // Market Mode ... + + // + bool PrepareMarketLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_BUY, + X_ORDER_MODE_MARKET, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + bool PrepareMarketShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_SELL, + X_ORDER_MODE_MARKET, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + // Stop Mode ... + + // + bool PrepareStopLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_BUY, + X_ORDER_MODE_STOP, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + bool PrepareStopShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_SELL, + X_ORDER_MODE_STOP, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + // Limit Mode ... + + // + bool PrepareLimitLong( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_BUY, + X_ORDER_MODE_LIMIT, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + bool PrepareLimitShort( + string mSymbol, // Trading Symbol + string mProvider, // Signal Provider + ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame + double mEntry, // Entry Price + double mVolume, // Volume + double sl = 0, // Stop Loss + double tp = 0 // Take Profit + ) + { + // + return Prepare( + mSymbol, + mProvider, + mPeriod, + POSITION_TYPE_SELL, + X_ORDER_MODE_LIMIT, + mEntry, + mVolume, + sl, + tp + // + ); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + entry = 0; + volume = 0; + positionId = 0; + + // + time = NULL; + type = NULL; + mode = NULL; + symbol = NULL; + period = NULL; + comment = NULL; + provider = NULL; + + // + Clean(tps); + Clean(sls); + Clean(supports); + supportResistances.Clean(); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(period) && + IsValid(symbol) && + NotEmpty(volume) && + NotEmpty(entry) && + (ArraySize(tps) > 0 || + ArraySize(sls) > 0) + // + ; + + // + return result; + } + + // + // Check Signal Executed or not ... + bool IsExecuted() + { + // + bool result = false; + + // + result = + // + IsValid() && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Generate Comment for Signal ... + string GenerateComment() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + if (IsValid(provider)) + { + // + // Generate Provider Tag ... + result += GenerateProviderTag(provider); + } + + // + if (IsValid(period)) + { + // + // Generate Period Tag ... + result += GeneratePeriodTag(period); + } + + // + return result; + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XSignal &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + mode == value.mode && + entry == value.entry && + volume == value.volume && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId && + ArraySize(sls) == ArraySize(value.sls) && + ArraySize(tps) == ArraySize(value.tps) + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XSignal &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_POSITION_TYPE mType = NULL, // Long (Buy), Short (Sell) + ENUM_X_ORDER_MODES mMode = NULL // Execution Mode + ) + { + // + bool result = false; + + // + result = + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // Mode Filter ... + IsModeFilterPassed( + mMode, + this + // + ) + // + ; + + // + return result; + } + + // + string GetToken() + { + // + string mType = GetTypeName(this); + + // + string result = mType; + + // + string parts[]; + int partsCount = SplitContent( + parts, + result, + " " + // + ); + if (partsCount <= 0) + { + // + result = mType; + return result; + } + + // + bool hasLastPart = GetLastItem( + result, + parts + // + ); + if (!hasLastPart) + { + // + result = mType; + return result; + } + + // + return result; + } + + // + // To String Representation ... + string ToString() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + // For Modeling a Signal we Only Used: + // - Period; + // - Provider; + // - Type; + // - Mode; + // - Symbol; + // - PositionID; + // - Entry; + // - Volume; + // - TPS; + // - SLS; + // - Issue Time; + + // + int iPeriodInt = (int)period; + + // + string periodStr = Surround(XPeriodToken, iPeriodInt); + string providerStr = Surround(XProviderToken, provider); + string typeStr = Surround(XTypeToken, type); + string modeStr = Surround(XModeToken, mode); + string SymbolStr = Surround(XSymbolToken, symbol); + string positionIdStr = Surround(XIDToken, positionId); + string entryStr = Surround(XEntryToken, entry); + string volumeStr = Surround(XVolumeToken, volume); + string timeStr = Surround(XTimeToken, time); + + // + // TP ... + string tpsContentStr = ToString(tps); + string tpsStr = Surround(XTPToken, tpsContentStr); + + // + // SL ... + string slsContentStr = ToString(sls); + string slsStr = Surround(XSLToken, slsContentStr); + + // + result = + // + GetToken() + + "[" + + // + periodStr + + providerStr + + typeStr + + modeStr + + SymbolStr + + positionIdStr + + entryStr + + volumeStr + + tpsStr + + slsStr + + timeStr + + // + "]" + // + ; + + // + return result; + } + + // + // Parse String Model and Fill Available + // Items ... + bool Parse(string value) + { + // + bool result = false; + + // + Clean(); + + // + if (!IsValid(value)) + { + return false; + } + + // + // For Modeling a Signal we Only Used: + // - Period; + // - Provider; + // - Type; + // - Mode; + // - Symbol; + // - PositionID; + // - Entry; + // - Volume; + // - TPS; + // - SLS; + // - Issue Time; + + // + entry = ParseDoubleSurrounded(value, XEntryToken); + volume = ParseDoubleSurrounded(value, XVolumeToken); + positionId = ParseLongSurrounded(value, XIDToken); + + // + time = ParseTimeSurrounded(value, XTimeToken); + symbol = ParseStringSurrounded(value, XSymbolToken); + provider = ParseStringSurrounded(value, XProviderToken); + type = ((ENUM_POSITION_TYPE)ParseIntSurrounded(value, XTypeToken)); + mode = ((ENUM_X_ORDER_MODES)ParseIntSurrounded(value, XModeToken)); + period = ((ENUM_TIMEFRAMES)ParseIntSurrounded(value, XPeriodToken)); + + // + // TPS ... + ParseDoubleArraySurrounded( + tps, + value, + XTPToken + // + ); + + // + // SLS ... + ParseDoubleArraySurrounded( + sls, + value, + XSLToken + // + ); + + // + // Validate ... + result = IsValid(); + ; + + // + return result; + } +}; + +// +// Model an Open Position ... +struct XPosition +{ + // + // Props ... + + // + // Magic Number ... + ulong magic; + + // + // Ticket ID ... + ulong ticket; + + // + // Tradinng Symbol ... + string symbol; + + // + // Trading Period ... + ENUM_TIMEFRAMES period; + + // + // Position Type ... + ENUM_POSITION_TYPE type; + + // + // Take Profit ... + double tp; + + // + // Stop Loss ... + double sl; + + // + // Position Current Profit ... + double profit; + + // + // Position Open Price ... + double entry; + + // + // Current Symbol Price ... + double price; + + // + // Position Swap ... + double swap; + + // + // Position Commission ... + double commission; + + // + // Volume ... + double volume; + + // + // Position Open Time ... + datetime openAt; + + // + // Sifnal Provider ... + string provider; + + // + // Position Comment ... + string comment; + + // + // Constructor ... + XPosition() + { + Clean(); + } + + // + // Initializers ... + + bool ByIndex(int index) + { + // + bool result = false; + + // + static CPositionInfo mPositionInfo; + + // + result = mPositionInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + ulong mTicket = mPositionInfo.Ticket(); + + // + result = ByTicket(mTicket); + + // + return result; + } + + bool ByTicket(ulong mTicket) + { + // + bool result = false; + + // + static CPositionInfo mPositionInfo; + + // + result = mPositionInfo.SelectByTicket(mTicket); + if (!result) + { + return result; + } + + // + swap = mPositionInfo.Swap(); + magic = mPositionInfo.Magic(); + openAt = mPositionInfo.Time(); + sl = mPositionInfo.StopLoss(); + ticket = mPositionInfo.Ticket(); + symbol = mPositionInfo.Symbol(); + tp = mPositionInfo.TakeProfit(); + profit = mPositionInfo.Profit(); + volume = mPositionInfo.Volume(); + comment = mPositionInfo.Comment(); + entry = mPositionInfo.PriceOpen(); + type = mPositionInfo.PositionType(); + price = mPositionInfo.PriceCurrent(); + commission = mPositionInfo.Commission(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + magic = 0; + ticket = 0; + tp = 0; + sl = 0; + swap = 0; + entry = 0; + price = 0; + profit = 0; + volume = 0; + openAt = 0; + commission = 0; + + // + type = NULL; + period = NULL; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XPosition &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + magic == value.magic && + entry == value.entry && + ticket == value.ticket && + volume == value.volume && + symbol == value.symbol && + provider == value.provider + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XPosition &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_POSITION_TYPE mType = NULL, // Long (Buy), Short (Sell) + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model an Order ... +struct XOrder +{ + // + // Time of order placement ... + datetime setupAt; + + // + // Time of order expiration ... + datetime expiredAt; + + // + // Time of order execution or cancellation ... + datetime executedAt; + + // + // Order type ... + ENUM_ORDER_TYPE type; + + // + // Order state ... + ENUM_ORDER_STATE state; + + // + // Type of execution by remainder ... + ENUM_ORDER_TYPE_FILLING filling; + + // + // Order lifetime ... + ENUM_ORDER_TYPE_TIME lifetime; + + // + // Order ticket ... + ulong ticket; + + // + // Magic Number ... + long magic; + + // + // Position id, that is placed on order, + // when it is executed. Each executed order invokes a + // deal, that opens new or changes existing + // position. Id of that position is placed on + // executed order in this moment. + long positionId; + + // + // Initial volume on order placement ... + double initialVolume; + + // + // Unfilled volume ... + double currentVolume; + + // + // Price, specified in the order ... + double openPrice; + + // + // Current price by order symbol ... + double currentPrice; + + // + // Price of placing Limit order when StopLimit order is triggered ... + double stopLimitPrice; + + // + // Take Profit level ... + double tp; + + // + // Stop Loss level ... + double sl; + + // + // Trading Symbol ... + string symbol; + + // + // Signal Provider ... + string provider; + + // + // Order Comment ... + string comment; + + // + ENUM_TIMEFRAMES period; + + // + // Constructor ... + XOrder() + { + Clean(); + } + + // + // Initializers ... + bool ByIndex( + int index // Fill By Index ... + ) + { + // + bool result = false; + + // + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + static COrderInfo mOrderInfo; + + // + result = mOrderInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + // Reading Order Info ... + magic = mOrderInfo.Magic(); + sl = mOrderInfo.StopLoss(); + tp = mOrderInfo.TakeProfit(); + ticket = mOrderInfo.Ticket(); + openPrice = mOrderInfo.PriceOpen(); + positionId = mOrderInfo.PositionId(); + currentPrice = mOrderInfo.PriceCurrent(); + initialVolume = mOrderInfo.VolumeInitial(); + currentVolume = mOrderInfo.VolumeCurrent(); + stopLimitPrice = mOrderInfo.PriceStopLimit(); + + // + symbol = mOrderInfo.Symbol(); + comment = mOrderInfo.Comment(); + + // + state = mOrderInfo.State(); + type = mOrderInfo.OrderType(); + lifetime = mOrderInfo.TypeTime(); + filling = mOrderInfo.TypeFilling(); + + // + setupAt = mOrderInfo.TimeSetup(); + executedAt = mOrderInfo.TimeDone(); + expiredAt = mOrderInfo.TimeExpiration(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Retrieve Specific History Order ... + bool HistoryByIndex( + int index // Fill By Index ... + ) + { + // + bool result = false; + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + static CHistoryOrderInfo mOrderInfo; + + // + result = mOrderInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + // Reading Order Info ... + magic = mOrderInfo.Magic(); + sl = mOrderInfo.StopLoss(); + tp = mOrderInfo.TakeProfit(); + ticket = mOrderInfo.Ticket(); + openPrice = mOrderInfo.PriceOpen(); + positionId = mOrderInfo.PositionId(); + currentPrice = mOrderInfo.PriceCurrent(); + initialVolume = mOrderInfo.VolumeInitial(); + currentVolume = mOrderInfo.VolumeCurrent(); + stopLimitPrice = mOrderInfo.PriceStopLimit(); + + // + symbol = mOrderInfo.Symbol(); + comment = mOrderInfo.Comment(); + + // + state = mOrderInfo.State(); + type = mOrderInfo.OrderType(); + lifetime = mOrderInfo.TypeTime(); + filling = mOrderInfo.TypeFilling(); + + // + setupAt = mOrderInfo.TimeSetup(); + executedAt = mOrderInfo.TimeDone(); + expiredAt = mOrderInfo.TimeExpiration(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + tp = 0; + sl = 0; + magic = 0; + ticket = 0; + positionId = 0; + openPrice = 0; + currentPrice = 0; + initialVolume = 0; + currentVolume = 0; + stopLimitPrice = 0; + + // + setupAt = NULL; + expiredAt = NULL; + executedAt = NULL; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + type = NULL; + state = NULL; + period = NULL; + filling = NULL; + lifetime = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XOrder &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + state == value.state && + magic == value.magic && + ticket == value.ticket && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XOrder &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_ORDER_TYPE mType = NULL, // Long (Buy), Short (Sell) + ENUM_ORDER_STATE mState = NULL, // Order State + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // State Filter ... + IsStateFilterPassed( + mState, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model a Deal ... +struct XDeal +{ + // + // the ID of the Expert Advisor, that executed the deal ... + ulong magic; + + // + // the ID of position, in which the deal was involved ... + ulong positionId; + + // + // Ticket ... + ulong ticket; + + // + // the name of the deal symbol ... + string symbol; + + // + // order by which the deal is executed ... + ulong order; + + // + // the time of deal execution ... + datetime time; + + // + // Deal price ... + double price; + + // + // the financial result of the deal (in deposit currency) ... + double profit; + + // + // the amount of swap when position is closed ... + double swap; + + // + // the amount of commission of the deal ... + double commission; + + // + // the volume of deal ... + double volume; + + // + // the deal comment ... + string comment; + + // + string provider; + + // + ENUM_TIMEFRAMES period; + + // + // the deal type ... + // ------------------------------------------------------------------ + // DEAL_TYPE_BUY => Buy ... + // DEAL_TYPE_SELL => Sell ... + // DEAL_TYPE_BUY_CANCELED => Canceled buy deal ... + // There can be a situation when a previously executed buy deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ... + // + // DEAL_TYPE_SELL_CANCELED => Canceled sell deal ... + // There can be a situation when a previously executed sell deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation + // + // DEAL_TYPE_BALANCE => Balance ... + // DEAL_TYPE_CREDIT => Credit ... + // DEAL_TYPE_CHARGE => Additional charge ... + // DEAL_TYPE_CORRECTION => Correction ... + // DEAL_TAX => Tax charges ... + // DEAL_TYPE_BONUS => Bonus ... + // DEAL_TYPE_INTEREST => Interest rate ... + // DEAL_DIVIDEND => Dividend operations... + // DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ... + // DEAL_TYPE_COMMISSION => Additional commission ... + // DEAL_TYPE_COMMISSION_DAILY => Daily commission ... + // DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ... + // DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ... + // DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission + ENUM_DEAL_TYPE type; + + // + // the deal direction ... + // ---------------------------------- + // DEAL_ENTRY_IN => Entry in ... + // DEAL_ENTRY_OUT => Entry out ... + // DEAL_ENTRY_INOUT => Reverse ... + // DEAL_ENTRY_OUT_BY => Close a position by an opposite one ... + ENUM_DEAL_ENTRY entry; + + // + // deal reson ... + // --------------------- + // DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ... + // DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ... + // DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ... + // DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ... + // DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ... + // DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ... + // DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ... + // DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ... + // DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ... + // DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ... + ENUM_DEAL_REASON reason; + + // + // Constructor ... + XDeal() + { + Clean(); + } + + // + // Initializers ... + bool ByIndex( + int index // Deal Index + ) + { + // + bool result = false; + + // + int dealsCount = HistoryDealsTotal(); + result = dealsCount > 0; + if (!result) + { + return result; + } + + // + static CDealInfo mDealInfo; + + // + result = mDealInfo.SelectByIndex(index); + if (!result) + { + // + return result; + } + + // + // Reading Order Info ... + swap = mDealInfo.Swap(); + magic = mDealInfo.Magic(); + order = mDealInfo.Order(); + ticket = mDealInfo.Ticket(); + time = mDealInfo.Time(); + price = mDealInfo.Price(); + symbol = mDealInfo.Symbol(); + profit = mDealInfo.Profit(); + volume = mDealInfo.Volume(); + comment = mDealInfo.Comment(); + positionId = mDealInfo.PositionId(); + entry = mDealInfo.Entry(); + commission = mDealInfo.Commission(); + type = mDealInfo.DealType(); + reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( + ticket, + DEAL_REASON); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + magic = 0; + positionId = 0; + ticket = 0; + order = 0; + time = 0; + price = 0; + profit = 0; + swap = 0; + commission = 0; + volume = 0; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + type = NULL; + entry = NULL; + period = NULL; + reason = NULL; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(symbol) && + NotEmpty(ticket) && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XDeal &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + magic == value.magic && + entry == value.entry && + reason == value.reason && + ticket == value.ticket && + volume == value.volume && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + const XDeal &values[] // Collection to Find + ) + { + // + return FindIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_DEAL_TYPE mType = NULL, // Deal Type + ENUM_DEAL_ENTRY mEntry = NULL, // Deal Entry + ENUM_DEAL_REASON mReason = NULL, // Deal Reason + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // Entry Filter ... + IsEntryFilterPassed( + mEntry, + this + // + ) + // + && + // + // Reason Filter ... + IsReasonFilterPassed( + mReason, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model OnTrade Event Handler Result on XCTrade Class ... +struct XOnTradeHandlerState +{ + // + bool hasNewDeal; + int newDeals; + + // + bool hasNewOrder; + int newOrders; + + // + bool hasNewPosition; + int newPositions; + + // + bool hasNewHistoryOrder; + int newHistoryOrders; + + // + // Constructor ... + XOnTradeHandlerState() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + hasNewDeal = false; + hasNewOrder = false; + hasNewPosition = false; + hasNewHistoryOrder = false; + + // + newDeals = 0; + newOrders = 0; + newPositions = 0; + newHistoryOrders = 0; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ( + // + hasNewDeal + ? newDeals > 0 + : true + // + ) + // + && + // + ( + // + hasNewOrder + ? newOrders > 0 + : true + // + ) + // + && + // + ( + // + hasNewPosition + ? newPositions > 0 + : true + // + ) + // + && + // + ( + // + hasNewHistoryOrder + ? newHistoryOrders > 0 + : true + // + ) + // + ; + + // + return result; + } +}; + +// +// Model a Position with all of it's Supports ... +struct XPositionPack +{ + // + ulong ticket; // Main Position's Ticket + + // + XPosition position; // Main Position (if Exists) + + // + int supportOrdersCount; // Supported Orders (Untriggered) + int supportPositionsCount; // Supported Positions + + // + XOrder supportOrders[]; // Supported Orders (Untriggered) + XPosition supportPositions[]; // Supported Positions + + // + // Constructor ... + XPositionPack() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + ticket = 0; + + // + position.Clean(); + + // + supportOrdersCount = 0; + supportPositionsCount = 0; + + // + Clean(supportOrders); + Clean(supportPositions); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + NotEmpty(ticket) && + ( + // + supportOrdersCount > 0 + ? ArraySize(supportOrders) == supportOrdersCount + : true + // + ) + // + && + // + ( + // + supportPositionsCount > 0 + ? ArraySize(supportPositions) == supportPositionsCount + : true + // + ) + // + ; + + // + return result; + } +}; + +// +// TypeDefs ... + +// +typedef void (*TOnDealsChanged)(int count); + +// +typedef void (*TOnOrdersChanged)(int count); + +// +typedef void (*TOnPositionsChanged)(int count); + +// +typedef void (*TOnStopLoss)(const XDeal &deal); +typedef void (*TOnTakeProfit)(const XDeal &deal); + +// +typedef void (*TOnTradeStateChanged)(const XOnTradeHandlerState &state); + +// +// Classes ... + +// +// Create a Signal Specfic Data Collector ... +class XSCSignalCollector +{ + // + // Public ... +public: + // + // Props ... + + // + // Constructor ... + void XSCSignalCollector() + { + // + XSCDataCollector mBase; + mBase.Clear(); + } + + // + // Deconstructor ... + + // + // Tools ... + + // + // Inheritanced Functions ... + + // + // Cleaning Store ... + void Clear() + { + // + XSCDataCollector mBase; + + // + mBase.Clear(); + } + + // + // Collect All Store ... + int Collect(XSignal &result[]) + { + // + int mResult = 0; + + // + XSCDataCollector mBase; + + // + mResult = mBase.Collect(result); + + // + return mResult; + } + + // + // Add Item To Store ... + bool Add(XSignal &item) + { + // + bool result = false; + + // + XSCDataCollector mBase; + + // + result = mBase.Add(item); + + // + return result; + } + + // + // Add Item(s) To Store ... + int Add(XSignal &items[]) + { + // + int result = 0; + + // + XSCDataCollector mBase; + + // + result = mBase.Add(items); + + // + return result; + } + + // + // Remove an Item from Store ... + bool Remove(XSignal &item) + { + // + bool result = false; + + // + XSCDataCollector mBase; + + // + result = mBase.Remove(item); + + // + return result; + } + + // + // Custom Functions ... + + // + int CollectSignals( + XSignal &result[], // Hold Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Timeframe + ENUM_POSITION_TYPE type = NULL, // Long (Buy), Short (Sell) + ENUM_X_ORDER_MODES mode = NULL // Execution Mode + ) + { + // + int mResult = 0; + + // // + // XSignal signals[]; + // int signalsCount = Collect(signals); + // if (signalsCount <= 0) + // { + // return mResult; + // } + + // // + // mResult = ArraySize(result); + + // // + // // Now we Have to Apply Filters ... + // for (int i = 0; i < signalsCount; i++) + // { + // // + // XSignal iSignal = signals[i]; + + // // // + // // bool isFiltersPassed = + // // iSignal.IsFilteresPassed( + // // symbol, + // // provider, + // // period, + // // type, + // // mode + // // // + // // ); + // // if (!isFiltersPassed) + // // { + // // continue; + // // } + + // // // + // // AddRef( + // // iPosition, + // // result + // // // + // // ); + // } + + // + return mResult; + } + + // + // Protected ... +protected: + // + // Tools ... + + // + // Private ... +private: + // + // Props ... + + // + // Tools ... +}; + +// +// Tools ... + +// +bool IsValid(ENUM_X_ORDER_MODES value) +{ + return value != X_ORDER_MODE_NOTHING; +} + +// +// Ages ... + +// +// Retrieve a Position Age ... +int GetAge( + XPosition &position, // Selected Position ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + position.symbol, + period, + position.openAt); + + // + return result; +} + +// +// Retrieve an Order Age ... +int GetAge( + XOrder &order, // Selected Order ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + order.symbol, + period, + order.setupAt); + + // + return result; +} + +// +// Retrieve a Deal Age ... +int GetAge( + XDeal &deal, // Selected Deal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + deal.symbol, + period, + deal.time); + + // + return result; +} + +// +// Get Oldest Deal ... +int GetOldest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Deal ... +int GetYoungest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldest Order ... +int GetOldest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Order ... +int GetYoungest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Oldes Position ... +int GetOldest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Get Youngest Position ... +int GetYoungest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} + +// +// Check Filters ... + +// +// Magic Filter ... +template +bool IsMagicFilterPassed( + ulong magic, + bool filterByMagic, + T &item + // +) +{ + // + return !filterByMagic + ? true + : !NotEmpty(magic) + ? false + : magic == item.magic; +} + +// +// Symbol Filter ... +template +bool IsSymbolFilterPassed( + string symbol, + T &item + // +) +{ + // + return !IsValid(symbol) + ? true + : symbol == item.symbol; +} + +// +// Provider Filter ... +template +bool IsProviderFilterPassed( + string provider, + T &item + // +) +{ + // + return !IsValid(provider) + ? true + : provider == item.provider; +} + +// +// Period Filter ... +template +bool IsPeriodFilterPassed( + ENUM_TIMEFRAMES period, + T &item + // +) +{ + // + return !IsValid(period) + ? true + : period == item.period; +} + +// +// Type Filter ... +template +bool IsTypeFilterPassed( + ENUM_POSITION_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} +template +bool IsTypeFilterPassed( + ENUM_ORDER_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} +template +bool IsTypeFilterPassed( + ENUM_DEAL_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} + +// +// Mode Filter ... +template +bool IsModeFilterPassed( + ENUM_X_ORDER_MODES mode, + T &item + // +) +{ + // + return mode == NULL + ? true + : mode == item.mode; +} + +// +// Entry Filter ... +template +bool IsEntryFilterPassed( + ENUM_DEAL_ENTRY entry, + T &item + // +) +{ + // + return entry == NULL + ? true + : entry == item.entry; +} + +// +// Reason Filter ... +template +bool IsReasonFilterPassed( + ENUM_DEAL_REASON reason, + T &item + // +) +{ + // + return reason == NULL + ? true + : reason == item.reason; +} + +// +// State Filter ... +template +bool IsStateFilterPassed( + ENUM_ORDER_STATE state, + T &item + // +) +{ + // + return state == NULL + ? true + : state == item.state; +} + +// + +// +// Find Specific Item Index inside a Collection ... +template +int FindIndex( + T &item, // Item to Find + const T &items[] // Items for Search +) +{ + // + int result = -1; + + // + // Check Item Validation ... + if (!item.IsValid()) + { + return result; + } + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < itemsCount; i++) + { + // + T iItem = items[i]; + + // + // Validate Item ... + if (!iItem.IsValid()) + { + continue; + } + + // + bool isSame = item.IsSameAs(iItem); + if (isSame && result <= -1) + { + // + result = i; + break; + } + } + + // + return result; +} + +// +// Tagging ... + +// +// Generate Specified Tag for Using in Comments ... +string GeneratePeriodTag(ENUM_TIMEFRAMES period) +{ + // + string strPeriod = ToString(period); + return Surround( + XPeriodToken, + strPeriod + // + ); +} + +// +// Extract Period from a Tagged string ... +ENUM_TIMEFRAMES ExtractPeriod(string value) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + string pStr = ParseStringSurrounded( + value, + XPeriodToken + // + ); + if (!IsValid(pStr)) + { + return result; + } + + // + result = ToPeriod(pStr); + + // + return result; +} + +// Generate Specified Tag for Using in Comments ... +string GenerateProviderTag(string provider) +{ + // + return Surround( + XProviderToken, + provider + // + ); +} + +// +// Extract Provider from a Tagged string ... +string ExtractProvider(string value) +{ + // + return ParseStringSurrounded( + value, + XProviderToken + // + ); +} + +// +// Generate Support Comment Tag ... +string GenerateSupportTag(ulong ticket) +{ + // + return Surround( + XSupportToken, + ticket + // + ); +} + +// +// Extract Support Positions from a Tagged string ... +ulong ExtractSupportedTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XSupportToken + // + ); +} + +// +// Generate EQM Support Comment Tag ... +string GenerateEQMSupportTag(ulong ticket) +{ + // + return Surround( + XEQMSupportToken, + ticket + // + ); +} + +// +// Extract EQM Support Positions from a Tagged string ... +ulong ExtractEQMSupportedTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XEQMSupportToken + // + ); +} + +//