Files
xEaPacks/EURUSD-5M-V0.1/MQ5/Libraries/x-saherelm.class.lib.mq5
T
2024-01-25 04:08:38 +03:30

3992 lines
89 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// --------------------------------------
// Name: XClass
// Description: provides all classes for use ...
//
//
// 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
//
#include <Trade\Trade.mqh>
#include <Trade\OrderInfo.mqh>
#include <Trade\AccountInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include "x-saherelm.draw.lib.mq5"
#include "x-saherelm.models.lib.mq5"
#include "x-saherelm.common.lib.mq5"
#include <Trade\HistoryOrderInfo.mqh>
//
// START Model Definitions ...
//
//
// END Model Definitions ...
//
//
// START Overrides ...
//
class XSCTrade : public CTrade
{
public:
//
// Specific Position Close ...
bool PositionClose(
const ulong ticket, // Position Ticket
const ulong deviation, // Deviation
const string comment // Comment For Close
)
{
//
bool result = false;
//
// check stopped ...
if (IsStopped(__FUNCTION__))
{
return result;
}
//
// check position existence
if (!PositionSelectByTicket(ticket))
{
return result;
}
//
string symbol = PositionGetString(POSITION_SYMBOL);
//
// Clean ...
ClearStructures();
//
// Check Position Type ...
// BUY / LONG ...
if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
//
// Prepare Request for Close BUY Position ...
m_request.type = ORDER_TYPE_SELL;
m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID);
}
//
// SELL / Short ...
else
{
//
// Prepare Request for Close SELL Position ...
m_request.type = ORDER_TYPE_BUY;
m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
}
//
// Setting Request Fields ...
m_request.symbol = symbol;
m_request.magic = m_magic;
m_request.position = ticket;
m_request.action = TRADE_ACTION_DEAL;
m_request.volume = PositionGetDouble(POSITION_VOLUME);
m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation;
//
// Specify Comment ...
m_request.comment = comment; // PositionGetString(POSITION_COMMENT); // "Comment anything";
//
// Log Info on Screen ...
PrintFormat("PositionClose #%I64d %s %.2f", ticket, EnumToString((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)), m_request.volume);
//
// Close Position ...
result = (OrderSend(m_request, m_result));
//
return result;
}
//
// Specific Position Close ...
bool PositionClose(
const ulong ticket, // Position Ticket
const string comment = "" // Comment For Close
)
{
//
bool result = false;
//
// check stopped ...
if (IsStopped(__FUNCTION__))
{
return result;
}
//
// check position existence
if (!PositionSelectByTicket(ticket))
{
return result;
}
//
string symbol = PositionGetString(POSITION_SYMBOL);
//
// Clean ...
ClearStructures();
//
// Check Position Type ...
// BUY / LONG ...
if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
//
// Prepare Request for Close BUY Position ...
m_request.type = ORDER_TYPE_SELL;
m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID);
}
//
// SELL / Short ...
else
{
//
// Prepare Request for Close SELL Position ...
m_request.type = ORDER_TYPE_BUY;
m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
}
//
// Setting Request Fields ...
m_request.symbol = symbol;
m_request.magic = m_magic;
m_request.position = ticket;
m_request.deviation = m_deviation;
m_request.action = TRADE_ACTION_DEAL;
m_request.volume = PositionGetDouble(POSITION_VOLUME);
//
// Specify Comment ...
m_request.comment = comment; // PositionGetString(POSITION_COMMENT); // "Comment anything";
//
// Log Info on Screen ...
PrintFormat("PositionClose #%I64d %s %.2f", ticket, EnumToString((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)), m_request.volume);
//
// Close Position ...
result = (OrderSend(m_request, m_result));
//
return result;
}
};
//
// END Overrides ...
//
//
// XSaherElm Account Info Class ...
class XCAccountInfo
{
//
// Public properties ...
public:
//
// Constructro ...
void XCAccountInfo()
{
//
mAccountInfo = new CAccountInfo();
//
mInitialBalance = mAccountInfo.Balance();
}
//
// Deconstructor ...
void ~XCAccountInfo()
{
//
mInitialBalance = 0;
}
//
// User Account ...
long GetUserAccount()
{
return mAccountInfo.Login();
}
//
// Account Leverage ...
long GetLeverage()
{
return mAccountInfo.Leverage();
}
//
// Get Trade Expert State ...
bool CanExpertTrade()
{
return mAccountInfo.TradeExpert();
}
//
// User Account Trade Mopde (ENUM_ACCOUNT_TRADE_MODE) ...
ENUM_ACCOUNT_TRADE_MODE GetTradeMode()
{
return mAccountInfo.TradeMode();
}
//
// Get Account Balance ...
double GetBalance()
{
return mAccountInfo.Balance();
}
//
// Get Initial Deposit Balance ...
double GetInitialBalance()
{
return mInitialBalance;
}
//
// Get the amount of give Credit ...
double GetCredit()
{
return mAccountInfo.Credit();
}
//
// Get the amount of current Profit on account ...
double GetProfit()
{
return mAccountInfo.Profit();
}
//
// Get the amount of current Equity on account ...
double GetEquity()
{
return mAccountInfo.Equity();
}
//
// Get the amount of reserved Margin ...
double GetMargin()
{
return mAccountInfo.Margin();
}
//
// Get the amount of free Margin ...
double GetFreeMargin()
{
return mAccountInfo.FreeMargin();
}
//
// Get the Level of Margin ...
double GetMarginLevel()
{
return mAccountInfo.MarginLevel();
}
//
// Get the Level Of Margin for a Deposit ...
double GetMarginCall()
{
return mAccountInfo.MarginCall();
}
//
// Get the Level of Margin for Stop out ...
double GetMarginStopOut()
{
return mAccountInfo.MarginStopOut();
}
//
// Get the Client Name ...
string GetName()
{
return mAccountInfo.Name();
}
//
// Get the Trade Server Name ...
string GetServerName()
{
return mAccountInfo.Server();
}
//
// Get deposit Currency Name ...
string GetCurrency()
{
return mAccountInfo.Currency();
}
//
// Get the Company Name that serves an Account ...
string GetCompany()
{
return mAccountInfo.Company();
}
//
// Calculate Profits for the current account based on passed parameters ...
double CalculateTradeProfit(
const string symbol, // trading symbol
ENUM_ORDER_TYPE type, // order type
double volume, // volume
double entry, // open price
double exit // close price
)
{
//
double result = mAccountInfo.OrderProfitCheck(
symbol,
type,
volume,
entry,
exit);
//
return result;
}
//
// Calculate amount of margin which required for trade operation ...
double CalculateMarging(
const string symbol, // trading symbol
ENUM_ORDER_TYPE type, // order type
double volume, // volume
double entry // open price
)
{
//
double result = mAccountInfo.MarginCheck(
symbol,
type,
volume,
entry);
//
return result;
}
//
// Calculate amount of free margin left after trade operation ...
double CalculateFreeMarging(
const string symbol, // trading symbol
ENUM_ORDER_TYPE type, // order type
double volume, // volume
double entry // open price
)
{
//
double result = mAccountInfo.FreeMarginCheck(
symbol,
type,
volume,
entry);
//
return result;
}
//
// Calculate the Maximum possible volume of trade operation ...
double CalculateMaxVolume(
const string symbol, // trading symbol
ENUM_ORDER_TYPE type, // order type
double entry, // open price
double percent = 100 // percent of available margin
)
{
//
double result = mAccountInfo.MaxLotCheck(
symbol,
type,
entry,
percent);
//
return result;
}
//
// Protected properties ...
protected:
//
// Private properties ...
private:
//
// Initial Account Balance ...
double mInitialBalance;
//
// Account Info ...
CAccountInfo mAccountInfo;
};
//
// START Global Definitions: Variables, Properties and etc ...
//
//
// XSaherElm Trade Class ...
class XCTrade
{
//
// all public features ...
public:
//
// Constructor ...
void XCTrade(
string tag, // Specify a Tag for Trader instance
string symbol, // Specify Trader Symbol
int slippage, // Specify Slippage
ulong magicNumber, // Specify Magic Number
int maxAllowedTrades, // Specify Max Allowed Trades
int maxAllowedSupportTrades, // Specify Max Allowed Support Trades for each Trade
double minTradeProfitsInPips, // Minimum Profit of each Trade in Pips
double supportTradesPriceDistanceInPips, // Support Trades Price Distance in Pips
double minAllowedFreeMarginForOpenTrades, // Minimum Free Marging for Open Trades
double minBallanceForOpenTrades // Minimum Balance for Open Trades
)
{
//
mTag = tag;
mSymbol = symbol;
mSlippage = slippage;
mMagicNumber = magicNumber;
mMaxAllowedTrades = maxAllowedTrades;
mMinTradeProfitsInPips = minTradeProfitsInPips;
mMaxAllowedSupportTrades = maxAllowedSupportTrades;
mMinBallanceForOpenTrades = minBallanceForOpenTrades;
mSupportTradesPriceDistanceInPips = supportTradesPriceDistanceInPips;
mMinAllowedFreeMarginForOpenTrades = minAllowedFreeMarginForOpenTrades;
//
mTrader = new XSCTrade();
//
mTrader.SetAsyncMode(false);
mTrader.SetDeviationInPoints(mSlippage);
mTrader.SetExpertMagicNumber(mMagicNumber);
}
//
// Deconstructor ...
void ~XCTrade()
{
}
//
// Count Open Positions ...
int Count()
{
//
int result = 0;
//
int total = PositionsTotal();
for (int i = 0; i < total; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
if (mPositionInfo.Symbol() != mSymbol)
{
continue;
}
//
result++;
}
//
return result;
}
//
// Count Longs ...
int CountLongs()
{
int result = CountByType(X_SIGNAL_LONG);
return result;
}
//
// Count Shorts ...
int CountShorts()
{
int result = CountByType(X_SIGNAL_SHORT);
return result;
}
//
// Count By Type ...
int CountByType(ENUM_X_SIGNAL_TYPE type)
{
//
// Validate Args ...
ENUM_POSITION_TYPE mType = POSITION_TYPE_BUY;
if (type == X_SIGNAL_LONG)
{
mType = POSITION_TYPE_BUY;
}
else if (type == X_SIGNAL_SHORT)
{
mType = POSITION_TYPE_SELL;
}
//
int result = CountByType(mType);
return result;
}
//
// Count By Type and Kind ...
int CountByKind(
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind // Specify Kind of Positions
)
{
//
int result = 0;
//
XSignal trades[];
GetPositionsByKind(
type,
kind,
trades);
//
result = ArraySize(trades);
//
return result;
}
int CountByKind(
ENUM_X_SIGNAL_KIND kind // Specify Kind of Positions
)
{
//
int result = 0;
//
// Count Longs ...
result = CountByKind(
X_SIGNAL_UNKNOWN,
kind);
//
return result;
}
//
// Count Supported Positions belongs to Specified Parent Signal ...
int CountSupportedPositions(
XSignal &parent // Specified Parent Signal
)
{
//
int result = 0;
//
XSignal supports[];
GetSupportedPositions(parent, supports);
result = ArraySize(supports);
//
return result;
}
//
// Retrieve Specified Position by it's Ticket ...
XSignal GetPosition(
ulong ticket // Specified Ticket
)
{
//
XSignal result = {};
//
result = PositionToSignal(ticket);
//
return result;
}
//
// Retrieve all Positions ...
void GetAllPositions(
XSignal &result[] // Holds Result ...
)
{
//
CleanBuffer(result);
//
int totalPositions = PositionsTotal();
for (int i = 0; i < totalPositions; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
if (mPositionInfo.Symbol() != mSymbol)
{
continue;
}
//
// Position to Signal ...
XSignal signal = PositionToSignal(i);
Add(
signal,
result);
}
}
//
// Retrieve all Long Positions ...
void GetLongPositions(
XSignal &result[] // Holds Result ...
)
{
GetAllPositionsByType(POSITION_TYPE_BUY, result);
}
//
// Retrieve all Short Positions ...
void GetShortPositions(
XSignal &result[] // Holds Result ...
)
{
GetAllPositionsByType(POSITION_TYPE_SELL, result);
}
//
// Get Positions by Specified Type ...
void GetPositionsByType(
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
XSignal &result[] // Holds Result ...
)
{
//
CleanBuffer(result);
//
switch (type)
{
//
case X_SIGNAL_LONG:
GetLongPositions(result);
break;
//
case X_SIGNAL_SHORT:
GetShortPositions(result);
break;
//
case X_SIGNAL_UNKNOWN:
default:
GetAllPositions(result);
break;
}
}
//
// Get Positions by Specified Type and Kind ...
void GetPositionsByKind(
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &result[] // Holds Result ...
)
{
//
CleanBuffer(result);
//
XSignal trades[];
switch (type)
{
//
case X_SIGNAL_LONG:
GetLongPositions(trades);
break;
//
case X_SIGNAL_SHORT:
GetShortPositions(trades);
break;
//
case X_SIGNAL_UNKNOWN:
default:
GetAllPositions(trades);
break;
}
//
int count = ArraySize(trades);
if (count <= 0)
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
XSignal trade = trades[i];
if (trade.kind != kind)
{
continue;
}
//
Add(
trade,
result);
}
}
//
// Retrieve List Of Supported Positions belongs to Specified Parent Signal ...
void GetSupportedPositions(
XSignal &parent, // Specified Parent Signal
XSignal &result[] // Holds Result ...
)
{
//
CleanBuffer(result);
//
// Validate Signal ...
bool isValidSignal = IsValid(parent, mMagicNumber);
if (!isValidSignal)
{
return;
}
//
// Validate Signal is Parent Signal ...
bool isParentSignal = parent.kind == X_KIND_TRADE;
if (!isParentSignal)
{
return;
}
//
// Retrieve All Support Signals ...
XSignal supports[];
GetPositionsByKind(
X_SIGNAL_UNKNOWN,
X_KIND_SUPPORT,
supports);
int supportsCount = ArraySize(supports);
if (supportsCount <= 0)
{
return;
}
//
// Loop Through Supports ...
for (int i = 0; i < supportsCount; i++)
{
//
XSignal support = supports[i];
//
bool isBelongsToParent = support.parent == parent.ticket;
if (isBelongsToParent)
{
//
Add(
support,
result);
}
}
}
//
// Get All Trades Which Candle Passed after Open ...
void GetLongTimeTrades(
int life, // Max Candle Passed after Trades Open
ENUM_TIMEFRAMES period, // Calculate Candles based on time frame
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &result[] // Holds Result
)
{
//
CleanBuffer(result);
//
// Normalize Period ...
if (period == EMPTY_VALUE)
{
period = _Period;
}
//
XSignal positions[];
GetPositionsByKind(
type,
kind,
positions);
int count = ArraySize(positions);
if (count <= 0)
{
return;
}
//
// Current Time Frame Candle Index ...
int currentBarIndex = 0;
//
// Loop through Positions ...
for (int i = 0; i < count; i++)
{
//
XSignal trade = positions[i];
//
// Retrieve Trade Open Bar Index based on Current Period ...
int tradeOpenBarIndex = iBarShift(
mSymbol,
period,
trade.time);
//
// Calculate Trade Life ...
int diff = MathAbs(currentBarIndex - tradeOpenBarIndex);
if (diff >= life)
{
//
Add(
trade,
result);
}
}
}
//
// Get In DrawDown Trades ...
void GetInDrawDownTrades(
double maxDrawDown, // Maximum DrawDown of Trades
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &result[] // Holds Result
)
{
//
CleanBuffer(result);
//
// Validate Args ...
if (maxDrawDown <= 0)
{
maxDrawDown = 0;
}
//
XSignal trades[];
//
// Retrieve Signals ...
GetPositionsByKind(
type,
kind,
trades);
//
// Check Trades Count ...
int count = ArraySize(trades);
if (count <= 0)
{
return;
}
//
// Loop through all retrieved trades ...
for (int i = 0; i < count; i++)
{
//
XSignal trade = trades[i];
if (trade.profit > 0)
{
continue;
}
//
bool isPassed = maxDrawDown == 0 ? true : (-1 * trade.profit) >= maxDrawDown;
if (isPassed)
{
//
Add(
trade,
result);
}
}
}
//
// Get In Profit Trades ...
void GetInProfitTrades(
double minProfit, // Minimum Profit To Close Trades
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &result[] // Holds Result
)
{
//
CleanBuffer(result);
//
XSignal trades[];
GetPositionsByKind(
type,
kind,
result);
//
// Check Trades Count ...
int count = ArraySize(trades);
if (count <= 0)
{
return;
}
//
// Loop through all retrieved trades ...
for (int i = 0; i < count; i++)
{
//
XSignal trade = trades[i];
if (trade.profit < 0)
{
continue;
}
//
bool isPassed = minProfit <= 0 ? true : trade.profit >= minProfit;
if (isPassed)
{
//
Add(
trade,
result);
}
}
}
//
// Filter Trades by Searching Comments ...
void FilterTrades(
string query, // Search String
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &result[] // Holds Result
)
{
//
// Free Buffer ...
CleanBuffer(result);
//
XSignal source[];
GetPositionsByKind(
type,
kind,
source);
int sourceCount = ArraySize(source);
//
if (sourceCount <= 0)
{
return;
}
//
// Do Filtering Signals ...
FilterSignals(
query,
source,
result);
}
//
// Filter In DrawDown Trades by Searching Comments ...
void FilterInDrawDowntTrades(
string query, // Search String
double maxDrawDown, // Maximum DrawDown of Trades
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &result[] // Holds Result
)
{
//
// Free Buffer ...
CleanBuffer(result);
//
XSignal source[];
GetInDrawDownTrades(
maxDrawDown,
type,
kind,
source);
int sourceCount = ArraySize(source);
//
if (sourceCount <= 0)
{
return;
}
//
// Do Filtering Signals ...
FilterSignals(
query,
source,
result);
}
//
// Filter In DrawDown Trades by Searching Comments ...
void FilterInProfitTrades(
string query, // Search String
double minProfit, // Minimum Profit of Trades
ENUM_X_SIGNAL_TYPE type, // Specify trades type to act
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &result[] // Holds Result
)
{
//
// Free Buffer ...
CleanBuffer(result);
//
XSignal source[];
GetInProfitTrades(
minProfit,
type,
kind,
source);
int sourceCount = ArraySize(source);
//
if (sourceCount <= 0)
{
return;
}
//
// Do Filtering Signals ...
FilterSignals(
query,
source,
result);
}
//
// Filter Trades by Searching Comments ...
void FilterTrades(
string query, // Search String
XSignal &source[], // Source Buffer to Filter
XSignal &result[] // Holds Result
)
{
//
// Free Buffer ...
CleanBuffer(result);
//
// Do Filtering Signals ...
FilterSignals(
query,
source,
result);
}
//
// Force Open a Buy/Long Position ...
bool Buy(
double volume, // position volume
double price, // execution price
double sl = 0, // stop loss price
double tp = 0, // take profit price
const string comment = "" // comment
)
{
//
bool result = false;
//
result = mTrader.Buy(
volume,
mSymbol,
price,
sl,
tp,
comment);
//
return result;
}
//
// Force Open a Sell/Short Position ...
bool Sell(
double volume, // position volume
double price, // execution price
double sl = 0, // stop loss price
double tp = 0, // take profit price
const string comment = "" // comment
)
{
//
bool result = false;
//
result = mTrader.Sell(
volume,
mSymbol,
price,
sl,
tp,
comment);
//
return result;
}
//
// Validate Signal ...
bool ValidateSignal(
XSignal &signal // Specify Signal for Execution
)
{
//
bool result = false;
//
// Validate Signal Type ...
result = signal.type != X_SIGNAL_UNKNOWN;
if (!result)
{
return result;
}
//
// Check Symbol ...
result = StringLen(signal.symbol) == 0 ? true : signal.symbol == mSymbol;
if (!result)
{
return result;
}
//
// Check magic number ...
result = signal.magicNumber <= 0 ? true : signal.magicNumber == mMagicNumber;
if (!result)
{
return result;
}
//
// Check Entry ...
result = signal.entry > 0;
if (!result)
{
return result;
}
//
// Check SL ...
result = signal.sl == 0 ? true : signal.type == X_SIGNAL_LONG ? signal.sl < signal.entry
: signal.sl > signal.entry;
if (!result)
{
return result;
}
//
// Check TP ...
result = signal.tp == 0 ? true : signal.type == X_SIGNAL_LONG ? signal.tp > signal.entry
: signal.tp < signal.entry;
if (!result)
{
return result;
}
//
// Check Volume ...
result = signal.volume > 0;
if (!result)
{
return result;
}
//
// Check Time ...
result = signal.time > 0;
if (!result)
{
return result;
}
//
return result;
}
//
// Execute an Specific XSignal instance ...
bool ExecuteSignal(
XSignal &signal, // Specify Signal for Execution
int &error // Error code if Happens
)
{
//
bool result = false;
//
// Validate Signal ...
result = ValidateSignal(signal);
if (!result)
{
//
error = X_INVALID_SIGNAL_ERROR;
return result;
}
//
signal.symbol = mSymbol;
//
bool isTrade = signal.kind == X_KIND_TRADE;
//
// Check Account Balance ...
result = IsAccountBalanceReadyForTrade();
if (!result)
{
//
error = X_XTRADER_NOT_ENOUGH_BALANCE_ERROR;
return result;
}
//
// Check Account Free Margin ...
result = IsFreeMarginReadyForTrade();
if (!result)
{
//
error = X_XTRADER_NOT_ENOUGH_MARIGIN_ERROR;
return result;
}
//
// Check Can Open Trades ...
result = CanOpenNewTrade(
signal.type,
signal.kind);
if (!result)
{
error = isTrade ?
//
X_XTRADER_MAX_ALLOWED_TRADE_KIND_REACHED_ERROR
:
//
X_XTRADER_MAX_ALLOWED_SUPPORT_KIND_REACHED_ERROR
//
;
}
//
ResetLastError();
//
// Execute Signal Trade ...
result =
//
signal.type == X_SIGNAL_LONG
//
?
//
Buy(
signal.volume,
signal.entry,
signal.sl,
signal.tp,
signal.comment)
//
:
//
signal.type == X_SIGNAL_SHORT
//
?
//
Sell(
signal.volume,
signal.entry,
signal.sl,
signal.tp,
signal.comment)
//
:
//
false
//
;
//
// if (!result)
// {
// //
// int errorCode = GetLastError();
// //
// // Not Enough Money, since Volume is High ...
// if (errorCode == 4756)
// {
// //
// signal.volume = NormalizeVolume(signal.volume / 3);
// result = ExecuteSignal(
// signal,
// error);
// }
// }
//
if (result)
{
//
error = X_SUCCEED_EXECUTION;
//
ulong positionTicket = 0;
if (mPositionInfo.SelectByIndex(PositionsTotal() - 1))
{
positionTicket = mPositionInfo.Ticket();
}
//
signal.id = positionTicket;
signal.ticket = positionTicket;
//
// Draw Signal On Chart ...
DrawSignalEvent(signal);
}
else
{
error = X_UNKNOWN_ERROR;
}
//
return result;
}
//
// Execute Support Signal ...
bool ExecuteSupportSignal(
XSignal &signal, // Specify Signal for Execution
int &error // Error code if Happens
)
{
//
bool result = false;
error = X_UNKNOWN_ERROR;
//
// Validate Signal ...
result = ValidateSignal(signal);
if (!result)
{
//
error = X_INVALID_SIGNAL_ERROR;
return result;
}
//
// Determines Signal is Long or Short ...
bool isLong = signal.type == X_SIGNAL_LONG;
//
// Check Signal Kind ...
result = signal.kind == X_KIND_SUPPORT;
if (!result)
{
//
error = X_INVALID_SIGNAL_ERROR;
return result;
}
//
// Check Signal Kind Based Properties ...
result = signal.parent > 0;
if (!result)
{
//
error = X_INVALID_SIGNAL_ERROR;
return result;
}
//
// Check Support Trade Parent Position Existance ...
XSignal parent = GetPosition(signal.parent);
result = IsValid(parent, mMagicNumber);
if (!result)
{
//
error = X_INVALID_SIGNAL_ERROR;
return result;
}
//
// Check Max Number Of Support Trades which belongs to Parent ...
int supportsCount = CountSupportedPositions(parent);
result = supportsCount < mMaxAllowedSupportTrades;
if (!result)
{
//
error = X_XTRADER_MAX_ALLOWED_SUPPORT_KIND_REACHED_ERROR;
return result;
}
//
// Check Support Trade Price Distance Passed ...
double supportTradesPriceDistance = PipsToPrice(mSupportTradesPriceDistanceInPips);
double supportPriceDistance = MathAbs(parent.entry - signal.entry);
result = supportPriceDistance >= supportTradesPriceDistance;
if (!result)
{
//
error = X_TRADER_SUPPORT_DISTANCE_NOT_HAPPENS_ERROR;
return result;
}
//
// Check Account Balance ...
result = IsAccountBalanceReadyForTrade();
if (!result)
{
//
error = X_XTRADER_NOT_ENOUGH_BALANCE_ERROR;
return result;
}
//
ResetLastError();
//
// Execute Signal Trade ...
result =
//
signal.type == X_SIGNAL_LONG
//
?
//
Buy(
signal.volume,
signal.entry,
signal.sl,
signal.tp,
signal.comment)
//
:
//
signal.type == X_SIGNAL_SHORT
//
?
//
Sell(
signal.volume,
signal.entry,
signal.sl,
signal.tp,
signal.comment)
//
:
//
false
//
;
//
// if (!result)
// {
// //
// int errorCode = GetLastError();
// //
// // Not Enough Money, since Volume is High ...
// if (errorCode == 4756)
// {
// //
// signal.volume = NormalizeVolume(signal.volume / 3);
// result = ExecuteSupportSignal(
// signal,
// error);
// }
// }
//
if (result)
{
//
error = X_SUCCEED_EXECUTION;
//
ulong positionTicket = 0;
if (mPositionInfo.SelectByIndex(PositionsTotal() - 1))
{
positionTicket = mPositionInfo.Ticket();
}
//
signal.id = positionTicket;
signal.ticket = positionTicket;
//
// Draw Signal On Chart ...
DrawSignalEvent(signal);
}
else
{
error = X_UNKNOWN_ERROR;
}
//
return result;
}
//
// Modify Position ...
bool Modify(
const ulong ticket, // position ticket
double sl = 0, // stop loss price
double tp = 0 // take profit
)
{
//
bool result = false;
//
// Validate Args ...
if (tp <= 0 && sl <= 0)
{
result = false;
return result;
}
//
result = mTrader.PositionModify(
ticket,
sl,
tp);
//
return result;
}
//
// Close Position By Ticket ...
bool Close(
ulong ticket, // Position Ticket
string comment // Close Position By Specific Comment
)
{
//
bool result = false;
//
// Try to Select Position ...
if (!mPositionInfo.SelectByTicket(ticket))
{
return result;
}
//
// Close Position By Specific Comment ...
result = mTrader.PositionClose(
ticket,
comment);
if (result)
{
RemoveSignal(ticket);
}
//
return result;
}
//
// Close Partial By Ticket ...
bool ClosePartial(ulong ticket, double volume)
{
//
bool result = false;
//
if (!mPositionInfo.SelectByTicket(ticket))
{
return result;
}
//
result = mTrader.PositionClosePartial(
ticket,
volume);
//
return result;
}
//
// Partial Close all Reached Signals ...
void RiskFreeSignals(
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &riskFrees[] // Holds all Executed Signals
)
{
//
CleanBuffer(riskFrees);
//
XSignal trades[];
GetPositionsByKind(
type,
kind,
trades);
int count = ArraySize(trades);
if (count <= 0)
{
return;
}
//
// Loop ...
for (int i = 0; i < count; i++)
{
//
XSignal trade = trades[i];
//
// Ignore Not Risk Free Signal ...
if (
trade.riskFree <= 0 ||
(trade.riskFree > 0 && trade.riskFreeRate <= 0))
{
continue;
}
//
bool isLong = trade.type == X_SIGNAL_LONG;
//
// Check Exit Price reached Risk Free ...
double exitPrice = GetExit(trade.type);
double isPriceReachedRiskFree = isLong ? exitPrice >= trade.riskFree : exitPrice <= trade.riskFree;
if (!isPriceReachedRiskFree)
{
continue;
}
//
double volume = trade.volume;
double riskFreeRate = trade.riskFreeRate;
double riskFreeVolume = riskFreeRate * volume;
riskFreeVolume = NormalizeVolume(riskFreeVolume);
//
// Check Trade Doesnt Closed Partial Before ...
// Check Volume is Enough for Partial Closing ...
if (
trade.sl > 0 ||
riskFreeVolume == volume)
{
continue;
}
//
bool isPartialClosed = ClosePartial(trade.ticket, riskFreeVolume);
if (isPartialClosed)
{
//
bool isLong = trade.type == X_SIGNAL_LONG;
double entry = GetEntry(trade.symbol, trade.type);
//
double tpValue = trade.tp;
double slDistance = 0; // PipsToPrice(2);
double slValue = isLong ? trade.entry - slDistance : trade.entry + slDistance;
//
ResetLastError();
bool isModified = Modify(trade.ticket, slValue, tpValue);
if (isModified)
{
//
Add(
trade,
riskFrees);
//
LogMessage("Order: " + (string)trade.ticket + " Modification Succeed ...");
}
else
{
LogMessage("Order: " + (string)trade.ticket + " Modification Failed: " + (string)GetLastError() + ", Desc: " + GetErrorDescription(GetLastError()));
}
}
}
}
void RiskFreeSignals(
XSignal &riskFrees[] // Holds all Executed Signals
)
{
//
CleanBuffer(riskFrees);
//
XSignal trades[];
RiskFreeSignals(
X_SIGNAL_UNKNOWN,
X_KIND_TRADE,
trades);
int tradesCount = ArraySize(trades);
if (tradesCount > 0)
{
//
// Loop ...
for (int i = 0; i < tradesCount; i++)
{
//
XSignal fTrade = trades[i];
//
Add(
fTrade,
riskFrees);
}
}
//
XSignal supports[];
RiskFreeSignals(
X_SIGNAL_UNKNOWN,
X_KIND_SUPPORT,
supports);
int supportsCount = ArraySize(supports);
if (supportsCount > 0)
{
//
// Loop ...
for (int i = 0; i < supportsCount; i++)
{
//
XSignal fTrade = supports[i];
//
Add(
fTrade,
riskFrees);
}
}
}
//
// Close All Open Positions ...
void CloseAllPositions(
XSignal &closed[] // Holds Closed Positions
)
{
//
CleanBuffer(closed);
//
XSignal allPositions[];
GetAllPositions(allPositions);
//
// Count all Specified Positions ...
int total = ArraySize(allPositions);
if (total <= 0)
{
return;
}
//
for (int i = 0; i < total; i++)
{
//
XSignal signal = allPositions[i];
string comment = GetSignalForceClosedComment(signal);
bool isClosed = Close(
signal.ticket,
comment);
if (isClosed)
{
//
Add(
signal,
closed);
}
}
}
//
// Close Positions By Type ...
void ClosePositionsByType(
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
XSignal &closed[] // Holds Closed Positions
)
{
//
CleanBuffer(closed);
//
XSignal allPositions[];
GetPositionsByType(
type,
allPositions);
//
// Count all Specified Positions ...
int total = ArraySize(allPositions);
if (total <= 0)
{
return;
}
//
for (int i = 0; i < total; i++)
{
//
XSignal signal = allPositions[i];
string comment = GetSignalForceClosedComment(signal);
bool isClosed = Close(
signal.ticket,
comment);
if (isClosed)
{
//
Add(
signal,
closed);
}
}
}
//
// Close Positions By Kind ...
void ClosePositionsByKind(
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &closed[] // Holds Closed Positions
)
{
//
CleanBuffer(closed);
//
XSignal allPositions[];
GetPositionsByKind(
type,
kind,
allPositions);
//
// Count all Specified Positions ...
int total = ArraySize(allPositions);
if (total <= 0)
{
return;
}
//
for (int i = 0; i < total; i++)
{
//
XSignal signal = allPositions[i];
string comment = GetSignalForceClosedComment(signal);
bool isClosed = Close(
signal.ticket,
comment);
if (isClosed)
{
//
Add(
signal,
closed);
}
}
}
//
// Close All Trades Which Candle Passed after Open ...
void CloseLongTimeTrades(
int life, // Max Candle Passed after Trades Open
ENUM_TIMEFRAMES period, // Calculate Candles based on time frame
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &closed[] // Holds Closed Trades
)
{
//
CleanBuffer(closed);
//
// Normalize Period ...
if (period == EMPTY_VALUE)
{
period = _Period;
}
//
XSignal positions[];
GetLongTimeTrades(
life,
period,
type,
kind,
positions);
int count = ArraySize(positions);
if (count <= 0)
{
return;
}
//
// Loop through Positions ...
for (int i = 0; i < count; i++)
{
//
XSignal trade = positions[i];
string comment = GetSignalForceClosedComment(trade);
bool isClosed = Close(
trade.ticket,
comment);
if (isClosed)
{
//
Add(
trade,
closed);
}
}
}
void CloseLongTimeTrades(
int life, // Max Candle Passed after Trades Open
ENUM_TIMEFRAMES period, // Calculate Candles based on time frame
XSignal &closed[] // Holds Closed Trades
)
{
//
CleanBuffer(closed);
//
XSignal trades[];
CloseLongTimeTrades(
life,
period,
X_SIGNAL_UNKNOWN,
X_KIND_TRADE,
trades);
int tradesCount = ArraySize(trades);
if (tradesCount > 0)
{
//
// Loop ...
for (int i = 0; i < tradesCount; i++)
{
//
XSignal fTrade = trades[i];
//
Add(
fTrade,
closed);
}
}
//
XSignal supports[];
CloseLongTimeTrades(
life,
period,
X_SIGNAL_UNKNOWN,
X_KIND_SUPPORT,
supports);
int supportsCount = ArraySize(supports);
if (supportsCount > 0)
{
//
// Loop ...
for (int i = 0; i < supportsCount; i++)
{
//
XSignal fTrade = supports[i];
//
Add(
fTrade,
closed);
}
}
}
//
// Close In DrawDown Trades ...
void CloseInDrawDownTrades(
double maxDrawDown, // Maximum DrawDown of Trades
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &closed[] // Holds Closed Trades
)
{
//
CleanBuffer(closed);
//
// Validate Args ...
if (maxDrawDown <= 0)
{
return;
}
//
XSignal trades[];
GetInDrawDownTrades(
maxDrawDown,
type,
kind,
trades);
//
// Check Trades Count ...
int count = ArraySize(trades);
if (count <= 0)
{
return;
}
//
// Loop through all retrieved trades ...
for (int i = 0; i < count; i++)
{
//
XSignal trade = trades[i];
string comment = GetSignalInDistanceClosedComment(trade);
bool isClosed = Close(
trade.ticket,
comment);
if (isClosed)
{
Add(
trade,
closed);
}
}
}
void CloseInDrawDownTrades(
double maxDrawDown, // Maximum DrawDown of Trades
XSignal &closed[] // Holds Closed Trades
)
{
//
CleanBuffer(closed);
//
XSignal trades[];
CloseInDrawDownTrades(
maxDrawDown,
X_SIGNAL_UNKNOWN,
X_KIND_TRADE,
trades);
int tradesCount = ArraySize(trades);
if (tradesCount > 0)
{
//
// Loop ...
for (int i = 0; i < tradesCount; i++)
{
//
XSignal fTrade = trades[i];
//
Add(
fTrade,
closed);
}
}
//
XSignal supports[];
CloseInDrawDownTrades(
maxDrawDown,
X_SIGNAL_UNKNOWN,
X_KIND_SUPPORT,
supports);
int supportsCount = ArraySize(supports);
if (supportsCount > 0)
{
//
// Loop ...
for (int i = 0; i < supportsCount; i++)
{
//
XSignal fTrade = supports[i];
//
Add(
fTrade,
closed);
}
}
}
//
// Close All In Profit Trades ...
void CloseInProfitTrades(
double minProfit, // Minimum Profit To Close Trades
ENUM_X_SIGNAL_TYPE type, // Specify trades type to act
ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions
XSignal &closed[] // Holds Closed Trades
)
{
//
CleanBuffer(closed);
//
XSignal trades[];
GetInProfitTrades(
minProfit,
type,
kind,
trades);
//
// Check Trades Count ...
int count = ArraySize(trades);
if (count <= 0)
{
return;
}
//
// Loop through all retrieved trades ...
for (int i = 0; i < count; i++)
{
//
XSignal trade = trades[i];
string comment = GetSignalInDistanceClosedComment(trade);
bool isClosed = Close(
trade.ticket,
comment);
if (isClosed)
{
Add(
trade,
closed);
}
}
}
void CloseInProfitTrades(
double minProfit, // Minimum Profit To Close Trades
XSignal &closed[] // Holds Closed Trades
)
{
//
CleanBuffer(closed);
//
XSignal trades[];
CloseInProfitTrades(
minProfit,
X_SIGNAL_UNKNOWN,
X_KIND_TRADE,
trades);
int tradesCount = ArraySize(trades);
if (tradesCount > 0)
{
//
// Loop ...
for (int i = 0; i < tradesCount; i++)
{
//
XSignal fTrade = trades[i];
//
Add(
fTrade,
closed);
}
}
//
XSignal supports[];
CloseInProfitTrades(
minProfit,
X_SIGNAL_UNKNOWN,
X_KIND_SUPPORT,
supports);
int supportsCount = ArraySize(supports);
if (supportsCount > 0)
{
//
// Loop ...
for (int i = 0; i < supportsCount; i++)
{
//
XSignal fTrade = supports[i];
//
Add(
fTrade,
closed);
}
}
}
//
// Pyramid Open Trades ...
void PyramidTrades(
XSignal &closed[] // Holds Closed Trades
)
{
//
CleanBuffer(closed);
//
// Check Open Positions In DrawDown Values ...
//
// Trades ...
XSignal inDDTrades[];
GetInDrawDownTrades(
0,
X_SIGNAL_UNKNOWN,
X_KIND_TRADE,
inDDTrades);
int inDDTradesCount = ArraySize(inDDTrades);
//
// Supports ...
XSignal inDDSupports[];
GetInDrawDownTrades(
0,
X_SIGNAL_UNKNOWN,
X_KIND_SUPPORT,
inDDSupports);
int inDDSupportsCount = ArraySize(inDDSupports);
//
// Prevent Going Forward ...
if (inDDTradesCount == 0 && inDDSupportsCount == 0)
{
return;
}
//
// Number Of In DD Trades ...
int count = inDDTradesCount + inDDSupportsCount;
if (count <= 1)
{
return;
}
//
// Select Longest inDD ...
XSignal longestDD = {};
//
// Trades ...
if (inDDTradesCount > 0)
{
//
for (int i = 0; i < inDDTradesCount; i++)
{
//
XSignal iSignal = inDDTrades[i];
//
longestDD = longestDD.profit == 0 || longestDD.profit > iSignal.profit ? iSignal : longestDD;
}
}
//
// Supports ...
if (inDDSupportsCount > 0)
{
//
for (int i = 0; i < inDDSupportsCount; i++)
{
//
XSignal iSignal = inDDSupports[i];
//
longestDD = longestDD.profit == 0 || longestDD.profit > iSignal.profit ? iSignal : longestDD;
}
}
//
// Check Longest In DD ...
LogMessage("Longest (" + (string)count + ") inDD: " + (string)longestDD.ticket + ", Profit: " + (string)longestDD.profit);
//
// Close Longest In DD ...
Close(longestDD.ticket, "Longets In Drawdown Position");
//
Add(
longestDD,
closed);
}
//
// START Signal Related ...
//
//
// Prepare a Signall ...
XSignal GenerateSignal(
ENUM_X_SIGNAL_TYPE type, // Signal Type
double tp = 0, // Take Profit
double sl = 0, // Stop Loss
double volume = 0, // Volume
double riskFree = 0, // Risk Free Price
double riskFreeRate = 0, // Risk Free Rate
ENUM_X_SIGNAL_KIND kind = X_KIND_TRADE, // Signal Kind
ulong parent = 0 // Support Kind Signal Parent
)
{
//
XSignal result = {};
//
// Validate Arg ...
if (type == X_SIGNAL_UNKNOWN)
{
return result;
}
//
// Check Signal Type ...
bool isLong = type == X_SIGNAL_LONG;
//
// Retrieve entry Price ...
double entry = GetEntry(mSymbol, type);
double spread = GetSpread(mSymbol);
//
double tpPrice = 0;
double slPrice = 0;
double riskFreePrice = 0;
//
// Normalize TP Value ...
if (tp <= 0)
{
//
double minReward = PipsToPrice(mMinTradeProfitsInPips);
tp = minReward;
}
//
if (riskFree > 0 && riskFreeRate > 0)
{
//
riskFreePrice = type == X_SIGNAL_LONG ? entry + riskFree : entry - riskFree;
riskFreePrice = NormalizePrice(riskFreePrice, mSymbol);
}
//
if (tp > 0)
{
//
tp += spread;
//
tpPrice = isLong ? entry + tp : entry - tp;
tpPrice = NormalizePrice(tpPrice, mSymbol);
}
//
if (sl > 0)
{
//
sl += spread;
//
slPrice = isLong ? entry - sl : entry + sl;
slPrice = NormalizePrice(slPrice, mSymbol);
}
//
result.type = type;
result.kind = kind;
result.tp = tpPrice;
result.sl = slPrice;
result.entry = entry;
result.parent = parent;
result.symbol = mSymbol;
result.riskFree = riskFreePrice;
result.magicNumber = mMagicNumber;
result.riskFreeRate = riskFreeRate;
result.time = iTime(mSymbol, _Period, 0);
result.volume = NormalizeVolume(volume, mSymbol);
//
// Since we Use signal instance to Generate Comment, this must be at the end ...
result.comment = GetSignalComment(result);
//
return result;
}
XSignal GenerateTradeSignal(
ENUM_X_SIGNAL_TYPE type, // Signal Type
double tp, // Take Profit
double sl, // Stop Loss
double volume, // Volume
double riskFree = 0, // Risk Free Price
double riskFreeRate = 0 // Risk Free Rate
)
{
//
XSignal result = GenerateSignal(
type,
tp,
sl,
volume,
riskFree,
riskFreeRate,
X_KIND_TRADE,
0
//
);
//
return result;
}
XSignal GenerateSupportSignal(
ENUM_X_SIGNAL_TYPE type, // Signal Type
double tp, // Take Profit
double sl, // Stop Loss
double volume, // Volume
double riskFree, // Risk Free Price
double riskFreeRate, // Risk Free Rate
ulong parent // Support Kind Signal Parent
)
{
//
XSignal result = GenerateSignal(
type,
tp,
sl,
volume,
riskFree,
riskFreeRate,
X_KIND_SUPPORT,
parent
//
);
//
return result;
}
//
// Calculate SignalAge ...
int GetSignalAge(
datetime time // Signal Execution Time
)
{
//
int result = 0;
//
// Validate Arg ...
if (time <= 0)
{
return result;
}
//
int sIndex = iBarShift(
mSymbol,
_Period,
time);
//
datetime cTime = iTime(
mSymbol,
_Period,
0);
int cIndex = iBarShift(
mSymbol,
_Period,
cTime);
//
result = MathAbs(cIndex - sIndex);
//
return result;
}
int GetSignalAge(
datetime time, // Signal Execution Time
ENUM_TIMEFRAMES period // Specify Time Frame
)
{
//
int result = 0;
//
// Validate Arg ...
if (time <= 0)
{
return result;
}
//
int sIndex = iBarShift(
mSymbol,
period,
time);
//
datetime cTime = iTime(
mSymbol,
period,
0);
int cIndex = iBarShift(
mSymbol,
_Period,
cTime);
//
result = MathAbs(cIndex - sIndex);
//
return result;
}
int GetSignalAge(
XSignal &signal // Specify Signal
)
{
//
int result = 0;
//
// Validate Arg ...
if (
signal.time <= 0 ||
!IsValid(signal, mMagicNumber))
{
return result;
}
//
result = GetSignalAge(signal.time);
//
return result;
}
int GetSignalAge(
XSignal &signal, // Specify Signal
ENUM_TIMEFRAMES period // Specify Time Frame
)
{
//
int result = 0;
//
// Validate Arg ...
if (
signal.time <= 0 ||
!IsValid(signal, mMagicNumber))
{
return result;
}
//
result = GetSignalAge(
signal.time,
period);
//
return result;
}
//
// Generate a Signal Object name for Draw Events On Chart ...
string GetSignalObjectName(
ulong ticket // Specify Ticket
)
{
//
string result = "";
//
// Validate Arg ...
if (ticket <= 0)
{
return result;
}
//
// TICKET ...
// it is very importants since they hold position info ...
result += "T(" + (string)ticket + ")";
//
return result;
}
string GetSignalObjectName(
XSignal &signal // Specify Signal
)
{
//
string result = "";
//
// Validate Arg ...
if (!IsValid(signal, mMagicNumber))
{
return result;
}
//
result = GetSignalObjectName(signal.ticket);
//
return result;
}
//
// Convert a Signal to String Representation ...
string ToString(
XSignal &signal // Specify Signal
)
{
//
string result = "";
//
if (!IsValid(signal, mMagicNumber) || signal.ticket <= 0)
{
return result;
}
//
// TICKET ...
// it is very importants since they hold position info ...
result += "T(" + (string)signal.ticket + ")";
//
// TYPE ...
string typeStr = GetSignalType(signal.type);
result += "_TY(" + typeStr + ")";
//
// KIND ...
string kindStr = GetSignalKind(signal.kind);
result += "_K(" + kindStr + ")";
//
// PARENT ...
result += "_PR(" + (string)signal.parent + ")";
//
// ENTRY ...
result += "_E(" + (string)signal.entry + ")";
//
// RISKFREE ...
result += "_RF(" + (string)signal.riskFree + ")";
//
// RISKFREERATE ...
result += "_RR(" + (string)signal.riskFreeRate + ")";
//
// VOLUME ...
result += "_V(" + (string)signal.volume + ")";
//
// TYPE ...
// KIND ...
// ENTRY ...
// TICKET ...
// PARENT ...
// VOLUME ...
// RISKFREE ...
// VIRTUALTP ...
// VIRTUALSL ...
// RISKFREERATE ...
// an String Representation of a Signal Carry above fields ...
//
// ID ...
// TP ...
// SL ...
// TIME ...
// SYMBOL ...
// PROFIT ...
// COMMENT ...
// MAGICNUMBER ...
// these above items can read using PositionInfo instance ...
// so they are not necessary ...
//
return result;
}
//
// Convert an string to signal ...
XSignal FromString(
string represent // String Represenation of a Signal
)
{
//
XSignal result = {};
//
// Validate Arg ...
if (StringLen(represent) == 0)
{
return result;
}
//
// TICKET ...
string ticketStr = ExtractString(
represent,
"T(",
")");
if (StringLen(ticketStr) > 0)
{
result.ticket = (ulong)ticketStr;
}
//
// TYPE ...
string typeStr = ExtractString(
represent,
"_TY(",
")");
if (StringLen(typeStr) > 0)
{
//
ENUM_X_SIGNAL_TYPE type = GetSignalType(typeStr);
result.type = type;
}
//
// KIND ...
string kindStr = ExtractString(
represent,
"_K(",
")");
if (StringLen(kindStr) > 0)
{
//
ENUM_X_SIGNAL_KIND kind = GetSignalKind(kindStr);
result.kind = kind;
}
//
// PARENT ...
string parentStr = ExtractString(
represent,
"_PR(",
")");
if (StringLen(parentStr) > 0)
{
result.parent = (ulong)parentStr;
}
//
// ENTRY ...
string entryStr = ExtractString(
represent,
"_E(",
")");
if (StringLen(entryStr) > 0)
{
result.entry = (double)entryStr;
}
//
// RISKFREE ...
string riskFreeStr = ExtractString(
represent,
"_RF(",
")");
if (StringLen(riskFreeStr) > 0)
{
result.riskFree = (double)riskFreeStr;
}
//
// RISKFREERATE ...
string riskFreeRateStr = ExtractString(
represent,
"_RR(",
")");
if (StringLen(riskFreeRateStr) > 0)
{
result.riskFreeRate = (double)riskFreeRateStr;
}
//
// VOLUME ...
string volumeStr = ExtractString(
represent,
"_V(",
")");
if (StringLen(volumeStr) > 0)
{
result.volume = (double)volumeStr;
}
//
return result;
}
void FromString(
XSignal &result, // Holds Result
string represent // String Represenation of a Signal
)
{
//
// Validate Arg ...
if (StringLen(represent) == 0)
{
return;
}
//
// TICKET ...
string ticketStr = ExtractString(
represent,
"T(",
")");
if (StringLen(ticketStr) > 0)
{
result.ticket = (ulong)ticketStr;
}
//
// TYPE ...
string typeStr = ExtractString(
represent,
"_TY(",
")");
if (StringLen(typeStr) > 0)
{
//
ENUM_X_SIGNAL_TYPE type = GetSignalType(typeStr);
result.type = type;
}
//
// KIND ...
string kindStr = ExtractString(
represent,
"_K(",
")");
if (StringLen(kindStr) > 0)
{
//
ENUM_X_SIGNAL_KIND kind = GetSignalKind(kindStr);
result.kind = kind;
}
//
// PARENT ...
string parentStr = ExtractString(
represent,
"_PR(",
")");
if (StringLen(parentStr) > 0)
{
result.parent = (ulong)parentStr;
}
//
// ENTRY ...
string entryStr = ExtractString(
represent,
"_E(",
")");
if (StringLen(entryStr) > 0)
{
result.entry = (double)entryStr;
}
//
// RISKFREE ...
string riskFreeStr = ExtractString(
represent,
"_RF(",
")");
if (StringLen(riskFreeStr) > 0)
{
result.riskFree = (double)riskFreeStr;
}
//
// RISKFREERATE ...
string riskFreeRateStr = ExtractString(
represent,
"_RR(",
")");
if (StringLen(riskFreeRateStr) > 0)
{
result.riskFreeRate = (double)riskFreeRateStr;
}
//
// VOLUME ...
string volumeStr = ExtractString(
represent,
"_V(",
")");
if (StringLen(volumeStr) > 0)
{
result.volume = (double)volumeStr;
}
}
//
// END Signal Related ...
//
//
// all protected features ...
protected:
//
// all private features ...
private:
//
// Specified Unique Tag ...
string mTag;
//
// which Symbol ...
string mSymbol;
//
// using deviation, it must be in Point ...
int mSlippage;
//
// using magic number ...
ulong mMagicNumber;
//
// Specify Max Allowed Trades
int mMaxAllowedTrades;
//
// Specify Max Allowed Support Trades for each Trade
int mMaxAllowedSupportTrades;
//
// Minimum Profit of each Trade in Pips
double mMinTradeProfitsInPips;
//
// Support Trades Price Distance in Pips
double mSupportTradesPriceDistanceInPips;
//
// Minimum Free Marging for Open Trades
double mMinAllowedFreeMarginForOpenTrades;
//
// Minimum Balance for Open Trades
double mMinBallanceForOpenTrades;
//
// using CTrade instance ...
XSCTrade mTrader;
//
// An Instance Of XCAccount Info for Handling Account Related Actions ...
XCAccountInfo mAccountInfo;
//
// using PositionInfo instance ...
CPositionInfo mPositionInfo;
//
// For Manage Deals ...
CDealInfo mDealInfo;
//
// using OrderInfo instance ...
COrderInfo mPendingInfo;
//
// using HistoryOrderInfo instance ...
CHistoryOrderInfo mHistoryInfo;
//
// Count Specific Type Of Positions ...
int CountByType(ENUM_POSITION_TYPE type)
{
//
int result = 0;
//
int total = PositionsTotal();
for (int i = 0; i < total; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Symbol() != mSymbol)
{
continue;
}
//
if (mPositionInfo.PositionType() != type)
{
continue;
}
//
result++;
}
//
return result;
}
//
// Convert Position to Signal by Index ...
XSignal PositionToSignal(int index)
{
//
XSignal result = {};
//
if (!mPositionInfo.SelectByIndex(index))
{
return result;
}
//
ulong ticket = mPositionInfo.Ticket();
string signalContent = RetrieveSignalContent(ticket);
if (StringLen(signalContent) > 0)
{
//
// Fill Additional Contents ...
FromString(
result,
signalContent);
}
//
// Ticket ...
result.ticket = mPositionInfo.Ticket();
//
// ID ...
result.id = mPositionInfo.Identifier();
//
// Symbol ...
result.symbol = mPositionInfo.Symbol();
//
// Type ...
ENUM_POSITION_TYPE pType = (ENUM_POSITION_TYPE)mPositionInfo.PositionType();
ENUM_X_SIGNAL_TYPE type = pType == POSITION_TYPE_BUY ? X_SIGNAL_LONG : X_SIGNAL_SHORT;
result.type = type;
//
// MagicNumber ...
result.magicNumber = mPositionInfo.Magic();
//
// Entry/Open Price ...
result.entry = mPositionInfo.PriceOpen();
//
// Take Profit ...
result.tp = mPositionInfo.TakeProfit();
//
// Stop Loss ...
result.sl = mPositionInfo.StopLoss();
//
// Profit ...
result.profit = mPositionInfo.Profit();
//
// Time ...
result.time = mPositionInfo.Time();
//
// Volume ...
result.volume = mPositionInfo.Volume();
//
// Comment ...
result.comment = mPositionInfo.Comment();
//
return result;
}
//
// Position To Signal by Ticket ...
XSignal PositionToSignal(ulong ticket)
{
//
XSignal result = {};
//
if (!mPositionInfo.SelectByTicket(ticket))
{
return result;
}
//
string signalContent = RetrieveSignalContent(ticket);
if (StringLen(signalContent) > 0)
{
//
// Fill Additional Contents ...
FromString(
result,
signalContent);
}
//
// Ticket ...
result.ticket = mPositionInfo.Ticket();
//
// ID ...
result.id = mPositionInfo.Identifier();
//
// Symbol ...
result.symbol = mPositionInfo.Symbol();
//
// Type ...
ENUM_POSITION_TYPE pType = (ENUM_POSITION_TYPE)mPositionInfo.PositionType();
ENUM_X_SIGNAL_TYPE type = pType == POSITION_TYPE_BUY ? X_SIGNAL_LONG : X_SIGNAL_SHORT;
result.type = type;
//
// MagicNumber ...
result.magicNumber = mPositionInfo.Magic();
//
// Entry/Open Price ...
result.entry = mPositionInfo.PriceOpen();
//
// Take Profit ...
result.tp = mPositionInfo.TakeProfit();
//
// Stop Loss ...
result.sl = mPositionInfo.StopLoss();
//
// Profit ...
result.profit = mPositionInfo.Profit();
//
// Time ...
result.time = mPositionInfo.Time();
//
// Volume ...
result.volume = mPositionInfo.Volume();
//
// Comment ...
result.comment = mPositionInfo.Comment();
//
return result;
}
//
// Convert Position to Signal by Index ...
XSignal OrderToSignal(int index)
{
//
XSignal result = {};
//
if (!mHistoryInfo.SelectByIndex(index))
{
return result;
}
//
// ID ...
result.id = mHistoryInfo.PositionId();
//
// Symbol ...
result.symbol = mHistoryInfo.Symbol();
//
// Type ...
ENUM_ORDER_TYPE pType = (ENUM_ORDER_TYPE)mHistoryInfo.OrderType();
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN;
switch (pType)
{
//
case ORDER_TYPE_BUY:
case ORDER_TYPE_BUY_LIMIT:
case ORDER_TYPE_BUY_STOP:
case ORDER_TYPE_BUY_STOP_LIMIT:
type = X_SIGNAL_LONG;
break;
//
case ORDER_TYPE_SELL:
case ORDER_TYPE_SELL_LIMIT:
case ORDER_TYPE_SELL_STOP:
case ORDER_TYPE_SELL_STOP_LIMIT:
type = X_SIGNAL_SHORT;
break;
//
// Default ...
default:
type = X_SIGNAL_UNKNOWN;
break;
}
result.type = type;
//
// MagicNumber ...
result.magicNumber = mHistoryInfo.Magic();
//
// Ticket ...
result.ticket = mHistoryInfo.Ticket();
//
// Entry/Open Price ...
result.entry = mHistoryInfo.PriceOpen();
//
// Take Profit ...
result.tp = mHistoryInfo.TakeProfit();
//
// Stop Loss ...
result.sl = mHistoryInfo.StopLoss();
//
// Profit ...
// TODO Calculate it ...
// result.profit = mHistoryInfo.Profit();
// //
// // Time ...
// result.time = mHistoryInfo.Time();
// //
// // Volume ...
// result.volume = mHistoryInfo.Volume();
//
// Comment ...
result.comment = mHistoryInfo.Comment();
//
return result;
}
//
// Draw a Signal on Screen ...
void DrawSignalEvent(
XSignal &signal, // Specify Draw which Signal on Screen
color longColor = clrAqua, // Long Signal Object Color
color shortColor = clrFuchsia, // Short Signal Object Color
int chartId = -1, // Specify Chart ID
int subWindow = -1 // Specify SubWindow ID
)
{
//
// Validate Args ...
if (
signal.ticket <= 0 ||
!IsValid(signal, mMagicNumber) ||
signal.type == X_SIGNAL_UNKNOWN)
{
return;
}
//
// Normalize Chart and SubWindow ID ...
if (chartId == -1)
{
chartId = 0;
}
if (subWindow == -1)
{
subWindow = 0;
}
//
bool isLong = signal.type == X_SIGNAL_LONG;
//
// Simply Draw an Arrow on Chart for Representing Signal Info ...
string name = GetSignalObjectName(signal);
string content = ToString(signal);
if (StringLen(content) == 0)
{
return;
}
//
color signalColor = isLong ? longColor : shortColor;
//
// Create an Event On Chart ...
bool isCreated = EventCreate(
chartId,
name,
subWindow,
content,
signal.time,
signalColor);
if (isCreated)
{
//
DrawSignalShape(
signal,
longColor,
shortColor);
}
}
//
// Filter Trades Buffer ...
void FilterSignals(
string query, // Search String
XSignal &source[], // Source Buffer to Filter
XSignal &result[] // Holds Result
)
{
//
// Free Buffer ...
CleanBuffer(result);
//
int sourceCount = ArraySize(source);
//
// Check Conditions and Validate Args ...
if (
sourceCount == 0 ||
StringLen(query) == 0)
{
return;
}
//
// Loop Through Source ...
for (int i = 0; i < sourceCount; i++)
{
//
// Retrieve Indexed Item ...
XSignal trade = source[i];
//
// Check Query Exists or not ...
int pos = StringFind(
trade.comment,
query);
//
// Continue if nothing found ...
if (pos <= -1)
{
continue;
}
//
// Resize the result array ...
ArrayResize(
result,
ArraySize(result) + 1);
result[ArraySize(result) - 1] = trade;
}
}
//
// Get all Positions based on Position Type ...
void GetAllPositionsByType(ENUM_POSITION_TYPE type, XSignal &result[])
{
//
int existsTotal = CountByType(type);
//
CleanBuffer(result);
ArrayResize(result, existsTotal);
//
int filledIndex = 0;
int total = PositionsTotal();
for (int i = 0; i < total; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
if (mPositionInfo.Symbol() != mSymbol)
{
continue;
}
//
if (mPositionInfo.PositionType() != type)
{
continue;
}
//
result[filledIndex] = PositionToSignal(i);
filledIndex++;
}
}
//
// Retrieve Signal Specified Object Text ...
string RetrieveSignalContent(
ulong ticket, // Specify Position Ticket
int chartId = -1, // Specify Chart ID
int subWindow = -1 // Specify SubWindow ID
)
{
//
string result = "";
//
// Validate Arg ...
if (ticket <= 0)
{
return result;
}
//
string signalObjectName = GetSignalObjectName(ticket);
if (StringLen(signalObjectName) == 0)
{
return result;
}
//
// Normalize Chart and SubWindow ID ...
if (chartId == -1)
{
chartId = 0;
}
if (subWindow == -1)
{
subWindow = 0;
}
//
// Search For Signal Object Name ...
int objectIndex = ObjectFind(
chartId,
signalObjectName);
if (objectIndex < 0)
{
return result;
}
//
// Loop Through Objects ...
int count = ObjectsTotal(
chartId,
subWindow);
for (int i = count - 1; i >= 0; i--)
{
//
// Retrieve Object Name ...
string objectName = ObjectName(chartId, i, subWindow);
//
// Find Signal Ticket Position in Object Name ...
int stPos = StringFind(
objectName,
signalObjectName);
if (stPos < 0)
{
continue;
}
//
// Retrieve Object Type and Check it Event ...
int oType = (int)ObjectGetInteger(chartId, objectName, OBJPROP_TYPE);
if (oType != OBJ_EVENT) {
continue;
}
//
// Retrieve Object Text as String Representation OF Signal ...
result = ObjectGetString(chartId, objectName, OBJPROP_TEXT);
break;
}
//
return result;
}
string RetrieveSignalContent(
XSignal &signal, // Specify Signal
int chartId = -1, // Specify Chart ID
int subWindow = -1 // Specify SubWindow ID
)
{
//
string result = "";
//
result = RetrieveSignalContent(
signal.ticket,
chartId,
subWindow);
//
return result;
}
//
// Remove Signal Object from Chart ...
bool RemoveSignal(
ulong ticket, // Specify Position Ticket
int chartId = -1 // Specify Chart ID
)
{
//
bool result = false;
//
// Validate Arg ...
if (ticket <= 0)
{
return result;
}
//
// Normalize Chart Id ...
if (chartId <= 0)
{
chartId = 0;
}
//
// Generate Signal Object Name ...
string signalObjectName = GetSignalObjectName(ticket);
//
// Remove Object from Chart ...
result = ObjectDelete(chartId, signalObjectName);
//
return result;
}
bool RemoveSignal(
XSignal &signal, // Specify Signal
int chartId = -1 // Specify Chart ID
)
{
//
bool result = false;
//
result = RemoveSignal(
signal.ticket,
chartId);
//
return result;
}
//
// Generate Comments for Specific Signal ...
string GetSignalComment(
ENUM_X_SIGNAL_KIND kind, // Specify Kind
ENUM_X_SIGNAL_TYPE type, // Specify Kind Signal Type
ulong parentTicket, // Parent Signal Ticket
double volume, // Signal Volume
double riskFree, // Risk Free Price
double riskFreeRate // Risk Free Volume Multiplier
)
{
//
string result = "";
//
string kindStr = GetSignalKind(kind);
string typeStr = GetSignalType(type);
if (
volume <= 0 ||
StringLen(kindStr) == 0 ||
StringLen(typeStr) == 0 ||
(parentTicket <= 0 && kind == X_KIND_SUPPORT))
{
return result;
}
//
// Normalize Data ...
//
if (riskFreeRate < 0)
{
riskFreeRate = 0;
}
else if (riskFreeRate > 1)
{
riskFreeRate = 0.75;
}
//
volume = NormalizeVolume(volume, mSymbol);
riskFree = NormalizePrice(riskFree, mSymbol);
//
if (riskFree > 0 && riskFreeRate == 0)
{
riskFreeRate = 0.75;
}
else if (riskFree <= 0 && riskFreeRate > 0)
{
riskFreeRate = 0;
}
//
string kindTitle = kind == X_KIND_TRADE ? kindStr : kindStr + "_For_" + (string)parentTicket;
result = mTag + "_" + typeStr + "_" + kindTitle;
//
return result;
}
string GetSignalComment(
XSignal &signal // Specify Signal
)
{
//
string result = GetSignalComment(
signal.kind,
signal.type,
signal.parent,
signal.volume,
signal.riskFree,
signal.riskFreeRate
//
);
//
return result;
}
//
// Generate TP Comment For Closing Signal ...
string GetSignalClosedOnTPComment(
XSignal &signal // Model Signal to Use
)
{
//
string result = "";
//
if (signal.ticket <= 0 ||
!IsValid(signal, mMagicNumber))
{
return result;
}
//
double exitPrice = GetExit(signal.type);
string prefix = GetSignalObjectName(signal);
//
// "_E(" + (string)signal.entry + ")" ...
result = prefix + "_TP(" + (string)exitPrice + ")";
//
return result;
}
//
// Generate SL Comment For Closing Signal ...
string GetSignalClosedOnSLComment(
XSignal &signal // Model Signal to Use
)
{
//
string result = "";
//
if (signal.ticket <= 0 ||
!IsValid(signal, mMagicNumber))
{
return result;
}
//
double exitPrice = GetExit(signal.type);
string prefix = GetSignalObjectName(signal);
//
// "_E(" + (string)signal.entry + ")" ...
result = prefix + "_SL(" + (string)exitPrice + ")";
//
return result;
}
//
// Generate Comment For Force Closing Signal ...
string GetSignalForceClosedComment(
XSignal &signal // Model Signal to Use
)
{
//
string result = "";
//
if (signal.ticket <= 0 ||
!IsValid(signal, mMagicNumber))
{
return result;
}
//
double exitPrice = GetExit(signal.type);
string prefix = GetSignalObjectName(signal);
//
// "_E(" + (string)signal.entry + ")" ...
result = "F_" + prefix + "_P(" + (string)exitPrice + ")";
//
return result;
}
//
// Generate Comment For In DrawDown and In Profit Closing Signal ...
string GetSignalInDistanceClosedComment(
XSignal &signal // Model Signal to Use
)
{
//
string result = "";
//
if (signal.ticket <= 0 ||
!IsValid(signal, mMagicNumber))
{
return result;
}
//
double exitPrice = GetExit(signal.type);
string prefix = GetSignalObjectName(signal);
string distanceStr = signal.profit > 0 ? "InP" : "InDD";
//
// "_E(" + (string)signal.entry + ") ...
// "_P(" + (string)exitPrice + ")" ...
result = distanceStr + "_" + prefix + "_D(" + (string)signal.profit + ")";
//
return result;
}
//
// Generate Comment For Long Time Closing Signal ...
string GetSignalLongTimeClosedComment(
XSignal &signal // Model Signal to Use
)
{
//
string result = "";
//
if (signal.ticket <= 0 ||
!IsValid(signal, mMagicNumber))
{
return result;
}
//
double exitPrice = GetExit(signal.type);
string prefix = GetSignalObjectName(signal);
//
int signalAge = GetSignalAge(signal);
//
// "_E(" + (string)signal.entry + ")" ...
// "_P(" + (string)exitPrice + ")" ...
result = "LT_" + prefix + "_A(" + (string)signalAge + ")" + "_D(" + (string)signal.profit + ")";
//
return result;
}
//
// Check Number Of Trades is Valid ...
bool CanOpenNewTrade(
ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions
ENUM_X_SIGNAL_KIND kind // Specify Kind of Positions
)
{
//
bool result = false;
//
int tradesCount = CountByKind(
type,
kind);
//
result = tradesCount <= 0;
if (!result)
{
return result;
}
//
bool isTradeKind = kind == X_KIND_TRADE;
//
// Check based on Trade Kind ...
result =
//
isTradeKind
//
?
//
tradesCount < mMaxAllowedTrades
//
:
//
tradesCount < mMaxAllowedSupportTrades
//
;
//
return result;
}
//
// Check Account Has Minimum Balance For Trade ...
bool IsAccountBalanceReadyForTrade()
{
//
bool result = false;
//
result = mAccountInfo.GetBalance() >= mMinBallanceForOpenTrades;
//
return result;
}
//
// Check Free Margin Has Enough For Trade ...
bool IsFreeMarginReadyForTrade()
{
//
bool result = false;
//
double freeMargin = mAccountInfo.GetFreeMargin();
//
result = freeMargin >= mMinAllowedFreeMarginForOpenTrades;
//
return result;
}
};
//
// END Global Definitions: Variables, Properties and etc ...
//