Initial Commit ...
This commit is contained in:
@@ -0,0 +1,710 @@
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 = 2; // 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.0003; // Lots Per Trade Percent
|
||||
input int maxOpenTrades = 4; // Maximum Open Trade
|
||||
input double maxDrawdownPercentPerPTrade = 0.45; // 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 ...
|
||||
lotsPerTradePercent < 0
|
||||
|| maxOpenTrades <= 0
|
||||
|| maxDrawdownPercentPerPTrade < 0
|
||||
|| minBalancePercent < 0
|
||||
|| maxEquityPercent < 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;
|
||||
}
|
||||
|
||||
//
|
||||
bool isPositionOpened = TradeSignal(
|
||||
request.signal,
|
||||
lotsPerTradePercent,
|
||||
//
|
||||
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: ", GetProviderIdentifier(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;
|
||||
}
|
||||
|
||||
//
|
||||
bool hasClosedLongTimeTrade = CloseAllLongTimeTrades(
|
||||
xMaximumCandlesPerTrade,
|
||||
X_XXX_PROVIDER
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// XR Signalling ...
|
||||
if (enableXRSignalling) {
|
||||
//
|
||||
if (xrCloseLongTrades) {
|
||||
//
|
||||
CloseAllProviderLongTrades(X_XR_PROVIDER);
|
||||
|
||||
//
|
||||
xrCloseLongTrades = false;
|
||||
}
|
||||
|
||||
//
|
||||
bool hasClosedLongTimeTrade = CloseAllLongTimeTrades(
|
||||
xRMaximumCandlesPerTrade,
|
||||
X_XR_PROVIDER
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Close Maximum DrawDown Passed Trades ...
|
||||
bool hasClosedInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades(
|
||||
maxDrawdownPercentPerPTrade
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// 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 = {};
|
||||
|
||||
//
|
||||
// START XR Signal Handler ...
|
||||
//
|
||||
//
|
||||
if (enableXRSignalling) {
|
||||
//
|
||||
CheckXRSignalHandler(
|
||||
bar_index
|
||||
);
|
||||
|
||||
//
|
||||
// Long Trades ...
|
||||
if (allowTrade && allowLongTrades) {
|
||||
//
|
||||
CheckXRLongSignalConditions(
|
||||
bar_index
|
||||
);
|
||||
|
||||
//
|
||||
XSignalRequest 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Short Trades ...
|
||||
if (allowTrade && allowShortTrades) {
|
||||
}
|
||||
}
|
||||
//
|
||||
// END XR Signal Handler ...
|
||||
//
|
||||
|
||||
//
|
||||
// START X Signal Handler ...
|
||||
//
|
||||
//
|
||||
if (enableXSignalling) {
|
||||
//
|
||||
CheckXSignalHandler(
|
||||
bar_index
|
||||
);
|
||||
|
||||
//
|
||||
// Long Trades ...
|
||||
if (allowTrade && allowLongTrades) {
|
||||
//
|
||||
if (xWaitForLongSignals) {
|
||||
//
|
||||
CheckXLongSignalConditions(
|
||||
bar_index
|
||||
);
|
||||
|
||||
//
|
||||
XSignalRequest 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
|
||||
);
|
||||
|
||||
//
|
||||
XSignalRequest 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;
|
||||
}
|
||||
Reference in New Issue
Block a user