757 lines
16 KiB
Plaintext
757 lines
16 KiB
Plaintext
////////////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 XOBD Signal Provider Library
|
|
// --------------------------------------------------------
|
|
// Name: XSignalProvider
|
|
// Description: 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 ...
|
|
//
|
|
input group "XOBD Provider";
|
|
|
|
//
|
|
input group "XOBD Common";
|
|
input bool enableXOBDProvider = true; // Enable Provider
|
|
input bool xOBDEnableAlerts = true; // Enable Events Alert
|
|
|
|
//
|
|
input group "XOBD Indicator";
|
|
input int xOBDLength = 5; // Market Length
|
|
input double xOBDArrowDistanceFromPrice = 0; // Arrow Distrance from Price
|
|
input uchar xOBDSwingHighArrowCode = 108; // Swing High Arrow Code
|
|
input color xOBDSwingHighArrowColor = clrMagenta; // Swing High Arrow Color
|
|
input uchar xOBDSwingLowArrowCode = 108; // Swing Low Arrow Code
|
|
input color xOBDSwingLowArrowColor = clrAqua; // Swing Low Arrow Color
|
|
|
|
//
|
|
input group "XOBD Trader";
|
|
input int xOBDMagicNumber = 16940562; // Trader MagicNumber
|
|
input int xOBDSlippage = 10; // Trader Slippage
|
|
|
|
//
|
|
input group "XOBD Trade Management";
|
|
input bool xOBDAllowLongTrades = true; // Allow Long Trades
|
|
input bool xOBDAllowShortTrades = false; // Allow Short Trades
|
|
input int xOBDMaxOpenTrades = 4; // Max Open Trades at Same Time
|
|
|
|
//
|
|
input group "XOBD Risk Management";
|
|
input bool xOBDUseTPSL = true; // Allow use TP and SL
|
|
input bool xOBDUseVirtualTPSL = false; // Allow Use Virtual TP and SL
|
|
input bool xOBDDrawTPSL = true; // Draw TP and SL
|
|
input double xOBDR2r = 1.5; // Risk To Reward Ratio
|
|
input int xOBDLoopback = 3; // Loopback Length for TP/SL Calculation
|
|
input double xOBDMinRiskPerTrade = 100; // Min Risk Per Trade in Points
|
|
input double xOBDMaxRiskPerTrade = 1000; // Max Risk Per Trade in Points
|
|
input bool xOBDUseDynamicVolume = false; // Enable Dynamic Volume
|
|
input double xOBDStaticVolume = 0.01; // Static Volume
|
|
input double xOBDBalanceIncreased = 500; // Balance Increase
|
|
input double xOBDVolumeIncreased = 0.01; // Volume Increase
|
|
//
|
|
// 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 ...
|
|
//
|
|
//
|
|
int xOBDHandler = INVALID_HANDLE;
|
|
double xOBDBuffer[];
|
|
|
|
//
|
|
XCTrade *xOBDTrader;
|
|
XCAccountInfo xOBDAccountInfo;
|
|
//
|
|
// END Global Definitions: Variables, Properties and etc ...
|
|
//
|
|
|
|
//
|
|
// START Provided Functions ...
|
|
//
|
|
//
|
|
// Initial Library if required ...
|
|
bool OnInInitXOBDSignalProviderLibrary()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Error Message ...
|
|
string message = "";
|
|
|
|
//
|
|
ResetLastError();
|
|
xOBDHandler = iCustom(
|
|
_Symbol,
|
|
_Period,
|
|
"x-saherelm.xobd.indicator",
|
|
//
|
|
xOBDLength,
|
|
xOBDArrowDistanceFromPrice,
|
|
xOBDSwingHighArrowCode,
|
|
xOBDSwingHighArrowColor,
|
|
xOBDSwingLowArrowCode,
|
|
xOBDSwingLowArrowColor);
|
|
if (xOBDHandler == INVALID_HANDLE)
|
|
{
|
|
//
|
|
LogMessage("error initializing XOBD Indicator: " + (string)GetLastError());
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Risk Management ...
|
|
if (xOBDUseDynamicVolume)
|
|
{
|
|
//
|
|
if (xOBDBalanceIncreased <= 0 || xOBDVolumeIncreased <= 0)
|
|
{
|
|
//
|
|
message = "invalid volume increased factors ...";
|
|
LogMessage(message);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
double maxAvailableVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
|
|
double minAvailableVolume = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
|
|
|
|
//
|
|
if (xOBDStaticVolume > maxAvailableVolume || xOBDStaticVolume < minAvailableVolume)
|
|
{
|
|
//
|
|
message = "invalid static volume ...";
|
|
LogMessage(message);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate use TPSL ...
|
|
if (xOBDUseTPSL)
|
|
{
|
|
//
|
|
if (xOBDR2r < 1.2)
|
|
{
|
|
//
|
|
LogMessage("Risk to Rewadrd Ratio is too small ...");
|
|
|
|
//
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make XCTrader instance ...
|
|
xOBDTrader = new XCTrade(
|
|
_Symbol,
|
|
xOBDSlippage,
|
|
xOBDMagicNumber);
|
|
|
|
//
|
|
result = true;
|
|
|
|
//
|
|
// Logging State ...
|
|
message = "Initializion of (" + "XOBD Provider" + " _ " + _Symbol + " _ " + EnumToString(_Period) + ") Succeeded ...";
|
|
LogMessage(message);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// DeInitial Library if required ...
|
|
void OnDeinitXOBDSignalProviderLibrary()
|
|
{
|
|
//
|
|
// Logging State ...
|
|
string message = "De Initializion of (" + "XOBD Provider" + ") Succeeded ...";
|
|
LogMessage(message);
|
|
}
|
|
|
|
//
|
|
// this is a Globally Function which do all of
|
|
// checkings and positions handling ...
|
|
void HandleXOBDSignalProviderTick()
|
|
{
|
|
//
|
|
// Reding XOBD Buffer ...
|
|
CopyBuffer(xOBDHandler, 0, 0, 5, xOBDBuffer);
|
|
|
|
//
|
|
// Handle Open Trades ...
|
|
XOBDHandleOpenTrades();
|
|
|
|
//
|
|
// Handle Close Trades ...
|
|
XOBDHandleCloseTrades();
|
|
}
|
|
|
|
//
|
|
// Check Market Conditions to find Long Primary Signals ...
|
|
bool XOBDHasPrimaryLongSignal()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Buy/Long Conditions ...
|
|
// Swing Low is a sign of Bullish Trend ...
|
|
result = xOBDBuffer[4] == -1;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Market Conditions to find Short Primary Signals ...
|
|
bool XOBDHasPrimaryShortSignal()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Sell/Short Conditions ...
|
|
// Swing High is a sign of Bearish Trend ...
|
|
result = xOBDBuffer[4] == 1;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Market Conditions for closing Long Trades ...
|
|
bool XOBDCanCloseLongTrades()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Market Conditions for Closing
|
|
// Long Trades ...
|
|
// result = xOBDBuffer[4] == 1;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Market Conditions for closing Short Trades ...
|
|
bool XOBDCanCloseShortTrades()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Market Conditions for Closing
|
|
// Short Trades ...
|
|
// result = xOBDBuffer[4] == -1;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Long/Buy for Primary Trades...
|
|
bool XOBDHandlePrimaryLong(
|
|
XSignal &signal, // return structure if signal founded
|
|
bool doTrade = true // do trade on signal
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ResetLastError();
|
|
|
|
//
|
|
// && xOBDTrader.CountLongs() == 0
|
|
if (XOBDHasPrimaryLongSignal())
|
|
{
|
|
//
|
|
double entry = GetAsk();
|
|
double volume = XOBDCalculateVolume();
|
|
|
|
//
|
|
double canDoTrade = XOBDCanDoTrade();
|
|
|
|
//
|
|
// Handle TP SL if it's enabled ...
|
|
if (xOBDUseTPSL)
|
|
{
|
|
XTPSL mTpSl = XOBDCalculateTPSL(X_SIGNAL_LONG, entry);
|
|
if (IsValid(mTpSl))
|
|
{
|
|
//
|
|
// Check for Draw TP and SL ...
|
|
if (xOBDDrawTPSL)
|
|
{
|
|
XOBDDrawTPSL(mTpSl);
|
|
}
|
|
|
|
//
|
|
// Set TP SL in Signal if it's required to add directly ...
|
|
if (!xOBDUseVirtualTPSL)
|
|
{
|
|
//
|
|
signal.tp = mTpSl.tp;
|
|
signal.sl = mTpSl.sl;
|
|
}
|
|
//
|
|
// Draw Virtual TP SL for Closing Trades ...
|
|
else
|
|
{
|
|
//
|
|
// TODO: implement this ...
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
signal.entry = entry;
|
|
signal.volume = volume;
|
|
signal.symbol = _Symbol;
|
|
signal.type = X_SIGNAL_LONG;
|
|
signal.magicNumber = xOBDMagicNumber;
|
|
signal.time = iTime(_Symbol, _Period, 0);
|
|
signal.comment = "Primary XOBD Long";
|
|
|
|
//
|
|
if (enableXOBDProvider && xOBDAllowLongTrades && doTrade && canDoTrade)
|
|
{
|
|
//
|
|
// Execute Signal ...
|
|
result = xOBDTrader.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 (xOBDEnableAlerts)
|
|
{
|
|
SendAlert(signal, true);
|
|
}
|
|
else
|
|
{
|
|
LogExecutedSignal(signal);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Short/Sell for Primary Trades...
|
|
bool XOBDHandlePrimaryShort(
|
|
XSignal &signal, // return structure if signal founded
|
|
bool doTrade = true // do trade on signal
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ResetLastError();
|
|
|
|
//
|
|
// && xOBDTrader.CountShorts() == 0
|
|
if (XOBDHasPrimaryShortSignal())
|
|
{
|
|
//
|
|
double entry = GetBid();
|
|
double volume = XOBDCalculateVolume();
|
|
|
|
//
|
|
double canDoTrade = XOBDCanDoTrade();
|
|
|
|
//
|
|
signal.entry = entry;
|
|
signal.volume = volume;
|
|
signal.symbol = _Symbol;
|
|
signal.type = X_SIGNAL_SHORT;
|
|
signal.magicNumber = xOBDMagicNumber;
|
|
signal.time = iTime(_Symbol, _Period, 0);
|
|
signal.comment = "Primary XOBD Short";
|
|
|
|
//
|
|
if (enableXOBDProvider && xOBDAllowShortTrades && doTrade && canDoTrade)
|
|
{
|
|
//
|
|
// Execute Signal ...
|
|
result = xOBDTrader.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 (xOBDEnableAlerts)
|
|
{
|
|
SendAlert(signal, true);
|
|
}
|
|
else
|
|
{
|
|
LogExecutedSignal(signal);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle Open Trades ...
|
|
void XOBDHandleOpenTrades()
|
|
{
|
|
//
|
|
// Primary Long Trade ...
|
|
XSignal primaryLongSignal = {};
|
|
bool isPrimaryLongSignalExecuted = XOBDHandlePrimaryLong(primaryLongSignal);
|
|
if (isPrimaryLongSignalExecuted)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Primary Short Trade ...
|
|
XSignal primaryShortSignal = {};
|
|
bool isPrimaryShortSignalExecuted = XOBDHandlePrimaryShort(primaryShortSignal);
|
|
if (isPrimaryShortSignalExecuted)
|
|
{
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Close Trades ...
|
|
void XOBDHandleCloseTrades()
|
|
{
|
|
//
|
|
// Handle Long/Buy Close ...
|
|
if (xOBDTrader.CountLongs() > 0 && XOBDCanCloseLongTrades())
|
|
{
|
|
//
|
|
xOBDTrader.CloseLongPositions();
|
|
|
|
//
|
|
string message = "XOBD Closing Long Trades ...";
|
|
|
|
//
|
|
if (xOBDEnableAlerts)
|
|
{
|
|
SendAlert(message);
|
|
}
|
|
else
|
|
{
|
|
LogMessage(message);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle Short/Sell Close ...
|
|
if (xOBDTrader.CountShorts() > 0 && XOBDCanCloseShortTrades())
|
|
{
|
|
//
|
|
xOBDTrader.CloseShortPositions();
|
|
|
|
//
|
|
string message = "XOBD Closing Short Trades ...";
|
|
|
|
//
|
|
if (xOBDEnableAlerts)
|
|
{
|
|
SendAlert(message);
|
|
}
|
|
else
|
|
{
|
|
LogMessage(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculating Volume for Tradings ...
|
|
double XOBDCalculateVolume()
|
|
{
|
|
//
|
|
double result = xOBDStaticVolume;
|
|
if (!xOBDUseDynamicVolume)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double accountBalance = xOBDAccountInfo.GetBalance();
|
|
double balanceIncreased = xOBDBalanceIncreased;
|
|
double volumeIncreased = xOBDVolumeIncreased;
|
|
|
|
//
|
|
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;
|
|
}
|
|
|
|
//
|
|
// Calculate TP and SL ...
|
|
XTPSL XOBDCalculateTPSL(
|
|
ENUM_X_SIGNAL_TYPE type, // Which Type to Calculate TP and SL
|
|
double entry // Signal Entry Price
|
|
)
|
|
{
|
|
//
|
|
XTPSL result = {};
|
|
result.type = X_SIGNAL_UNKNOWN;
|
|
result.tp = 0;
|
|
result.sl = 0;
|
|
result.r2r = 0;
|
|
result.entry = 0;
|
|
|
|
//
|
|
if (!xOBDUseTPSL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Validate Args ...
|
|
if (entry <= 0 || type == X_SIGNAL_UNKNOWN)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result.type = type;
|
|
result.r2r = xOBDR2r;
|
|
result.entry = entry;
|
|
|
|
//
|
|
bool isLong = type == X_SIGNAL_LONG;
|
|
|
|
//
|
|
// Retrieve Market Highest High and Lowest Low ...
|
|
double hh = GetHighestHigh(
|
|
xOBDLoopback,
|
|
0);
|
|
double ll = GetLowestLow(
|
|
xOBDLoopback,
|
|
0);
|
|
|
|
//
|
|
double maxRisk = xOBDMaxRiskPerTrade * _Point;
|
|
double minRisk = xOBDMinRiskPerTrade * _Point;
|
|
|
|
//
|
|
// Calculate and Normalize risk ...
|
|
double risk = isLong ? entry - ll : hh - entry;
|
|
// if (risk > maxRisk)
|
|
// {
|
|
// risk = maxRisk;
|
|
// }
|
|
// else if (risk < minRisk)
|
|
// {
|
|
// risk = minRisk;
|
|
// }
|
|
|
|
//
|
|
double reward = risk * xOBDR2r;
|
|
|
|
//
|
|
double tp = isLong ? entry + reward : entry - reward;
|
|
double sl = isLong ? entry - risk : entry + risk;
|
|
|
|
//
|
|
tp = NormalizeDouble(tp, _Digits);
|
|
sl = NormalizeDouble(sl, _Digits);
|
|
|
|
//
|
|
result.tp = tp;
|
|
result.sl = sl;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Determine based on current account state
|
|
bool XOBDCanDoTrade()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Check Max Open Trades ...
|
|
int totalOpenTrades = xOBDTrader.Count();
|
|
result = totalOpenTrades <= xOBDMaxOpenTrades;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// START Draw Functions ...
|
|
//
|
|
void XOBDDrawTPSL(
|
|
XTPSL &model // an instance of XTPS structure
|
|
)
|
|
{
|
|
//
|
|
// Validate Args ...
|
|
if (!IsValid(model))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
string entryName = "T_" + EnumToString(model.type) + "_Entry_" + (string)model.entry;
|
|
string slName = entryName + "_SL_" + (string)model.sl;
|
|
string tpName = entryName + "_TP_" + (string)model.tp;
|
|
datetime time1 = iTime(_Symbol, _Period, 2);
|
|
datetime time2 = iTime(_Symbol, _Period, 0);
|
|
color tpColor = xOBDSwingLowArrowColor;
|
|
color slColor = xOBDSwingHighArrowColor;
|
|
|
|
//
|
|
// Draw Entry ...
|
|
DrawTrendLine(
|
|
0,
|
|
entryName,
|
|
0,
|
|
time1,
|
|
model.entry,
|
|
time2,
|
|
model.entry,
|
|
clrYellow);
|
|
|
|
//
|
|
// Draw TP ...
|
|
if (model.tp > 0)
|
|
{
|
|
//
|
|
DrawTrendLine(
|
|
0,
|
|
tpName,
|
|
0,
|
|
time1,
|
|
model.tp,
|
|
time2,
|
|
model.tp,
|
|
tpColor);
|
|
}
|
|
|
|
//
|
|
// Draw SL ...
|
|
if (model.sl > 0)
|
|
{
|
|
//
|
|
DrawTrendLine(
|
|
0,
|
|
slName,
|
|
0,
|
|
time1,
|
|
model.sl,
|
|
time2,
|
|
model.sl,
|
|
slColor);
|
|
}
|
|
}
|
|
//
|
|
// END Draw Functions ...
|
|
//
|
|
//
|
|
// END Provided Functions ...
|
|
//
|