/////////////////////////////////////////////////////// // // SaherElm IT Center MQL4 X Signal Global Library // --------------------------------------------------- // saherelm useful tools and definitions ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://www.saherelm.ir" #property version "1.00" #property strict // // Includes library ... #include "../Libraries/x-saherelm.lib.mq4" // // Includes Indicator library ... #include "../Libraries/x-saherelm.indicator.lib.mq4" // // Includes Models library ... #include "../Libraries/x-saherelm.models.lib.mq4" // // START Global Requirement Functions ... // // // X Based Signal Conditions ... struct XSignalConditions { datetime startTime; datetime signalTime; }; // static XSignalConditions xLongConds; static XSignalConditions xShortConds; // static bool xCloseLongTrades = false; static bool xWaitForLongSignals = true; static datetime xWaitForLongSignalChangeTime; // static bool xWaitForShortSignals = true; static bool xCloseShortTrades = false; // bool isLastTrendUp = false; // // END Global Requirement Functions ... // // // START Functions ... // // // Check and Fill Long Signal Conditions ... void CheckXLongSignalConditions( const int bar_index, const int marketLen, const XState &states[], // const double smoother = 5 ) { // datetime barTime = iTime( _Symbol, _Period, bar_index ); // // // bool isCrossUnder = // states[1].osc.fast < states[1].osc.slow // && !(states[2].osc.fast < states[2].osc.slow) // ; // // // bool isCrossOver = // states[1].osc.fast > states[1].osc.slow // && !(states[2].osc.fast > states[2].osc.slow) // ; // XOHCL pCandle = GetCandleModel(1); // // // bool isTrendingUp = // pCandle.low > states[0].bnd.high // && pCandle.high > states[0].bnd.high; // // // bool isTrendingDown = // pCandle.high < states[0].bnd.low // && pCandle.low < states[0].bnd.low; // bool isTrendingUp = states[1].bnd.open < states[1].bnd.close && !(states[2].bnd.open < states[2].bnd.close) ; // bool isTrendingDown = states[1].bnd.open > states[1].bnd.close && !(states[2].bnd.open > states[2].bnd.close) ; // bool isCrossUnder = isTrendingDown && !isTrendingUp ; // bool isCrossOver = isTrendingUp && !isTrendingDown ; // // Check Market For Enable/Disable Signal Handlers ... // Checking Market for Long Signals ... if (xWaitForLongSignals) { // bool isLCFastOnTrendingUpTouchLowestLow = // // LC Trending Up ... states[1].lc.fast > states[1].lc.slow && states[2].lc.fast > states[2].lc.slow // // LC Fast Touch Market Lowest Low ... && states[1].lc.fast > states[1].mkt.lowestLow && !(states[2].lc.fast > states[2].mkt.lowestLow) ; // bool isMCSlowCrossOverBNDHigh = states[1].mc.fast > states[1].mc.slow && states[1].mc.slow > states[1].bnd.high && !(states[2].mc.slow > states[2].bnd.high) ; // // Disable Long Trade Handlers ... if ( isMCSlowCrossOverBNDHigh || isLCFastOnTrendingUpTouchLowestLow ) { // xWaitForLongSignals = false; xWaitForLongSignalChangeTime = TimeCurrent(); LogMessage("Disable Long: " + TimeCurrent()); } } else { // bool isAllTrendingUp = // // SC ... states[1].sc.fast > states[1].sc.slow // // MC ... && states[1].mc.fast > states[1].mc.slow && !(states[2].mc.fast > states[2].mc.slow) // // LC ... && states[1].lc.fast > states[1].lc.slow ; // int lastWaitChangeBarIndex = iBarShift( _Symbol, _Period, xWaitForLongSignalChangeTime ); // // Enable Long Trade Handlers ... if ( isAllTrendingUp && lastWaitChangeBarIndex - bar_index >= marketLen ) { xWaitForLongSignals = true; LogMessage("Enable Long: " + TimeCurrent()); } } // if ( isCrossUnder && xLongConds.startTime == 0 ) { // xLongConds.startTime = barTime; return; } // if ( isCrossOver && xLongConds.startTime > 0 && xLongConds.signalTime == 0 ) { // xLongConds.signalTime = barTime; return; } } // // Check and Fill Short Signal Conditions ... void CheckXShortSignalConditions( const int bar_index, const int marketLen, const XState &states[], // const double smoother = 5 ) { // datetime barTime = iTime( _Symbol, _Period, bar_index ); // bool isCrossUnder = states[1].osc.fast < states[1].osc.slow && !(states[2].osc.fast < states[2].osc.slow) ; // bool isCrossOver = states[1].osc.fast > states[1].osc.slow && !(states[2].osc.fast > states[2].osc.slow) ; // if ( isCrossOver && xShortConds.startTime == 0 ) { // xShortConds.startTime = barTime; return; } // if ( isCrossUnder && xShortConds.startTime > 0 && xShortConds.signalTime == 0 ) { // xShortConds.signalTime = barTime; return; } } // // Convert Long Signal Conditions to XSignal ... XSignalRequest GenerateXSignal( const ENUM_X_SIGNAL_TYPE type, // Signal Type ... const int bar_index, // Bar Index ... const int marketLen, // MarketLength for TP and SL ... const double r2r, // Risk to Reward ratio ... const XState &states[], // const double smoother = 5 ) { // XSignalRequest result = {}; // result.hasSignal = false; result.type = X_SIGNAL_NONE; result.provider = X_UNKNOWN_PROVIDER; // bool requestLong = type == X_SIGNAL_LONG; // if (requestLong) { // if ( !ValidateXLongConditions( marketLen, states, smoother ) ) { return result; } } else { // if ( !ValidateXShortConditions( marketLen, states, smoother ) ) { return result; } } // // Price Calculations ... // RefreshRates(); // double askPrice = SymbolInfoDouble( _Symbol, SYMBOL_ASK ); // double bidPrice = SymbolInfoDouble( _Symbol, SYMBOL_BID ); // double entryPrice = requestLong ? askPrice : bidPrice; // double exitPrice = requestLong ? bidPrice : askPrice; // double priceGap = MathAbs(entryPrice - exitPrice); // double ll = GetMarketLowestLow( bar_index, marketLen ); // double hh = GetMarketHighestHigh( bar_index, marketLen ); // double openPrice = iOpen( _Symbol, _Period, bar_index ); // double closePrice = iClose( _Symbol, _Period, bar_index ); // double risk = requestLong ? MathMin(openPrice, closePrice) - ll : hh - MathMax(openPrice, closePrice); double reward = risk * r2r; // risk * r2r; // 300 * _Point; // if (risk > (500 * _Point)) { // reward = 300 * _Point; // } // double sl = 0; // ll; double tp = requestLong ? entryPrice + reward : entryPrice - reward; // datetime barTime = iTime( _Symbol, _Period, bar_index ); // result.signal.tp = tp; result.signal.sl = sl; result.signal.symbol = _Symbol; result.signal.type = type; result.signal.id = totalSignals + 1; result.signal.entry = entryPrice; result.signal.provider = X_XXX_PROVIDER; result.signal.time = barTime; // result.hasSignal = true; result.type = type; result.provider = X_XXX_PROVIDER; // return result; } // // Validate Signal Conditions ... bool ValidateXLongConditions( const int marketLen, const XState &states[], // const double smoother = 5 ) { // bool isConditionsFilled = xLongConds.startTime > 0 && xLongConds.signalTime > 0 ; // bool isBLFilled = false; if (isConditionsFilled) { // int startBarIndex = iBarShift( _Symbol, _Period, xLongConds.startTime ); // int signalBarIndex = iBarShift( _Symbol, _Period, xLongConds.signalTime ); // isBLFilled = // xLongConds.signalTime > xLongConds.startTime && MathAbs(signalBarIndex - startBarIndex) > 2 ; } // bool result = isBLFilled && isConditionsFilled && xWaitForLongSignals ; // // Since maybe Conditions Filled but // Slope is Negative, for Handling Next Signals and // Prevent from infinity loop, here we Clear Signal Conditions ... if ( !result && isConditionsFilled ) { ClearXLongSignalConditions(); } // return result; } bool ValidateXShortConditions( const int marketLen, const XState &states[], // const double smoother = 5 ) { // bool isConditionsFilled = xShortConds.startTime > 0 && xShortConds.signalTime > 0 ; // bool isBLFilled = false; if (isConditionsFilled) { // int startBarIndex = iBarShift( _Symbol, _Period, xShortConds.startTime ); // int signalBarIndex = iBarShift( _Symbol, _Period, xShortConds.signalTime ); // isBLFilled = // xShortConds.signalTime > xShortConds.startTime && MathAbs(signalBarIndex - startBarIndex) > 2 ; } // bool result = isBLFilled && isConditionsFilled && xWaitForLongSignals ; // // Since maybe Conditions Filled but // Slope is Negative, for Handling Next Signals and // Prevent from infinity loop, here we Clear Signal Conditions ... if ( !result && isConditionsFilled ) { ClearXShortSignalConditions(); } // return result; } // // Clear Long Signal Conditions for New One ... void ClearXLongSignalConditions() { // xLongConds.startTime = 0; xLongConds.signalTime = 0; } // // Clear Short Signal Conditions for New One ... void ClearXShortSignalConditions() { // xShortConds.startTime = 0; xShortConds.signalTime = 0; } // // Check State for Long Signals ... bool IsReadyForXSignals( const XSignal &signal, const XState &states[], const int marketLen, // double smoother = 100 ) { // bool result = false; // bool isSCTrendUp = states[1].sc.fast > states[1].sc.slow && states[2].sc.fast > states[2].sc.slow; // // // bool isSCTrendDown = // states[1].sc.fast < states[1].sc.slow // && states[2].sc.fast < states[2].sc.slow; // bool isMCTrendUp = states[1].mc.fast > states[1].mc.slow && states[2].mc.fast > states[2].mc.slow; // // // bool isMCTrendDown = // states[1].mc.fast < states[1].mc.slow // && states[2].mc.fast < states[2].mc.slow; // bool isLCTrendUp = states[1].lc.fast > states[1].lc.slow && states[2].lc.fast > states[2].lc.slow; // // // bool isLCTrendDown = // states[1].lc.fast < states[1].lc.slow // && states[2].lc.fast < states[2].lc.slow; // // // bool isTrendingUp = // pCandle.low > states[0].bnd.high // && pCandle.high > states[0].bnd.high; // // // bool isTrendingDown = // pCandle.high < states[0].bnd.low // && pCandle.low < states[0].bnd.low; // // // if (isTrendingUp && !isTrendingDown) { // isLastTrendUp = true; // } else if (isTrendingDown && !isTrendingUp) { // isLastTrendUp = false; // } // // // if (isLastTrendUp) { // // // LogMessage( // StringConcatenate( // "isLastTrendUp: ", isLastTrendUp // ) // ); // } // XOHCL pCandle = GetCandleModel(1); // // Verify Long Signals ... if (signal.type == X_SIGNAL_LONG) { // result = // true // && isSCTrendUp && isMCTrendUp && isLCTrendUp // && ( pCandle.high < states[1].longCycleHighestHigh && !(MathAbs(states[1].longCycleHighestHigh - pCandle.high) < 20 * _Point) ) // && ( states[1].lc.fast > states[1].mc.fast && states[1].lc.slow > states[1].mc.fast ? states[1].lc.slow < states[1].mkt.lowestLow : true ) // // && signal.entry <= states[1].mkt.highestOpen // // // && ( // ( // states[1].mc.slow < states[1].bnd.low // && states[1].mc.fast < MathMin(states[1].bnd.open, states[1].bnd.close) // ) || ( // states[1].lc.fast > states[1].bnd.low // && states[1].lc.fast > states[1].mc.fast // ) // ) // && MathAbs(states[1].mc.fast - states[1].bnd.low) > 50 * _Point ; } else // // Verify Short Signals ... if (signal.type == X_SIGNAL_SHORT) { // result = false ; } // return result; } // // END Functions ... //