3992 lines
89 KiB
Plaintext
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 ...
|
|
//
|