1371 lines
28 KiB
Plaintext
1371 lines
28 KiB
Plaintext
////////////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 XMAP Signal Provider Library
|
|
// --------------------------------------------------------
|
|
// Name: XMAPSignalProvider
|
|
// Description: XMAP 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
|
|
|
|
//
|
|
// START Inputs ...
|
|
//
|
|
#include "x-saherelm.xmap.provider.inputs.lib.mq5"
|
|
//
|
|
// END Inputs ...
|
|
//
|
|
|
|
//
|
|
// Include Common Library ...
|
|
#include "x-saherelm.common.lib.mq5"
|
|
|
|
//
|
|
// Include Logger Library ...
|
|
#include "x-saherelm.log.lib.mq5"
|
|
|
|
//
|
|
// Include Alert Library ...
|
|
#include "x-saherelm.alert.lib.mq5"
|
|
|
|
//
|
|
// Include Draw Library ...
|
|
#include "x-saherelm.draw.lib.mq5"
|
|
|
|
//
|
|
// Include Class Libraries ...
|
|
#include "x-saherelm.class.lib.mq5"
|
|
|
|
//
|
|
// START Global Definitions: Variables, Properties and etc ...
|
|
//
|
|
//
|
|
XCTrade *xMAPTrader;
|
|
XCAccountInfo xMAPAccountInfo;
|
|
|
|
//
|
|
#include "x-saherelm.xmap.provider.indicators.lib.mq5"
|
|
|
|
//
|
|
// XOHCL xMAPCandles[];
|
|
|
|
//
|
|
double xMAPDeposit = 0;
|
|
double xMAPBalance = 0;
|
|
double xMAPFreeMargin = 0;
|
|
double xMAPMaxDrawDownPerTrade = 0;
|
|
double xMAPGridPriceDistance = 0;
|
|
double xMAPFreeMarginForOpenTrades = 0;
|
|
double xMAPBalanceForOpenTrades = 0;
|
|
//
|
|
// END Global Definitions: Variables, Properties and etc ...
|
|
//
|
|
|
|
//
|
|
// START Provided Functions ...
|
|
//
|
|
//
|
|
// Initial Library if required ...
|
|
bool OnInInitXMAPSignalProviderLibrary()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Inputs ...
|
|
result = XMAPValidateInputs();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Init Indicators ...
|
|
result = XMAPInitIndicators();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculations ...
|
|
|
|
//
|
|
// Calculate Account Deposit ...
|
|
xMAPDeposit = xMAPAccountInfo.GetInitialBalance();
|
|
|
|
//
|
|
// Calculate Max DrawDown Per Trade ...
|
|
if (xMAPMaxDrawDownPerTradeFactor > 0)
|
|
{
|
|
xMAPMaxDrawDownPerTrade = xMAPDeposit * xMAPMaxDrawDownPerTradeFactor;
|
|
}
|
|
|
|
//
|
|
// Calculate Grid Distance Price ...
|
|
if (xMAPGridPriceDistanceInPips > 0)
|
|
{
|
|
xMAPGridPriceDistance = PipsToPrice(xMAPGridPriceDistanceInPips);
|
|
}
|
|
|
|
//
|
|
// Calculate Min Balance for Trades ...
|
|
if (xMAPBalanceFactorForOpenTrades > 0)
|
|
{
|
|
xMAPBalanceForOpenTrades = xMAPBalanceFactorForOpenTrades * xMAPDeposit;
|
|
}
|
|
|
|
//
|
|
// Claculate Min Free Marging for Trades ...
|
|
if (xMAPFreeMarginFactorForOpenTrades > 0)
|
|
{
|
|
xMAPFreeMarginForOpenTrades = xMAPFreeMarginFactorForOpenTrades * xMAPDeposit;
|
|
}
|
|
|
|
//
|
|
// Make XCTrader instance ...
|
|
xMAPTrader = new XCTrade(
|
|
_Symbol,
|
|
xMAPSlippage,
|
|
xMAPMagicNumber);
|
|
|
|
//
|
|
result = true;
|
|
|
|
//
|
|
// Logging State ...
|
|
string message = "Initializion of (" + "XMAP Provider" + " _ " + _Symbol + " _ " + EnumToString(_Period) + ") Succeeded ...";
|
|
LogMessage(message);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// DeInitial Library if required ...
|
|
void OnDeinitXMAPSignalProviderLibrary()
|
|
{
|
|
//
|
|
// Release Handlers ...
|
|
XMAPReleaseIndicators();
|
|
|
|
//
|
|
// Logging State ...
|
|
string message = "De Initializion of (" + "XMAP Provider" + ") Succeeded ...";
|
|
LogMessage(message);
|
|
}
|
|
|
|
//
|
|
// this is a Globally Function which do all of
|
|
// checkings and positions handling ...
|
|
void HandleXMAPSignalProviderTick()
|
|
{
|
|
//
|
|
// Update account Balance ...
|
|
xMAPBalance = xMAPAccountInfo.GetBalance();
|
|
xMAPFreeMargin = xMAPAccountInfo.GetFreeMargin();
|
|
|
|
//
|
|
// Reading Indicator Buffers ...
|
|
XMAPHandleReadingBuffers();
|
|
if (xMAPCalculatedBars < xMAPMaxLengthOfInputs)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Handle Open Trades ...
|
|
XMAPHandleOpenTrades();
|
|
|
|
//
|
|
// Handle Close Trades ...
|
|
XMAPHandleCloseTrades();
|
|
|
|
//
|
|
// XMAPLogTrades();
|
|
}
|
|
|
|
//
|
|
// Handle Open Trades ...
|
|
void XMAPHandleOpenTrades()
|
|
{
|
|
//
|
|
// Count Max Open Trades ...
|
|
bool canOpenPrimaryTrades = true;
|
|
if (xMAPMaxAllowedPrimaryTrades > 0)
|
|
{
|
|
//
|
|
int count = XMAPCountPrimaryTrades();
|
|
canOpenPrimaryTrades = !(count >= xMAPMaxAllowedPrimaryTrades);
|
|
}
|
|
|
|
//
|
|
// Check Free Margin ...
|
|
if (xMAPFreeMargin <= xMAPFreeMarginForOpenTrades)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Account Balance ...
|
|
if (xMAPBalance <= xMAPBalanceForOpenTrades)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (canOpenPrimaryTrades)
|
|
{
|
|
//
|
|
// Primary Long Trade ...
|
|
if (xMAPAllowLongTrades)
|
|
{
|
|
//
|
|
XSignal primaryLongSignal = {};
|
|
bool isPrimaryLongSignalExecuted = XMAPHandlePrimaryLong(primaryLongSignal);
|
|
if (isPrimaryLongSignalExecuted)
|
|
{
|
|
}
|
|
}
|
|
|
|
//
|
|
// Primary Short Trade ...
|
|
if (xMAPAllowShortTrades)
|
|
{
|
|
//
|
|
XSignal primaryShortSignal = {};
|
|
bool isPrimaryShortSignalExecuted = XMAPHandlePrimaryShort(primaryShortSignal);
|
|
if (isPrimaryShortSignalExecuted)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
if (xMAPGridPriceDistance > 0 && xMAPMaxAllowedGridTrades > 0)
|
|
{
|
|
//
|
|
bool isGridLongTradeOpened = XMAPHandleGridLong();
|
|
if (isGridLongTradeOpened)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Close Trades ...
|
|
void XMAPHandleCloseTrades()
|
|
{
|
|
//
|
|
// Handle Long/Buy Close ...
|
|
if (xMAPTrader.CountLongs() > 0 && XMAPCanCloseLongTrades())
|
|
{
|
|
//
|
|
XSignal closed[];
|
|
xMAPTrader.CloseLongPositions(closed);
|
|
bool hasClosed = ArraySize(closed) > 0;
|
|
if (hasClosed)
|
|
{
|
|
//
|
|
string message = "XMAP Closing Long Trades ...";
|
|
if (xMAPEnableAlerts)
|
|
{
|
|
SendAlert(message);
|
|
}
|
|
else
|
|
{
|
|
LogMessage(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Short/Sell Close ...
|
|
if (xMAPTrader.CountShorts() > 0 && XMAPCanCloseShortTrades())
|
|
{
|
|
//
|
|
XSignal closed[];
|
|
xMAPTrader.CloseShortPositions(closed);
|
|
bool hasClosed = ArraySize(closed) > 0;
|
|
if (hasClosed)
|
|
{
|
|
//
|
|
string message = "XMAP Closing Short Trades ...";
|
|
if (xMAPEnableAlerts)
|
|
{
|
|
SendAlert(message);
|
|
}
|
|
else
|
|
{
|
|
LogMessage(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// MaxDrawDown Trades ...
|
|
if (xMAPMaxDrawDownPerTrade > 0)
|
|
{
|
|
//
|
|
XSignal inDrawDownPrimarySignals[];
|
|
XSignal closed[];
|
|
XMAPGetInDrawDownPrimaryTrades(inDrawDownPrimarySignals);
|
|
for (int i = 0; i < ArraySize(inDrawDownPrimarySignals); i++)
|
|
{
|
|
//
|
|
XSignal inDP = inDrawDownPrimarySignals[i];
|
|
|
|
//
|
|
double drawDown = -1 * inDP.profit;
|
|
|
|
//
|
|
bool canClose = drawDown >= xMAPMaxDrawDownPerTrade;
|
|
if (!canClose)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isClosed = xMAPTrader.Close(inDP.ticket);
|
|
if (isClosed)
|
|
{
|
|
//
|
|
Add(
|
|
inDP,
|
|
closed);
|
|
|
|
//
|
|
// Check and Close Belongs to Primary Grid Trades ...
|
|
// XSignal grids[];
|
|
// XMAPGetGridTradesOfPrimary(inDP, grids);
|
|
// int gridCount = ArraySize(grids);
|
|
// if (gridCount == 0) {
|
|
// continue;
|
|
// }
|
|
|
|
// //
|
|
// for (int j = 0; j < gridCount; j++) {
|
|
// //
|
|
// XSignal grid = grids[j];
|
|
// bool isGridClosed = xMAPTrader.Close(grid.ticket);
|
|
// }
|
|
}
|
|
}
|
|
|
|
xMAPTrader.CloseInDrawDownTrades(
|
|
xMAPMaxDrawDownPerTrade,
|
|
X_SIGNAL_UNKNOWN,
|
|
closed);
|
|
bool hasClosed = ArraySize(closed) > 0;
|
|
if (hasClosed)
|
|
{
|
|
//
|
|
string message = "Close Max DrawDown Trades ...";
|
|
if (xMAPEnableAlerts)
|
|
{
|
|
SendAlert(message);
|
|
}
|
|
else
|
|
{
|
|
LogMessage(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close Old Primary Trades ...
|
|
if (xMAPMaxPrimaryTradeAge > 0)
|
|
{
|
|
//
|
|
XSignal trades[];
|
|
xMAPTrader.GetLongTimeTrades(
|
|
xMAPMaxPrimaryTradeAge,
|
|
_Period,
|
|
trades);
|
|
int count = ArraySize(trades);
|
|
if (count > 0)
|
|
{
|
|
//
|
|
// Lopp ...
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSignal trade = trades[i];
|
|
if (!XMAPIsPrimaryTrade(trade))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isClosed = xMAPTrader.Close(trade.ticket);
|
|
if (isClosed)
|
|
{
|
|
//
|
|
string message = "Primary: " + (string)trade.ticket + " Closed because of Long Time Passed ...";
|
|
if (xMAPEnableAlerts)
|
|
{
|
|
SendAlert(message);
|
|
}
|
|
else
|
|
{
|
|
LogMessage(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close Old Grid Trades ...
|
|
if (xMAPMaxGridTradeAge > 0)
|
|
{
|
|
//
|
|
XSignal trades[];
|
|
xMAPTrader.GetLongTimeTrades(
|
|
xMAPMaxGridTradeAge,
|
|
_Period,
|
|
trades);
|
|
int count = ArraySize(trades);
|
|
if (count > 0)
|
|
{
|
|
//
|
|
// Lopp ...
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSignal trade = trades[i];
|
|
if (!XMAPIsGridTrade(trade))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isClosed = xMAPTrader.Close(trade.ticket);
|
|
if (isClosed)
|
|
{
|
|
//
|
|
string message = "Grid: " + (string)trade.ticket + " Closed because of Long Time Passed ...";
|
|
if (xMAPEnableAlerts)
|
|
{
|
|
SendAlert(message);
|
|
}
|
|
else
|
|
{
|
|
LogMessage(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Long/Buy for Primary Trades...
|
|
bool XMAPHandlePrimaryLong(
|
|
XSignal &signal, // return structure if signal founded
|
|
bool doTrade = true // do trade on signal
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ResetLastError();
|
|
|
|
//
|
|
// && xMAPTrader.CountLongs() == 0 ...
|
|
if (XMAPHasPrimaryLongSignal())
|
|
{
|
|
//
|
|
double entry = GetAsk();
|
|
double volume = XMAPCalculateVolume();
|
|
|
|
//
|
|
signal.entry = entry;
|
|
signal.volume = volume;
|
|
signal.symbol = _Symbol;
|
|
signal.type = X_SIGNAL_LONG;
|
|
signal.magicNumber = xMAPMagicNumber;
|
|
signal.time = iTime(_Symbol, _Period, 0);
|
|
signal.comment = "Primary_XMAP_Long";
|
|
|
|
//
|
|
// Setting TP ...
|
|
signal.tp = XMAPCalculateTP(signal.type);
|
|
if (signal.tp == entry)
|
|
{
|
|
//
|
|
result = false;
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (enableXMAPProvider && xMAPAllowLongTrades && doTrade)
|
|
{
|
|
//
|
|
// Execute Signal ...
|
|
result = xMAPTrader.ExecuteSignal(signal);
|
|
|
|
//
|
|
// Since this means an error happens, we have to log this error ...
|
|
if (!result)
|
|
{
|
|
string errMessage = "failed to execute Long signal: " + (string)GetLastError();
|
|
LogMessage(errMessage);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Alerts ...
|
|
if (result)
|
|
{
|
|
//
|
|
if (xMAPEnableAlerts)
|
|
{
|
|
SendAlert(signal, true);
|
|
}
|
|
else
|
|
{
|
|
LogExecutedSignal(signal);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Short/Sell for Primary Trades...
|
|
bool XMAPHandlePrimaryShort(
|
|
XSignal &signal, // return structure if signal founded
|
|
bool doTrade = true // do trade on signal
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ResetLastError();
|
|
|
|
//
|
|
if (XMAPHasPrimaryShortSignal() && xMAPTrader.CountShorts() == 0)
|
|
{
|
|
//
|
|
double entry = GetBid();
|
|
double volume = XMAPCalculateVolume();
|
|
|
|
//
|
|
signal.entry = entry;
|
|
signal.volume = volume;
|
|
signal.symbol = _Symbol;
|
|
signal.type = X_SIGNAL_SHORT;
|
|
signal.magicNumber = xMAPMagicNumber;
|
|
signal.time = iTime(_Symbol, _Period, 0);
|
|
signal.comment = "Primary_XMAP_Short";
|
|
|
|
//
|
|
if (enableXMAPProvider && xMAPAllowShortTrades && doTrade)
|
|
{
|
|
//
|
|
// Execute Signal ...
|
|
result = xMAPTrader.ExecuteSignal(signal);
|
|
|
|
//
|
|
// Since this means an error happens, we have to log this error ...
|
|
if (!result)
|
|
{
|
|
string errMessage = "failed to execute Short signal: " + (string)GetLastError();
|
|
LogMessage(errMessage);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Alerts ...
|
|
if (result)
|
|
{
|
|
//
|
|
if (xMAPEnableAlerts)
|
|
{
|
|
SendAlert(signal, true);
|
|
}
|
|
else
|
|
{
|
|
LogExecutedSignal(signal);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Long Grid Trades ...
|
|
bool XMAPHandleGridLong()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Grid Long Conditions ...
|
|
result = XMAPHasGridLongSignal();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve all In DrawDown Primary Trades ...
|
|
XSignal inDrawDownPrimaryTrades[];
|
|
XMAPGetInDrawDownPrimaryTrades(inDrawDownPrimaryTrades);
|
|
int count = ArraySize(inDrawDownPrimaryTrades);
|
|
if (count == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSignal primary = inDrawDownPrimaryTrades[i];
|
|
if (primary.type != X_SIGNAL_LONG)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Grids of Primary ...
|
|
XSignal grids[];
|
|
XMAPGetGridTradesOfPrimary(primary, grids);
|
|
int gridsCount = ArraySize(grids);
|
|
if (gridsCount >= xMAPMaxAllowedGridTrades)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
XSignal firstGrid = XMAPGetFirstGridOfPrimary(primary);
|
|
XSignal latestGrid = XMAPGetLastGridOfPrimary(primary);
|
|
bool hasFirsttGrid = IsValid(firstGrid, xMAPMagicNumber) && XMAPIsGridTrade(firstGrid);
|
|
bool hasLatestGrid = IsValid(latestGrid, xMAPMagicNumber) && XMAPIsGridTrade(latestGrid);
|
|
|
|
//
|
|
double entry = GetEntry(primary.type);
|
|
double latestEntry = hasLatestGrid ? latestGrid.entry : primary.entry;
|
|
double entryPriceDiff = (latestEntry - entry);
|
|
double gridDistancePrice = xMAPGridPriceDistance;
|
|
if (entryPriceDiff >= gridDistancePrice)
|
|
{
|
|
//
|
|
// Here we Can Create a Grid Signal ...
|
|
XSignal grid = XMAPGenerateGridSignal(primary, latestGrid);
|
|
if (!IsValid(grid, xMAPMagicNumber))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
ResetLastError();
|
|
bool isGridExecuted = xMAPTrader.ExecuteSignal(grid);
|
|
if (isGridExecuted && !result)
|
|
{
|
|
//
|
|
// if (gridsCount > 1 && hasFirsttGrid)
|
|
// {
|
|
// //
|
|
// bool isClosed = xMAPTrader.Close(firstGrid.ticket);
|
|
// }
|
|
|
|
//
|
|
// bool isClosed = xMAPTrader.Close(primary.ticket);
|
|
|
|
//
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Market Conditions to find Long Primary Signals ...
|
|
bool XMAPHasPrimaryLongSignal()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool isXCHMAHasSignal = XTMCanOpenLongTrades();
|
|
|
|
//
|
|
result =
|
|
//
|
|
isXCHMAHasSignal
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Market Conditions to find Short Primary Signals ...
|
|
bool XMAPHasPrimaryShortSignal()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Sell/Short Conditions ...
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Has Long Grid Signal ...
|
|
bool XMAPHasGridLongSignal()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Get Long Conditions ...
|
|
result = XTMCanOpenLongTrades();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Market Conditions for closing Long Trades ...
|
|
bool XMAPCanCloseLongTrades()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = XTMCanCloseLongTrades();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Market Conditions for closing Short Trades ...
|
|
bool XMAPCanCloseShortTrades()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculating Volume for Tradings ...
|
|
double XMAPCalculateVolume()
|
|
{
|
|
//
|
|
double result = xMAPStaticVolume;
|
|
// if (!xMAPUseDynamicVolume)
|
|
// {
|
|
// return result;
|
|
// }
|
|
|
|
// //
|
|
// double accountBalance = xMAPAccountInfo.GetBalance();
|
|
// double balanceIncreased = xMAPBalanceIncreased;
|
|
// double volumeIncreased = xMAPVolumeIncreased;
|
|
|
|
// //
|
|
// result = (volumeIncreased * accountBalance) / balanceIncreased;
|
|
|
|
//
|
|
// Normalize Volume ...
|
|
result = NormalizeDouble(result, 2);
|
|
|
|
//
|
|
double maxAvailableVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
|
double minAvailableVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
|
|
|
//
|
|
// Validate Result ...
|
|
if (result > maxAvailableVolume)
|
|
{
|
|
result = maxAvailableVolume;
|
|
}
|
|
else if (result < minAvailableVolume)
|
|
{
|
|
result = minAvailableVolume;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//
|
|
// END Provided Functions ...
|
|
//
|
|
|
|
//
|
|
// START Private Functions ...
|
|
//
|
|
//
|
|
// Calculate Signal TP ...
|
|
double XMAPCalculateTP(
|
|
ENUM_X_SIGNAL_TYPE type // Position Type
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (type == X_SIGNAL_UNKNOWN)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double ask = GetAsk();
|
|
double bid = GetBid();
|
|
double spread = GetSpread();
|
|
|
|
//
|
|
bool isLong = type == X_SIGNAL_LONG;
|
|
|
|
//
|
|
double entry = isLong ? ask : bid;
|
|
|
|
//
|
|
// double swingLow = XOBDGetSmallestSwingLow(
|
|
// entry,
|
|
// numberOfSwings);
|
|
// double swingHigh = XOBDGetBiggestSwingHigh(
|
|
// entry,
|
|
// numberOfSwings);
|
|
|
|
//
|
|
// Find Risk ..
|
|
|
|
//
|
|
double reward = PipsToPrice(xMAPMinRewardPerTradeInPips) + spread;
|
|
// swingHigh - entry;
|
|
// PipsToPrice(5) + spread;
|
|
|
|
//
|
|
result = isLong ? entry + reward : entry - reward;
|
|
|
|
// //
|
|
// if (result == entry)
|
|
// {
|
|
// result += PipsToPrice(1);
|
|
// }
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Signal is Primary or not...
|
|
bool XMAPIsPrimaryTrade(XSignal &trade)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int titlePosition = StringFind(trade.comment, "Primary");
|
|
result = titlePosition >= 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Signal is Grid or not...
|
|
bool XMAPIsGridTrade(XSignal &trade)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int titlePosition = StringFind(trade.comment, "Grid");
|
|
result = titlePosition >= 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Primary Trades ...
|
|
void XMAPGetPrimaryTrades(XSignal &result[])
|
|
{
|
|
//
|
|
CleanBuffer(result);
|
|
|
|
//
|
|
XSignal trades[];
|
|
xMAPTrader.GetAllPositions(trades);
|
|
int count = ArraySize(trades);
|
|
if (count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSignal trade = trades[i];
|
|
if (!XMAPIsPrimaryTrade(trade))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
Add(trade, result);
|
|
}
|
|
}
|
|
int XMAPCountPrimaryTrades()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
XSignal trades[];
|
|
XMAPGetPrimaryTrades(trades);
|
|
result = ArraySize(trades);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve PrGridimary Trades ...
|
|
void XMAPGetGridTrades(XSignal &result[])
|
|
{
|
|
//
|
|
CleanBuffer(result);
|
|
|
|
//
|
|
XSignal trades[];
|
|
xMAPTrader.GetAllPositions(trades);
|
|
int count = ArraySize(trades);
|
|
if (count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSignal trade = trades[i];
|
|
if (!XMAPIsGridTrade(trade))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
Add(trade, result);
|
|
}
|
|
}
|
|
int XMAPCountGridTrades()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
XSignal trades[];
|
|
XMAPGetGridTrades(trades);
|
|
result = ArraySize(trades);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve In DrawDown Primary Trades ...
|
|
void XMAPGetInDrawDownPrimaryTrades(XSignal &result[])
|
|
{
|
|
//
|
|
CleanBuffer(result);
|
|
|
|
//
|
|
XSignal primaryTrades[];
|
|
XMAPGetPrimaryTrades(primaryTrades);
|
|
int count = ArraySize(primaryTrades);
|
|
if (count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSignal primary = primaryTrades[i];
|
|
if (primary.profit > 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
Add(primary, result);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Count In DrawDown Primary Trades ...
|
|
int XMAPCountInDrawDownPrimaryTrades()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
XSignal trades[];
|
|
XMAPGetInDrawDownPrimaryTrades(trades);
|
|
result = ArraySize(trades);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve In Profit Primary Trades ...
|
|
void XMAPGetInProfitPrimaryTrades(XSignal &result[])
|
|
{
|
|
//
|
|
CleanBuffer(result);
|
|
|
|
//
|
|
XSignal primaryTrades[];
|
|
XMAPGetPrimaryTrades(primaryTrades);
|
|
int count = ArraySize(primaryTrades);
|
|
if (count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSignal primary = primaryTrades[i];
|
|
if (primary.profit <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
Add(primary, result);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Count In Profit Primary Trades ...
|
|
int XMAPCountInProfitPrimaryTrades()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
XSignal trades[];
|
|
XMAPGetInProfitPrimaryTrades(trades);
|
|
result = ArraySize(trades);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Generate a Grid Trades Comment based on a Primary Trade ...
|
|
string XMAPGetGridTradeComment(XSignal &primary)
|
|
{
|
|
//
|
|
string result = "";
|
|
|
|
//
|
|
if (!XMAPIsPrimaryTrade(primary))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = "Grid_" + GetSignalType(primary) + "_Ticket(" + (string)primary.ticket + ")";
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check a Grid Trade Belongs to a Primary Trade or not ...
|
|
bool XMAPIsGridBelongsToPrimary(
|
|
XSignal &grid, // grid signal ...
|
|
XSignal &primary // primary signal ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (
|
|
!XMAPIsGridTrade(grid) ||
|
|
grid.type != primary.type ||
|
|
!XMAPIsPrimaryTrade(primary))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string comment = XMAPGetGridTradeComment(primary);
|
|
if (StringLen(comment) == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int titlePosition = StringFind(grid.comment, comment);
|
|
result = titlePosition >= 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Grid Trades which belongs to an Specified Primery Trades ...
|
|
void XMAPGetGridTradesOfPrimary(
|
|
XSignal &primary, // primary trade
|
|
XSignal &result[] // hold results
|
|
)
|
|
{
|
|
//
|
|
CleanBuffer(result);
|
|
|
|
//
|
|
string comment = XMAPGetGridTradeComment(primary);
|
|
if (StringLen(comment) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get all Grid Trades ...
|
|
XSignal grids[];
|
|
XMAPGetGridTrades(grids);
|
|
int count = ArraySize(grids);
|
|
if (count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSignal grid = grids[i];
|
|
bool isBelongsToPrimary = XMAPIsGridBelongsToPrimary(
|
|
grid,
|
|
primary);
|
|
if (!isBelongsToPrimary)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
Add(
|
|
grid,
|
|
result);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find Last Grid Trade of a Primary Trade ...
|
|
XSignal XMAPGetLastGridOfPrimary(XSignal &primary)
|
|
{
|
|
//
|
|
XSignal result = {};
|
|
|
|
//
|
|
if (!XMAPIsPrimaryTrade(primary))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XSignal grids[];
|
|
XMAPGetGridTradesOfPrimary(primary, grids);
|
|
int count = ArraySize(grids);
|
|
if (count == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSignal grid = grids[i];
|
|
|
|
//
|
|
if (!IsValid(result, xMAPMagicNumber))
|
|
{
|
|
result = grid;
|
|
}
|
|
|
|
//
|
|
if (IsLong(primary))
|
|
{
|
|
result = grid.entry < result.entry ? grid : result;
|
|
}
|
|
else if (IsShort(primary))
|
|
{
|
|
result = grid.entry > result.entry ? grid : result;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find First Grid Trade of a Primary Trade ...
|
|
XSignal XMAPGetFirstGridOfPrimary(XSignal &primary)
|
|
{
|
|
//
|
|
XSignal result = {};
|
|
|
|
//
|
|
if (!XMAPIsPrimaryTrade(primary))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XSignal grids[];
|
|
XMAPGetGridTradesOfPrimary(primary, grids);
|
|
int count = ArraySize(grids);
|
|
if (count == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSignal grid = grids[i];
|
|
|
|
//
|
|
if (!IsValid(result, xMAPMagicNumber))
|
|
{
|
|
result = grid;
|
|
}
|
|
|
|
//
|
|
if (IsLong(primary))
|
|
{
|
|
result = grid.entry > result.entry ? grid : result;
|
|
}
|
|
else if (IsShort(primary))
|
|
{
|
|
result = grid.entry < result.entry ? grid : result;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Prepare and Generate XSignal instance for Grid Trades ...
|
|
XSignal XMAPGenerateGridSignal(
|
|
XSignal &primary, // Main Primary Trade
|
|
XSignal &grid // Latest Grid Trade which Belongs to Primary
|
|
)
|
|
{
|
|
//
|
|
XSignal result = {};
|
|
|
|
//
|
|
if (!XMAPIsPrimaryTrade(primary))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool hasLatestGrid =
|
|
IsValid(grid, xMAPMagicNumber) &&
|
|
XMAPIsGridBelongsToPrimary(
|
|
grid,
|
|
primary);
|
|
|
|
// double gridThreshold = 7;
|
|
// double gridVolumeMultiplier = gridsCount < gridThreshold ? 2 : 1;
|
|
// double girdVolumeBase = gridsCount < gridThreshold ? grid.volume : primary.volume;
|
|
// double volume = NormalizeDouble(girdVolumeBase * gridVolumeMultiplier, 2);
|
|
|
|
//
|
|
bool isLong = primary.type == X_SIGNAL_LONG;
|
|
|
|
//
|
|
double entry = GetEntry(primary.type);
|
|
string comment = XMAPGetGridTradeComment(primary);
|
|
double volume = NormalizeDouble((hasLatestGrid ? grid.volume : primary.volume) * xMAPGridVolumeMultiplier, 2);
|
|
// if (volume >= 7 * primary.volume)
|
|
// {
|
|
// volume = primary.volume;
|
|
// }
|
|
|
|
//
|
|
double reward = NormalizeDouble(MathAbs((hasLatestGrid ? grid.entry : primary.tp) - entry) / 3, _Digits);
|
|
double tp = entry + reward;
|
|
|
|
//
|
|
result.tp = tp;
|
|
result.entry = entry;
|
|
result.sl = primary.sl;
|
|
result.volume = volume;
|
|
result.comment = comment;
|
|
result.type = primary.type;
|
|
result.magicNumber = primary.magicNumber;
|
|
result.time = iTime(_Symbol, _Period, 0);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//
|
|
// END Private Functions ...
|
|
//
|