584 lines
11 KiB
Plaintext
584 lines
11 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Seriallize Library
|
|
// ---------------------------------------
|
|
// Name: XSupportSignal
|
|
// Description: provides Seriallizing EA abilities ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
#include "../Libraries/x-saherelm.models.lib.mq5"
|
|
#include "../Libraries/x-saherelm.common.lib.mq5"
|
|
#include "../Classes/x-saherelm.xtrade.class.mq5"
|
|
#include "../Libraries/x-saherelm.seriallizer.lib.mq5"
|
|
#include "../Classes/x-saherelm.x121.provider.class.mq5"
|
|
|
|
//
|
|
// TODO: add this to Configurations ...
|
|
double supportVolumeMultiplier = 2;
|
|
int oldAgeSupportForReNewFactor = 35;
|
|
int oldAgePositionForSupportFactor = 17;
|
|
|
|
//
|
|
// Required Variables ...
|
|
double minProfitPerTrade = 0.15;
|
|
double minProfitPerVolumeFactor = 0.01;
|
|
|
|
//
|
|
double supportsSginalTpPoint = 30;
|
|
|
|
//
|
|
// NOTE:
|
|
// Define some tokens to Specify types of Supports ...
|
|
string XEQMSupportToken = "XEQM";
|
|
|
|
//
|
|
// Define Two Main Support Types of EQM ...
|
|
enum ENUM_X121EQM_SUPPORT_TYPES
|
|
{
|
|
//
|
|
XEQM_UNBOUND = 0, // Without TP ...
|
|
XEQM_INBOUND = 1, // With TP ...
|
|
};
|
|
|
|
//
|
|
// Generate Signal Period Comment Part ...
|
|
string GeneratePeriodComment(
|
|
ENUM_TIMEFRAMES period = NULL // Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
if (period == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = XPeriodToken + "(" + ToString(period) + ")";
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Generate String Tag for EQM Support Signals ...
|
|
string GenerateXEQMSupportComment(
|
|
ENUM_TIMEFRAMES period = NULL // Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
string result = XEQMSupportToken;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Comment belongs to a EQM Support or not ...
|
|
bool IsEQMSupport(string comment)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (StringLen(comment) <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tokenPosition = StringFind(
|
|
comment,
|
|
XEQMSupportToken);
|
|
result = tokenPosition >= 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Select EQM Support Orders ...
|
|
int GetEQMSupportOrders(
|
|
XOrder &supports[], // Hold Result ...
|
|
XOrder &orders[], // List of All Orders ...
|
|
ENUM_TIMEFRAMES period = NULL // Specified Period ...
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(supports);
|
|
|
|
//
|
|
int ordersCount = ArraySize(orders);
|
|
if (ordersCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop through Orders ...
|
|
for (int i = 0; i < ordersCount; i++)
|
|
{
|
|
//
|
|
XOrder iOrder = orders[i];
|
|
|
|
//
|
|
// Check Order is Support or not ...
|
|
bool isSupport = IsEQMSupport(iOrder.comment);
|
|
if (!isSupport)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Order is not Triggered ...
|
|
if (iOrder.state != ORDER_STATE_PLACED)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Period ...
|
|
if (period != NULL && iOrder.period != period)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// we now sure this order is EQM Support ...
|
|
Add(
|
|
iOrder,
|
|
supports);
|
|
}
|
|
|
|
//
|
|
// Count Result ...
|
|
result = ArraySize(supports);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Select EQM Support Orders by Type ...
|
|
int GetEQMSupportsByType(
|
|
XOrder &supports[], // Hold Result ...
|
|
XOrder &orders[], // List of All Orders ...
|
|
ENUM_TIMEFRAMES period = NULL, // Specified Period ...
|
|
ENUM_X121EQM_SUPPORT_TYPES type = NULL // EQM Support Type ...
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
XOrder mOrders[];
|
|
result = GetEQMSupportOrders(mOrders, orders, period);
|
|
if (result <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (type == NULL)
|
|
{
|
|
//
|
|
Copy(
|
|
mOrders,
|
|
supports);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
for (int i = 0; i < result; i++)
|
|
{
|
|
//
|
|
XOrder iOrder = mOrders[i];
|
|
|
|
//
|
|
if (iOrder.tp > 0 && type == XEQM_INBOUND)
|
|
{
|
|
//
|
|
Add(
|
|
iOrder,
|
|
supports);
|
|
}
|
|
else if (iOrder.tp == 0 && type == XEQM_UNBOUND)
|
|
{
|
|
//
|
|
Add(
|
|
iOrder,
|
|
supports);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(supports);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// NOTE:
|
|
// here we add all Supporting Signals preparations ...
|
|
// 1- must have at least TWO Support Signal without tp ...
|
|
// 2- there are some signals by providing tp ...
|
|
// 3- Trend base and Conditional Supports by tp ...
|
|
|
|
//
|
|
// UNBOUND Support => Support Signals with TP ...
|
|
// INBOUND Support => Support Signals without TP ...
|
|
|
|
//
|
|
// in each time when there are an open positions in DrawDown and it's passed
|
|
// a certain candles ...
|
|
// we Have to Placed atleast 2 UNBOUND Support Signals ...
|
|
|
|
//
|
|
// LIFETIME of Supports ...
|
|
// Each Support Signal must be Cancel if their doesn't triggered
|
|
// for an specific Number of Candels ...
|
|
|
|
//
|
|
// SUPPORT GENERATORs ...
|
|
|
|
//
|
|
// Generate Supports Signal For Market ...
|
|
int GenerateMarketSupports(
|
|
XSignal &supports[], // Hold Result
|
|
string symbol, // Trading Symbol
|
|
ENUM_TIMEFRAMES period, // Trading Timeframe
|
|
XSCX121Provider *analyzer, // Market Analizer
|
|
double volume = 0.01 // Provided Volume
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
// TODO: Variable ...
|
|
int numberOfItems = 10;
|
|
|
|
//
|
|
Clean(supports);
|
|
|
|
//
|
|
// Calculate Lng Exit Price ...
|
|
double longExit = GetExit(symbol, POSITION_TYPE_BUY);
|
|
|
|
//
|
|
// Generate Support and Resistances ...
|
|
XOHCLSupRes longSupRes = analyzer.GenerateSupportAndResistance(
|
|
longExit,
|
|
numberOfItems);
|
|
|
|
//
|
|
// Calculate Short Exit Price ...
|
|
double shortExit = GetExit(symbol, POSITION_TYPE_SELL);
|
|
|
|
//
|
|
// Generate Support and Resistances ...
|
|
XOHCLSupRes shortSupRes = analyzer.GenerateSupportAndResistance(
|
|
shortExit,
|
|
numberOfItems);
|
|
|
|
//
|
|
X121MarketConditions mConditions = analyzer.GetMarketConditions(1);
|
|
|
|
//
|
|
double tp = 0;
|
|
double sl = 0;
|
|
double max = 0;
|
|
double med = 0;
|
|
double min = 0;
|
|
double entry = 0;
|
|
double tpPointPrice = PointToPrice(
|
|
symbol,
|
|
supportsSginalTpPoint);
|
|
|
|
//
|
|
XSignal mSignal;
|
|
Clean(mSignal);
|
|
|
|
//
|
|
// 1- Breakout PEAK to UP ...
|
|
// 2- Breakout PEAK to Down ...
|
|
// 3- Breakeout VALE Down ...
|
|
|
|
//
|
|
mSignal.ignoreTP = false;
|
|
mSignal.ignoreSL = false;
|
|
mSignal.calculateTP = false;
|
|
mSignal.useRiskAmountAsVolume = true;
|
|
|
|
//
|
|
mSignal.symbol = symbol;
|
|
mSignal.period = period;
|
|
mSignal.riskAmount = volume;
|
|
|
|
//
|
|
// 1
|
|
|
|
//
|
|
mSignal.mode = X_ORDER_MODE_LIMIT;
|
|
mSignal.type = POSITION_TYPE_SELL;
|
|
|
|
//
|
|
entry = mConditions.xpvInfo.peak;
|
|
tp = entry - tpPointPrice;
|
|
|
|
//
|
|
mSignal.tp = tp;
|
|
mSignal.entry = entry;
|
|
|
|
//
|
|
Add(
|
|
mSignal,
|
|
supports);
|
|
|
|
//
|
|
Clean(mSignal);
|
|
|
|
//
|
|
mSignal.ignoreTP = false;
|
|
mSignal.ignoreSL = false;
|
|
mSignal.calculateTP = false;
|
|
mSignal.useRiskAmountAsVolume = true;
|
|
|
|
//
|
|
mSignal.symbol = symbol;
|
|
mSignal.period = period;
|
|
mSignal.riskAmount = volume;
|
|
|
|
//
|
|
// 2
|
|
|
|
//
|
|
mSignal.mode = X_ORDER_MODE_STOP;
|
|
mSignal.type = POSITION_TYPE_BUY;
|
|
|
|
//
|
|
entry = mConditions.xpvInfo.peak;
|
|
tp = entry + tpPointPrice;
|
|
|
|
//
|
|
mSignal.tp = tp;
|
|
mSignal.entry = entry;
|
|
|
|
//
|
|
Add(
|
|
mSignal,
|
|
supports);
|
|
|
|
//
|
|
Clean(mSignal);
|
|
|
|
//
|
|
mSignal.ignoreTP = false;
|
|
mSignal.ignoreSL = false;
|
|
mSignal.calculateTP = false;
|
|
mSignal.useRiskAmountAsVolume = true;
|
|
|
|
//
|
|
mSignal.symbol = symbol;
|
|
mSignal.period = period;
|
|
mSignal.riskAmount = volume;
|
|
|
|
//
|
|
// 3
|
|
|
|
//
|
|
mSignal.mode = X_ORDER_MODE_STOP;
|
|
mSignal.type = POSITION_TYPE_SELL;
|
|
|
|
//
|
|
entry = mConditions.xpvInfo.vale;
|
|
tp = entry + tpPointPrice;
|
|
|
|
//
|
|
mSignal.tp = tp;
|
|
mSignal.entry = entry;
|
|
|
|
//
|
|
Add(
|
|
mSignal,
|
|
supports);
|
|
|
|
//
|
|
Clean(mSignal);
|
|
|
|
//
|
|
result = ArraySize(supports);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Generate Support Signal for Specific Signal ...
|
|
bool GenerateSignalSupports(
|
|
XSignal &signal, // Source Signal
|
|
XSCX121Provider *analyzer // Market Analizer
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
Clean(signal.supports);
|
|
|
|
//
|
|
string providerStr = signal.providers[0];
|
|
if (StringLen(providerStr) == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X121_SIGNAL_PROVIDERS provider = ToProvider(providerStr);
|
|
bool isAllowed = analyzer.IsAllowdSignaller(provider);
|
|
if (!isAllowed)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(
|
|
signal.type);
|
|
bool isLongSupport = !isLong;
|
|
|
|
//
|
|
ENUM_POSITION_TYPE type =
|
|
isLong
|
|
? POSITION_TYPE_SELL
|
|
: POSITION_TYPE_BUY;
|
|
|
|
//
|
|
double tp = 0;
|
|
double sl = 0;
|
|
double volume = signal.volume * 2;
|
|
double entry = GetEntry(
|
|
type);
|
|
|
|
//
|
|
double tpPriceDistance = MathAbs(signal.entry - signal.tp);
|
|
double tpPoint = PriceToPoint(
|
|
signal.symbol,
|
|
tpPriceDistance);
|
|
|
|
//
|
|
double ll3 = GetLowestLow(
|
|
signal.symbol,
|
|
signal.period,
|
|
3,
|
|
0);
|
|
|
|
//
|
|
double hh3 = GetHighestHigh(
|
|
signal.symbol,
|
|
signal.period,
|
|
3,
|
|
0);
|
|
|
|
//
|
|
// XPV ...
|
|
double fl1 = analyzer.mXPVHelper.fl1Buffer[0];
|
|
double fl2 = analyzer.mXPVHelper.fl2Buffer[0];
|
|
double fl3 = analyzer.mXPVHelper.fl3Buffer[0];
|
|
double peak = analyzer.mXPVHelper.peaksBuffer[0];
|
|
double vales = analyzer.mXPVHelper.valesBuffer[0];
|
|
|
|
//
|
|
double distancePrice =
|
|
isLong
|
|
? MathAbs(signal.entry - ll3)
|
|
: MathAbs(signal.entry - hh3);
|
|
double distancePoint =
|
|
PriceToPoint(
|
|
signal.symbol,
|
|
distancePrice);
|
|
double supportTpPrice =
|
|
PointToPrice(
|
|
signal.symbol,
|
|
distancePoint + tpPoint);
|
|
|
|
entry =
|
|
isLongSupport
|
|
? hh3
|
|
: ll3;
|
|
tp =
|
|
isLongSupport
|
|
? entry + supportTpPrice
|
|
: entry - supportTpPrice;
|
|
|
|
//
|
|
XSignal tmpSignal;
|
|
Clean(tmpSignal);
|
|
|
|
//
|
|
tmpSignal.r2r = 0;
|
|
tmpSignal.volume = volume;
|
|
tmpSignal.ignoreTP = false;
|
|
tmpSignal.ignoreSL = false;
|
|
tmpSignal.riskAmount = volume;
|
|
tmpSignal.calculateTP = false;
|
|
tmpSignal.symbol = signal.symbol;
|
|
tmpSignal.period = signal.period;
|
|
tmpSignal.useRiskAmountAsVolume = true;
|
|
tmpSignal.useSupportAndResistance = false;
|
|
|
|
//
|
|
tmpSignal.type = type;
|
|
|
|
//
|
|
Add(
|
|
providerStr,
|
|
tmpSignal.providers);
|
|
|
|
//
|
|
switch (provider)
|
|
{
|
|
//
|
|
// X92 ...
|
|
case X92:
|
|
//
|
|
tmpSignal.tp = tp;
|
|
tmpSignal.sl = sl;
|
|
tmpSignal.entry = entry;
|
|
tmpSignal.mode = X_ORDER_MODE_STOP;
|
|
|
|
//
|
|
Add(
|
|
tmpSignal,
|
|
signal.supports);
|
|
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(signal.supports) > 0;
|
|
|
|
//
|
|
return result;
|
|
} |