Files
xMQL5/BKPS/14020924/Libraries/x-saherelm.class.lib.mq5
2024-01-25 04:09:42 +03:30

3190 lines
72 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 ...
//
//
string X_SIGNAL_TP = "TP";
string X_SIGNAL_SL = "SL";
string X_SIGNAL_TYPE = "TY";
string X_SIGNAL_TICKET = "T";
string X_SIGNAL_RISKFREE_STEP = "RFS";
string X_SIGNAL_RISKFREE_RATE = "RFR";
//
struct XTraderHandlerResult
{
//
// List Of Closed On SL Signals ...
XSignal sl[];
//
// List Of Closed On TP Signals ...
XSignal tp[];
//
// List Of Risk Free Signals ...
XSignal rf[];
};
//
// END Model Definitions ...
//
//
// START Overrides ...
//
class XSCTrade : public CTrade
{
public:
//
// Modify Specific Position, by Specific Comment ...
bool PositionModify(
const string symbol, // Symbol
const double sl, // Stop Loss
const double tp, // Take Profit
const string comment = "" // Comment For Modify
)
{
//
// check stopped
if (IsStopped(__FUNCTION__))
{
return (false);
}
//
// check position existence
if (!SelectPosition(symbol))
{
return (false);
}
//
// clean
ClearStructures();
//
// setting request
m_request.action = TRADE_ACTION_SLTP;
m_request.symbol = symbol;
m_request.magic = m_magic;
m_request.sl = sl;
m_request.tp = tp;
m_request.position = PositionGetInteger(POSITION_TICKET);
//
// Specified Comment ...
if (StringLen(comment) > 0)
{
m_request.comment = comment;
}
//
// action and return the result
return (OrderSend(m_request, m_result));
}
bool PositionModify(
const ulong ticket, // Position Ticket
const double sl, // Stop Loss
const double tp, // Take Profit
const string comment = "" // Comment For Modify
)
{
//
// check stopped
if (IsStopped(__FUNCTION__))
{
return (false);
}
//
// check position existence
if (!PositionSelectByTicket(ticket))
{
return (false);
}
//
// clean
ClearStructures();
//
// setting request
m_request.action = TRADE_ACTION_SLTP;
m_request.position = ticket;
m_request.symbol = PositionGetString(POSITION_SYMBOL);
m_request.magic = m_magic;
m_request.sl = sl;
m_request.tp = tp;
//
// Specified Comment ...
if (StringLen(comment) > 0)
{
m_request.comment = comment;
}
//
// action and return the result
return (OrderSend(m_request, m_result));
}
//
// Close Specific Position, by Specific Comment ...
bool PositionClose(
const string symbol, // Symbol
const ulong deviation, // Deviation
const string comment = "" // Comment For Close
)
{
//
bool partial_close = false;
int retry_count = 10;
uint retcode = TRADE_RETCODE_REJECT;
//
// check stopped
if (IsStopped(__FUNCTION__))
{
return (false);
}
//
// clean
ClearStructures();
//
// check filling
if (!FillingCheck(symbol))
{
return (false);
}
//
do
{
//
// check
if (SelectPosition(symbol))
{
//
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);
}
else
{
//
// prepare request for close SELL position
m_request.type = ORDER_TYPE_BUY;
m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
}
}
else
{
//
// position not found
m_result.retcode = retcode;
return (false);
}
//
// setting request
m_request.action = TRADE_ACTION_DEAL;
m_request.symbol = symbol;
m_request.volume = PositionGetDouble(POSITION_VOLUME);
m_request.magic = m_magic;
m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation;
m_request.position = PositionGetInteger(POSITION_TICKET);
//
// Specify Comment ...
m_request.comment = comment;
//
// check volume
double max_volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
if (m_request.volume > max_volume)
{
//
m_request.volume = max_volume;
partial_close = true;
}
else
{
partial_close = false;
}
//
// hedging? just send order
if (IsHedging())
{
return (OrderSend(m_request, m_result));
}
//
// order send
if (!OrderSend(m_request, m_result))
{
//
if (--retry_count != 0)
{
continue;
}
//
if (retcode == TRADE_RETCODE_DONE_PARTIAL)
{
m_result.retcode = retcode;
}
//
return (false);
}
//
//--- WARNING. If position volume exceeds the maximum volume allowed for deal,
//--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely,
//--- but partially. It is decreased by the maximum volume allowed for deal.
if (m_async_mode)
{
break;
}
//
retcode = TRADE_RETCODE_DONE_PARTIAL;
if (partial_close)
{
Sleep(1000);
}
} while (partial_close);
//
// succeed
return (true);
}
bool PositionClose(
const ulong ticket, // Position Ticket
const ulong deviation, // Deviation
const string comment = "" // Comment For Close
)
{
//
// check stopped
if (IsStopped(__FUNCTION__))
{
return (false);
}
//
// check position existence
if (!PositionSelectByTicket(ticket))
{
return (false);
}
//
string symbol = PositionGetString(POSITION_SYMBOL);
//
// clean
ClearStructures();
//
// check filling
if (!FillingCheck(symbol))
{
return (false);
}
//
// check
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);
}
else
{
//
// prepare request for close SELL position
m_request.type = ORDER_TYPE_BUY;
m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
}
//
// setting request
m_request.action = TRADE_ACTION_DEAL;
m_request.position = ticket;
m_request.symbol = symbol;
m_request.volume = PositionGetDouble(POSITION_VOLUME);
m_request.magic = m_magic;
m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation;
//
// Specify Comment ...
m_request.comment = comment;
//
// close position
return (OrderSend(m_request, m_result));
}
//
// Partial Close Specific Position, by Specific Comment ...
bool PositionClosePartial(
const string symbol, // Symbol
const double volume, // Partial Closing Volume
const ulong deviation, // Deviation
const string comment = "" // Comment For Close
)
{
//
uint retcode = TRADE_RETCODE_REJECT;
//
// check stopped
if (IsStopped(__FUNCTION__))
{
return (false);
}
//
// for hedging mode only
if (!IsHedging())
{
return (false);
}
//
// clean
ClearStructures();
//
// check filling
if (!FillingCheck(symbol))
{
return (false);
}
//
// check
if (SelectPosition(symbol))
{
//
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);
}
else
{
//
// prepare request for close SELL position
m_request.type = ORDER_TYPE_BUY;
m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
}
}
else
{
//
// position not found
m_result.retcode = retcode;
return (false);
}
//
// check volume
double position_volume = PositionGetDouble(POSITION_VOLUME);
if (position_volume > volume)
{
position_volume = volume;
}
//
// setting request
m_request.action = TRADE_ACTION_DEAL;
m_request.symbol = symbol;
m_request.volume = position_volume;
m_request.magic = m_magic;
m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation;
m_request.position = PositionGetInteger(POSITION_TICKET);
//
// Specifieng Comment ...
m_request.comment = comment;
//
// hedging? just send order
return (OrderSend(m_request, m_result));
}
bool PositionClosePartial(
const ulong ticket, // Position Ticket
const double volume, // Partial Closing Volume
const ulong deviation, // Deviation
const string comment = "" // Comment For Close
)
{
//
// check stopped
if (IsStopped(__FUNCTION__))
{
return (false);
}
//
// for hedging mode only
if (!IsHedging())
{
return (false);
}
//
// check position existence
if (!PositionSelectByTicket(ticket))
{
return (false);
}
//
string symbol = PositionGetString(POSITION_SYMBOL);
//
// clean
ClearStructures();
//
// check filling
if (!FillingCheck(symbol))
{
return (false);
}
//
// check
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);
}
else
{
//
// prepare request for close SELL position
m_request.type = ORDER_TYPE_BUY;
m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK);
}
//
// check volume
double position_volume = PositionGetDouble(POSITION_VOLUME);
if (position_volume > volume)
{
position_volume = volume;
}
//
// setting request
m_request.action = TRADE_ACTION_DEAL;
m_request.position = ticket;
m_request.symbol = symbol;
m_request.volume = position_volume;
m_request.magic = m_magic;
m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation;
//
// Specifieng Comment ...
m_request.comment = comment;
//
// close position
return (OrderSend(m_request, m_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
double minBallanceForOpenTrades, // Specify Minimum Balance for Open Trades
double minAllowedFreeMarginForOpenTrades // Specify Minimum Free Marging for Open Trades
)
{
//
mTag = tag;
mSymbol = symbol;
mSlippage = slippage;
mMagicNumber = magicNumber;
mMaxAllowedTrades = maxAllowedTrades;
mMinBallanceForOpenTrades = minBallanceForOpenTrades;
mMinAllowedFreeMarginForOpenTrades = minAllowedFreeMarginForOpenTrades;
//
mTrader = new XSCTrade();
//
mTrader.SetAsyncMode(false);
mTrader.SetDeviationInPoints(mSlippage);
mTrader.SetExpertMagicNumber(mMagicNumber);
}
//
// Deconstructor ...
void ~XCTrade()
{
}
//
// START Count ...
//
//
// 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 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;
}
//
// 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;
}
//
// END Count ...
//
//
// START Retrieve ...
//
//
// Retrieve Specified Position by it's Ticket ...
XSignal GetSignal(
ulong ticket // Specified Ticket
)
{
//
XSignal result = {};
//
result = PositionToSignal(ticket);
//
return result;
}
//
// Retrieve All Positions ...
void GetSignals(
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 Type Specific Signals ...
void GetSignals(
XSignal &result[], // Holds Result ...
ENUM_X_SIGNAL_TYPE type // Specified Sginal Type ...
)
{
//
CleanBuffer(result);
//
XSignal signals[];
GetSignals(signals);
//
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
// Loop ...
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
if (type == X_SIGNAL_UNKNOWN)
{
Add(
iSignal,
result);
}
else if (iSignal.type == type)
{
Add(
iSignal,
result);
}
}
}
//
// Get All Trades Which Candle Passed after Open ...
void GetOldSignals(
XSignal &result[], // Holds Result
int life, // Max Candle Passed after Trades Open
ENUM_TIMEFRAMES period = NULL, // Calculate Candles based on time frame
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions
)
{
//
CleanBuffer(result);
//
// Normalize Period ...
if (period == NULL)
{
period = _Period;
}
//
XSignal signals[];
GetSignals(
signals,
type);
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
// Current Time Frame Candle Index ...
int currentBarIndex = 0;
//
// Loop through Positions ...
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
// Retrieve Trade Open Bar Index based on Current Period ...
int tradeOpenBarIndex = iBarShift(
mSymbol,
period,
iSignal.time);
//
// Calculate Trade Life ...
int diff = MathAbs(currentBarIndex - tradeOpenBarIndex);
//
bool isPassed = diff >= life;
if (isPassed)
{
//
Add(
iSignal,
result);
}
}
}
//
// Get In Profit Signals ...
void GetInProfitSignals(
XSignal &result[], // Holds Result
double minProfit = 0, // Minimum Profit To Close Trades
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions
)
{
//
CleanBuffer(result);
//
XSignal signals[];
GetSignals(
signals,
type);
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
// Loop ...
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
bool isPassed = minProfit <= 0 && iSignal.profit > 0
? true
: iSignal.profit >= minProfit;
if (isPassed)
{
Add(
iSignal,
result);
}
}
}
//
// Get In Drawdown Signals ...
void GetInDrawdownSignals(
XSignal &result[], // Holds Result
double maxDrawDown = 0, // Minimum Profit To Close Trades
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions
)
{
//
CleanBuffer(result);
//
XSignal signals[];
GetSignals(
signals,
type);
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
// Loop ...
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
bool isPassed = maxDrawDown <= 0 && iSignal.profit < 0
? true
: iSignal.profit >= (-1 * maxDrawDown);
if (isPassed)
{
Add(
iSignal,
result);
}
}
}
//
// END Retrieve ...
//
//
// START Signal Execution Actions ...
//
//
// Execute a Signal in Market ...
ENUM_EXECUTION_SIGNAL_RESULT ExecuteSignal(
XSignal &signal, // Specified Signal
bool ignoreTPSL = false, // Ignore Signal TP and SL for Virtal Handling
bool ignoreNumberOfTraes = true, // Ignore Number of Trades
bool checkAccountConditions = true // Check Account Balance, Equity and Free Margin for Signal Execution
)
{
//
ENUM_EXECUTION_SIGNAL_RESULT result = X_TRADER_UNKNOWN_ERROR;
//
// Validate Signal ...
bool isValid = IsValidSignal(signal);
if (!isValid)
{
//
result = X_TRADER_INVALID_SIGNAL_ERROR;
return result;
}
//
// Check Account Equity ...
bool isEquityPassed = !checkAccountConditions
? true
: IsEquityReadyForTrade();
if (!isEquityPassed)
{
//
result = X_TRADER_NOT_ENOUGH_EQUITY_ERROR;
return result;
}
//
// Check Account Balance ...
bool isBalancePassed = !checkAccountConditions
? true
: IsBalanceReadyForTrade();
if (!isBalancePassed)
{
//
result = X_TRADER_NOT_ENOUGH_BALANCE_ERROR;
return result;
}
//
// Check Account FreeMargin ...
bool isFreeMarginPassed = !checkAccountConditions
? true
: IsFreeMarginReadyForTrade();
if (!isFreeMarginPassed)
{
//
result = X_TRADER_NOT_ENOUGH_MARIGIN_ERROR;
return result;
}
//
// Check Number of Open Trades ...
int openTradesCount = Count();
bool isTradeCountPassed = ignoreNumberOfTraes
? true
: openTradesCount < mMaxAllowedTrades;
if (!isTradeCountPassed)
{
//
result = X_TRADER_MAX_TRADES_REACHED_ERROR;
return result;
}
//
bool isExecuted =
signal.type == X_SIGNAL_LONG
? Buy(
signal.volume,
signal.entry,
ignoreTPSL
? 0
: signal.sl,
ignoreTPSL
? 0
: signal.tp,
signal.comment)
: signal.type == X_SIGNAL_SHORT
? Sell(
signal.volume,
signal.entry,
ignoreTPSL
? 0
: signal.sl,
ignoreTPSL
? 0
: signal.tp,
signal.comment)
: false;
if (isExecuted)
{
//
ulong ticket = PositionGetTicket(PositionsTotal() - 1);
//
signal.id = ticket;
signal.ticket = ticket;
//
AddOrUpdateSignalInfo(signal);
//
result = X_TRADER_SUCCEED_EXECUTION;
}
//
return result;
}
//
// This Function, Handling Following Works on Open Positions:
// - Close On SL if Reached ...
// - Close On TP if Reached ...
// - Make Risk Free Trades ...
void HandleSignals(
XTraderHandlerResult &result, // Holds Result
bool ignoreTPSL = true, // Ignore Signal TP and SL for Virtal Handling
bool ignoreRiskFree = false // Ignore Risk Free Trdaes
)
{
//
// Cleanup Result ...
CleanBuffer(result.sl);
CleanBuffer(result.tp);
CleanBuffer(result.rf);
//
// Reading Open Positions ...
XSignal signals[];
GetSignals(signals);
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
double deviation = mSlippage * GetPoints(mSymbol);
//
// Loop ...
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
double entry = GetEntry(iSignal.symbol, iSignal.type);
double exit = GetExit(iSignal.symbol, iSignal.type);
double appliedTPPrice =
iSignal.tp > 0
? iSignal.type == X_SIGNAL_LONG
? iSignal.tp - deviation
: iSignal.tp + deviation
: 0;
double appliedSLPrice =
iSignal.sl > 0
? iSignal.type == X_SIGNAL_LONG
? iSignal.sl + deviation
: iSignal.sl - deviation
: 0;
//
// Handle SL ...
if (
//
!ignoreTPSL
//
&&
//
iSignal.sl > 0
//
&&
//
exit <= appliedSLPrice
//
)
{
//
string comment = GenerateSignalSLComment(iSignal);
//
bool isClosed = Close(
iSignal.ticket,
comment);
if (isClosed)
{
Add(
iSignal,
result.sl);
}
}
//
// Handle TP ...
if (
//
!ignoreTPSL
//
&&
//
iSignal.tp > 0
//
&&
//
exit >= appliedTPPrice
//
)
{
//
string comment = GenerateSignalTPComment(iSignal);
//
bool isClosed = Close(
iSignal.ticket,
comment);
if (isClosed)
{
Add(
iSignal,
result.tp);
}
}
//
// Handle Risk Free ...
if (
//
!ignoreRiskFree
//
&&
//
iSignal.riskFreeStep > 0
//
&&
//
iSignal.riskFreeRate > 0
//
)
{
//
// Base Price is ENTRY, then Last Level, in each level SL is Last Level ...
int level = 1;
bool isLong = iSignal.type == X_SIGNAL_LONG;
double stepPrice = PipsToPrice(iSignal.riskFreeStep);
double basePrice =
isLong
? iSignal.sl > iSignal.entry ? iSignal.sl : iSignal.entry
: iSignal.sl < iSignal.entry ? iSignal.sl
: iSignal.entry;
double priceLevel = (exit - basePrice) / stepPrice;
//
if (priceLevel > 1)
{
//
while (priceLevel > level && priceLevel > level + 1)
{
level++;
}
//
double baseRiskFreeLevelExitPrice = (level * stepPrice);
double riskFreeLevelExitPrice =
isLong
? (basePrice + baseRiskFreeLevelExitPrice) - deviation
: (basePrice - baseRiskFreeLevelExitPrice) + deviation;
//
bool canRiskFree =
isLong
? exit >= riskFreeLevelExitPrice
: exit <= riskFreeLevelExitPrice;
//
if (canRiskFree)
{
//
double volume = iSignal.volume;
double riskFreeRate = iSignal.riskFreeRate;
double riskFreeVolume = riskFreeRate * volume;
riskFreeVolume = NormalizeVolume(riskFreeVolume);
//
double spread = GetSpread(iSignal.symbol);
double slDistance = spread;
double sl =
isLong
? riskFreeLevelExitPrice - slDistance
: riskFreeLevelExitPrice + slDistance;
//
double tp = iSignal.tp += stepPrice;
//
string comment = GenerateSignalRFComment(iSignal, (int)level);
//
ResetLastError();
//
bool isClosedPartial = ClosePartial(
iSignal.ticket,
riskFreeVolume,
comment);
//
if (isClosedPartial)
{
//
bool isModified = Modify(
iSignal.ticket,
sl,
tp);
//
if (isModified)
{
//
Add(
iSignal,
result.rf);
//
AddOrUpdateSignalInfo(iSignal);
}
}
}
}
// //
// // Check TP Step Price ...
// double stepPrice = PipsToPrice(iSignal.riskFreeStep);
// double level = MathAbs(exit - iSignal.entry) / stepPrice;
// double roundedLevel = MathRound(level);
// if (level > 1 && (roundedLevel - level) < 0)
// {
// //
// level = roundedLevel;
// //
// double basePrice = iSignal.sl > 0 ? iSignal.sl : iSignal.entry;
// double step = (level * stepPrice);
// step =
// iSignal.type == X_SIGNAL_LONG
// ? (basePrice + step) - deviation
// : (basePrice - step) + deviation;
// //
// bool canRiskFree =
// iSignal.type == X_SIGNAL_LONG
// ? exit >= step
// : exit <= step;
// //
// if (canRiskFree)
// {
// }
// }
}
}
}
//
// Close All Trades ...
void CloseSignals(
XSignal &result[], // Holds Result
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions
)
{
//
CleanBuffer(result);
//
XSignal signals[];
GetSignals(
signals,
type);
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
string comment = GenerateSignalForceCloseComment(iSignal);
//
bool isClosed = Close(
iSignal.ticket,
comment);
if (isClosed)
{
Add(
iSignal,
result);
}
}
}
//
// Close Pyramid Signals ...
void CloseInPyramidSignals(
XSignal &result[], // Holds Result
double pyramid = 0, // Close Pyramid Profit
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions
)
{
//
CleanBuffer(result);
//
XSignal signals[];
GetSignals(
signals,
type);
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
double profit = 0;
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
profit += iSignal.profit;
}
//
// Normalize Pyramid ...
if (pyramid < 0)
{
pyramid = 0;
}
//
if (profit > pyramid)
{
CloseSignals(result);
}
}
//
// Close All Trades Which Candle Passed after Open ...
void CloseOldSignals(
XSignal &result[], // Holds Result
int life, // Max Candle Passed after Trades Open
ENUM_TIMEFRAMES period = NULL, // Calculate Candles based on time frame
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions
)
{
//
CleanBuffer(result);
//
XSignal signals[];
GetOldSignals(
signals,
life,
period,
type);
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
string comment = GenerateSignalAgeComment(iSignal);
//
bool isClosed = Close(
iSignal.ticket,
comment);
if (isClosed)
{
Add(
iSignal,
result);
}
}
}
//
// Close In Profit Signals ...
void CloseInProfitSignals(
XSignal &result[], // Holds Result
double minProfit = 0, // Minimum Profit To Close Trades
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions
)
{
//
CleanBuffer(result);
//
XSignal signals[];
GetInProfitSignals(
signals,
minProfit,
type);
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
string comment = GenerateSignalProfitComment(iSignal);
//
bool isClosed = Close(
iSignal.ticket,
comment);
if (isClosed)
{
Add(
iSignal,
result);
}
}
}
//
// Close In Drawdown Signals ...
void CloseInDrawdownSignals(
XSignal &result[], // Holds Result
double maxDrawDown = 0, // Minimum Profit To Close Trades
ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN // Specify Type of Positions
)
{
//
CleanBuffer(result);
//
XSignal signals[];
GetInDrawdownSignals(
signals,
maxDrawDown,
type);
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
string comment = GenerateSignalProfitComment(iSignal);
//
bool isClosed = Close(
iSignal.ticket,
comment);
if (isClosed)
{
Add(
iSignal,
result);
}
}
}
//
// END Signal Execution Actions ...
//
//
// START Actions ...
//
//
// 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;
}
//
// Modify Position ...
bool Modify(
const ulong ticket, // position ticket
double sl = 0, // stop loss price
double tp = 0, // take profit
const string comment = "" // comment
)
{
//
bool result = false;
//
// Validate Args ...
if (tp <= 0 && sl <= 0)
{
result = false;
return result;
}
//
result = mTrader.PositionModify(
ticket,
sl,
tp,
comment);
//
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,
mSlippage,
comment);
if (result)
{
RemoveSignal(ticket);
}
//
return result;
}
//
// Close Partial By Ticket ...
bool ClosePartial(
ulong ticket, // Position Ticket
double volume, // Volume Size for Partial Closing
string comment = "" // Close Position By Specific Comment
)
{
//
bool result = false;
//
if (!mPositionInfo.SelectByTicket(ticket))
{
return result;
}
//
result = mTrader.PositionClosePartial(
ticket,
volume,
mSlippage,
comment);
//
return result;
}
//
// END Actions ...
//
//
// START Account Related ...
//
//
// Check Account Has Minimum Balance For Trade ...
bool IsBalanceReadyForTrade()
{
//
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;
}
//
// Check Equity Has Enough For Trade ...
bool IsEquityReadyForTrade()
{
//
bool result = false;
//
double equity = mAccountInfo.GetEquity();
//
result = equity >= mMinAllowedFreeMarginForOpenTrades;
//
return result;
}
//
// END Account Related ...
//
//
// START Signal Related ...
//
//
// Validate Signal ...
bool IsValidSignal(
XSignal &signal // Specified 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;
}
//
// Get Signal InDirection (Reversal) Type ...
ENUM_X_SIGNAL_TYPE GetSignalIndirectionType(
XSignal &signal // Specified Signal
)
{
//
ENUM_X_SIGNAL_TYPE result = X_SIGNAL_UNKNOWN;
//
switch (signal.type)
{
//
case X_SIGNAL_LONG:
result = X_SIGNAL_SHORT;
break;
//
case X_SIGNAL_SHORT:
result = X_SIGNAL_LONG;
break;
}
//
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 // Specified 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;
}
//
// 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 riskFreeStep = 0, // Risk Free Step Price
double riskFreeRate = 0 // Risk Free Rate
)
{
//
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);
//
result.tp = tp;
result.sl = sl;
result.type = type;
result.entry = entry;
result.symbol = mSymbol;
result.magicNumber = mMagicNumber;
result.riskFreeStep = riskFreeStep;
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 = GenerateSignalComment(result);
//
return result;
}
//
// Generate Comments for Specific Signal ...
string GenerateSignalComment(
ENUM_X_SIGNAL_TYPE type, // Specify Kind Signal Type
double volume // Signal Volume
)
{
//
string result = "";
//
string typeStr = GetSignalType(type);
if (
volume <= 0 ||
StringLen(typeStr) == 0)
{
return result;
}
//
volume = NormalizeVolume(volume, mSymbol);
//
result = mTag + "_" + typeStr;
//
return result;
}
string GenerateSignalComment(
XSignal &signal // Specified Signal
)
{
//
string result = GenerateSignalComment(
signal.type,
signal.volume
//
);
//
return result;
}
//
// Generate Signal RF TP Comment ...
string GenerateSignalRFComment(
XSignal &signal, // Specified Signal
int level // Which Step of RFS
)
{
//
string result = "";
//
// Validate Signal and it's Ticket ...
if (!IsValidSignal(signal) || signal.ticket <= 0)
{
return result;
}
//
double exit = GetExit(signal.symbol, signal.type);
//
result =
//
X_SIGNAL_RISKFREE_STEP + "(" + (string)signal.ticket + ")_" + (string)level + ": " + string(exit);
//
;
//
return result;
}
//
// Generate Signal TP Comment ...
string GenerateSignalTPComment(
XSignal &signal // Specified Signal
)
{
//
string result = "";
//
// Validate Signal and it's Ticket ...
if (!IsValidSignal(signal) || signal.ticket <= 0)
{
return result;
}
//
double exit = GetExit(signal.symbol, signal.type);
//
result =
//
X_SIGNAL_TP + "(" + (string)signal.ticket + "): " + string(exit);
//
;
//
return result;
}
//
// Generate Signal SL Comment ...
string GenerateSignalSLComment(
XSignal &signal // Specified Signal
)
{
//
string result = "";
//
// Validate Signal and it's Ticket ...
if (!IsValidSignal(signal) || signal.ticket <= 0)
{
return result;
}
//
double exit = GetExit(signal.symbol, signal.type);
//
result =
//
X_SIGNAL_SL + "(" + (string)signal.ticket + "): " + string(exit);
//
;
//
return result;
}
//
// Generate Signal Profit Comment ...
string GenerateSignalProfitComment(
XSignal &signal // Specified Signal
)
{
//
string result = "";
//
// Validate Signal and it's Ticket ...
if (!IsValidSignal(signal) || signal.ticket <= 0)
{
return result;
}
//
result =
//
"Profit(" + (string)signal.ticket + "): " + string(signal.profit);
//
;
//
return result;
}
//
// Generate Signal Force Close Comment ...
string GenerateSignalForceCloseComment(
XSignal &signal // Specified Signal
)
{
//
string result = "";
//
// Validate Signal and it's Ticket ...
if (!IsValidSignal(signal) || signal.ticket <= 0)
{
return result;
}
//
result =
//
"FC(" + (string)signal.ticket + "): " + string(signal.profit);
//
;
//
return result;
}
//
// Generate Signal Age Comment ...
string GenerateSignalAgeComment(
XSignal &signal // Specified Signal
)
{
//
string result = "";
//
// Validate Signal and it's Ticket ...
if (!IsValidSignal(signal) || signal.ticket <= 0)
{
return result;
}
//
int age = GetSignalAge(signal);
//
result =
//
"(" + (string)signal.ticket + ") A: " + (string)age + ", P:" + string(signal.profit);
//
;
//
return result;
}
//
// Generate a Signal Object name for Draw Events On Chart ...
string GenerateSignalObjectName(
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 GenerateSignalObjectName(
XSignal &signal // Specified Signal
)
{
//
string result = "";
//
// Validate Arg ...
if (!IsValid(signal, mMagicNumber))
{
return result;
}
//
result = GenerateSignalObjectName(signal.ticket);
//
return result;
}
//
// Genrate a Signal Event Object Name ...
string GenerateSignalEventObjectName(
ulong ticket // Specify Ticket
)
{
//
string result = "";
//
result = GenerateSignalObjectName(ticket) + "_Event";
//
return result;
}
string GenerateSignalEventObjectName(
XSignal &signal // Specified Signal
)
{
//
string result = "";
//
result = GenerateSignalEventObjectName(signal.ticket);
//
return result;
}
//
// Convert a Signal to String Representation ...
string ToString(
XSignal &signal // Specified Signal
)
{
//
string result = "";
//
if (!IsValid(signal, mMagicNumber) || signal.ticket <= 0)
{
return result;
}
//
// TICKET ...
// it is very importants since they hold position info ...
result += X_SIGNAL_TICKET + "(" + (string)signal.ticket + ")";
//
// TYPE ...
string typeStr = GetSignalType(signal.type);
result += "_" + X_SIGNAL_TYPE + "(" + typeStr + ")";
//
// TP ...
result += "_" + X_SIGNAL_TP + "(" + (string)signal.tp + ")";
//
// SL ...
result += "_" + X_SIGNAL_SL + "(" + (string)signal.sl + ")";
//
// RFS ...
result += "_" + X_SIGNAL_RISKFREE_STEP + "(" + (string)signal.riskFreeStep + ")";
//
// RFR ...
result += "_" + X_SIGNAL_RISKFREE_RATE + "(" + (string)signal.riskFreeRate + ")";
//
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,
X_SIGNAL_TICKET + "(",
")");
if (StringLen(ticketStr) > 0)
{
result.ticket = (ulong)ticketStr;
}
//
// TYPE ...
string typeStr = ExtractString(
represent,
"_" + X_SIGNAL_TYPE + "(",
")");
if (StringLen(typeStr) > 0)
{
//
ENUM_X_SIGNAL_TYPE type = GetSignalType(typeStr);
result.type = type;
}
//
// TP ...
string tpStr = ExtractString(
represent,
"_" + X_SIGNAL_TP + "(",
")");
if (StringLen(tpStr) > 0)
{
//
double tp = (double)tpStr;
result.tp = tp;
}
//
// SL ...
string slStr = ExtractString(
represent,
"_" + X_SIGNAL_SL + "(",
")");
if (StringLen(slStr) > 0)
{
//
double sl = (double)slStr;
result.sl = sl;
}
//
// RFS ...
string rfsStr = ExtractString(
represent,
"_" + X_SIGNAL_RISKFREE_STEP + "(",
")");
if (StringLen(rfsStr) > 0)
{
//
double rfs = (double)rfsStr;
result.riskFreeStep = rfs;
}
//
// RFR ...
string rfrStr = ExtractString(
represent,
"_" + X_SIGNAL_RISKFREE_RATE + "(",
")");
if (StringLen(rfrStr) > 0)
{
//
double rfr = (double)rfrStr;
result.riskFreeRate = rfr;
}
//
return result;
}
void FromString(
XSignal &result, // Holds Result
string represent // String Represenation of a Signal
)
{
//
// Validate Arg ...
if (StringLen(represent) == 0)
{
return;
}
//
XSignal fs = FromString(represent);
//
// Fillisg Result by Retrieved Values ...
result.tp = fs.tp;
result.sl = fs.sl;
result.type = fs.type;
result.ticket = fs.ticket;
result.riskFreeStep = fs.riskFreeStep;
result.riskFreeRate = fs.riskFreeRate;
}
//
// 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;
//
// 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;
//
// START Signal Private ...
//
//
// Add Or Update Signal ...
void AddOrUpdateSignalInfo(
XSignal &signal // Specified Signal
)
{
//
string name = GenerateSignalEventObjectName(signal);
//
bool isExists = IsDrawExists(name);
if (isExists)
{
RemoveSignal(signal.ticket);
}
//
DrawSignalEvent(signal);
}
//
// Retrieve Signal String From Chart Event ...
string RetrieveSignalContent(
ulong ticket, // Specify Position Ticket
int chartId = -1, // Specify Chart ID
int subWindow = -1 // Specify SubWindow ID
)
{
//
string result = "";
//
// Normalize Chart and SubWindow ID ...
if (chartId == -1)
{
chartId = 0;
}
if (subWindow == -1)
{
subWindow = 0;
}
//
// Validate Args ...
if (ticket <= 0)
{
return result;
}
//
// Get Signal Event Name ...
string sObjName = GenerateSignalEventObjectName(ticket);
if (StringLen(sObjName) == 0)
{
return result;
}
//
// Check Signal Event Exists ...
bool isExists = IsDrawExists(sObjName);
if (!isExists)
{
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,
sObjName);
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;
}
XSignal RetrieveSignal(
ulong ticket // Specify Position Ticket
)
{
//
XSignal result = {};
//
if (ticket <= 0)
{
return result;
}
//
string signalContent = RetrieveSignalContent(ticket);
result = FromString(
signalContent);
//
return result;
}
void RetrieveSignal(
XSignal &signal // Specified Signal
)
{
//
string signalContent = RetrieveSignalContent(signal.ticket);
//
FromString(
signal,
signalContent);
}
//
// 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 = GenerateSignalEventObjectName(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);
}
}
//
// 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 = GenerateSignalEventObjectName(ticket);
//
// Remove Object from Chart ...
result = RemoveDraw(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;
}
//
// Converts a Position to Signal ...
//
// Convert Position to Signal by Index ...
XSignal PositionToSignal(int index)
{
//
XSignal result = {};
//
if (!mPositionInfo.SelectByIndex(index))
{
return result;
}
//
ulong ticket = mPositionInfo.Ticket();
result = PositionToSignal(ticket);
//
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 = result.tp <= 0 && mPositionInfo.TakeProfit() > 0
? mPositionInfo.TakeProfit()
: result.tp;
//
// Stop Loss ...
result.sl = result.sl <= 0 && mPositionInfo.StopLoss() > 0
? mPositionInfo.StopLoss()
: result.sl;
//
// Profit ...
result.profit = mPositionInfo.Profit();
//
// Time ...
result.time = mPositionInfo.Time();
//
// Volume ...
result.volume = mPositionInfo.Volume();
//
// Comment ...
result.comment = mPositionInfo.Comment();
//
return result;
}
//
// END Signal Private ...
//
};
//
// END Global Definitions: Variables, Properties and etc ...
//