Files
xMQL5/BKPS/14041018/Classes/x-saherelm.x-signaller.class.mq5
T
2026-01-08 11:39:42 +03:30

743 lines
16 KiB
Plaintext

///////////////////////////////////////////////////////
//
// 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[];
};
//