1554 lines
32 KiB
Plaintext
1554 lines
32 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Expert Advisor
|
|
// ----------------------------------------
|
|
// Name: XEA
|
|
// Description: this is an expert controller
|
|
// advisors which provides a mechanism for use them ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://saherelm.ir"
|
|
#property version "1.00"
|
|
#property description "SaherElm XEA EA"
|
|
#property strict
|
|
|
|
//
|
|
// START Definitions ...
|
|
//
|
|
|
|
//
|
|
string mProviderPrefix = "PRV";
|
|
string mSupportPrefix = "SP";
|
|
|
|
//
|
|
enum ENUM_X_SIGNAL_PROVIDERS
|
|
{
|
|
NONE = 0,
|
|
XICHI = 1,
|
|
};
|
|
|
|
//
|
|
// END Definitions ...
|
|
//
|
|
|
|
//
|
|
// START Inputs ...
|
|
//
|
|
|
|
//
|
|
// EA ...
|
|
input group "Common";
|
|
input bool xEAEnable = true; // Enable EA
|
|
input int xEASlippage = 10; // Slippgae
|
|
input ulong xEAMagicNumber = 1604056; // Magic Number
|
|
|
|
//
|
|
// Determine Symbols and TimeFrames ...
|
|
input group "Symbols and Time Frames";
|
|
//
|
|
// (EURUSDb|M5|0.0005)
|
|
// (EURUSDb|M5|0.0005)_(USDCHFb|M5|0.0005)_(USDJPYb|M5|0.0005)_(GBPUSDb|M5|0.0005)
|
|
// (EURUSDb|M5,M15,M30|0.0005)_(USDCHFb|M5,M15|0.0005)_(USDJPYb|M5,M15|0.0005)_(GBPUSDb|M5,M15,M30|0.0005)_(AUDUSDb|M5,M15|0.0005)_(USDCADb|M5,M15|0.0005)_(NZDUSDb|M5,M15|0.0005)_(XAUUSDb|M5|0.0005)
|
|
input string xEAProvidersDescription = "(EURUSDb|M5|0.0005)"; // Specify Symbols and Time Frames
|
|
|
|
//
|
|
// Signals ...
|
|
input group "Signals";
|
|
input bool xEAEnableLongs = true; // Enable Long Trades
|
|
input bool xEAEnableShorts = true; // Enable Short Trades
|
|
|
|
//
|
|
// Risk Management ...
|
|
input group "Risk Management";
|
|
input int xEAMaxOpenPositions = 15; // Max Allowed Open Positions
|
|
input bool xEABalancePositions = true; // Balance Positions
|
|
input double xEAMaxAllowedDrawDownFactor = 0.15; // Max Allowed Drawdown Factor
|
|
input int xEATrailStopsInPoint = 0; // Trail Stops Moving Rate in Points
|
|
input int xEAMinProfitForHedging = 5; // Hedge Positions on Minimum Profit
|
|
input double xEAMaxDrawdownForClosePosition = 0; // Max Drawdown For Close Positions
|
|
input double xEAMaxDrawdownForSupportPosition = 0; // Max Drawdown For Open Support Positions
|
|
|
|
//
|
|
// Alerts ...
|
|
input group "Alerts";
|
|
input bool xEAEnableAlerts = true; // Enable Events Alert
|
|
input bool xEAEnableHourlyAlerts = false; // Send Alert on each new Hour
|
|
input bool xEAEnableDailyAlerts = false; // Send Alert on each new Day
|
|
input bool xEAEnableWeeklyAlerts = false; // Send Alert on each new Week
|
|
input bool xEAEnableMonthlyAlerts = false; // Send Alert on each new Month
|
|
|
|
//
|
|
// END Inputs ...
|
|
//
|
|
|
|
//
|
|
// START Including Providers ...
|
|
//
|
|
|
|
//
|
|
// Logger Library ...
|
|
#include "../Libraries/x-saherelm.log.lib.mq5"
|
|
|
|
//
|
|
// Common Library ...
|
|
#include "../Libraries/x-saherelm.common.lib.mq5"
|
|
|
|
//
|
|
// Alert Library ...
|
|
#include "../Libraries/x-saherelm.alert.lib.mq5"
|
|
|
|
//
|
|
// Draw Library ...
|
|
#include "../Libraries/x-saherelm.draw.lib.mq5"
|
|
|
|
//
|
|
// Account Class ...
|
|
#include "../Classes/x-saherelm.xaccount.class.mq5"
|
|
|
|
//
|
|
// Trade Class ...
|
|
#include "../Classes/x-saherelm.xtrade.class.mq5"
|
|
|
|
//
|
|
// Signal Provider Class Library ...
|
|
#include "../Providers/x.saherelm.x121.provider.mq5"
|
|
|
|
//
|
|
// END Including Providers ...
|
|
//
|
|
|
|
//
|
|
// START Global Definitions: Variables, Properties and etc ...
|
|
//
|
|
|
|
//
|
|
bool isXEANewHour;
|
|
bool isXEANewDay;
|
|
bool isXEANewWeek;
|
|
bool isXEANewMonth;
|
|
|
|
//
|
|
// Determines EA is Running On Test Mode or not ...
|
|
bool xEAIsTestMode = false;
|
|
|
|
//
|
|
// Check prevent Double Signalling on Same Candle ...
|
|
bool xEAWaitUntilNextCandle = false;
|
|
|
|
//
|
|
XSCTrade *xEATrade;
|
|
XSCAccount *xEAAccount;
|
|
XLastSignal xEALastSignals[];
|
|
X121SignalProvider xEAProviders[];
|
|
|
|
//
|
|
// END Global Definitions: Variables, Properties and etc ...
|
|
//
|
|
|
|
//
|
|
// START Event Handlers ...
|
|
//
|
|
|
|
//
|
|
// Initialization ...
|
|
int OnInit()
|
|
{
|
|
//
|
|
logTag = "XEA";
|
|
drawPrefix = logTag;
|
|
alertPrefix = logTag;
|
|
|
|
//
|
|
// Reset Timings ...
|
|
ResetTiming();
|
|
|
|
//
|
|
// Validate Inputs ...
|
|
if (!ValidateInputs())
|
|
{
|
|
return INIT_PARAMETERS_INCORRECT;
|
|
}
|
|
|
|
//
|
|
// Initialize XEA Providers ...
|
|
if (!InitializeProviders())
|
|
{
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
//
|
|
// Initialize Trade Class ...
|
|
xEATrade = new XSCTrade(
|
|
xEASlippage,
|
|
xEAMagicNumber);
|
|
|
|
//
|
|
// Initialize Account Class ...
|
|
xEAAccount = new XSCAccount();
|
|
|
|
//
|
|
// Init Succeed ...
|
|
return INIT_SUCCEEDED;
|
|
}
|
|
|
|
//
|
|
// DeInitialization ...
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//
|
|
// REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function
|
|
// REASON_REMOVE 1 Program removed from a chart
|
|
// REASON_RECOMPILE 2 Program recompiled
|
|
// REASON_CHARTCHANGE 3 A symbol or a chart period is changed
|
|
// REASON_CHARTCLOSE 4 Chart closed
|
|
// REASON_PARAMETERS 5 Inputs changed by a user
|
|
// REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings
|
|
// REASON_TEMPLATE 7 Another chart template applied
|
|
// REASON_INITFAILED 8 The OnInit() handler returned a non-zero value
|
|
// REASON_CLOSE 9 Terminal closed
|
|
|
|
//
|
|
// Here we can handle De Initialization Reasons ...
|
|
delete xEATrade;
|
|
delete xEAAccount;
|
|
|
|
//
|
|
// De Initialize XEA Providers ...
|
|
}
|
|
|
|
//
|
|
// On Tick Handler ...
|
|
void OnTick()
|
|
{
|
|
//
|
|
// Handle Monthly Alert ...
|
|
bool isFirstMonth = xMonth == -1;
|
|
isXEANewMonth = IsNewMonth();
|
|
bool canMonthlyAlert =
|
|
isXEANewMonth &&
|
|
xEAEnableAlerts &&
|
|
xEAEnableMonthlyAlerts;
|
|
if (canMonthlyAlert)
|
|
{
|
|
//
|
|
string message = "New Month ...";
|
|
|
|
//
|
|
SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Handle Weekly Alert ...
|
|
bool isFirstWeek = xDayOfWeek == -1;
|
|
isXEANewWeek = IsNewWeek();
|
|
bool canWeeklyAlert =
|
|
isXEANewWeek &&
|
|
xEAEnableAlerts &&
|
|
xEAEnableWeeklyAlerts;
|
|
if (canWeeklyAlert)
|
|
{
|
|
//
|
|
string message = "New Week ...";
|
|
|
|
//
|
|
SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Handle Daily Alert ...
|
|
bool isFirstDay = xDay == -1;
|
|
isXEANewDay = IsNewDay();
|
|
bool canDailyAlert =
|
|
isXEANewDay &&
|
|
xEAEnableAlerts &&
|
|
xEAEnableDailyAlerts;
|
|
if (canDailyAlert)
|
|
{
|
|
//
|
|
string message = "New Day ...";
|
|
|
|
//
|
|
SendAlert(message);
|
|
}
|
|
|
|
//
|
|
// Handle Hourly Alert ...
|
|
bool isFirstHour = xHour == -1;
|
|
isXEANewHour = IsNewHour();
|
|
bool canHourlyAlert =
|
|
isXEANewHour &&
|
|
xEAEnableAlerts &&
|
|
xEAEnableHourlyAlerts;
|
|
if (canHourlyAlert)
|
|
{
|
|
//
|
|
string message = "New Hour ...";
|
|
|
|
//
|
|
SendAlert(message);
|
|
}
|
|
|
|
//
|
|
Guard();
|
|
|
|
//
|
|
// Prevent Going Forward if user Disable it ...
|
|
if (xEAEnable)
|
|
{
|
|
//
|
|
// Call All Providers OnTick Method ...
|
|
CallProvidersOnTick();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Trade Events ...
|
|
void OnTrade()
|
|
{
|
|
//
|
|
// TODO: Complete this ...
|
|
}
|
|
|
|
//
|
|
// END Event Handlers ...
|
|
//
|
|
|
|
//
|
|
// START Functions ...
|
|
//
|
|
|
|
//
|
|
// Validate Input Args for Initialization ...
|
|
bool ValidateInputs()
|
|
{
|
|
//
|
|
// TODO: Fix this ...
|
|
bool result = true;
|
|
|
|
//
|
|
// Validate Args ...
|
|
result =
|
|
//
|
|
xEASlippage > 0 &&
|
|
xEAMagicNumber > 0 &&
|
|
xEAMaxOpenPositions > 0 &&
|
|
xEAMaxAllowedDrawDownFactor > 0 &&
|
|
xEAMaxAllowedDrawDownFactor <= 0.4 &&
|
|
StringLen(xEAProvidersDescription) > 0
|
|
//
|
|
;
|
|
|
|
//
|
|
// Logging State ...
|
|
string message = "Validation of (" + logTag + ") Inputs " + (result ? "Succeeded" : "Failed") + " ...";
|
|
LogMessage(message);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract Signal Provider Struct from User Input ...
|
|
bool InitializeProviders()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
string workingString = xEAProvidersDescription;
|
|
StringTrimLeft(workingString);
|
|
StringTrimRight(workingString);
|
|
if (StringLen(workingString) == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string descriptors[];
|
|
int numOfDescriptors = StringSplit(
|
|
workingString,
|
|
StringGetCharacter("_", 0),
|
|
descriptors);
|
|
if (numOfDescriptors <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop Through Descriptors ...
|
|
for (int iDX = 0; iDX < numOfDescriptors; iDX++)
|
|
{
|
|
//
|
|
string descriptor = descriptors[iDX];
|
|
|
|
//
|
|
// Clear Start and End Pranteses ...
|
|
StringReplace(
|
|
descriptor,
|
|
"(",
|
|
"");
|
|
StringReplace(
|
|
descriptor,
|
|
")",
|
|
"");
|
|
|
|
//
|
|
string descriptorData[];
|
|
int numOfData = StringSplit(
|
|
descriptor,
|
|
StringGetCharacter("|", 0),
|
|
descriptorData);
|
|
if (numOfData < 3)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
string symbols[];
|
|
int numOfSymbols = StringSplit(
|
|
descriptorData[0],
|
|
StringGetCharacter(",", 0),
|
|
symbols);
|
|
if (numOfSymbols <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
string timeFrames[];
|
|
int numOfTimeFrames = StringSplit(
|
|
descriptorData[1],
|
|
StringGetCharacter(",", 0),
|
|
timeFrames);
|
|
if (numOfTimeFrames <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
string riskAmounts[];
|
|
int numOfRiskAmounts = StringSplit(
|
|
descriptorData[2],
|
|
StringGetCharacter(",", 0),
|
|
riskAmounts);
|
|
if (numOfRiskAmounts <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
for (int cpIdx = 0; cpIdx < numOfSymbols; cpIdx++)
|
|
{
|
|
//
|
|
string symbol = symbols[cpIdx];
|
|
|
|
//
|
|
for (int tfIdx = 0; tfIdx < numOfTimeFrames; tfIdx++)
|
|
{
|
|
//
|
|
string timeFrame = timeFrames[tfIdx];
|
|
ENUM_TIMEFRAMES period = ToPeriod(timeFrame);
|
|
|
|
//
|
|
double riskAmount = (double)(numOfRiskAmounts == numOfTimeFrames
|
|
? riskAmounts[tfIdx]
|
|
: riskAmounts[0]);
|
|
|
|
//
|
|
string magicNumberString = "169" + (string)iDX + (string)cpIdx + (string)tfIdx + (string)PeriodSeconds(period) + "4056";
|
|
ulong magicNumber = (ulong)magicNumberString;
|
|
|
|
//
|
|
X121SignalProvider providerDescriptor;
|
|
|
|
//
|
|
providerDescriptor.symbol = symbol;
|
|
providerDescriptor.period = period;
|
|
providerDescriptor.riskAmount = riskAmount;
|
|
providerDescriptor.magicNumber = magicNumber;
|
|
|
|
//
|
|
// Initial Provider Class Instance ...
|
|
XSCX121Provider *x121Provider = new XSCX121Provider(
|
|
symbol,
|
|
period);
|
|
|
|
//
|
|
// Attach On Signal Event Listener ...
|
|
x121Provider.AddOnSignalEventHandler(OnSignalRecieved);
|
|
|
|
//
|
|
providerDescriptor.provider = x121Provider;
|
|
|
|
//
|
|
Add(
|
|
providerDescriptor,
|
|
xEAProviders);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
result = true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void CallProvidersOnTick()
|
|
{
|
|
//
|
|
int providersCount = ArraySize(xEAProviders);
|
|
if (providersCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Loop Through Providers ...
|
|
for (int i = 0; i < providersCount; i++)
|
|
{
|
|
//
|
|
X121SignalProvider providerDescriptor = xEAProviders[i];
|
|
|
|
//
|
|
providerDescriptor.provider.OnTick();
|
|
}
|
|
}
|
|
|
|
//
|
|
void OnSignalRecieved(
|
|
XSignalInfo &info)
|
|
{
|
|
//
|
|
// Ignore Disabled Signals ...
|
|
if ((info.type == POSITION_TYPE_BUY && !xEAEnableLongs) ||
|
|
(info.type == POSITION_TYPE_SELL && !xEAEnableShorts))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Find Provider based On Signal Info ...
|
|
int providersCount = ArraySize(xEAProviders);
|
|
if (providersCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (StringLen(info.symbol) == 0 || info.period == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool isFoundDescriptor = false;
|
|
X121SignalProvider providerDescriptor;
|
|
|
|
//
|
|
for (int i = 0; i < providersCount; i++)
|
|
{
|
|
//
|
|
X121SignalProvider provDesc = xEAProviders[i];
|
|
|
|
//
|
|
if (provDesc.symbol == info.symbol &&
|
|
provDesc.period == info.period)
|
|
{
|
|
//
|
|
isFoundDescriptor = true;
|
|
providerDescriptor = provDesc;
|
|
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Prevent Moving Forward if there is no Descriptor Found ...
|
|
if (!isFoundDescriptor)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Count Open Positions ...
|
|
int openPositionsCount = xEATrade.OpenPositionsCount();
|
|
|
|
//
|
|
if (xEABalancePositions)
|
|
{
|
|
//
|
|
// Count Same Signals for Balancing ...
|
|
int smaeTypeOpenPositionsCount = xEATrade.OpenPositionsCount("", info.type);
|
|
|
|
//
|
|
if (openPositionsCount > (int)xEAMaxOpenPositions / 3)
|
|
{
|
|
//
|
|
if (smaeTypeOpenPositionsCount > (int)openPositionsCount / 2)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
string mTagId = GenerateTag(info);
|
|
|
|
//
|
|
// Check Last Signal ...
|
|
datetime barTime = iTime(
|
|
info.symbol,
|
|
info.period,
|
|
0);
|
|
|
|
//
|
|
XLastSignal lastSignal = {};
|
|
int foundedLastSignalId = -1;
|
|
bool isFoundLastSignal = false;
|
|
int lastSignalsCount = ArraySize(xEALastSignals);
|
|
|
|
//
|
|
for (int i = 0; i < lastSignalsCount; i++)
|
|
{
|
|
//
|
|
XLastSignal mLS = xEALastSignals[i];
|
|
if (mLS.provider == mTagId)
|
|
{
|
|
//
|
|
lastSignal = mLS;
|
|
foundedLastSignalId = i;
|
|
isFoundLastSignal = true;
|
|
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (isFoundLastSignal)
|
|
{
|
|
//
|
|
bool isSameDate = xEALastSignals[foundedLastSignalId].at == barTime;
|
|
if (isSameDate)
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
xEALastSignals[foundedLastSignalId].at = barTime;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
lastSignal.at = barTime;
|
|
lastSignal.provider = mTagId;
|
|
|
|
//
|
|
ArrayResize(
|
|
xEALastSignals,
|
|
ArraySize(xEALastSignals) + 1);
|
|
|
|
//
|
|
xEALastSignals[ArraySize(xEALastSignals) - 1] = lastSignal;
|
|
}
|
|
|
|
//
|
|
// Retrieve Tradable Balance ...
|
|
double availableBalance = xEAAccount.GetEquity();
|
|
|
|
//
|
|
// Here we Have to Check Some Conditions for Open
|
|
// Positions, before Do Calculations, for improve Performance ...
|
|
|
|
//
|
|
// Verify Open Positions ...
|
|
if (openPositionsCount >= xEAMaxOpenPositions)
|
|
{
|
|
//
|
|
LogMessage("Max Allowed Positions Reached ...");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Verify Available Balance ...
|
|
double balance = xEAAccount.GetBalance();
|
|
double minBalanceForTrades = balance * xEAMaxAllowedDrawDownFactor;
|
|
if (availableBalance <= minBalanceForTrades)
|
|
{
|
|
//
|
|
LogMessage("Max Drawdown Reached ...");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Here i Must Calculate TP and SL based on R2R and riskable Factor ...
|
|
bool isLong = IsLong(info.type);
|
|
|
|
//
|
|
// Correct Period ...
|
|
if (info.period == NULL)
|
|
{
|
|
info.period = providerDescriptor.period;
|
|
}
|
|
|
|
//
|
|
// Check Order Mode ...
|
|
if (info.mode == NULL)
|
|
{
|
|
//
|
|
// Set Market Execution as Default ...
|
|
info.mode = X_ORDER_MODE_MARKET;
|
|
}
|
|
|
|
//
|
|
// Calculate Entry Price ...
|
|
if (info.entry <= 0)
|
|
{
|
|
//
|
|
info.entry = GetEntry(
|
|
info.symbol,
|
|
info.type);
|
|
}
|
|
|
|
//
|
|
// R2R ...
|
|
if (info.r2r <= 0)
|
|
{
|
|
//
|
|
// Set Default Risk to Reward Ratio to 1 ...
|
|
info.r2r = 1;
|
|
}
|
|
|
|
//
|
|
// Set Risk Amount Factor ...
|
|
if (info.riskAmount <= 0)
|
|
{
|
|
//
|
|
info.riskAmount = providerDescriptor.riskAmount;
|
|
}
|
|
|
|
//
|
|
// Calculate TP and SL ...
|
|
double mPoint = GetPoints(info.symbol);
|
|
|
|
//
|
|
// Normalize SL Price ...
|
|
if (info.sl > 0)
|
|
{
|
|
info.sl = NormalizePrice(info.sl, info.symbol);
|
|
}
|
|
|
|
//
|
|
// Retrieve Symbol Point Value ...
|
|
double pointValue = xEAAccount.GetPointValue(info.symbol);
|
|
|
|
//
|
|
// Calculate Risk ...
|
|
double riskPrice = MathAbs(info.entry - info.sl);
|
|
riskPrice = NormalizePrice(riskPrice, info.symbol);
|
|
|
|
//
|
|
double riskPoints = PriceToPoint(riskPrice);
|
|
riskPoints = NormalizeDouble(riskPoints, 0);
|
|
|
|
//
|
|
// Calculating Reward based On Ratio ...
|
|
double rewardPoints = riskPoints * info.r2r;
|
|
double rewardPrice = PointToPrice(rewardPoints);
|
|
rewardPrice = NormalizePrice(rewardPrice, info.symbol);
|
|
|
|
//
|
|
// TODO: Remove This ...
|
|
// rewardPrice = PipsToPrice(
|
|
// info.symbol,
|
|
// 15
|
|
// );
|
|
|
|
//
|
|
// Calculate TP Price ...
|
|
double tpValue = isLong
|
|
? info.entry + rewardPrice
|
|
: info.entry - rewardPrice;
|
|
|
|
//
|
|
// Calculate SL Price ...
|
|
double slValue = isLong
|
|
? info.entry - riskPrice
|
|
: info.entry + riskPrice;
|
|
|
|
//
|
|
// Balance Amount which we risks on each Provider's Trade ...
|
|
double amount = availableBalance * info.riskAmount;
|
|
|
|
//
|
|
// Calculating Trade Volume based on risk Points and Amount ...
|
|
double volume = xEAAccount.CalculateVolume(
|
|
info.symbol,
|
|
amount,
|
|
riskPoints);
|
|
volume = NormalizeVolume(volume, info.symbol);
|
|
|
|
//
|
|
// Set Caculated TP, SL and Volume ...
|
|
info.tp = tpValue;
|
|
info.sl = slValue;
|
|
info.volume = 0.01; // volume;
|
|
|
|
//
|
|
string comment = "";
|
|
int signalProvidersCount = ArraySize(info.providers);
|
|
if (signalProvidersCount > 0)
|
|
{
|
|
//
|
|
string prvs = "";
|
|
for (int i = 0; i < signalProvidersCount; i++)
|
|
{
|
|
//
|
|
string p = info.providers[i];
|
|
|
|
//
|
|
if (StringLen(prvs) > 0)
|
|
{
|
|
prvs += ",";
|
|
}
|
|
|
|
//
|
|
prvs += p;
|
|
}
|
|
|
|
//
|
|
comment = "PRV(" + prvs + ")";
|
|
}
|
|
|
|
//
|
|
bool isPositionOpen = false;
|
|
|
|
//
|
|
// Open Signal Position ...
|
|
if (isLong)
|
|
{
|
|
//
|
|
isPositionOpen = xEATrade.Buy(
|
|
info.symbol,
|
|
info.period,
|
|
info.volume,
|
|
info.entry,
|
|
info.sl,
|
|
info.tp,
|
|
comment);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
isPositionOpen = xEATrade.Sell(
|
|
info.symbol,
|
|
info.period,
|
|
info.volume,
|
|
info.entry,
|
|
info.sl,
|
|
info.tp,
|
|
comment);
|
|
}
|
|
|
|
//
|
|
if (isPositionOpen)
|
|
{
|
|
//
|
|
// Retrieve Position Ticket ...
|
|
ulong ticket = xEATrade.GetLastOpenPositionTicket();
|
|
if (ticket == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Draw Signal ...
|
|
ReDrawSignal(ticket, info);
|
|
|
|
//
|
|
// Alert Position ...
|
|
LogMessage("Position: " + (string)ticket + " was Open ...");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do Guard Actions ...
|
|
void Guard()
|
|
{
|
|
//
|
|
// Close Max In Drawdown Position ...
|
|
HandleMaxDrawdown();
|
|
|
|
//
|
|
// Trailing Stops ...
|
|
HandleTrailing();
|
|
|
|
//
|
|
// Close All Open Positions in Pyramid ...
|
|
HandleHedging();
|
|
|
|
//
|
|
// Handle Support Signal Opening ...
|
|
HandleSupport();
|
|
}
|
|
|
|
//
|
|
// it is a way to Protect Open Signal ...
|
|
void HandleTrailing()
|
|
{
|
|
//
|
|
if (xEATrailStopsInPoint <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XPosition inProfitPositions[];
|
|
xEATrade.GetInProfitPositions(inProfitPositions);
|
|
int inProfitPositionsCount = ArraySize(inProfitPositions);
|
|
if (inProfitPositionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < inProfitPositionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = inProfitPositions[i];
|
|
|
|
//
|
|
bool isLong = IsLong(iPosition.type);
|
|
|
|
//
|
|
// Retrieve Exit Price ...
|
|
double exitPrice = GetExit(
|
|
iPosition.symbol,
|
|
iPosition.type);
|
|
|
|
//
|
|
double entryPrice = GetEntry(
|
|
iPosition.symbol,
|
|
iPosition.type);
|
|
|
|
//
|
|
// Calculate Price Distance ...
|
|
double distancePrice = iPosition.sl == 0
|
|
? MathAbs(iPosition.entry - exitPrice)
|
|
: MathAbs(iPosition.sl - exitPrice);
|
|
double distancePoint = PriceToPoint(
|
|
iPosition.symbol,
|
|
distancePrice);
|
|
|
|
//
|
|
if (distancePoint >= xEATrailStopsInPoint)
|
|
{
|
|
//
|
|
double trailStepPrice = PointToPrice(
|
|
iPosition.symbol,
|
|
xEATrailStopsInPoint);
|
|
|
|
//
|
|
double tp =
|
|
isLong
|
|
? iPosition.tp + trailStepPrice
|
|
: iPosition.tp - trailStepPrice;
|
|
double sl =
|
|
iPosition.sl == 0
|
|
? isLong
|
|
? entryPrice - trailStepPrice
|
|
: entryPrice + trailStepPrice
|
|
: isLong
|
|
? iPosition.sl + trailStepPrice
|
|
: iPosition.sl - trailStepPrice;
|
|
|
|
//
|
|
bool isModified = xEATrade.Modify(
|
|
iPosition.ticket,
|
|
sl,
|
|
tp);
|
|
if (isModified)
|
|
{
|
|
//
|
|
// Convert Position to Signal ...
|
|
|
|
//
|
|
XSignalInfo signal = ToSignalInfo(iPosition);
|
|
// ReDrawSignal(iPosition.ticket, signal);
|
|
|
|
//
|
|
// Alert Trailing ...
|
|
LogMessage("Position: " + (string)iPosition.ticket + ", was Trailed ...");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Hedging Close Positions ...
|
|
void HandleHedging()
|
|
{
|
|
//
|
|
if (xEAMinProfitForHedging <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int positionsCount = xEATrade.OpenPositionsCount();
|
|
if (positionsCount <= 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
double profit = xEATrade.GetPositionsProfit();
|
|
|
|
//
|
|
if (profit < xEAMinProfitForHedging)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Hedging Pyramid ...";
|
|
|
|
//
|
|
xEATrade.CloseAllPositions(comment);
|
|
}
|
|
|
|
//
|
|
// Support Positions ...
|
|
void HandleSupport()
|
|
{
|
|
//
|
|
if (xEAMaxDrawdownForSupportPosition <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int positionsCount = xEATrade.OpenPositionsCount();
|
|
if (positionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XPosition inDrawdownPositions[];
|
|
xEATrade.GetInDrawdownPositions(inDrawdownPositions);
|
|
int inDrawdownPositionsCount = ArraySize(inDrawdownPositions);
|
|
if (inDrawdownPositionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < inDrawdownPositionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = inDrawdownPositions[i];
|
|
|
|
//
|
|
if (MathAbs(iPosition.profit) >= xEAMaxDrawdownForSupportPosition)
|
|
{
|
|
//
|
|
// Here we have to Open Support Indirectional Position ...
|
|
OpenSupportPosition(iPosition);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close Max In Drawdown Position ...
|
|
void HandleMaxDrawdown()
|
|
{
|
|
//
|
|
if (xEAMaxDrawdownForClosePosition <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int positionsCount = xEATrade.OpenPositionsCount();
|
|
if (positionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XPosition inDrawdownPositions[];
|
|
xEATrade.GetInDrawdownPositions(inDrawdownPositions);
|
|
int inDrawdownPositionsCount = ArraySize(inDrawdownPositions);
|
|
if (inDrawdownPositionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < inDrawdownPositionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = inDrawdownPositions[i];
|
|
|
|
//
|
|
if (MathAbs(iPosition.profit) >= xEAMaxDrawdownForClosePosition)
|
|
{
|
|
//
|
|
// Here we have to Force Close Position ...
|
|
string comment = "Close On Guard ...";
|
|
bool isClosed = xEATrade.Close(
|
|
iPosition.ticket,
|
|
comment);
|
|
if (isClosed)
|
|
{
|
|
LogMessage("Position: " + (string)iPosition.ticket + " was Closed On Guard ...");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Draw Signal ...
|
|
void ReDrawSignal(const ulong ticket, XSignalInfo &signal)
|
|
{
|
|
//
|
|
return;
|
|
|
|
//
|
|
bool isLong = IsLong(signal.type);
|
|
|
|
//
|
|
string prefix = (string)ticket + "_" + ToString(signal.period);
|
|
|
|
//
|
|
RemoveDraws(prefix);
|
|
|
|
//
|
|
// Retrieve Time ...
|
|
datetime time = iTime(
|
|
signal.symbol,
|
|
signal.period,
|
|
0);
|
|
|
|
//
|
|
// Retrieve 3 Time ...
|
|
datetime time3 = iTime(
|
|
signal.symbol,
|
|
signal.period,
|
|
3);
|
|
|
|
//
|
|
color posColor = isLong
|
|
? clrAqua
|
|
: clrMagenta;
|
|
color tpColor = clrAqua;
|
|
color slColor = clrMagenta;
|
|
color entryColor = clrGold;
|
|
|
|
//
|
|
ENUM_LINE_STYLE vLineStyle = STYLE_DOT;
|
|
ENUM_LINE_STYLE tpLineStyle = STYLE_SOLID;
|
|
ENUM_LINE_STYLE slLineStyle = STYLE_SOLID;
|
|
ENUM_LINE_STYLE entryLineStyle = STYLE_SOLID;
|
|
|
|
//
|
|
long chartID = ChartID();
|
|
|
|
//
|
|
// Vertical Line ...
|
|
string vlName = prefix + "_" + (string)time;
|
|
|
|
//
|
|
DrawVerticalLine(
|
|
chartID,
|
|
vlName,
|
|
0,
|
|
time,
|
|
posColor,
|
|
vLineStyle);
|
|
|
|
//
|
|
// TP ...
|
|
double profit = (MathAbs(signal.tp - signal.entry)) * signal.volume;
|
|
string tpName = prefix + "_TP_" + (string)profit;
|
|
|
|
//
|
|
DrawTrendLine(
|
|
chartID,
|
|
tpName,
|
|
0,
|
|
time3,
|
|
signal.tp,
|
|
time,
|
|
signal.tp,
|
|
tpColor,
|
|
tpLineStyle);
|
|
|
|
//
|
|
// SL ...
|
|
double lost = (MathAbs(signal.sl - signal.entry)) * signal.volume;
|
|
string slName = prefix + "_SL_" + (string)lost;
|
|
|
|
//
|
|
DrawTrendLine(
|
|
chartID,
|
|
slName,
|
|
0,
|
|
time3,
|
|
signal.sl,
|
|
time,
|
|
signal.sl,
|
|
slColor,
|
|
slLineStyle);
|
|
|
|
//
|
|
// ENTRY ...
|
|
string entryName = prefix + "_ENTRY_" + (string)lost;
|
|
|
|
//
|
|
DrawTrendLine(
|
|
chartID,
|
|
entryName,
|
|
0,
|
|
time3,
|
|
signal.entry,
|
|
time,
|
|
signal.entry,
|
|
entryColor,
|
|
entryLineStyle);
|
|
}
|
|
|
|
//
|
|
// Convert Position to Signal ...
|
|
XSignalInfo ToSignalInfo(
|
|
XPosition &position)
|
|
{
|
|
//
|
|
XSignalInfo result;
|
|
|
|
//
|
|
result.tp = position.tp;
|
|
result.sl = position.sl;
|
|
result.type = position.type;
|
|
result.entry = position.entry;
|
|
result.symbol = position.symbol;
|
|
result.period = position.period;
|
|
result.volume = position.volume;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string ToString(ENUM_X_SIGNAL_PROVIDERS provider)
|
|
{
|
|
//
|
|
return EnumToString(provider);
|
|
}
|
|
|
|
//
|
|
ENUM_X_SIGNAL_PROVIDERS ToProvider(string provider)
|
|
{
|
|
//
|
|
ENUM_X_SIGNAL_PROVIDERS result;
|
|
|
|
//
|
|
if (ToString(XICHI) == provider)
|
|
{
|
|
result = XICHI;
|
|
}
|
|
else
|
|
{
|
|
result = NONE;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract Position Provider ...
|
|
ENUM_X_SIGNAL_PROVIDERS ExtractProviderFromComment(string comment)
|
|
{
|
|
//
|
|
ENUM_X_SIGNAL_PROVIDERS result = NONE;
|
|
|
|
//
|
|
if (StringLen(comment) <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string providerStr = ExtractString(
|
|
comment,
|
|
mProviderPrefix + "(",
|
|
")");
|
|
if (StringLen(providerStr) <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ToProvider(providerStr);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specific Type of Providers Positions ...
|
|
void GetSpecificProviderPositions(
|
|
XPosition &result[], // Holds Result
|
|
string symbol, // Trading Symbol
|
|
ENUM_TIMEFRAMES period, // Trading Period
|
|
ENUM_X_SIGNAL_PROVIDERS provider // Position Provider
|
|
)
|
|
{
|
|
//
|
|
Clear(result);
|
|
|
|
//
|
|
if (StringLen(symbol) == 0 || provider == NONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int positionsCount = xEATrade.OpenPositionsCount();
|
|
if (positionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XPosition symbolPeriodPositions[];
|
|
xEATrade.GetPositions(
|
|
symbolPeriodPositions,
|
|
symbol,
|
|
period);
|
|
int symbolPeriodPositionsCount = ArraySize(symbolPeriodPositions);
|
|
if (symbolPeriodPositionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < symbolPeriodPositionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = symbolPeriodPositions[i];
|
|
|
|
//
|
|
ENUM_X_SIGNAL_PROVIDERS iProvider = ExtractProviderFromComment(iPosition.comment);
|
|
if (iProvider == NONE || iProvider != provider)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
Add(
|
|
iPosition,
|
|
result);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find Reversal Position Type ...
|
|
ENUM_POSITION_TYPE GetSupportPositionType(ENUM_POSITION_TYPE type)
|
|
{
|
|
//
|
|
ENUM_POSITION_TYPE result = POSITION_TYPE_BUY;
|
|
|
|
//
|
|
if (type == POSITION_TYPE_BUY)
|
|
{
|
|
result = POSITION_TYPE_SELL;
|
|
}
|
|
else
|
|
{
|
|
result = POSITION_TYPE_BUY;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Position Has Supportable or not ...
|
|
bool IsSupportablePosition(XPosition &position)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (StringLen(position.comment) <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int supStrPos = StringFind(
|
|
position.comment,
|
|
mSupportPrefix + "(");
|
|
|
|
//
|
|
result = supStrPos < 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Position has Support Position or not ...
|
|
bool HasSupportPosition(XPosition &position)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int positionsCount = xEATrade.OpenPositionsCount();
|
|
|
|
//
|
|
if (positionsCount <= 0 ||
|
|
position.ticket == 0 ||
|
|
StringLen(position.comment) <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string supCommentStr = mSupportPrefix + "(" + (string)position.ticket + ")";
|
|
|
|
//
|
|
XPosition positions[];
|
|
xEATrade.GetPositions(positions);
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
int supCommentPos = StringFind(
|
|
iPosition.comment,
|
|
supCommentStr);
|
|
|
|
//
|
|
result = supCommentPos >= 0;
|
|
if (result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Open a Support Position based on Exists ...
|
|
void OpenSupportPosition(XPosition &position)
|
|
{
|
|
//
|
|
bool isSupportable = IsSupportablePosition(position);
|
|
if (!isSupportable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool hasSupport = HasSupportPosition(position);
|
|
if (hasSupport)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
ENUM_POSITION_TYPE type = GetSupportPositionType(position.type);
|
|
double entry = GetEntry(
|
|
position.symbol,
|
|
type);
|
|
|
|
//
|
|
bool isLong = IsLong(type);
|
|
|
|
//
|
|
double tpPrice = PipsToPrice(
|
|
position.symbol,
|
|
10);
|
|
double slPrice = PipsToPrice(
|
|
position.symbol,
|
|
5);
|
|
|
|
//
|
|
double tp = 0;
|
|
// isLong
|
|
// ? entry + tpPrice
|
|
// : entry - tpPrice;
|
|
|
|
//
|
|
double sl = 0;
|
|
// isLong
|
|
// ? entry - slPrice
|
|
// : entry + slPrice;
|
|
|
|
//
|
|
string comment = mSupportPrefix + "(" + (string)position.ticket + ")";
|
|
|
|
//
|
|
bool isPositionOpen = false;
|
|
//
|
|
// Open Signal Position ...
|
|
if (isLong)
|
|
{
|
|
//
|
|
isPositionOpen = xEATrade.Buy(
|
|
position.symbol,
|
|
position.period,
|
|
position.volume,
|
|
entry,
|
|
sl,
|
|
tp,
|
|
comment);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
isPositionOpen = xEATrade.Sell(
|
|
position.symbol,
|
|
position.period,
|
|
position.volume,
|
|
entry,
|
|
sl,
|
|
tp,
|
|
comment);
|
|
}
|
|
|
|
//
|
|
if (isPositionOpen)
|
|
{
|
|
//
|
|
LogMessage("Open Support Psition for: " + position.comment);
|
|
}
|
|
}
|
|
|
|
//
|
|
// END Functions ...
|
|
//
|