743 lines
16 KiB
Plaintext
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[];
|
|
};
|
|
|
|
//
|