/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class // ------------------------------------------------- // Name: XCBaseSignaller ... // Description: Base Signaller Class ... // // - Create an Instance based on this ... // - Attach Required Helpers for Indicator Usages ... // - Override Virtual Methdos: // - [] ProcessTick: Processing All Ticks // - [] ProcessNewBar: Processing All New Bars // - [] CheckForGuard: Check For Guards // - [] NormalizeSignal: Normalizing Prepared Signal ... // - [] CheckAdditionslSignallerValidations: Additional Class Validations // // - Dont Forget to Call OnSignal Event in Process Methods when // a signal Appears ... // // - also Whenever you want you can call PrepareSignal Action to // provide a Signal based on Current Market State ... // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property description "SaherElm Base Signaller Class" #property strict // // Imports ... #include "../Classes/x-saherelm.base.class.mq5" #include "../Classes/x-saherelm.x-market.pattern.class.mq5" #include "../Libraries/x-saherelm.x-trade.lib.mq5" // // Definitions ... // // Implementations ... class XCBaseSignaller : public XCBase { // // Public ... public: // // Props ... string name; // Name ... string symbol; // Symbol ... ENUM_TIMEFRAMES period; // Period ... // bool ignoreTargets; // Ignore Signal Targets ... double slAdditionDistance; // SL Addition Distance ... double maxAllowedRiskDistance; // Max Allowed Risk In Points ... // // Restrictions ... datetime restUntil; // Resting Time ... int restingSignals; // Resting Signals ... datetime lastSignalAt; // Holding Last Signal's Time ... int restingDelay; // Resting Bars After Last Signal ... int loosingTrades; // Loosing Trades ... // TCanAnalyse canAnalyseEventListener; // XCMarketPatternDetector *patternDetector; // // Constructor ... XCBaseSignaller( string _name, // Name ... string _symbol, // Symbol ... ENUM_TIMEFRAMES _period, // Period ... bool _processAllTicks = false, // Process All Ticks ... double _defaultSignalR2R = 1.5, // Default Signal Risk To Reward Ratio ... double _defaultSignalRiskInPoint = 50, // Default Signal Risk In Point ... double _defaultSignalVolume = 0.01 // Default Signal Volume ... ) { // // Assign Properties ... name = _name; symbol = _symbol; period = _period; // ignoreTargets = false; slAdditionDistance = 0; maxAllowedRiskDistance = 0; // processAllTicks = _processAllTicks; defaultSignalR2R = _defaultSignalR2R; defaultSignalVolume = _defaultSignalVolume; defaultSignalRiskInPoint = _defaultSignalRiskInPoint; // // Normalize ... defaultSignalR2R = NormalizeDouble(defaultSignalR2R, 1, 10); defaultSignalVolume = NormalizeDouble(defaultSignalVolume, 0.01); defaultSignalVolume = NormalizeVolume(defaultSignalVolume, symbol, 2); defaultSignalRiskInPoint = NormalizeDouble(defaultSignalRiskInPoint, 10); // // Set Dfault Values ... mProcessedTicksCount = 0; mLastCheckedBarTime = NULL; // patternDetector = new XCMarketPatternDetector(); } // // Deconstructor ... ~XCBaseSignaller() { // // Cleanup Event Listeners ... SpecifiedClean(onSignalEventListeners); // delete patternDetector; ZeroMemory(patternDetector); } // // Event Listeners ... /** * Add On Signal Event Listener ... * * @param listener: TOnSignal instance ... */ void AddOnSignalEventHandler(TOnSignal listener) { // // Validate ... if (listener == NULL) { return; } // Add( listener, onSignalEventListeners // ); } // // Actions ... /** * Check Signaller Validation ... * * @return ( bool ) */ bool IsValid() { // bool result = false; // result = // IsSpecifiedValid(name) && IsSpecifiedValid(symbol) && IsSpecifiedValid(period) && // patternDetector != NULL && // CheckAdditionslSignallerValidations() // ; // return result; } /** * Handling On Tick Event ... * * @param barIndex: int, Specified Bar Index ... */ void OnTick(int barIndex = 0) { // // Normalize Bar Index ... if (barIndex < 0) { barIndex = 0; } // // Define Requirements ... XOHCL iBar; bool has = false; bool isNewBar = false; // // Get Current Bar Time ... datetime cBarTime = GetBarTime( symbol, period, barIndex // ); // // Validate Bar Time ... has = IsSpecifiedValid(cBarTime); if (!has) { return; } // // Check Rest Until ... has = !IsXValid(restUntil) || (IsXValid(restUntil) && cBarTime > restUntil); if (!has) { return; } // // Check Process Permissions ... has = CanAnalyseMarket(cBarTime); if (!has) { return; } // // Check if new Bar, Reset Processed Ticks Count ... isNewBar = cBarTime > mLastCheckedBarTime; if (isNewBar) { // mProcessedTicksCount = 0; ProcessNewBar(barIndex); return; } // // Check Allow Process ... // Process All Ticks ... // Process New Bars ... has = processAllTicks || (!processAllTicks && isNewBar); if (!has) { return; } // // Set Last Works ... mProcessedTicksCount++; mLastCheckedBarTime = cBarTime; // ProcessTick(barIndex); } // // Virtuals ... /** * Processing Tick ... * * @param barIndex: int, Specified Bar Index ... */ virtual void ProcessTick(int barIndex = 0) { } /** * Processing New Bar ... * * @param barIndex: int, Specified Bar Index ... */ virtual void ProcessNewBar(int barIndex = 0) { } /** * Check Guards Based on MarketConditions ... * * @param guards: XGuard, reference collection to holds result ... * @param positions: XPosition, reference collection to provides positions ... * @param barIndex: int * * @return ( int ) */ int virtual CheckForGuard( XGuard &guards[], XPosition &positions[], int barIndex = 0 // ) { // int result = 0; // SpecifiedClean(guards); // result = ArraySize(guards); // return result; } /** * Check Additional Validations on Childs Instances ... * * @return ( bool virtual ) */ bool virtual CheckAdditionslSignallerValidations() { return true; } /** * Normalizing Signal by Signaller Custom Props ... * * @param signal: XSignal ... */ void virtual NormalizeSignal(XSignal &signal) { } /** * Prepare Restrictions Update For Losing Trades ... */ void LoseTrade() { // restingSignals++; loosingTrades++; } /** * Prepare Restrictions For Winning Trades ... */ void WinTrade() { // if (loosingTrades > 0) { loosingTrades--; } // if (restingSignals > 0) { restingSignals--; } } // // Protected ... protected: // // Props ... // bool processAllTicks; // Specified Processing All Ticks or not ... // int mProcessedTicksCount; // Prcoessed Ticks Count ... datetime mLastCheckedBarTime; // Last Checked Bar Time ... // double defaultSignalR2R; // Default Signal Risk To Reward Ratio ... double defaultSignalVolume; // Default Signal Volume ... double defaultSignalRiskInPoint; // Default Signal Risk In Point ... // // Event Notifiers ... /** * Notify OnSignal Event Listeners ... * * @param signal: XSignal, Specified Signal to Notify ... */ void NotifySignalEventListeners(XSignal &signal) { // int count = ArraySize(onSignalEventListeners); // // Validate ... if (!IsValidSize(count) || !signal.IsValid()) { return; } // // Check Restrictions ... if (HasRestrictions()) { // bool ignore = HandleRestrictions(signal); if (ignore) { return; } } // // Do Notify ... for (int i = 0; i < count; i++) { onSignalEventListeners[i](signal); } // lastSignalAt = signal.time; } /** * Calling Can Analyse Event Listeners ... * Check Can Analayse Market or not ... * * @param time: datetime, Specified Time for Checking ... * * @return ( bool ) */ bool CanAnalyseMarket(datetime time = NULL) { // bool result = false; // // Normalize ... time = NormalizeTime(time); // // Validation ... result = IsValid(); if (!result) { return result; } // result = canAnalyseEventListener == NULL; if (result) { return result; } // // Calling Can Analyse Event Listener ... result = canAnalyseEventListener( symbol, period, time // ); // return result; } /** * Preparing Default Signal ... * * @param signal: XSignal, holding result Signal ... * @param forDir: ENUM_X_DIRECTION * @param targets: XTarget Array, Provides Signal Targets (Price) ... * @param r2r: double, Provides Signal (r2r), if not Provided uses Default R2R ... * @param slPrice: double, Provides Signal SL Price, if not Provided uses riskInPoint ... * @param riskInPoint: double, Provides Signal Risk Amount which Multiplied to Points, if not Provided uses DefaultRiskInPoint ... * * @return ( bool ) */ bool PrepareSignal( XSignal &signal, ENUM_X_DIRECTION forDir, XTarget &targets[], // double r2r = 0, double slPrice = 0, double riskInPoint = 0 // ) { // bool result = false; // // Prepare ... signal.Clean(); // // Normalize ... // // Validate ... result = IsValid() && HasDirection(forDir); if (!result) { return result; } // bool isBullish = IsSpecifiedBullish(forDir); // double point = GetPoints(symbol); double spread = GetSpread(symbol); double volume = defaultSignalVolume; double entry = GetEntry(symbol, forDir); // riskInPoint = riskInPoint > 0 && slPrice <= 0 ? riskInPoint : defaultSignalRiskInPoint; double risk = (riskInPoint * point); risk = slPrice > 0 ? MathAbs(entry - slPrice) : risk; // r2r = r2r > 0 ? r2r : defaultSignalR2R; double reward = (risk * r2r) + spread; // double tp = isBullish ? entry + reward : entry - reward; // double sl = isBullish ? entry - risk : entry + risk; // // Filling Values ... signal.tp = tp; signal.sl = sl; signal.entry = entry; signal.provider = name; signal.symbol = symbol; signal.period = period; signal.volume = volume; signal.time = TimeCurrent(); signal.type = isBullish ? POSITION_TYPE_BUY : POSITION_TYPE_SELL; signal.mode = X_ORDER_MODE_MARKET; // // Apply Targets ... if (HasChild(targets)) { // ApplyTargetsOnSignal( forDir, targets, signal // ); } // // Validate Signal ... result = signal.IsValid(); if (result) { // NormalizeSignal(signal); result = signal.IsValid(); } // if (!result) { signal.Clean(); } // return result; } /** * Check Signaller Has Restrictions or not ... * * @return ( bool ) */ bool HasRestrictions() { // bool result = false; // result = // // Rest Delay ... restingDelay > 0 || // // Resting Signals ... restingSignals > 0 || // // Rest Until ... IsXValid(restUntil) // ; // return result; } /** * Handle Restrictions On Signal ... * * @param signal: XSignal, reference to Provided Sginal ... * * @return ( bool ) */ bool HandleRestrictions(XSignal &signal) { // // Ignore Signal Execution ... bool result = true; // // Check Restrictions Exists ... if (!HasRestrictions()) { // // Disable Signal Ignoring and Allow Notify Signal ... result = false; return result; } // datetime cTime = TimeCurrent(); // // Resting Signals ... if (restingSignals > 0) { // restingSignals--; return result; } // // Rest Until ... if (IsXValid(restUntil)) { // if (cTime > restUntil) { // restUntil = NULL; // // Disable Signal Ignoring and Allow Notify Signal ... result = false; return result; } else { // // Ignore Signal ... return result; } } // // Resting Delay ... if (restingDelay > 0 && IsXValid(lastSignalAt)) { // int lastSignalIDX = GetBarIndex( signal.symbol, signal.period, lastSignalAt // ); if (IsValidIndex(lastSignalIDX)) { // if (lastSignalIDX > restingDelay) { // restingDelay = 0; // // Disable Signal Ignoring and Allow Notify Signal ... result = false; return result; } else { // // Ignore Signal ... return result; } } } // return result; } /** * Reset All Restrictions ... */ void ResetRestrictions() { // restingDelay = 0; restUntil = NULL; restingSignals = 0; } // // Private ... private: // // Props ... // // Event Listeners ... TOnSignal onSignalEventListeners[]; }; //