Files
MQL5Data/XOM1EA/Classes/xom1ea.signaller.class.mq5
T
2025-09-09 16:49:16 +03:30

711 lines
17 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class
// -------------------------------------------------
// Name: XCXOM1Signaller ...
// Description: XOM1EA Signaller Class ...
//
//
// 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 XOM1EA Signaller Class"
#property strict
//
// Imports ...
#include "../../Helpers/x-saherelm.xom1.helper.mq5"
#include "../Classes/xom1ea.x-poi.drawer.class.mq5"
#include "../Libraries/xom1ea.lib.mq5"
//
// Definitions ...
//
// All Available Signaller Configurations
// which allow to Decide Based on Zones ...
struct XOM1SignallerConfig
{
//
// Props ...
bool processAllTicks; // Do Process All Ticks ...
//
// Constructor ...
XOM1SignallerConfig()
{
Clean();
}
//
// Tools ...
/**
* Cleanup ...
*/
void Clean()
{
ZeroMemory(this);
}
};
//
// Implementation ...
//
// Base Signaller Class ...
// Provides Zone Detection Mechanism ...
class XCXOM1SignallerBase
{
//
// Public ...
public:
//
// Props ...
string name; // Name ...
string symbol; // Symbol ...
XOM1Zone zones[]; // Detected Zones ...
XOM1Inputs inputs; // Indicator Inputs ...
ENUM_TIMEFRAMES period; // Period ...
XOM1SignallerConfig config; // Configuration ...
XCXOM1POIDrawer drawer; // POI Drawer ...
//
// Constructor ...
XCXOM1SignallerBase(
string _name, // Name ...
string _symbol, // Symbol ...
ENUM_TIMEFRAMES _period, // Period ...
XOM1Inputs &_inputs, // Indicator Inputs ...
XOM1SignallerConfig &_config // Config ...
)
{
//
// Validate ...
bool isValid =
IsSpecifiedValid(_name) &&
IsSpecifiedValid(_symbol) &&
IsSpecifiedValid(_period) &&
_inputs.IsValid();
if (!isValid)
{
return;
}
//
// Make Helper Class Instance ...
mHelper = new XCXOM1Helper();
bool isInited = mHelper.Init(
_symbol,
_period,
_inputs //
);
if (!isInited)
{
//
delete mHelper;
ZeroMemory(mHelper);
return;
}
//
// Set Props ...
name = _name;
symbol = _symbol;
period = _period;
inputs = _inputs;
config = _config;
//
// Set Dfault Values ...
mProcessedTicksCount = 0;
mLastCheckedBarTime = NULL;
}
//
// Deconstructor ...
~XCXOM1SignallerBase()
{
//
inputs.Clean();
//
SpecifiedClean(zones);
//
delete mHelper;
ZeroMemory(mHelper);
}
//
// Signal Event Handlers ...
//
void AddOnSignalEventHandler(TOnSignal handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mOnSignalEventHandlers //
);
}
//
void NotifyOnSignalEvent(XSignal &signal)
{
//
int count = ArraySize(mOnSignalEventHandlers);
bool has = IsValidSize(count) && signal.IsValid();
if (!has)
{
return;
}
//
// Calling Event Handlers ...
for (int i = 0; i < count; i++)
{
mOnSignalEventHandlers[i](signal);
}
}
//
// Actions ...
/**
* Handle Ticks Process ...
*
* @param barIndex: int
*/
void ProcessTick(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 if new Bar, Reset Processed Ticks Count ...
isNewBar = cBarTime > mLastCheckedBarTime;
if (isNewBar)
{
//
mProcessedTicksCount = 0;
ProcessNewBar(barIndex);
}
//
// Check Allow Process ...
// Process All Ticks ...
// Process New Bars ...
has = config.processAllTicks ||
(!config.processAllTicks && isNewBar);
if (!has)
{
return;
}
//
// Set Last Works ...
mProcessedTicksCount++;
mLastCheckedBarTime = cBarTime;
//
// Initialize iBar ...
has = iBar.Init(
symbol,
period,
barIndex //
);
if (!has)
{
//
iBar.Clean();
return;
}
//
// Update Indicator Helper ...
mHelper.Update(barIndex);
//
// Process Exists Zone ...
ProcessZones(barIndex);
//
// Do All Processing Mechanism ...
//
// Reading Conditions from Helper ...
XOM1Conditions iConditions;
has = mHelper.GetConditions(
iConditions,
barIndex //
);
if (!has)
{
//
iBar.Clean();
iConditions.Clean();
return;
}
//
int zIdx = 0;
int cIdx = zIdx + 1;
int pIdx = cIdx + 1;
int p2Idx = pIdx + 1;
//
// Check Zones Flags ...
bool checkPVZones = false;
bool checkMAZones = true;
//
// Check PV Zones ...
if (checkPVZones)
{
//
// Check New Peak or Vale Happens ...
//
// New Vale Over Last ...
bool isValeReason = iConditions.valeBuffer[cIdx] > iConditions.valeBuffer[pIdx];
//
// New Peak Under Last ...
bool isPeakReason = iConditions.peakBuffer[cIdx] < iConditions.peakBuffer[pIdx];
//
has = isValeReason || isPeakReason;
if (has)
{
//
// Prepare Reason ...
ENUM_XOM1_ZONE_REASON iReason = isValeReason
? X_OM1_ZONE_REASON_VALE
: X_OM1_ZONE_REASON_PEAK;
//
// Extract Upper / Lower Values ...
double iUpper = iConditions.peakBuffer[pIdx];
double iLower = iConditions.valeBuffer[pIdx];
//
// Calculate Mid Range ...
double iMiddle = iLower + ((iUpper - iLower) / 2);
if (iMiddle > 0)
{
iMiddle = NormalizePrice(iMiddle, symbol);
}
//
// Detect Reason Price ...
double iPrice =
isValeReason
? iConditions.valeBuffer[cIdx]
: iConditions.peakBuffer[cIdx];
if (iPrice > 0)
{
iPrice = NormalizePrice(iPrice, symbol);
}
//
// Detect Reason Direction ...
ENUM_X_DIRECTION iDir = iPrice > iMiddle
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
// Try to Initialize Zone ...
XOM1Zone iZone;
has = iZone.Init(
symbol,
period,
name, // Signaller Name ...
iUpper,
iLower,
iPrice,
iDir,
iReason,
iConditions.bars[pIdx].time, // From ...
iConditions.bars[zIdx].time // To
);
if (has)
{
//
// Add New Detected Zone to Zones ...
AddRef(
iZone,
zones //
);
//
// Prepare Signal ...
PrepareSignal(iZone);
}
//
iZone.Clean();
}
}
//
// Check MA Zones ...
if (checkMAZones)
{
//
// Crossed Over ...
bool isFastCrossedOverSlow = iConditions.maFastBuffer[cIdx] > iConditions.maSlowBuffer[cIdx] &&
!(iConditions.maFastBuffer[pIdx] >= iConditions.maSlowBuffer[pIdx]);
//
// Crossed Under ...
bool isFastCrossedUnderSlow = iConditions.maFastBuffer[cIdx] < iConditions.maSlowBuffer[cIdx] &&
!(iConditions.maFastBuffer[pIdx] <= iConditions.maSlowBuffer[pIdx]);
//
double iFast = iConditions.maFastBuffer[cIdx];
double iSlow = iConditions.maSlowBuffer[cIdx];
double iFibUpper = iConditions.fiboUpperBuffer[cIdx];
double iFibLower = iConditions.fiboLowerBuffer[cIdx];
//
double iValues[] = {
iFast,
iSlow,
iFibUpper,
iFibLower //
};
//
// Extract Upper / Lower Values ...
double iUpper = GetMax(iValues);
double iLower = GetMin(iValues);
//
double iZoneUpper = MathMax(iFibUpper, iFibLower);
double iZoneLower = MathMin(iFibUpper, iFibLower);
//
has = isFastCrossedOverSlow || isFastCrossedUnderSlow;
//
// Validate Cross Between Zone ...
if (has)
{
//
// Validate MA Place ...
has = iFast >= iZoneLower &&
iFast <= iZoneUpper &&
iSlow >= iZoneLower &&
iSlow <= iZoneUpper;
//
// Validate PSar ...
bool isSarBullish = iConditions.sarStateBuffer[cIdx] > 0;
bool isSarBearish = iConditions.sarStateBuffer[cIdx] < 0;
has =
has &&
(isFastCrossedOverSlow
? isSarBullish
: isSarBearish //
);
//
// Validate Fibo Zone ...
for (int idx = cIdx; idx < cIdx + 2; idx++)
{
//
// Check Fibo Upper ...
has = has &&
iConditions.fiboUpperBuffer[idx] == iConditions.fiboUpperBuffer[idx + 1];
if (!has)
{
break;
}
//
// Check Fibo Lower ...
has = has &&
iConditions.fiboLowerBuffer[idx] == iConditions.fiboLowerBuffer[idx + 1];
if (!has)
{
break;
}
}
}
//
// Moving Forward if Validated ...
if (has)
{
//
// Prepare Reason ...
ENUM_XOM1_ZONE_REASON iReason = isFastCrossedOverSlow
? X_OM1_ZONE_REASON_FCOS
: X_OM1_ZONE_REASON_FCUS;
//
// Calculate Mid Range ...
double iMiddle = iLower + ((iUpper - iLower) / 2);
if (iMiddle > 0)
{
iMiddle = NormalizePrice(iMiddle, symbol);
}
//
// Detect Reason Price ...
double iPrice = iConditions.maFastBuffer[cIdx];
if (iPrice > 0)
{
iPrice = NormalizePrice(iPrice, symbol);
}
//
// Detect Reason Direction ...
ENUM_X_DIRECTION iDir = isFastCrossedOverSlow
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
// Try to Initialize Zone ...
XOM1Zone iZone;
has = iZone.Init(
symbol,
period,
name, // Signaller Name ...
iZoneUpper,
iZoneLower,
iPrice,
iDir,
iReason,
iConditions.bars[pIdx].time, // From ...
iConditions.bars[zIdx].time // To
);
if (has)
{
//
// Add New Detected Zone to Zones ...
AddRef(
iZone,
zones //
);
//
// Prepare Signal ...
PrepareSignal(iZone);
}
//
iZone.Clean();
}
//
Clean(iValues);
}
//
// Clean Resources ...
iBar.Clean();
iConditions.Clean();
}
//
// Virtuals ...
//
// Protected ...
protected:
//
// Private ...
private:
//
// Props ...
//
XCXOM1Helper *mHelper; // Indicator Helper ...
//
TOnSignal mOnSignalEventHandlers[]; // Signal Recieved Event Handlers ...
//
int mProcessedTicksCount; // Prcoessed Ticks Count ...
datetime mLastCheckedBarTime; // Last Checked Bar Time ...
/**
* Handle New Bar's Process ...
*
* @param barIndex: int
*/
void ProcessNewBar(int barIndex = 0)
{
//
// Normalize Bar Index ...
if (barIndex < 0)
{
barIndex = 0;
}
//
// Try to Update Zone's Lifetime ...
int count = ArraySize(zones);
bool has = count > 0;
if (has)
{
//
// Loop through Zones ...
for (int i = 0; i < count; i++)
{
//
// Update Lifetime by Bar Index ...
// zones[i].UpdateByBarIndex(barIndex);
//
// drawer.DrawZone(
// zones[i],
// true, // Draw Price ...
// true, // Draw Middle ...
// true // Draw From ...
// );
}
}
//
// Check XOMZones Validations ...
}
/**
* Process Exists Zones ...
* Detect a Zone for trigger ...
*
* @param barIndex: int
*/
void ProcessZones(int barIndex = 0)
{
//
// Check Zones Exists ...
int count = ArraySize(zones);
bool has = IsValidSize(count);
if (!has)
{
return;
}
//
// Loop Through Zones ...
for (int i = 0; i < count; i++)
{
//
}
}
/**
* Converts iZone to Signal and Notify Signal ...
*
* @param iZone: XOM1Zone
*/
void PrepareSignal(XOM1Zone &zone)
{
//
// Validate Zone ...
if (!zone.IsValid())
{
return;
}
//
// Create Signal ...
XSignal signal;
//
signal.time = zone.to;
signal.provider = name;
signal.symbol = zone.symbol;
signal.period = zone.period;
signal.mode = X_ORDER_MODE_MARKET;
signal.conditions = "XConditions";
signal.comment = ToXString(zone.reason);
signal.type = zone.IsBullish()
? POSITION_TYPE_BUY
: POSITION_TYPE_SELL;
//
// Get Entry ...
signal.entry = GetXEntry(zone.symbol, zone.dir);
//
// Calculate SL ...
double providedSL = zone.IsBullish()
? zone.lower
: zone.upper;
signal.sl = providedSL;
//
// Calculate Risk ...
double risk = MathAbs(signal.entry - signal.sl);
//
// Calculate Reward ...
double r2r = 2;
double reward = risk * r2r;
//
// Calculate TP ...
double providedTP = zone.IsBullish()
? signal.entry + reward
: signal.entry - reward;
signal.tp = providedTP;
//
// Calculate Targets ...
// TODO: Handle this ...
//
// Set Min Volume ...
signal.volume = 0.01;
//
NotifyOnSignalEvent(signal);
}
};
//