1354 lines
28 KiB
Plaintext
1354 lines
28 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Expert Advisor
|
|
// ----------------------------------------
|
|
// Name: XEA TEST
|
|
// 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 mSupportToken = "SP";
|
|
string mProviderToken = "PRV";
|
|
string mRiskFreeToken = "RF";
|
|
|
|
//
|
|
enum ENUM_X_SIGNAL_PROVIDERS
|
|
{
|
|
NONE = 0,
|
|
XTRND = 1,
|
|
XICHI = 2,
|
|
XTest = 10,
|
|
};
|
|
|
|
//
|
|
// 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
|
|
|
|
//
|
|
// Signals ...
|
|
input group "Signals";
|
|
input bool xEAEnableLongs = true; // Enable Long Trades
|
|
input bool xEAEnableShorts = true; // Enable Short Trades
|
|
|
|
//
|
|
// 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 ...
|
|
//
|
|
|
|
//
|
|
// Classes ...
|
|
#include "../../Classes/x-saherelm.xtrade.class.mq5"
|
|
#include "../../Classes/x-saherelm.xaccount.class.mq5"
|
|
#include "../../Classes/x-saherelm.xdatacollector.class.mq5"
|
|
|
|
//
|
|
// Test Provider Library ...
|
|
#include "../../Providers/Test/x121.test.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;
|
|
XSCDataCollector *xEACollector;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// Init Provider ...
|
|
if (!XTestPRVDOnInit())
|
|
{
|
|
return INIT_FAILED;
|
|
}
|
|
|
|
//
|
|
xEAIsTestMode = IsRunningOnTestMode();
|
|
|
|
//
|
|
xEACollector = new XSCDataCollector("XTestEA");
|
|
xEACollector.CleanStore();
|
|
|
|
//
|
|
// Initialize Trade Class ...
|
|
xEATrade = new XSCTrade(
|
|
xEASlippage,
|
|
xEAMagicNumber);
|
|
|
|
//
|
|
// Attach Event Handlers ...
|
|
xEATrade.AddOnStopLossEventHandler(OnStopLossTriggered);
|
|
xEATrade.AddOnTakeProfitEventHandler(OnTakeProfitTriggered);
|
|
xEATrade.AddOnDealsChangedEventHandler(OnDealsChangedHandler);
|
|
xEATrade.AddOnOrdersChangedEventHandler(OnOrdersChangedHandler);
|
|
|
|
//
|
|
// 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;
|
|
delete xEACollector;
|
|
|
|
//
|
|
// De Initialize XEA Providers ...
|
|
XTestPRVDOnDeInit();
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
//
|
|
// Prevent Going Forward if user Disable it ...
|
|
if (xEAEnable)
|
|
{
|
|
//
|
|
// Call All Providers OnTick Method ...
|
|
XTestPRVDOnTick();
|
|
|
|
//
|
|
// Do all Guard Mechanism ...
|
|
HandleGuard();
|
|
|
|
//
|
|
// Check Can Ignore Tick or not ..
|
|
bool canIgnoreTick = xEAIsTestMode
|
|
? !IsNewCandle()
|
|
: !IsNewCandle() && xEAWaitUntilNextCandle;
|
|
if (canIgnoreTick)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
xEAWaitUntilNextCandle = false;
|
|
|
|
//
|
|
XSignal signal;
|
|
bool hasSignal = XTestPRVDProcessSignals(signal);
|
|
if (hasSignal)
|
|
{
|
|
//
|
|
xEAWaitUntilNextCandle = true;
|
|
OnSignalRecieved(signal);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Trade Events ...
|
|
void OnTrade()
|
|
{
|
|
//
|
|
// Process Trades ...
|
|
xEATrade.HandleOnTrade();
|
|
}
|
|
|
|
//
|
|
// 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
|
|
//
|
|
;
|
|
|
|
//
|
|
// Logging State ...
|
|
string message = "Validation of (" + logTag + ") Inputs " + (result ? "Succeeded" : "Failed") + " ...";
|
|
LogMessage(message);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Signal Recieved Event ...
|
|
void OnSignalRecieved(
|
|
XSignal &signal // Recieved Signal ...
|
|
)
|
|
{
|
|
//
|
|
// Ignore Disabled Signals ...
|
|
if ((signal.type == POSITION_TYPE_BUY && !xEAEnableLongs) ||
|
|
(signal.type == POSITION_TYPE_SELL && !xEAEnableShorts))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (StringLen(signal.symbol) == 0 || signal.period == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
xEACollector.CollectSignal(signal);
|
|
|
|
//
|
|
// Count Open Positions ...
|
|
int openPositionsCount = xEATrade.PositionsCount();
|
|
|
|
//
|
|
string mTagId = GenerateTag(signal);
|
|
|
|
//
|
|
// Check Last Signal ...
|
|
datetime barTime = iTime(
|
|
signal.symbol,
|
|
signal.period,
|
|
0);
|
|
|
|
//
|
|
// Retrieve Tradable Balance ...
|
|
double availableBalance = xEAAccount.GetEquity();
|
|
|
|
//
|
|
// Verify Available Balance ...
|
|
double balance = xEAAccount.GetBalance();
|
|
|
|
//
|
|
// Here i Must Calculate TP and SL based on R2R and riskable Factor ...
|
|
bool isLong = IsLong(signal.type);
|
|
|
|
//
|
|
// Check Order Mode ...
|
|
if (signal.mode == NULL)
|
|
{
|
|
//
|
|
// Set Market Execution as Default ...
|
|
signal.mode = X_ORDER_MODE_MARKET;
|
|
}
|
|
|
|
//
|
|
// Calculate Entry Price ...
|
|
if (signal.entry <= 0)
|
|
{
|
|
//
|
|
signal.entry = GetEntry(
|
|
signal.symbol,
|
|
signal.type);
|
|
}
|
|
|
|
//
|
|
// R2R ...
|
|
if (signal.r2r <= 0)
|
|
{
|
|
//
|
|
// Set Default Risk to Reward Ratio to 1 ...
|
|
signal.r2r = 1;
|
|
}
|
|
|
|
//
|
|
// Calculate TP and SL ...
|
|
double mPoint = GetPoints(signal.symbol);
|
|
|
|
//
|
|
// Normalize SL Price ...
|
|
if (signal.sl > 0)
|
|
{
|
|
signal.sl = NormalizePrice(signal.sl, signal.symbol);
|
|
}
|
|
|
|
//
|
|
// Retrieve Symbol Point Value ...
|
|
double pointValue = xEAAccount.GetPointValue(signal.symbol);
|
|
|
|
//
|
|
// Calculate Risk ...
|
|
double riskPrice = MathAbs(signal.entry - signal.sl);
|
|
riskPrice = NormalizePrice(riskPrice, signal.symbol);
|
|
|
|
//
|
|
double riskPoints = PriceToPoint(riskPrice);
|
|
riskPoints = NormalizeDouble(riskPoints, 0);
|
|
|
|
//
|
|
// Calculating Reward based On Ratio ...
|
|
double rewardPoints = riskPoints * signal.r2r;
|
|
double rewardPrice = PointToPrice(rewardPoints);
|
|
rewardPrice = NormalizePrice(rewardPrice, signal.symbol);
|
|
|
|
//
|
|
// Calculate TP Price ...
|
|
double tpValue = isLong
|
|
? signal.entry + rewardPrice
|
|
: signal.entry - rewardPrice;
|
|
|
|
//
|
|
// Calculate SL Price ...
|
|
double slValue = isLong
|
|
? signal.entry - riskPrice
|
|
: signal.entry + riskPrice;
|
|
|
|
//
|
|
// Balance Amount which we risks on each Provider's Trade ...
|
|
double amount = availableBalance * signal.riskAmount;
|
|
|
|
//
|
|
// Calculating Trade Volume based on risk Points and Amount ...
|
|
double volume = 0.02;
|
|
// xEAAccount.CalculateVolume(
|
|
// signal.symbol,
|
|
// amount,
|
|
// riskPoints);
|
|
volume = NormalizeVolume(volume, signal.symbol);
|
|
|
|
//
|
|
// Set Caculated TP, SL and Volume ...
|
|
signal.tp = tpValue;
|
|
signal.sl = slValue;
|
|
signal.volume = volume;
|
|
|
|
//
|
|
string comment = "";
|
|
int signalProvidersCount = ArraySize(signal.providers);
|
|
if (signalProvidersCount > 0)
|
|
{
|
|
//
|
|
string prvs = "";
|
|
for (int i = 0; i < signalProvidersCount; i++)
|
|
{
|
|
//
|
|
string p = signal.providers[i];
|
|
|
|
//
|
|
if (StringLen(prvs) > 0)
|
|
{
|
|
prvs += ",";
|
|
}
|
|
|
|
//
|
|
prvs += p;
|
|
}
|
|
|
|
//
|
|
comment = "PRV(" + prvs + ")";
|
|
}
|
|
|
|
//
|
|
// Here before Open Signal Position ...
|
|
// and after complete TP SL and Volume Calculations ...
|
|
// Recieve a List Of Supported Positions, based on retrieve Support and Resistance ares
|
|
// for Signal ...
|
|
XSignal supportSignals[];
|
|
xEATrade.GenerateSupportSignals(
|
|
supportSignals,
|
|
signal);
|
|
int supportSignalsCount = ArraySize(supportSignals);
|
|
|
|
//
|
|
bool isPositionOpen = xEATrade.ExecuteSignal(
|
|
signal,
|
|
comment);
|
|
|
|
//
|
|
if (isPositionOpen)
|
|
{
|
|
//
|
|
// Retrieve Position Ticket ...
|
|
ulong ticket = xEATrade.GetLastOpenPositionTicket();
|
|
if (ticket == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (supportSignalsCount >= 0)
|
|
{
|
|
//
|
|
// Here we Must Place Orders ...
|
|
string comment = mSupportToken + "(" + (string)ticket + ")";
|
|
|
|
//
|
|
// CleanSupport Positions SLs ...
|
|
// for (int i = 0; i < supportSignalsCount; i++) {
|
|
// //
|
|
// XSignal iSignal = supportSignals[i];
|
|
|
|
// //
|
|
// // iSignal.sl = 0;
|
|
// }
|
|
|
|
//
|
|
// TODO: Add Expiration Date, Volume Calculation ...
|
|
// int executedSignals = xEATrade.ExecuteSignals(
|
|
// supportSignals,
|
|
// comment);
|
|
}
|
|
|
|
//
|
|
// Draw Signal ...
|
|
ReDrawSignal(ticket, signal);
|
|
|
|
//
|
|
// Alert Position ...
|
|
LogMessage("Position: " + (string)ticket + " was Open ...");
|
|
} else {
|
|
DrawSupportResistance(1, signal.supportAndResistance);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle StopLoss Event ...
|
|
void OnStopLossTriggered(const XDeal &deal)
|
|
{
|
|
//
|
|
string msg = "SL: " + (string)deal.positionId;
|
|
LogMessage(msg);
|
|
|
|
//
|
|
xEACollector.CollectLog(msg);
|
|
|
|
//
|
|
xEACollector.CollectDeal(deal);
|
|
}
|
|
|
|
//
|
|
// Handle TakeProfit Event ...
|
|
void OnTakeProfitTriggered(const XDeal &deal)
|
|
{
|
|
//
|
|
string msg = "TP: " + (string)deal.positionId;
|
|
LogMessage(msg);
|
|
|
|
//
|
|
xEACollector.CollectLog(msg);
|
|
|
|
//
|
|
xEACollector.CollectDeal(deal);
|
|
}
|
|
|
|
//
|
|
void OnDealsChangedHandler(int count)
|
|
{
|
|
//
|
|
string msg = "Deals Changed: " + (string)count;
|
|
LogMessage(msg);
|
|
xEACollector.CollectLog(msg);
|
|
}
|
|
|
|
//
|
|
void OnOrdersChangedHandler(int count)
|
|
{
|
|
//
|
|
string msg = "Orders Changed: " + (string)count;
|
|
LogMessage(msg);
|
|
xEACollector.CollectLog(msg);
|
|
}
|
|
|
|
//
|
|
void HandleGuard()
|
|
{
|
|
//
|
|
// Handle Force Close Positions ...
|
|
// HandleForceClosing();
|
|
|
|
//
|
|
// Trailing Stops and Make Positions Risk Free ...
|
|
// HandleRiskFree();
|
|
|
|
//
|
|
// When all Positions Profit Going Positive ...
|
|
// HandlePyramidHedge();
|
|
|
|
//
|
|
// When a Position running in profit long time ...
|
|
// HandleCloseOldInProfitTrades();
|
|
}
|
|
|
|
//
|
|
// Force Close Provider's Signals on Special Conditions ...
|
|
void HandleForceClosing()
|
|
{
|
|
//
|
|
// Force Close all XTRND Short Positions ...
|
|
bool canCloseAllXTRNDShortPositions =
|
|
//
|
|
XTRNDForceCloseAllShorts()
|
|
//
|
|
;
|
|
if (canCloseAllXTRNDShortPositions)
|
|
{
|
|
//
|
|
XPosition positions[];
|
|
GetSpecificProviderPositions(
|
|
positions,
|
|
_Symbol,
|
|
_Period,
|
|
XTRND,
|
|
POSITION_TYPE_SELL);
|
|
int positionsCount = ArraySize(positions);
|
|
if (positionsCount > 0)
|
|
{
|
|
//
|
|
string comment = "Force Close XTRND Shorts ...";
|
|
|
|
//
|
|
xEATrade.ClosePositions(
|
|
positions,
|
|
comment);
|
|
|
|
//
|
|
DrawForceCloseEvent();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Force Close all XTRND Long Positions ...
|
|
bool canCloseAllXTRNDLongPositions =
|
|
//
|
|
XTRNDForceCloseAllLongs()
|
|
//
|
|
;
|
|
if (canCloseAllXTRNDLongPositions)
|
|
{
|
|
//
|
|
XPosition positions[];
|
|
GetSpecificProviderPositions(
|
|
positions,
|
|
_Symbol,
|
|
_Period,
|
|
XTRND,
|
|
POSITION_TYPE_BUY);
|
|
int positionsCount = ArraySize(positions);
|
|
if (positionsCount > 0)
|
|
{
|
|
//
|
|
string comment = "Force Close XTRND Shorts ...";
|
|
|
|
//
|
|
xEATrade.ClosePositions(
|
|
positions,
|
|
comment);
|
|
|
|
//
|
|
DrawForceCloseEvent();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make Positions Risk Free and Trailing Stops ...
|
|
void HandleRiskFree()
|
|
{
|
|
//
|
|
double distanceFactorForRiskFree = 0.3;
|
|
|
|
//
|
|
XPosition inProfitPositions[];
|
|
xEATrade.GetInProfitPositions(inProfitPositions);
|
|
int inProfitPositionsCount = ArraySize(inProfitPositions);
|
|
if (inProfitPositionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < inProfitPositionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = inProfitPositions[i];
|
|
|
|
//
|
|
// Only Make Positions Risk Free based On their SL or TP ...
|
|
if (iPosition.tp <= 0 && iPosition.sl <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(iPosition.type);
|
|
|
|
//
|
|
bool isRFBefore = StringFind(
|
|
iPosition.comment,
|
|
"RF") > 0;
|
|
|
|
//
|
|
double lastRFPrice = iPosition.entry;
|
|
string lastRFPriceStr = "";
|
|
if (isRFBefore) {
|
|
//
|
|
lastRFPriceStr = ExtractString(
|
|
iPosition.comment,
|
|
mRiskFreeToken + "(",
|
|
")"
|
|
);
|
|
if (StringLen(lastRFPriceStr) > 0) {
|
|
lastRFPrice = (double) lastRFPriceStr;
|
|
}
|
|
}
|
|
|
|
//
|
|
double tpDistancePrice = MathAbs(lastRFPrice - iPosition.tp);
|
|
double rfPrice = (tpDistancePrice * distanceFactorForRiskFree);
|
|
|
|
//
|
|
bool canRiskFree = MathAbs(lastRFPrice - iPosition.price) > rfPrice;
|
|
if (!canRiskFree)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
double tp =
|
|
isLong
|
|
? iPosition.tp + rfPrice
|
|
: iPosition.tp - rfPrice;
|
|
double sl =
|
|
isLong
|
|
? iPosition.tp - rfPrice
|
|
: iPosition.sl - rfPrice;
|
|
|
|
//
|
|
string comment = iPosition.comment;
|
|
if (isRFBefore) {
|
|
//
|
|
StringReplace(
|
|
comment,
|
|
lastRFPriceStr,
|
|
""
|
|
);
|
|
}
|
|
|
|
//
|
|
comment += mRiskFreeToken + "(" + (string)iPosition.price + ")";
|
|
|
|
//
|
|
bool isModified = xEATrade.Modify(
|
|
iPosition.ticket,
|
|
sl,
|
|
tp,
|
|
comment);
|
|
if (isModified)
|
|
{
|
|
//
|
|
string msg = "Make Position (" + (string)iPosition.ticket + ") Risk Free ...";
|
|
LogMessage(msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Pyramid Hedging ...
|
|
void HandlePyramidHedge()
|
|
{
|
|
//
|
|
int positionsCount = xEATrade.PositionsCount();
|
|
if (positionsCount <= 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
double minProfitForHedging = positionsCount * 1;
|
|
double positionsProfit = xEATrade.GetPositionsProfit();
|
|
|
|
//
|
|
if (positionsProfit < minProfitForHedging)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Pyramid Hedging ...";
|
|
|
|
//
|
|
xEATrade.CloseAllPositions(comment);
|
|
}
|
|
|
|
//
|
|
// Close In Profit Old Trades ...
|
|
void HandleCloseOldInProfitTrades()
|
|
{
|
|
//
|
|
int oldAge = 50;
|
|
double minProfit = 1;
|
|
bool onlySupports = false;
|
|
|
|
//
|
|
XPosition inProfitPositions[];
|
|
xEATrade.GetInProfitPositions(inProfitPositions);
|
|
int inProfitPositionsCount = ArraySize(inProfitPositions);
|
|
if (inProfitPositionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < inProfitPositionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = inProfitPositions[i];
|
|
if (iPosition.profit < minProfit ||
|
|
(iPosition.tp > 0 &&
|
|
MathAbs(iPosition.entry - iPosition.price) < MathAbs(iPosition.entry - iPosition.tp) / 2))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Position Age ...
|
|
int iPositionBarIndex = xEATrade.GetPositionOpenBarIndex(iPosition.ticket);
|
|
int iPositionAge = MathAbs(iPositionBarIndex - 0);
|
|
if (iPositionAge < oldAge)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
string comment = "Close On Old In Profit Trade ...";
|
|
|
|
//
|
|
bool isPositionClosed = false;
|
|
|
|
//
|
|
if (onlySupports)
|
|
{
|
|
//
|
|
// Check Position is Support or not ...
|
|
bool isSupport = IsSupportPosition(iPosition);
|
|
if (isSupport)
|
|
{
|
|
//
|
|
// Close Position ...
|
|
isPositionClosed = xEATrade.Close(
|
|
iPosition.ticket,
|
|
comment);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Close Position ...
|
|
isPositionClosed = xEATrade.Close(
|
|
iPosition.ticket,
|
|
comment);
|
|
}
|
|
|
|
//
|
|
// Alert Events ...
|
|
string msg = "Position (" + (string)iPosition.ticket + ") Closed due InProfit Old Event ...";
|
|
LogMessage(msg);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Tools and Usefull Functions ...
|
|
//
|
|
|
|
//
|
|
// Convert Position to Signal ...
|
|
XSignal ToSignalInfo(
|
|
XPosition &position)
|
|
{
|
|
//
|
|
XSignal 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(XTest) == provider)
|
|
{
|
|
result = XTest;
|
|
}
|
|
else if (ToString(XTRND) == provider)
|
|
{
|
|
result = XTRND;
|
|
} else 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,
|
|
mProviderToken + "(",
|
|
")");
|
|
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
|
|
ENUM_POSITION_TYPE type = NULL // Position Type
|
|
)
|
|
{
|
|
//
|
|
Clean(result);
|
|
|
|
//
|
|
if (StringLen(symbol) == 0 || provider == NONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int positionsCount = xEATrade.PositionsCount();
|
|
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;
|
|
}
|
|
|
|
//
|
|
if (type == NULL)
|
|
{
|
|
//
|
|
Add(
|
|
iPosition,
|
|
result);
|
|
}
|
|
else if (type == iPosition.type)
|
|
{
|
|
//
|
|
Add(
|
|
iPosition,
|
|
result);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Determines a Position is Support Position or not ...
|
|
bool IsSupportPosition(XPosition &position)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (StringLen(position.comment) <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int supTokenPos = StringFind(
|
|
position.comment,
|
|
mSupportToken + "(");
|
|
result = supTokenPos >= 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// END Functions ...
|
|
//
|
|
|
|
//
|
|
// Draw Signal ...
|
|
void ReDrawSignal(const ulong ticket, XSignal &signal)
|
|
{
|
|
//
|
|
// return;
|
|
|
|
//
|
|
DrawSupportResistance(1, signal.supportAndResistance);
|
|
|
|
//
|
|
bool isLong = IsLong(signal.type);
|
|
|
|
//
|
|
string prefix = (string)ticket + "_" + ToString(signal.period);
|
|
|
|
//
|
|
// Retrieve Time ...
|
|
datetime time = iTime(
|
|
signal.symbol,
|
|
signal.period,
|
|
0);
|
|
|
|
//
|
|
// Retrieve 3 Time ...
|
|
datetime time3 = iTime(
|
|
signal.symbol,
|
|
signal.period,
|
|
3);
|
|
|
|
//
|
|
color posColor = isLong
|
|
? clrSpringGreen
|
|
: clrTomato;
|
|
color tpColor = clrSpringGreen;
|
|
color slColor = clrTomato;
|
|
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;
|
|
|
|
//
|
|
int lineWidth = 2;
|
|
|
|
//
|
|
long chartID = ChartID();
|
|
|
|
//
|
|
// Vertical Line ...
|
|
string vlName = prefix + "_" + (string)time;
|
|
|
|
//
|
|
DrawVerticalLine(
|
|
chartID,
|
|
vlName,
|
|
0,
|
|
time,
|
|
posColor,
|
|
vLineStyle,
|
|
lineWidth);
|
|
|
|
//
|
|
// 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,
|
|
lineWidth);
|
|
|
|
//
|
|
// 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,
|
|
lineWidth);
|
|
|
|
//
|
|
// ENTRY ...
|
|
string entryName = prefix + "_ENTRY_" + (string)lost;
|
|
|
|
//
|
|
DrawTrendLine(
|
|
chartID,
|
|
entryName,
|
|
0,
|
|
time3,
|
|
signal.entry,
|
|
time,
|
|
signal.entry,
|
|
entryColor,
|
|
entryLineStyle,
|
|
lineWidth);
|
|
}
|
|
|
|
//
|
|
// Alert Force Close Event on Chart ...
|
|
void DrawForceCloseEvent()
|
|
{
|
|
//
|
|
datetime barTime = GetCandleTime(
|
|
_Symbol,
|
|
_Period,
|
|
1);
|
|
|
|
//
|
|
long chartID = ChartID();
|
|
string vlName = "XTRND Force Close: " + (string)barTime;
|
|
|
|
//
|
|
DrawVerticalLine(
|
|
chartID,
|
|
vlName,
|
|
0,
|
|
barTime,
|
|
clrDarkViolet,
|
|
STYLE_SOLID,
|
|
2);
|
|
}
|
|
|
|
//
|
|
void DrawSupportResistance(
|
|
int bar_index,
|
|
XOHCLSupRes &data,
|
|
string prefix = "",
|
|
color supportColor = clrLime,
|
|
color resistanceColor = clrRed)
|
|
{
|
|
//
|
|
// return;
|
|
|
|
//
|
|
datetime barTime = GetCandleTime(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index);
|
|
|
|
//
|
|
datetime prevBarTime = GetCandleTime(
|
|
_Symbol,
|
|
_Period,
|
|
bar_index + 5);
|
|
|
|
//
|
|
long chID = ChartID();
|
|
int subWindiw = 0;
|
|
int lineWidth = 2;
|
|
|
|
//
|
|
string mPrefix = prefix + "_" + (string)barTime + "_";
|
|
|
|
//
|
|
// SUPPORTS ...
|
|
|
|
//
|
|
int supCount = ArraySize(data.sup);
|
|
if (supCount > 0)
|
|
{
|
|
//
|
|
for (int i = 0; i < supCount; i++)
|
|
{
|
|
//
|
|
double iSup = data.sup[i];
|
|
|
|
//
|
|
string supTlName = mPrefix + "SUP[" + (string)(i + 1) + "]_(" + (string)iSup + ")";
|
|
|
|
//
|
|
// Draw Support ...
|
|
DrawTrendLine(
|
|
chID,
|
|
supTlName,
|
|
subWindiw,
|
|
prevBarTime,
|
|
iSup,
|
|
barTime,
|
|
iSup,
|
|
supportColor,
|
|
STYLE_DOT,
|
|
lineWidth,
|
|
true);
|
|
}
|
|
}
|
|
|
|
//
|
|
// RESISTANCES ...
|
|
|
|
//
|
|
int resCount = ArraySize(data.res);
|
|
if (resCount > 0)
|
|
{
|
|
//
|
|
for (int i = 0; i < resCount; i++)
|
|
{
|
|
//
|
|
double iRes = data.res[i];
|
|
|
|
//
|
|
string resTlName = mPrefix + "RES[" + (string)(i + 1) + "]_(" + (string)iRes + ")";
|
|
|
|
//
|
|
// Draw Support ...
|
|
DrawTrendLine(
|
|
chID,
|
|
resTlName,
|
|
subWindiw,
|
|
prevBarTime,
|
|
iRes,
|
|
barTime,
|
|
iRes,
|
|
resistanceColor,
|
|
STYLE_DOT,
|
|
2,
|
|
true);
|
|
}
|
|
}
|
|
}
|