1374 lines
29 KiB
Plaintext
1374 lines
29 KiB
Plaintext
////////////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 XTEST Signal Provider Library
|
|
// --------------------------------------------------------
|
|
// Name: XTESTSignalProvider
|
|
// Description: XTEST based signal provider ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright 2023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
#define XTESTProviderName "XTEST"
|
|
|
|
//
|
|
// START Inputs ...
|
|
//
|
|
|
|
#include "x-saherelm.xtest.provider.inputs.lib.mq5";
|
|
|
|
//
|
|
// END Inputs ...
|
|
//
|
|
|
|
//
|
|
// Include Common Library ...
|
|
#include "../Libraries/x-saherelm.common.lib.mq5"
|
|
|
|
//
|
|
// Include Logger Library ...
|
|
#include "../Libraries/x-saherelm.log.lib.mq5"
|
|
|
|
//
|
|
// Include Alert Library ...
|
|
#include "../Libraries/x-saherelm.alert.lib.mq5"
|
|
|
|
//
|
|
// Include Draw Library ...
|
|
#include "../Libraries/x-saherelm.draw.lib.mq5"
|
|
|
|
//
|
|
// Include Class Libraries ...
|
|
#include "../Classes/x-saherelm.class.lib.mq5"
|
|
|
|
//
|
|
// START Global Definitions: Variables, Properties and etc ...
|
|
//
|
|
|
|
//
|
|
XCGuard *xTESTGuard;
|
|
XCTrade *xTESTTrader;
|
|
XCReporter *xTESTReporter;
|
|
XCCollector *xTESTCollector;
|
|
XCAccountInfo *xTESTAccountInfo;
|
|
XCVolumeManager *xTESTVolumeManager;
|
|
|
|
//
|
|
#include "x-saherelm.xtest.provider.indicators.lib.mq5"
|
|
|
|
//
|
|
// Controlling Variables ...
|
|
bool xTESTMEnableProvider = false;
|
|
bool xTESTMAllowLongTrades = false;
|
|
bool xTESTMAllowShortTrades = false;
|
|
|
|
//
|
|
double xTESTDeposit = 0;
|
|
double xTESTBalance = 0;
|
|
double xTESTMinReward = 0;
|
|
double xTESTFreeMargin = 0;
|
|
double xTESTBalanceForOpenTrades = 0;
|
|
double xTESTFreeMarginForOpenTrades = 0;
|
|
|
|
//
|
|
// Guard ...
|
|
double xTESTCriticalDrawDown = 0;
|
|
double xTESTMaxAllowedDrawDown = 0;
|
|
|
|
//
|
|
double xTESTMaxDrawUp = 0;
|
|
double xTESTMaxDrawDown = 0;
|
|
|
|
//
|
|
int NOT_ENOUGH_MONEY_ERROR = 4756;
|
|
const string XTEST_SUPPORT_ID = "SP";
|
|
|
|
//
|
|
// END Global Definitions: Variables, Properties and etc ...
|
|
//
|
|
|
|
//
|
|
// START Provided Functions ...
|
|
//
|
|
|
|
//
|
|
// Initial Library if required ...
|
|
bool XTESTInitSignalProviderLibrary()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (!xTESTEnableProvider)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Controlling Variables ...
|
|
xTESTMEnableProvider = xTESTEnableProvider;
|
|
xTESTMAllowLongTrades = xTESTAllowLongTrades;
|
|
xTESTMAllowShortTrades = xTESTAllowShortTrades;
|
|
|
|
//
|
|
// Validate Inputs ...
|
|
result = XTESTValidateInputs();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Init Indicators ...
|
|
result = XTESTInitIndicators();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
xTESTReporter = new XCReporter();
|
|
xTESTCollector = new XCCollector();
|
|
xTESTAccountInfo = new XCAccountInfo();
|
|
|
|
//
|
|
// Calculate Account Deposit ...
|
|
xTESTDeposit = xTESTAccountInfo.GetInitialBalance();
|
|
|
|
//
|
|
// Prepare Min Reward ...
|
|
if (xTESTMinRewardInPips > 0)
|
|
{
|
|
xTESTMinReward = PipsToPrice(xTESTMinRewardInPips);
|
|
}
|
|
|
|
//
|
|
// Calculate Min Balance for Trades ...
|
|
if (xTESTBalanceFactorForOpenTrades > 0)
|
|
{
|
|
xTESTBalanceForOpenTrades = xTESTBalanceFactorForOpenTrades * xTESTDeposit;
|
|
}
|
|
|
|
//
|
|
// Claculate Min Free Marging for Trades ...
|
|
if (xTESTFreeMarginFactorForOpenTrades > 0)
|
|
{
|
|
xTESTFreeMarginForOpenTrades = xTESTFreeMarginFactorForOpenTrades * xTESTDeposit;
|
|
}
|
|
|
|
//
|
|
// Calculate Init Time Critical DrawDown Value ...
|
|
if (xTESTCriticalDrawDownFactor > 0)
|
|
{
|
|
xTESTCriticalDrawDown = xTESTCriticalDrawDownFactor * xTESTDeposit;
|
|
}
|
|
|
|
//
|
|
// Calculate Init Time Max Allowed DrawDown Value ...
|
|
if (xTESTMaxAllowedDrawDownFactor > 0)
|
|
{
|
|
xTESTMaxAllowedDrawDown = xTESTMaxAllowedDrawDownFactor * xTESTDeposit;
|
|
}
|
|
|
|
//
|
|
// Instant Volume Manager ...
|
|
xTESTVolumeManager = new XCVolumeManager(
|
|
xTESTStaticVolumeFactor,
|
|
xTESTStaticVolumeMethod,
|
|
xTESTVolumeMultiplier,
|
|
xTESTApplyVolumeMultiplierFactor,
|
|
xTESTMaxSupportedVolumePerTradeFactor,
|
|
xTESTIncreasedMaxSupportedVolumeRate);
|
|
|
|
//
|
|
// Make XCTrader instance ...
|
|
xTESTTrader = new XCTrade(
|
|
XTESTProviderName,
|
|
_Symbol,
|
|
xTESTSlippage,
|
|
xTESTMagicNumber,
|
|
xTESTUseVirtualTPSl,
|
|
xTESTMaxAllowedTrades,
|
|
xTESTFreeMarginForOpenTrades,
|
|
xTESTBalanceForOpenTrades);
|
|
|
|
//
|
|
// Instantiate Account Guard ...
|
|
xTESTGuard = new XCGuard(
|
|
//
|
|
// Old Trades ...
|
|
xTESTMaxAllowedTradeAge,
|
|
xTESTOldTradesAction,
|
|
//
|
|
// Critical DrawDown ...
|
|
xTESTCriticalDrawDownFactor,
|
|
xTESTCriticalGuardAction,
|
|
//
|
|
// Max Allowed DrawDown ...
|
|
xTESTMaxAllowedDrawDownFactor,
|
|
xTESTMaxAllowedGuardAction,
|
|
xTESTGuardStopoutFiredAfterTouches,
|
|
//
|
|
// xTESTGuardSupportMethod
|
|
X_SUPPORT_DO_NOTHING
|
|
//
|
|
);
|
|
|
|
//
|
|
// Reset Calculations Buffers and Variables ...
|
|
XTESTResetCollectors();
|
|
|
|
//
|
|
XTESTUpdateReports();
|
|
|
|
//
|
|
result = true;
|
|
|
|
//
|
|
// Logging State ...
|
|
XTESTIssueInitializationSucceedAlert();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// DeInitial Library if required ...
|
|
void XTESTDeinitSignalProviderLibrary(const int reason)
|
|
{
|
|
//
|
|
// Release Handlers ...
|
|
XTESTReleaseIndicators();
|
|
|
|
//
|
|
// Logging State ...
|
|
XTESTIssueDeinitializationSucceedAlert();
|
|
}
|
|
|
|
//
|
|
// this is a Globally Function which do all of
|
|
// checkings and positions handling ...
|
|
void XTESTSignalProviderHandleTick()
|
|
{
|
|
//
|
|
// Check Provider is Enable or Not ...
|
|
if (!xTESTMEnableProvider)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XTESTSignalProviderDoControlState();
|
|
|
|
//
|
|
// Reading Indicator Buffers ...
|
|
XTESTHandleReadingBuffers();
|
|
if (xTESTCalculatedBars < xTESTMaxLengthOfInputs)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Handle Open Trades ...
|
|
XTESTHandleOpenTrades();
|
|
|
|
//
|
|
// Handle Close Trades ...
|
|
XTESTHandleCloseTrades();
|
|
|
|
//
|
|
// DrawDown and DrawUp ...
|
|
XTESTHandleCalculateDrawDownUp();
|
|
}
|
|
|
|
//
|
|
// Do Control Checks here ...
|
|
void XTESTSignalProviderDoControlState()
|
|
{
|
|
//
|
|
// Update account Balance ...
|
|
xTESTBalance = xTESTAccountInfo.GetBalance();
|
|
xTESTFreeMargin = xTESTAccountInfo.GetFreeMargin();
|
|
|
|
//
|
|
// Check Provider is Enable or Not ...
|
|
if (!xTESTMEnableProvider)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Protect Account by Guarding Maximum Drawdown ...
|
|
// TODO: add Guard Result here ...
|
|
string guardMessage = "";
|
|
XGuardHandlerResult guardHandlerResult;
|
|
bool isGuarded = xTESTGuard.Guard(
|
|
guardHandlerResult,
|
|
guardMessage,
|
|
xTESTTrader,
|
|
_Period);
|
|
if (isGuarded)
|
|
{
|
|
//
|
|
// Criticals ...
|
|
int criticalsCount = ArraySize(guardHandlerResult.criticals);
|
|
if (criticalsCount > 0)
|
|
{
|
|
//
|
|
for (int i = 0; i < criticalsCount; i++)
|
|
{
|
|
//
|
|
XSignal iSignal = guardHandlerResult.criticals[i];
|
|
|
|
//
|
|
XTESTOnGuard(
|
|
iSignal,
|
|
X_GUARDED_CRITICAL,
|
|
guardMessage);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Maxes ...
|
|
int maxesCount = ArraySize(guardHandlerResult.maxes);
|
|
if (maxesCount > 0)
|
|
{
|
|
//
|
|
for (int i = 0; i < maxesCount; i++)
|
|
{
|
|
//
|
|
XSignal iSignal = guardHandlerResult.maxes[i];
|
|
|
|
//
|
|
XTESTOnGuard(
|
|
iSignal,
|
|
X_GUARDED_MAX,
|
|
guardMessage,
|
|
guardHandlerResult.isStopOut);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Olds ...
|
|
int oldsCount = ArraySize(guardHandlerResult.olds);
|
|
if (oldsCount > 0)
|
|
{
|
|
//
|
|
for (int i = 0; i < oldsCount; i++)
|
|
{
|
|
//
|
|
XSignal iSignal = guardHandlerResult.olds[i];
|
|
|
|
//
|
|
XTESTOnGuard(
|
|
iSignal,
|
|
X_GUARDED_OLD,
|
|
guardMessage);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Signal Protection ...
|
|
XSignal protectSupports[];
|
|
bool isSupported = xTESTGuard.ProtectSignals(
|
|
protectSupports,
|
|
xTESTTrader);
|
|
if (isSupported)
|
|
{
|
|
//
|
|
LogMessage("Guard do Support Trdae ...");
|
|
}
|
|
|
|
//
|
|
// Handling Signals ...
|
|
XTraderHandlerResult signalHandlerResult;
|
|
xTESTTrader.HandleSignals(
|
|
signalHandlerResult,
|
|
false // Ignore Risk Free Trdaes
|
|
);
|
|
|
|
//
|
|
// Handle Sl Reports ...
|
|
int handledSLsCount = ArraySize(signalHandlerResult.sl);
|
|
if (handledSLsCount > 0)
|
|
{
|
|
//
|
|
for (int i = 0; i < handledSLsCount; i++)
|
|
{
|
|
//
|
|
XSignal iSignal = signalHandlerResult.sl[i];
|
|
XTESTOnSL(iSignal);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle TP Reports ...
|
|
int handledTPsCount = ArraySize(signalHandlerResult.tp);
|
|
if (handledTPsCount > 0)
|
|
{
|
|
//
|
|
for (int i = 0; i < handledTPsCount; i++)
|
|
{
|
|
//
|
|
XSignal iSignal = signalHandlerResult.tp[i];
|
|
XTESTOnTP(iSignal);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle RFs as TP Reports ...
|
|
int handledRFsCount = ArraySize(signalHandlerResult.rf);
|
|
if (handledRFsCount > 0)
|
|
{
|
|
//
|
|
for (int i = 0; i < handledRFsCount; i++)
|
|
{
|
|
//
|
|
XSignal iSignal = signalHandlerResult.rf[i];
|
|
XTESTOnRF(iSignal);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Trades when OnTrade Event Hnadler Calls ...
|
|
void XTESTSignalProviderHandleTrade()
|
|
{
|
|
//
|
|
// Check Provider Enabled ...
|
|
if (!xTESTMEnableProvider)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Handle OnTrade Event ...
|
|
XOnTradeHandlerResult result = {};
|
|
xTESTTrader.HandleOnTradeEvent(
|
|
result);
|
|
|
|
//
|
|
// Detected TP or SL ...
|
|
if (result.hasNewDeal)
|
|
{
|
|
//
|
|
XDeal last = xTESTTrader.GetLastDeal();
|
|
|
|
//
|
|
if (last.reason == DEAL_REASON_SL)
|
|
{
|
|
xTESTReporter.AddTradeSLInReports();
|
|
}
|
|
else if (last.reason == DEAL_REASON_TP)
|
|
{
|
|
xTESTReporter.AddTradeTPInReports();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Open Trades ...
|
|
void XTESTHandleOpenTrades()
|
|
{
|
|
//
|
|
// Check Can Trade ...
|
|
bool canTrade = xTESTMAllowLongTrades || xTESTMAllowShortTrades;
|
|
if (!canTrade)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Max Open Trades ...
|
|
int openSignals = xTESTTrader.Count();
|
|
bool canOpenPositions = openSignals < xTESTMaxAllowedTrades;
|
|
if (!canOpenPositions)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Signals Exists ...
|
|
XProvidedSignal longSignalInfo;
|
|
XProvidedSignal shortSignalInfo;
|
|
bool hasLongSignal = XTESTCanOpenLongTrade(longSignalInfo);
|
|
bool hasShortSignal = XTESTCanOpenShortTrade(shortSignalInfo);
|
|
if (!hasLongSignal && !hasShortSignal)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Update Reports ...
|
|
XTESTUpdateReports();
|
|
|
|
//
|
|
xTESTWaitUntilNextCandle = true;
|
|
|
|
//
|
|
// Open Long Trades ...
|
|
if (
|
|
//
|
|
hasLongSignal &&
|
|
xTESTMAllowLongTrades)
|
|
{
|
|
//
|
|
bool isOpened = XTESTOpenLongPosition(longSignalInfo);
|
|
}
|
|
|
|
//
|
|
// Open Short Trades ...
|
|
if (
|
|
//
|
|
hasShortSignal &&
|
|
xTESTMAllowShortTrades)
|
|
{
|
|
//
|
|
bool isOpened = XTESTOpenShortPosition(shortSignalInfo);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Close Trades ...
|
|
void XTESTHandleCloseTrades()
|
|
{
|
|
//
|
|
// Force Close Long Trades ...
|
|
bool isClosedLongTrades = false;
|
|
bool canCloseLongTrades = XTESTCanCloseLongTrade();
|
|
if (xTESTMAllowLongTrades && canCloseLongTrades)
|
|
{
|
|
//
|
|
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_LONG;
|
|
|
|
//
|
|
XSignal closed[];
|
|
xTESTTrader.CloseSignals(
|
|
closed,
|
|
type);
|
|
|
|
//
|
|
int closedTradesCount = ArraySize(closed);
|
|
isClosedLongTrades = closedTradesCount > 0;
|
|
if (isClosedLongTrades)
|
|
{
|
|
//
|
|
for (int i = 0; i < closedTradesCount; i++)
|
|
{
|
|
//
|
|
XSignal iSignal = closed[i];
|
|
XTESTOnFC(iSignal);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Force Close Short Trades ...
|
|
bool isClosedShortTrades = false;
|
|
bool canCloseShortTrades = XTESTCanCloseShortTrade();
|
|
if (xTESTMAllowShortTrades && canCloseShortTrades)
|
|
{
|
|
//
|
|
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_SHORT;
|
|
|
|
//
|
|
XSignal closed[];
|
|
xTESTTrader.CloseSignals(
|
|
closed,
|
|
type);
|
|
|
|
//
|
|
int closedTradesCount = ArraySize(closed);
|
|
isClosedShortTrades = closedTradesCount > 0;
|
|
if (isClosedShortTrades)
|
|
{
|
|
//
|
|
for (int i = 0; i < closedTradesCount; i++)
|
|
{
|
|
//
|
|
XSignal iSignal = closed[i];
|
|
XTESTOnFC(iSignal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open Long Position ...
|
|
bool XTESTOpenLongPosition(
|
|
XProvidedSignal &info // Retrieve Signal Additional Info on this Object
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Calculate Required Data for Position ...
|
|
double entry = GetEntry(_Symbol, X_SIGNAL_LONG);
|
|
double sl = info.sl > 0 ? info.sl : 0;
|
|
// entry - (200 * _Point);
|
|
// info.sl > 0 ? info.sl : 0;
|
|
double tp = info.tp > 0 ? info.tp : entry + xTESTMinReward;
|
|
double riskFreeRate = xTESTRiskFreeRate;
|
|
double riskFreeStep = xTESTRiskFreeStepInPips;
|
|
double volume = XTESTCalculateVolume(ArraySize(info.signallers));
|
|
|
|
//
|
|
XSignal signal = {};
|
|
signal = xTESTTrader.GenerateSignal(
|
|
X_SIGNAL_LONG,
|
|
tp,
|
|
sl,
|
|
volume,
|
|
riskFreeStep,
|
|
riskFreeRate);
|
|
bool isValidSignal = IsValid(
|
|
signal,
|
|
xTESTMagicNumber);
|
|
if (!isValidSignal)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int signalsCount = xTESTTrader.Count();
|
|
bool isCross = signalsCount >= 1;
|
|
if (isCross)
|
|
{
|
|
//
|
|
// Handle Cross Signals ...
|
|
XTESTHnadleCrossSignal(signal);
|
|
}
|
|
|
|
//
|
|
// Retrieve Can Execute Signal or not ...
|
|
bool canExecuteSignal =
|
|
!isCross
|
|
//
|
|
||
|
|
//
|
|
(
|
|
//
|
|
isCross &&
|
|
xTESTCrossSignalsMethod != X_CROSS_SIGNAL_DO_NOTHING
|
|
//
|
|
);
|
|
if (!canExecuteSignal)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Execute Signal ...
|
|
ENUM_EXECUTION_SIGNAL_RESULT executionResult = xTESTTrader.ExecuteSignal(
|
|
signal,
|
|
false, // Ignore Number of Trades ...
|
|
true // Check Account Conditions ...
|
|
);
|
|
result = executionResult == X_TRADER_SUCCEED_EXECUTION;
|
|
if (result)
|
|
{
|
|
//
|
|
// Update Reports ...
|
|
string providers[];
|
|
ArrayCopy(
|
|
providers,
|
|
info.signallers
|
|
);
|
|
|
|
//
|
|
XSignal tSignal = xTESTTrader.GetSignal(signal.ticket);
|
|
|
|
//
|
|
XTESTOnSignal(
|
|
tSignal,
|
|
providers);
|
|
}
|
|
else
|
|
{
|
|
XTESTIssueSignalExecutionError(executionResult);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Open Short Position ...
|
|
bool XTESTOpenShortPosition(
|
|
XProvidedSignal &info // Retrieve Signal Additional Info on this Object
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Calculate Required Data for Position ...
|
|
double entry = GetEntry(_Symbol, X_SIGNAL_SHORT);
|
|
double sl = info.sl > 0 ? info.sl : 0;
|
|
// entry + (200 * _Point);
|
|
// info.sl > 0 ? info.sl : 0;
|
|
double tp = info.tp > 0 ? info.tp : entry - xTESTMinReward;
|
|
double riskFreeRate = xTESTRiskFreeRate;
|
|
double riskFreeStep = xTESTRiskFreeStepInPips;
|
|
double volume = XTESTCalculateVolume(ArraySize(info.signallers));
|
|
|
|
//
|
|
XSignal signal = {};
|
|
signal = xTESTTrader.GenerateSignal(
|
|
X_SIGNAL_SHORT,
|
|
tp,
|
|
sl,
|
|
volume,
|
|
riskFreeStep,
|
|
riskFreeRate);
|
|
bool isValidSignal = IsValid(
|
|
signal,
|
|
xTESTMagicNumber);
|
|
if (!isValidSignal)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int signalsCount = xTESTTrader.Count();
|
|
bool isCross = signalsCount >= 1;
|
|
if (isCross)
|
|
{
|
|
//
|
|
// Handle Cross Signals ...
|
|
XTESTHnadleCrossSignal(signal);
|
|
}
|
|
|
|
//
|
|
// Retrieve Can Execute Signal or not ...
|
|
bool canExecuteSignal =
|
|
!isCross
|
|
//
|
|
||
|
|
//
|
|
(
|
|
//
|
|
isCross &&
|
|
xTESTCrossSignalsMethod != X_CROSS_SIGNAL_DO_NOTHING
|
|
//
|
|
);
|
|
if (!canExecuteSignal)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Execute Signal ...
|
|
ENUM_EXECUTION_SIGNAL_RESULT executionResult = xTESTTrader.ExecuteSignal(
|
|
signal,
|
|
false, // Ignore Number of Trades ...
|
|
true // Check Account Conditions ...
|
|
);
|
|
result = executionResult == X_TRADER_SUCCEED_EXECUTION;
|
|
if (result)
|
|
{
|
|
string providers[];
|
|
ArrayCopy(
|
|
providers,
|
|
info.signallers
|
|
);
|
|
|
|
//
|
|
XSignal tSignal = xTESTTrader.GetSignal(signal.ticket);
|
|
|
|
//
|
|
XTESTOnSignal(
|
|
tSignal,
|
|
providers);
|
|
}
|
|
else
|
|
{
|
|
XTESTIssueSignalExecutionError(executionResult);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Apply Cross Signal Actions ...
|
|
void XTESTHnadleCrossSignal(
|
|
XSignal &signal // Specified Signal ...
|
|
)
|
|
{
|
|
//
|
|
// Check Cross Signal Handling Enabled ...
|
|
if (xTESTCrossSignalsMethod == X_CROSS_SIGNAL_DO_NOTHING)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// First We have to Change Cross Signals Comment ...
|
|
string comment = xTESTTrader.GenerateSignalComment(
|
|
signal,
|
|
true);
|
|
|
|
//
|
|
signal.comment = comment;
|
|
|
|
//
|
|
// If Every thing is Regular, prevent any changes here ...
|
|
if (xTESTCrossSignalsMethod == X_CROSS_SIGNAL_REGULAR)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Retrieve Max in Drawdown Signal ...
|
|
XSignal maxInDDSignal = xTESTTrader.GetMaxInDrawdownSignal();
|
|
|
|
//
|
|
// Validate Signal ...
|
|
bool isValidSignal =
|
|
maxInDDSignal.ticket > 0 &&
|
|
maxInDDSignal.symbol == signal.symbol &&
|
|
IsValid(maxInDDSignal, xTESTMagicNumber);
|
|
if (!isValidSignal)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
double volume = signal.volume;
|
|
bool isDirectional = maxInDDSignal.type == signal.type;
|
|
|
|
//
|
|
// Prevent any changes on Regular Conditions ...
|
|
bool isRegular =
|
|
isDirectional
|
|
? (
|
|
//
|
|
xTESTCrossSignalsMethod == X_CROSS_SIGNAL_DIRECTION_REGULAR ||
|
|
xTESTCrossSignalsMethod == X_CROSS_SIGNAL_DIRECTION_REGULAR_INDIRECTION_IMPORTANT
|
|
//
|
|
)
|
|
: (
|
|
//
|
|
xTESTCrossSignalsMethod == X_CROSS_SIGNAL_INDIRECTION_REGULAR ||
|
|
xTESTCrossSignalsMethod == X_CROSS_SIGNAL_DIRECTION_IMPORTANT_INDIRECTION_REGULAR
|
|
//
|
|
);
|
|
if (isRegular)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Important Act needs to Multiply volume by 2 ...
|
|
volume *= 2;
|
|
|
|
//
|
|
// Set Volume of signal ...
|
|
signal.volume = volume;
|
|
}
|
|
|
|
//
|
|
// Calculate Usefull data ...
|
|
void XTESTHandleCalculateDrawDownUp()
|
|
{
|
|
//
|
|
XSignal signals[];
|
|
xTESTTrader.GetSignals(signals);
|
|
int signalsCount = ArraySize(signals);
|
|
if (signalsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
double profit = 0;
|
|
double volume = 0;
|
|
XCollector collector = {};
|
|
double maxAllowedVolume = xTESTVolumeManager.GetMaxAllowedVolume();
|
|
for (int i = 0; i < signalsCount; i++)
|
|
{
|
|
//
|
|
XSignal iSignal = signals[i];
|
|
|
|
//
|
|
profit += iSignal.profit;
|
|
|
|
//
|
|
volume =
|
|
volume == 0 ||
|
|
volume < iSignal.volume
|
|
? iSignal.volume
|
|
: volume;
|
|
}
|
|
|
|
//
|
|
if (profit < 0)
|
|
{
|
|
//
|
|
xTESTMaxDrawDown =
|
|
xTESTMaxDrawDown == 0 ||
|
|
xTESTMaxDrawDown > MathAbs(profit)
|
|
? MathAbs(profit)
|
|
: xTESTMaxDrawDown;
|
|
|
|
//
|
|
// Update Buffers ...
|
|
datetime time = iTime(_Symbol, _Period, 0);
|
|
|
|
//
|
|
// Calculate Max Allowed Drawdown ...
|
|
//
|
|
collector.time = time;
|
|
collector.volume = volume;
|
|
collector.maxDrawDown = xTESTMaxDrawDown;
|
|
collector.maxAllowedVolume = maxAllowedVolume;
|
|
collector.minBalanceForOpenTrade = xTESTTrader.GetMinBalanceForOpenTrades();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
xTESTMaxDrawUp =
|
|
xTESTMaxDrawUp == 0 ||
|
|
xTESTMaxDrawUp < profit
|
|
? profit
|
|
: xTESTMaxDrawUp;
|
|
}
|
|
|
|
//
|
|
// Update Collector ...
|
|
xTESTCollector.Add(collector);
|
|
|
|
//
|
|
// Update Reports ...
|
|
xTESTReporter.UpdateMaxDrawUpInReports(xTESTMaxDrawUp);
|
|
xTESTReporter.UpdateMaxDrawDownInReports(xTESTMaxDrawDown);
|
|
xTESTReporter.UpdateMaxSameTimeTradesInReports(signalsCount);
|
|
}
|
|
|
|
//
|
|
// START Event Handlers ...
|
|
//
|
|
|
|
//
|
|
// Runs When a Signal Successfully Executed ...
|
|
void XTESTOnSignal(
|
|
XSignal &signal, // Specified Signal
|
|
string &providers[] // Signal Providers
|
|
)
|
|
{
|
|
//
|
|
// Issue Propper Alert ...
|
|
XTESTIssueSignalExecutionAlert(
|
|
signal,
|
|
providers);
|
|
|
|
//
|
|
// Add Signal To Supports on Guard ...
|
|
xTESTGuard.AddSupport(signal);
|
|
|
|
//
|
|
// Update Reports ...
|
|
xTESTReporter.AddSignalToReports(
|
|
signal,
|
|
providers);
|
|
}
|
|
|
|
//
|
|
// Runs when a Position Got Take Profit ...
|
|
void XTESTOnTP(
|
|
XSignal &signal // Specified Signal
|
|
)
|
|
{
|
|
//
|
|
// Issue Propper Alert ...
|
|
XTESTIssueTPAlert(signal);
|
|
|
|
//
|
|
// Remove Signal From Guard Protector ...
|
|
xTESTGuard.Remove(signal.ticket);
|
|
xTESTGuard.RemoveSupport(signal.ticket);
|
|
|
|
//
|
|
// Update Reports ...
|
|
xTESTReporter.AddTradeTPInReports();
|
|
XTESTUpdateReports();
|
|
}
|
|
|
|
//
|
|
// Runs when a Position Got Stop Loss ...
|
|
void XTESTOnSL(
|
|
XSignal &signal // Specified Signal
|
|
)
|
|
{
|
|
//
|
|
// Issue Propper Alert ...
|
|
XTESTIssueSLAlert(signal);
|
|
|
|
//
|
|
// Remove Signal From Guard Protector ...
|
|
xTESTGuard.Remove(signal.ticket);
|
|
xTESTGuard.RemoveSupport(signal.ticket);
|
|
|
|
//
|
|
// Update Reports ...
|
|
xTESTReporter.AddTradeSLInReports();
|
|
XTESTUpdateReports();
|
|
}
|
|
|
|
//
|
|
// Runs when a Position Risk Free ...
|
|
void XTESTOnRF(
|
|
XSignal &signal // Specified Signal
|
|
)
|
|
{
|
|
//
|
|
// Issue Propper Alert ...
|
|
XTESTIssueRFAlert(signal);
|
|
|
|
//
|
|
// Remove Signal From Guard Protector ...
|
|
// since RiskFree Signals has SL ...
|
|
xTESTGuard.Remove(signal.ticket);
|
|
xTESTGuard.RemoveSupport(signal.ticket);
|
|
|
|
//
|
|
// Update Reports ...
|
|
xTESTReporter.AddTradeSLInReports();
|
|
XTESTUpdateReports();
|
|
}
|
|
|
|
//
|
|
// Runs when a Position Force Closed ...
|
|
void XTESTOnFC(
|
|
XSignal &signal // Specified Signal
|
|
)
|
|
{
|
|
//
|
|
// Issue Propper Alert ...
|
|
XTESTIssueFCAlert(signal);
|
|
|
|
//
|
|
// Remove Signal From Guard Protector ...
|
|
xTESTGuard.Remove(signal.ticket);
|
|
xTESTGuard.RemoveSupport(signal.ticket);
|
|
|
|
//
|
|
// Update Reports ...
|
|
xTESTReporter.AddTradeSLInReports();
|
|
XTESTUpdateReports();
|
|
}
|
|
|
|
//
|
|
// Runs when a Position Guarded ...
|
|
void XTESTOnGuard(
|
|
XSignal &signal, // Specified Signal
|
|
ENUM_X_GUARD_REASONS reason, // Reason of Guard Applied
|
|
string message, // Guard Returned Message
|
|
bool isStopOut = false // Specified StopOut Fired or not
|
|
)
|
|
{
|
|
//
|
|
// Chekc StopOut ...
|
|
if (isStopOut)
|
|
{
|
|
//
|
|
LogMessage(message);
|
|
|
|
//
|
|
xTESTMEnableProvider = false;
|
|
}
|
|
|
|
//
|
|
// Issue Propper Alert ...
|
|
XTESTIssueGuardAlert(signal, reason, isStopOut);
|
|
|
|
//
|
|
// Update Reports ...
|
|
xTESTReporter.AddTradeSLInReports();
|
|
XTESTUpdateReports();
|
|
}
|
|
|
|
//
|
|
// END Event Handlers ...
|
|
//
|
|
|
|
//
|
|
// END Provided Functions ...
|
|
//
|
|
|
|
//
|
|
// START Private Functions ...
|
|
//
|
|
|
|
//
|
|
// START Volume Baseed Functions ...
|
|
//
|
|
|
|
//
|
|
// Calculating Volume for Tradings ...
|
|
double XTESTCalculateVolume(
|
|
double forceMultiplier = 0 // some times we get more than one signal at the same time, here we increase volume using this ...
|
|
)
|
|
{
|
|
//
|
|
// Check Open Trades ...
|
|
int openSignals = xTESTTrader.Count();
|
|
|
|
//
|
|
double result = xTESTVolumeManager.CalculateVolume(
|
|
openSignals,
|
|
_Symbol);
|
|
|
|
//
|
|
result *= forceMultiplier;
|
|
|
|
//
|
|
// Normalize Volume ...
|
|
result = NormalizeVolume(result, _Symbol, 2);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// END Volume Baseed Functions ...
|
|
//
|
|
|
|
//
|
|
// START Report/Collect and Guard Functions ...
|
|
//
|
|
|
|
//
|
|
// Update Report Info ...
|
|
void XTESTUpdateReports()
|
|
{
|
|
//
|
|
double staticVolume = xTESTVolumeManager.GetStaticVolume();
|
|
string staticVolumeCalculationMethod = EnumToString(xTESTStaticVolumeMethod);
|
|
double maxAllowedVolume = xTESTVolumeManager.GetMaxAllowedVolume();
|
|
double volumeIncreaseMultiplier = xTESTVolumeManager.GetVolumeMultiplier();
|
|
double balanceGowingToApplyMultiplier = xTESTVolumeManager.GetIncreaseMultiplierBalance();
|
|
|
|
double balanceGrowingToIncreaseMaxAllowedVolume = xTESTVolumeManager.GetIncreaseMaxAllowedVolumeBalance();
|
|
|
|
//
|
|
// Update Reports Volume Info ...
|
|
xTESTReporter.UpdateReportsVolumeInfo(
|
|
staticVolume,
|
|
staticVolumeCalculationMethod,
|
|
maxAllowedVolume,
|
|
volumeIncreaseMultiplier,
|
|
balanceGowingToApplyMultiplier,
|
|
balanceGrowingToIncreaseMaxAllowedVolume);
|
|
|
|
//
|
|
// Calculate Max Allowed Drawdown ...
|
|
double minBalanceForTradeBasedOnBalance = xTESTTrader.GetMinBalanceForOpenTrades();
|
|
xTESTReporter.UpdateMinBalanceForOpenTradesInReports(minBalanceForTradeBasedOnBalance);
|
|
}
|
|
|
|
//
|
|
// Reset XTEST Info Buffers ...
|
|
void XTESTResetCollectors()
|
|
{
|
|
//
|
|
// Reset Calculations Buffers and Variables ...
|
|
xTESTMaxDrawUp = 0;
|
|
xTESTMaxDrawDown = 0;
|
|
|
|
//
|
|
xTESTTrader.Reset();
|
|
xTESTReporter.Reset();
|
|
xTESTCollector.Reset();
|
|
xTESTVolumeManager.ResetForceVolumeMultiplier();
|
|
}
|
|
|
|
//
|
|
// END Report/Collect and Guard Functions ...
|
|
//
|
|
|
|
//
|
|
// START Alert Functions ...
|
|
//
|
|
|
|
//
|
|
// Send Alert ...
|
|
void XTESTIssueAlert(string message)
|
|
{
|
|
//
|
|
// Validate Args ...
|
|
if (StringLen(message) <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (xTESTEnableAlerts)
|
|
{
|
|
SendAlert(message);
|
|
}
|
|
else
|
|
{
|
|
LogMessage(message);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Send Take Profit Alert on Specific Signal ...
|
|
void XTESTIssueTPAlert(
|
|
XSignal &signal // Specified Signal
|
|
)
|
|
{
|
|
//
|
|
string message = "";
|
|
|
|
//
|
|
message = xTESTTrader.GenerateSignalTPComment(signal);
|
|
|
|
//
|
|
XTESTIssueAlert(message);
|
|
}
|
|
|
|
//
|
|
// Send Stop Loss Alert on Specific Signal ...
|
|
void XTESTIssueSLAlert(
|
|
XSignal &signal // Specified Signal
|
|
)
|
|
{
|
|
//
|
|
string message = "";
|
|
|
|
//
|
|
message = xTESTTrader.GenerateSignalSLComment(signal);
|
|
|
|
//
|
|
XTESTIssueAlert(message);
|
|
}
|
|
|
|
//
|
|
// Send Force Close Alert on Specific Signal ...
|
|
void XTESTIssueFCAlert(
|
|
XSignal &signal // Specified Signal
|
|
)
|
|
{
|
|
//
|
|
string message = "";
|
|
|
|
//
|
|
message = xTESTTrader.GenerateSignalForceCloseComment(signal);
|
|
|
|
//
|
|
XTESTIssueAlert(message);
|
|
}
|
|
|
|
//
|
|
// Send Risk Free Alert on Specific Signal ...
|
|
void XTESTIssueRFAlert(
|
|
XSignal &signal // Specified Signal
|
|
)
|
|
{
|
|
//
|
|
string message = "";
|
|
|
|
//
|
|
message = xTESTTrader.GenerateSignalRFComment(signal, 0);
|
|
|
|
//
|
|
XTESTIssueAlert(message);
|
|
}
|
|
|
|
//
|
|
// Send Guard Alert on Specific Signal ...
|
|
void XTESTIssueGuardAlert(
|
|
XSignal &signal, // Specified Signal
|
|
ENUM_X_GUARD_REASONS reason, // Specified Guard Reason
|
|
bool isStopOut = false // Specified StopOut Fired or not
|
|
)
|
|
{
|
|
//
|
|
string message = "";
|
|
|
|
//
|
|
message = xTESTGuard.GenerateGuardedSignalComment(
|
|
signal,
|
|
reason);
|
|
|
|
//
|
|
XTESTIssueAlert(message);
|
|
}
|
|
|
|
//
|
|
// Send Initialization Succeed Alert ...
|
|
void XTESTIssueInitializationSucceedAlert()
|
|
{
|
|
//
|
|
string message = "Initializion of (" + XTESTProviderName + " Provider" + " _ " + _Symbol + " _ " + EnumToString(_Period) + ") Succeeded ...";
|
|
XTESTIssueAlert(message);
|
|
}
|
|
|
|
//
|
|
// Send De Initialization Succeed Alert ...
|
|
void XTESTIssueDeinitializationSucceedAlert()
|
|
{
|
|
//
|
|
string message = "De Initializion of (" + XTESTProviderName + " Provider" + ") Succeeded ...";
|
|
XTESTIssueAlert(message);
|
|
}
|
|
|
|
//
|
|
// Send Signal Successfully Execution Alert ...
|
|
void XTESTIssueSignalExecutionAlert(
|
|
XSignal &signal, // Specified Signal
|
|
string &providers[] // Signal Providers
|
|
)
|
|
{
|
|
//
|
|
string message = xTESTTrader.ToString(signal);
|
|
|
|
//
|
|
string providersMsg = ToString(providers);
|
|
if (StringLen(providersMsg) > 0)
|
|
{
|
|
message += ", Providers: " + providersMsg;
|
|
}
|
|
|
|
//
|
|
XTESTIssueAlert(message);
|
|
}
|
|
|
|
//
|
|
// Send Signal Execution Alert ...
|
|
void XTESTIssueSignalExecutionError(int error)
|
|
{
|
|
//
|
|
string message = GetSignalExecutionError(error);
|
|
if (StringLen(message) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XTESTIssueAlert(message);
|
|
}
|
|
|
|
//
|
|
// END Alert Functions ...
|
|
//
|
|
|
|
//
|
|
// END Private Functions ...
|
|
//
|