Files
MQL4Data/Bkp/BTCUSD-15M/Experts/x-saherelm.ea.mq4
T
2024-01-25 04:05:58 +03:30

1039 lines
26 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center XST Strategy Expert Advisor
// ---------------------------------------------
// saherelm implementation of strategy expert advisor ...
// in this EA, we try to combine multiple tools, to ashive best
// results ...
//
// ShortName: XST
//
// Maintainer:
// ------------
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
// +989121694056
//
//////////////////////////////////////////////////////
//
// Global Properties ...
#property copyright "Copyright 2023, SaherElm IT Center"
#property link "https://saherelm.ir"
#property version "1.00"
#property description "SaherElm XST Strategy Expert Advisor"
#property strict
//
// START Inputs ...
//
//
// Signal Prefixe ...
input string signalPrefix = "XST_EA"; // Signal Prefix
//
// Signal Draw Specifications ...
input string bullishSignalLabel = "X_BUY"; // Bullish Signal Label
input color bullishSignalColor = clrAqua; // Bullish Signal Color
//
input string bearishSignalLabel = "X_SELL"; // Bearish Signal Label
input color bearishSignalColor = clrFuchsia; // Bearish Signal Color
//
input color signalEntryColor = clrAquamarine; // Signal Entry Ptice Color
input color signalSLColor = clrRed; // Signal SL Color
input color signalTPColor = clrGreen; // Signal TP Color
//
input int candleGapBetweenSignals = 7; // How many Candle waits to new Signal from last one
//
// Trade ...
input bool allowTrade = true; // Allow Trade Based on given Signals
input bool allowLongTrades = true; // Allow Long Trades
input bool allowShortTrades = true; // Allow Short Trades
//
// Alerts ...
input bool alertEvents = true; // Alert Events
input bool alertPositions = true; // Alert Positions
input bool longPositionAlerts = true; // Alert Long Positions
input bool shortPositionAlerts = true; // Alert Short Positions
//
// Alert Types ...
input bool terminalAlert = false; // Terminal Alert
input bool pushAlert = false; // Push Notification Alerts
//
// Balance and Finanical Specifications ...
input double lotsPerTradePercent = 0.00001; // Lots Per Trade Percent
input int maxOpenTrades = 4; // Maximum Open Trade
input double maxDrawdownPercentPerPTrade = 0.1; // Maximum DrawDown Per Trade
input double minBalancePercent = 0.5; // Minimum Balance for Trading
input double maxEquityPercent = 0.1; // Maximum Trade Equity
//
// START Global Definitions: Variables, Properties and etc ...
//
int lastSignalledBar = 0;
//
// Includes our shared library ...
#include "../Libraries/x-saherelm.lib.mq4"
//
// Includes our shared library ...
#include "../Libraries/x-saherelm.signal.lib.mq4"
//
int maxMarketLength = 0;
//
// END Global Definitions: Variables, Properties and etc ...
//
//
// Start Event Handlers ...
//
//
// Initialization ...
int OnInit() {
//
// Validate Inputs ...
bool inputsNotValiid =
//
// EA ...
maxOpenTrades <= 0
|| maxEquityPercent < 0
|| minBalancePercent < 0
|| lotsPerTradePercent < 0
|| maxDrawdownPercentPerPTrade < 0
;
//
if (inputsNotValiid) {
return INIT_PARAMETERS_INCORRECT;
}
//
totalSignals = 0;
totalLongSignals = 0;
totalShortSignals = 0;
//
initialBalance = 0;
//
// START Define Array Series ...
//
//
// END Define Array Series ...
//
//
// here we specify logging enabled or not ...
enableLogging = true;
//
// this is a Tag which attached to our Logger ...
logTag = "XST";
//
ClearSignalConditions();
//
maxMarketLength = MathMax(0, GetDailyCandleCount());
//
return INIT_SUCCEEDED;
}
//
// DeInitialization ...
void OnDeinit(const int reason) {
}
//
// Ticker Event Handler ...
void OnTick() {
//
isNewDay = IsNewDay();
if (isNewDay) {
//
LogMessage(
StringConcatenate(
"New Day ..."
)
);
}
//
// Process Signals to Open Positions ...
ProcessSignals();
//
// Checking State for Signal Handling ...
CheckState();
//
// Process Open Positions for Trailing Stop Loss or Close ...
ProcessOpenPositions();
}
//
// END Event Handlers ...
//
//
// START Functions ...
//
//
// Check State for Signal Handling ...
void CheckState() {
//
// Here we Must to Check Market State for enable or disable
// Signal Handlers and also make dection to close all long/short
// trades ...
}
//
// Calculate Signals and Process Based on Exists Signals ...
void ProcessSignals() {
//
XSignalRequest request = {};
request.type = X_SIGNAL_NONE;
request.hasSignal = false;
//
// Prevent Multiple Calculating on Same Bars ...
isNewBar = IsNewBar();
if (isNewBar) {
countedBars++;
}
//
if (countedBars < maxMarketLength) {
return;
}
//
bool allowDoTrade = true;
//
// Check Balance ...
if (initialBalance > 0) {
//
// Retrieve Account Balance ...
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double minimumBalanceForTrade =
balance > initialBalance
?
minBalancePercent * balance
:
minBalancePercent * initialBalance;
//
// Retrieve Account Equity ...
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double maxAllowedEquity = balance - (balance * maxEquityPercent);
//
// Retrieve Free Marigin ...
double freeMargin = AccountFreeMargin();
double maximumMariginRisk = balance - (balance * maxEquityPercent);
//
if (
//
// Do not Open Positions if equity not passed ...
equity < maxAllowedEquity ||
//
// Do not Open Positions if free margin not passed ...
freeMargin <= maximumMariginRisk ||
//
// Do not open positions if balance less than minimum ...
balance <= minimumBalanceForTrade
) {
//
static bool tradingPauseAlerted;
//
allowDoTrade = false;
//
if (!tradingPauseAlerted) {
//
string message = StringConcatenate(
"Trading Pause => ",
"Balance: ", balance,
", Equity: ", equity,
", FreeMargin: ", freeMargin
);
//
LogMessage(message);
SendAlert(message);
//
tradingPauseAlerted = true;
}
}
}
//
// Retrieve Signal Exists ...
request = GenerateSignal(0);
//
// Prevent doing anything else, if there is no signals ...
if (
!allowDoTrade ||
!request.hasSignal ||
request.type == X_SIGNAL_NONE
) {
return;
}
//
bool hasLongSignal = request.type == X_SIGNAL_LONG;
//
// Check last Signalled Bar with Counted Bars ...
// Prevent Multiple Signalling on Same Bar ...
bool isInLastSignalledBars = false;
for (int i=0; i < candleGapBetweenSignals; i++) {
//
isInLastSignalledBars =
isInLastSignalledBars
|| lastSignalledBar == countedBars - i
;
}
if (isInLastSignalledBars) {
//
// Clear Signal Conditions ...
if (hasLongSignal) {
ClearLongSignalConditions();
} else {
ClearShortSignalConditions();
}
//
return;
}
//
// increase last signalled bar ...
lastSignalledBar = countedBars;
//
// Calculate Can Trade or not ...
allowDoTrade = allowTrade
&& (
hasLongSignal ?
allowLongTrades :
allowShortTrades
);
//
// Chack Maximum Open Positions ...
int openTrades = CountOpenTrades();
if (maxOpenTrades > 0) {
//
if (openTrades >= maxOpenTrades) {
//
allowDoTrade = false;
//
if (!allowDoTrade) {
//
string message = StringConcatenate(
"Trading Pause => ",
"Max Open Trades (",
maxOpenTrades,
") reached ..."
);
//
LogMessage(message);
SendAlert(message);
}
}
}
//
// Check Trading is Enable or not ...
// nothing to do if trading is disabled ...
if (!allowDoTrade) {
//
// Clear Signal Conditions ...
if (hasLongSignal) {
ClearLongSignalConditions();
} else {
ClearShortSignalConditions();
}
//
string message = StringConcatenate(
"Trading Not Allowed ..."
);
//
LogMessage(message);
SendAlert(message);
return;
}
//
// Retrieve Signal Lots Per Trade ...
double lPTradePercent = GetSignalLottage(
request.signal,
lotsPerTradePercent
);
//
bool isPositionOpened = TradeSignal(
request.signal,
lPTradePercent,
//
bullishSignalLabel,
bullishSignalColor,
bearishSignalLabel,
bearishSignalColor
);
//
totalSignals++;
if (hasLongSignal) {
//
totalLongSignals++;
ClearLongSignalConditions();
} else {
//
totalShortSignals++;
ClearShortSignalConditions();
}
//
if (isPositionOpened) {
//
bool canAlert =
alertPositions
&& (
hasLongSignal ?
longPositionAlerts
:
shortPositionAlerts
);
//
if (canAlert) {
//
// Alert Message ...
string message = StringConcatenate(
"Trade on Signal ID: ", request.signal.id,
", ProvidedBy: ", GetSignalProviderIdentifier(request.signal.provider),
", Entry: ", request.signal.entry,
", TP: ", request.signal.tp
);
//
// Terminal Alert ...
if (terminalAlert) {
Alert(message);
}
//
// Push Alert ...
if (pushAlert) {
SendNotification(message);
}
}
}
}
//
// Process All Open Positions ...
void ProcessOpenPositions() {
//
// XSignalling ...
if (enableXSignalling) {
//
// Close All XXX Provided Signals on it's Specific Condition ...
if (xCloseLongTrades) {
//
CloseAllProviderLongTrades(X_XXX_PROVIDER);
//
xCloseLongTrades = false;
}
//
if (xCloseShortTrades) {
//
CloseAllProviderShortTrades(X_XTPW_PROVIDER);
//
xCloseShortTrades = false;
}
//
// Close Maximum DrawDown Passed Trades ...
//
// Longs ...
bool hasClosedLongInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades(
xLongMaxDrawdownPerTradePercent,
X_SIGNAL_LONG,
X_XXX_PROVIDER
);
//
// Shorts ...
bool hasClosedShortInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades(
xShortMaxDrawdownPerTradePercent,
X_SIGNAL_SHORT,
X_XXX_PROVIDER
);
//
// Close All Long Time Trades based on Provider provided Length ...
bool hasClosedLongTimeTrade = CloseAllLongTimeTrades(
xMaximumCandlesPerTrade,
X_XXX_PROVIDER
);
//
if (
hasClosedLongTimeTrade
|| hasClosedLongInDrawDownLongTrade
|| hasClosedShortInDrawDownLongTrade
) {
xFailedSignals++;
}
}
//
// XR Signalling ...
if (enableXRSignalling) {
//
if (xRCloseLongTrades) {
//
CloseAllProviderLongTrades(X_XR_PROVIDER);
//
xRCloseLongTrades = false;
}
//
if (xRCloseShortTrades) {
//
CloseAllProviderShortTrades(X_XR_PROVIDER);
//
xRCloseShortTrades = false;
}
//
// Close Maximum DrawDown Passed Trades ...
//
// Longs ...
bool hasClosedLongInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades(
xRLongMaxDrawdownPerTradePercent,
X_SIGNAL_LONG,
X_XR_PROVIDER
);
//
// Shorts ...
bool hasClosedShortInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades(
xRShortMaxDrawdownPerTradePercent,
X_SIGNAL_SHORT,
X_XR_PROVIDER
);
//
// Close All Long Time Trades based on Provider provided Length ...
bool hasClosedLongTimeTrade = CloseAllLongTimeTrades(
xRMaximumCandlesPerTrade,
X_XR_PROVIDER
);
//
if (
hasClosedLongTimeTrade
|| hasClosedLongInDrawDownLongTrade
|| hasClosedShortInDrawDownLongTrade
) {
xRFailedSignals++;
}
}
//
// XTPW Signalling ...
if (enableXTPWSignalling) {
//
if (xTPWCloseLongTrades) {
//
CloseAllProviderLongTrades(X_XTPW_PROVIDER);
//
xTPWCloseLongTrades = false;
}
//
if (xTPWCloseShortTrades) {
//
CloseAllProviderShortTrades(X_XTPW_PROVIDER);
//
xTPWCloseShortTrades = false;
}
//
// Close Maximum DrawDown Passed Trades ...
//
// Longs ...
bool hasClosedLongInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades(
xTPWLongMaxDrawdownPerTradePercent,
X_SIGNAL_LONG,
X_XTPW_PROVIDER
);
//
// Shorts ...
bool hasClosedShortInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades(
xTPWShortMaxDrawdownPerTradePercent,
X_SIGNAL_SHORT,
X_XTPW_PROVIDER
);
//
// Close All Long Time Trades based on Provider provided Length ...
bool hasClosedLongTimeTrade = CloseAllLongTimeTrades(
xTPWMaximumCandlesPerTrade,
X_XTPW_PROVIDER
);
//
if (
hasClosedLongTimeTrade
|| hasClosedLongInDrawDownLongTrade
|| hasClosedShortInDrawDownLongTrade
) {
xTPWFailedSignals++;
}
}
//
// Close Maximum DrawDown Passed Trades ...
// this is the Maximum Controller ...
//
double maxOfXPercent = enableXSignalling ?
MathMax(
xLongMaxDrawdownPerTradePercent,
xShortMaxDrawdownPerTradePercent
) : 0
;
//
double maxOfXRPercent = enableXRSignalling ?
MathMax(
xRLongMaxDrawdownPerTradePercent,
xRShortMaxDrawdownPerTradePercent
) : 0
;
//
double maxOfXTPWPercent = enableXTPWSignalling ?
MathMax(
xTPWLongMaxDrawdownPerTradePercent,
xTPWShortMaxDrawdownPerTradePercent
) : 0
;
//
double maxDrawDownPercent = MathMax(
maxOfXPercent,
maxOfXRPercent
);
maxDrawDownPercent = MathMax(
maxDrawDownPercent,
maxOfXTPWPercent
);
maxDrawDownPercent = MathMax(
maxDrawDownPercent,
maxDrawdownPercentPerPTrade
);
//
// we Calculate Max DrawDown Percent Per Trade ...
// then try to Close based on them ...
bool hasClosedInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades(
maxDrawDownPercent
);
}
//
// Send Special Type of Alerts ...
void SendAlert(string message) {
//
if (!alertEvents) {
return;
}
//
// Terminal Alert ...
if (terminalAlert) {
Alert(message);
}
//
// Push Alert ...
if (pushAlert) {
SendNotification(message);
}
}
//
// END Functions ...
//
//
//
// Calculate Signal ...
// in this function we calculate a signal exists in
// specific bar or not ...
XSignalRequest GenerateSignal(
const int bar_index // Bar Index ...
) {
//
// create temp result ...
XSignalRequest result = {};
result.hasSignal = false;
result.type = X_SIGNAL_NONE;
result.provider = X_UNKNOWN_PROVIDER;
//
bool hasSignal = false;
bool hasLongSignal = false;
bool hasShortSignal = false;
//
XSignal signal = {};
//
// Define Template Signal Requests for Managing Multiple Signals ...
//
// X ...
XSignalRequest xLongSignalRequest = {};
XSignalRequest xShortSignalRequest = {};
//
// XR ...
XSignalRequest xrLongSignalRequest = {};
XSignalRequest xrShortSignalRequest = {};
//
// XTPW ...
XSignalRequest xTPWLongSignalRequest = {};
XSignalRequest xTPWShortSignalRequest = {};
//
// START XR Signal Handler ...
//
//
if (enableXRSignalling) {
//
CheckXRSignalHandler(
bar_index
);
//
// Long Trades ...
if (allowTrade && allowLongTrades) {
//
if (xRWaitForLongSignals) {
//
CheckXRLongSignalConditions(
bar_index
);
//
xrLongSignalRequest = GenerateXRSignal(
X_SIGNAL_LONG,
signalPrefix,
bar_index
);
//
if (xrLongSignalRequest.hasSignal) {
//
// Here we can Check and Filter Signals Based On State ...
bool isReady = IsReadyForXRSignals(
xrLongSignalRequest.signal
);
//
if (isReady && xRWaitForLongSignals) {
//
hasLongSignal = true;
signal = xrLongSignalRequest.signal;
} else {
ClearXRLongSignalConditions();
}
}
} else {
ClearXRLongSignalConditions();
}
}
//
// Short Trades ...
if (allowTrade && allowShortTrades) {
//
if (xRWaitForShortSignals) {
//
CheckXRShortSignalConditions(
bar_index
);
//
xrShortSignalRequest = GenerateXRSignal(
X_SIGNAL_SHORT,
signalPrefix,
bar_index
);
//
if (xrShortSignalRequest.hasSignal) {
//
// Here we can Check and Filter Signals Based On State ...
bool isReady = IsReadyForXRSignals(
xrShortSignalRequest.signal
);
//
if (isReady && xRWaitForShortSignals) {
//
hasShortSignal = true;
signal = xrShortSignalRequest.signal;
} else {
ClearXRShortSignalConditions();
}
}
} else {
ClearXRShortSignalConditions();
}
}
}
//
// END XR Signal Handler ...
//
//
// START XTPW Signal Handler ...
//
if (enableXTPWSignalling) {
//
CheckXTPWSignalHandler(
bar_index
);
//
// Long Trades ...
if (allowTrade && allowLongTrades) {
//
if (xTPWWaitForLongSignals) {
//
CheckXTPWLongSignalConditions(
bar_index
);
//
xTPWLongSignalRequest = GenerateXTPWSignal(
X_SIGNAL_LONG,
signalPrefix,
bar_index
);
//
if (xTPWLongSignalRequest.hasSignal) {
//
// Here we can Check and Filter Signals Based On State ...
bool isReady = IsReadyForXTPWSignals(
xTPWLongSignalRequest.signal
);
//
if (isReady && xTPWWaitForLongSignals) {
//
hasLongSignal = true;
signal = xTPWLongSignalRequest.signal;
} else {
ClearXTPWLongSignalConditions();
}
}
} else {
ClearXTPWLongSignalConditions();
}
}
//
// Short Trades ...
if (allowTrade && allowShortTrades) {
//
if (xTPWWaitForShortSignals) {
//
CheckXTPWShortSignalConditions(
bar_index
);
//
xTPWShortSignalRequest = GenerateXTPWSignal(
X_SIGNAL_SHORT,
signalPrefix,
bar_index
);
//
if (xTPWShortSignalRequest.hasSignal) {
//
// Here we can Check and Filter Signals Based On State ...
bool isReady = IsReadyForXTPWSignals(
xTPWShortSignalRequest.signal
);
//
if (isReady && xTPWWaitForShortSignals) {
//
hasShortSignal = true;
signal = xTPWShortSignalRequest.signal;
} else {
ClearXTPWShortSignalConditions();
}
}
} else {
ClearXTPWShortSignalConditions();
}
}
}
//
// END XTPW Signal Handler ...
//
//
// START X Signal Handler ...
//
//
if (enableXSignalling) {
//
CheckXSignalHandler(
bar_index
);
//
// Long Trades ...
if (allowTrade && allowLongTrades) {
//
if (xWaitForLongSignals) {
//
CheckXLongSignalConditions(
bar_index
);
//
xLongSignalRequest = GenerateXSignal(
X_SIGNAL_LONG,
signalPrefix,
bar_index
);
//
if (xLongSignalRequest.hasSignal) {
//
// Here we can Check and Filter Signals Based On State ...
bool isReady = IsReadyForXSignals(
xLongSignalRequest.signal
);
//
if (isReady && xWaitForLongSignals) {
//
hasLongSignal = true;
signal = xLongSignalRequest.signal;
} else {
ClearXLongSignalConditions();
}
}
} else {
ClearXLongSignalConditions();
}
}
//
// Short Trades ...
if (allowTrade && allowShortTrades) {
//
if (xWaitForShortSignals) {
//
CheckXShortSignalConditions(
bar_index
);
//
xShortSignalRequest = GenerateXSignal(
X_SIGNAL_SHORT,
signalPrefix,
bar_index
);
//
if (xShortSignalRequest.hasSignal) {
//
// Here we can Check and Filter Signals Based On State ...
bool isReady = IsReadyForXSignals(
xShortSignalRequest.signal
);
//
if (isReady && xWaitForShortSignals) {
//
hasShortSignal = true;
signal = xShortSignalRequest.signal;
} else {
ClearXShortSignalConditions();
}
}
} else {
ClearXShortSignalConditions();
}
}
}
//
// END XR Signal Handler ...
//
//
hasSignal = hasLongSignal || hasShortSignal;
//
if (!hasSignal) {
//
signal.type = X_SIGNAL_NONE;
result.type = X_SIGNAL_NONE;
}
//
// Normalize TP, SL and Entry Price ...
signal.tp = NormalizeDouble(signal.tp, _Digits);
signal.sl = NormalizeDouble(signal.sl, _Digits);
signal.entry = NormalizeDouble(signal.entry, _Digits);
//
result.signal = signal;
result.type = signal.type;
result.hasSignal = hasSignal;
result.provider = signal.provider;
//
// Return Result ...
return result;
}