Files
xMQL5/MQLTestWorkspace/X121/Old/Classes/x-saherelm.xtrade.class.mq5
T
2024-05-01 14:46:50 +03:30

4194 lines
96 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// ----------------------------------------------
// Name: XSCTrade
// Description: provides all Trade requirements ...
//
//
// Maintainer:
// ------------
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
//
//////////////////////////////////////////////////////
//
// Global Properties ...
#property library
#property copyright "Copyright 2023, SaherElm IT Center"
#property link "https://www.saherelm.ir"
#property version "1.00"
#property strict
//
// START Definitions ...
//
//
// Model an Open Position ...
struct XPosition
{
//
// Magic Number ...
ulong magic;
//
// Ticket ID ...
ulong ticket;
//
// Tradinng Symbol ...
string symbol;
//
// Trading Period ...
ENUM_TIMEFRAMES period;
//
// Position Type ...
ENUM_POSITION_TYPE type;
//
// Take Profit ...
double tp;
//
// Stop Loss ...
double sl;
//
// Position Current Profit ...
double profit;
//
// Position Open Price ...
double entry;
//
// Current Symbol Price ...
double price;
//
// Position Swap ...
double swap;
//
// Position Commission ...
double commission;
//
// Volume ...
double volume;
//
// Position Open Time ...
datetime openAt;
//
// Position Comment ...
string comment;
};
//
// Model an Order ...
struct XOrder
{
//
// Time of order placement ...
datetime setupAt;
//
// Time of order expiration ...
datetime expiredAt;
//
// Time of order execution or cancellation ...
datetime executedAt;
//
// Order type ...
ENUM_ORDER_TYPE type;
//
// Order state ...
ENUM_ORDER_STATE state;
//
// Type of execution by remainder ...
ENUM_ORDER_TYPE_FILLING filling;
//
// Order lifetime ...
ENUM_ORDER_TYPE_TIME lifetime;
//
// Order ticket ...
ulong ticket;
//
// Magic Number ...
long magic;
//
// Position id, that is placed on order,
// when it is executed. Each executed order invokes a
// deal, that opens new or changes existing
// position. Id of that position is placed on
// executed order in this moment.
long pocitionID;
//
// Initial volume on order placement ...
double initialVolume;
//
// Unfilled volume ...
double currentVolume;
//
// Price, specified in the order ...
double openPrice;
//
// Current price by order symbol ...
double currentPrice;
//
// Price of placing Limit order when StopLimit order is triggered ...
double stopLimitPrice;
//
// Take Profit level ...
double tp;
//
// Stop Loss level ...
double sl;
//
// Trading Symbol ...
string smybol;
//
// Order Comment ...
string comment;
//
ENUM_TIMEFRAMES period;
};
//
// Model a Deal ...
struct XDeal
{
//
// the ID of the Expert Advisor, that executed the deal ...
ulong magic;
//
// the ID of position, in which the deal was involved ...
ulong positionId;
//
// Ticket ...
ulong ticket;
//
// the name of the deal symbol ...
string symbol;
//
// order by which the deal is executed ...
ulong order;
//
// the time of deal execution ...
datetime time;
//
// Deal price ...
double price;
//
// the financial result of the deal (in deposit currency) ...
double profit;
//
// the amount of swap when position is closed ...
double swap;
//
// the amount of commission of the deal ...
double commission;
//
// the volume of deal ...
double volume;
//
// the deal comment ...
string comment;
//
// the deal type ...
// ------------------------------------------------------------------
// DEAL_TYPE_BUY => Buy ...
// DEAL_TYPE_SELL => Sell ...
// DEAL_TYPE_BUY_CANCELED => Canceled buy deal ...
// There can be a situation when a previously executed buy deal is canceled. In this case,
// the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED,
// and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ...
//
// DEAL_TYPE_SELL_CANCELED => Canceled sell deal ...
// There can be a situation when a previously executed sell deal is canceled. In this case,
// the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED,
// and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation
//
// DEAL_TYPE_BALANCE => Balance ...
// DEAL_TYPE_CREDIT => Credit ...
// DEAL_TYPE_CHARGE => Additional charge ...
// DEAL_TYPE_CORRECTION => Correction ...
// DEAL_TAX => Tax charges ...
// DEAL_TYPE_BONUS => Bonus ...
// DEAL_TYPE_INTEREST => Interest rate ...
// DEAL_DIVIDEND => Dividend operations...
// DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ...
// DEAL_TYPE_COMMISSION => Additional commission ...
// DEAL_TYPE_COMMISSION_DAILY => Daily commission ...
// DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ...
// DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ...
// DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission
ENUM_DEAL_TYPE type;
//
// the deal direction ...
// ----------------------------------
// DEAL_ENTRY_IN => Entry in ...
// DEAL_ENTRY_OUT => Entry out ...
// DEAL_ENTRY_INOUT => Reverse ...
// DEAL_ENTRY_OUT_BY => Close a position by an opposite one ...
ENUM_DEAL_ENTRY entry;
//
// deal reson ...
// ---------------------
// DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ...
// DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ...
// DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ...
// DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ...
// DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ...
// DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ...
// DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ...
// DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ...
// DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ...
// DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ...
ENUM_DEAL_REASON reason;
};
//
// Model a Position with all of it's Supports ...
struct XPositionPack
{
//
ulong ticket;
//
XPosition position;
//
int supportOrdersCount;
int supportPositionsCount;
//
XOrder supportOrders[];
XPosition supportPositions[];
};
//
// Model OnTrade Event Handler Result on XCTrade Class ...
struct XOnTradeHandlerState
{
//
bool hasNewDeal;
int newDeals;
//
bool hasNewOrder;
int newOrders;
//
bool hasNewPosition;
int newPositions;
//
bool hasNewHistoryOrder;
int newHistoryOrders;
};
//
typedef void (*TOnDealsChanged)(int count);
//
typedef void (*TOnOrdersChanged)(int count);
//
typedef void (*TOnPositionsChanged)(int count);
//
typedef void (*TOnStopLoss)(const XDeal &deal);
typedef void (*TOnTakeProfit)(const XDeal &deal);
//
typedef void (*TOnTradeStateChanged)(const XOnTradeHandlerState &state);
//
// END Definitions ...
//
//
// START Import and Inclused requirements ...
//
//
// Includes ...
#include <Trade/Trade.mqh>
#include "../Libraries/x-saherelm.log.lib.mq5"
#include "../Libraries/x-saherelm.common.lib.mq5"
#include "../Libraries/x-saherelm.seriallizer.lib.mq5"
//
// END Import and Inclused requirements ...
//
//
// START Overrides ...
//
//
// XCTrade Base Class ...
class XSCTradeBase : 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 ...
//
//
// a Class for Manage Trades ...
class XSCTrade
{
//
// Public ...
public:
//
// Constructor ...
void XSCTrade(
int slippage, // Specify Slippage
ulong magicNumber // Specify Magic Number
)
{
//
mSlippage = slippage;
mMagicNumber = magicNumber;
//
mPeriodPrefix = "PR";
//
mTrader = new XSCTradeBase();
//
mTrader.SetAsyncMode(false);
mTrader.SetDeviationInPoints(mSlippage);
mTrader.SetExpertMagicNumber(mMagicNumber);
//
// Setting Log Level ...
mTrader.LogLevel(LOG_LEVEL_ERRORS);
//
// Prepare Trade Event Materials ...
//
mDaysForRead = 1;
mScanStarted = false;
//
// Reset On Trade Counter ...
ResetOnTradeContext();
//
// Init On Trade Context ...
InitOnTradeContext();
}
//
// Deconstructor ...
void ~XSCTrade()
{
}
//
// START Event Processing ...
//
//
// This Must be Called Every time OnTrade Event Happening ...
XOnTradeHandlerState HandleOnTrade()
{
//
// Handle OnTrade Event ...
XOnTradeHandlerState state = {};
HandleOnTradeEvent(state);
if (
!state.hasNewDeal &&
!state.hasNewOrder &&
!state.hasNewPosition &&
!state.hasNewHistoryOrder)
{
return state;
}
//
// STATE ...
//
// Notfy Trade State Changed Event ...
NotifyTradeStateChangeEvent(state);
//
// DEALS ...
if (state.hasNewDeal)
{
//
// Notfy Deals Changed Event ...
NotifyDealsChangeEvent(state.newDeals);
//
// Retrieve Last Deal ...
XDeal deals[];
GetDeals(deals);
int dealsCount = ArraySize(deals);
if (dealsCount > 0)
{
//
XDeal lastDeal = deals[0];
//
if (lastDeal.reason == DEAL_REASON_TP)
{
NotifyTakeProfitEvent(lastDeal);
}
else if (lastDeal.reason == DEAL_REASON_SL)
{
NotifyStopLossEvent(lastDeal);
}
}
}
//
// ORDERS ...
if (state.hasNewOrder || state.hasNewHistoryOrder)
{
//
// Notfy Orders Changed Event ...
NotifyOrdersChangeEvent(state.newOrders + state.newHistoryOrders);
}
//
// POSITIONS ...
if (state.hasNewPosition)
{
//
// Notfy Positions Changed Event ...
NotifyPositionsChangeEvent(state.newPositions);
}
//
return state;
}
//
// Process On Trade Requirement
void HandleOnTradeEvent(
XOnTradeHandlerState &result // Hold's Result
)
{
//
if (mScanStarted)
{
ProcessOnTradeContext(result);
}
else
{
InitOnTradeContext();
}
}
//
// Event Emitters ...
//
// STATE Changed ...
//
// Clear Trade State Changed Event Handlers ...
void ClearOnTradeStateChangedEventHandlers()
{
//
ArrayFree(mTradeStateChangedEventHandlers);
//
ArrayResize(mTradeStateChangedEventHandlers, 0);
}
//
// Add New Deals Changed Event Handler ...
void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler)
{
//
ArrayResize(
mTradeStateChangedEventHandlers,
ArraySize(mTradeStateChangedEventHandlers) + 1);
//
mTradeStateChangedEventHandlers[ArraySize(mTradeStateChangedEventHandlers) - 1] = handler;
}
//
// DEALS ...
//
// Clear Deals Changed Event Handlers ...
void ClearOnDealsChangedEventHandlers()
{
//
ArrayFree(mDealsChangedEventHandlers);
//
ArrayResize(mDealsChangedEventHandlers, 0);
}
//
// Add New Deals Changed Event Handler ...
void AddOnDealsChangedEventHandler(TOnDealsChanged handler)
{
//
ArrayResize(
mDealsChangedEventHandlers,
ArraySize(mDealsChangedEventHandlers) + 1);
//
mDealsChangedEventHandlers[ArraySize(mDealsChangedEventHandlers) - 1] = handler;
}
//
// ORDERS ...
//
// Clear Orders Changed Event Handlers ...
void ClearOnOrdersChangedEventHandlers()
{
//
ArrayFree(mOrdersChangedEventHandlers);
//
ArrayResize(mOrdersChangedEventHandlers, 0);
}
//
// Add New Orders Changed Event Handler ...
void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler)
{
//
ArrayResize(
mOrdersChangedEventHandlers,
ArraySize(mOrdersChangedEventHandlers) + 1);
//
mOrdersChangedEventHandlers[ArraySize(mOrdersChangedEventHandlers) - 1] = handler;
}
//
// POSITIONS ...
//
// Clear Positions Changed Event Handlers ...
void ClearOnPositionsChangedEventHandlers()
{
//
ArrayFree(mPositionsChangedEventHandlers);
//
ArrayResize(mPositionsChangedEventHandlers, 0);
}
//
// Add New Positions Changed Event Handler ...
void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler)
{
//
ArrayResize(
mPositionsChangedEventHandlers,
ArraySize(mPositionsChangedEventHandlers) + 1);
//
mPositionsChangedEventHandlers[ArraySize(mPositionsChangedEventHandlers) - 1] = handler;
}
//
// TPSL ...
//
// Clear Stop Loss Event Handlers ...
void ClearOnStopLossEventHandlers()
{
//
ArrayFree(mStopLossEventHandlers);
//
ArrayResize(mStopLossEventHandlers, 0);
}
//
// Add New Stop Loss Event Handler ...
void AddOnStopLossEventHandler(TOnStopLoss handler)
{
//
ArrayResize(
mStopLossEventHandlers,
ArraySize(mStopLossEventHandlers) + 1);
//
mStopLossEventHandlers[ArraySize(mStopLossEventHandlers) - 1] = handler;
}
//
// Clear Take Profit Event Handlers ...
void ClearOnTakeProfitEventHandlers()
{
//
ArrayFree(mTakeProfitEventHandlers);
//
ArrayResize(mTakeProfitEventHandlers, 0);
}
//
// Add New Stop Loss Event Handler ...
void AddOnTakeProfitEventHandler(TOnTakeProfit handler)
{
//
ArrayResize(
mTakeProfitEventHandlers,
ArraySize(mTakeProfitEventHandlers) + 1);
//
mTakeProfitEventHandlers[ArraySize(mTakeProfitEventHandlers) - 1] = handler;
}
//
// END Event Processing ...
//
//
// START Provided Functions ...
//
//
// Count Currently Open Positions ...
int CountPositions(
string symbol = "", // Specified Symbol
ENUM_POSITION_TYPE type = NULL // Specified Type
)
{
//
int result = 0;
//
int allPositions = 0;
int longPositions = 0;
int shortPositions = 0;
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
string positionSymbol = mPositionInfo.Symbol();
//
ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType();
//
if (
type == NULL &&
StringLen(symbol) <= 0)
{
//
allPositions++;
//
continue;
}
else if (
type != NULL &&
StringLen(symbol) > 0)
{
//
if (type == positionType &&
symbol == positionSymbol)
{
//
if (type == POSITION_TYPE_BUY)
{
longPositions++;
}
else
{
shortPositions++;
}
//
continue;
}
}
else if (StringLen(symbol) > 0)
{
//
if (positionSymbol == symbol)
{
//
allPositions++;
//
continue;
}
}
else if (type != NULL)
{
//
if (type == positionType)
{
//
if (type == POSITION_TYPE_BUY)
{
longPositions++;
}
else
{
shortPositions++;
}
//
continue;
}
}
}
//
// Specify Result ...
if (
type == NULL &&
StringLen(symbol) <= 0)
{
//
result = allPositions;
}
else if (
type != NULL &&
StringLen(symbol) > 0)
{
//
if (type == POSITION_TYPE_BUY)
{
result = longPositions;
}
else
{
result = shortPositions++;
}
}
else if (StringLen(symbol) > 0)
{
//
result = allPositions;
}
else if (type != NULL)
{
//
if (type == POSITION_TYPE_BUY)
{
result = longPositions;
}
else
{
result = shortPositions;
}
}
//
return result;
}
//
// Retrieve Max In Profit Position Ticket ...
ulong GetMaxInProfitPosition(
string symbol = "", // Specified Symbol
ENUM_POSITION_TYPE type = NULL // Specified Type
)
{
//
ulong result = -1;
//
double profit = 0;
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
ulong positionTicket = mPositionInfo.Ticket();
//
string positionSymbol = mPositionInfo.Symbol();
//
double positionProfit = mPositionInfo.Profit();
double positionAbsProfit = MathAbs(positionProfit);
if (positionProfit <= 0)
{
continue;
}
//
ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType();
//
if (
type == NULL &&
StringLen(symbol) <= 0)
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
//
continue;
}
else if (
type != NULL &&
StringLen(symbol) > 0)
{
//
if (type == positionType &&
symbol == positionSymbol)
{
//
if (type == POSITION_TYPE_BUY)
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
}
else
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
}
//
continue;
}
}
else if (StringLen(symbol) > 0)
{
//
if (positionSymbol == symbol)
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
//
continue;
}
}
else if (type != NULL)
{
//
if (type == positionType)
{
//
if (type == POSITION_TYPE_BUY)
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
}
else
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
}
//
continue;
}
}
}
//
return result;
}
//
// Retrieve Max In DrawDown Position Ticket ...
ulong GetMaxInDrawDownPosition(
string symbol = "", // Specified Symbol
ENUM_POSITION_TYPE type = NULL // Specified Type
)
{
//
ulong result = -1;
//
double profit = 0;
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
ulong positionTicket = mPositionInfo.Ticket();
//
string positionSymbol = mPositionInfo.Symbol();
//
double positionProfit = mPositionInfo.Profit();
double positionAbsProfit = MathAbs(positionProfit);
if (positionProfit >= 0)
{
continue;
}
//
ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType();
//
if (
type == NULL &&
StringLen(symbol) <= 0)
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
//
continue;
}
else if (
type != NULL &&
StringLen(symbol) > 0)
{
//
if (type == positionType &&
symbol == positionSymbol)
{
//
if (type == POSITION_TYPE_BUY)
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
}
else
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
}
//
continue;
}
}
else if (StringLen(symbol) > 0)
{
//
if (positionSymbol == symbol)
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
//
continue;
}
}
else if (type != NULL)
{
//
if (type == positionType)
{
//
if (type == POSITION_TYPE_BUY)
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
}
else
{
//
if (profit < positionAbsProfit)
{
//
result = positionTicket;
profit = positionAbsProfit;
}
}
//
continue;
}
}
}
//
return result;
}
//
// Retrieve Specific Position's Profit ...
double GetPositionProfit(
const ulong ticket // Specified Position Ticket
)
{
//
double result = 0;
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
ulong positionTicket = mPositionInfo.Ticket();
if (positionTicket != ticket)
{
continue;
}
//
result = mPositionInfo.Profit();
break;
}
//
return result;
}
//
// Retrieve Specific Position's OpenDate ...
datetime GetPositionOpenDate(
const ulong ticket // Specified Position Ticket
)
{
//
datetime result = 0;
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
ulong positionTicket = mPositionInfo.Ticket();
if (positionTicket != ticket)
{
continue;
}
//
result = mPositionInfo.Time();
break;
}
//
return result;
}
//
// Retrieve Specific Position's Comment ...
string GetPositionComment(
const ulong ticket // Specified Position Ticket
)
{
//
string result = "";
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
ulong positionTicket = mPositionInfo.Ticket();
if (positionTicket != ticket)
{
continue;
}
//
result = mPositionInfo.Comment();
break;
}
//
return result;
}
//
// Retrieve All Open Positions Profit ...
double GetPositionsProfit(
string symbol = "", // Specified Symbol
ENUM_POSITION_TYPE type = NULL // Specified Type
)
{
//
double result = 0;
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
ulong positionTicket = mPositionInfo.Ticket();
//
string positionSymbol = mPositionInfo.Symbol();
//
double positionProfit = mPositionInfo.Profit();
//
ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType();
//
if (
type == NULL &&
StringLen(symbol) <= 0)
{
//
result += positionProfit;
//
continue;
}
else if (
type != NULL &&
StringLen(symbol) > 0)
{
//
if (type == positionType &&
symbol == positionSymbol)
{
//
if (type == POSITION_TYPE_BUY)
{
result += positionProfit;
}
else
{
result += positionProfit;
}
//
continue;
}
}
else if (StringLen(symbol) > 0)
{
//
if (positionSymbol == symbol)
{
result += positionProfit;
//
continue;
}
}
else if (type != NULL)
{
//
if (type == positionType)
{
//
if (type == POSITION_TYPE_BUY)
{
result += positionProfit;
}
else
{
result += positionProfit;
}
//
continue;
}
}
}
//
return result;
}
//
// Find Oldes Position ...
ulong GetOldestPosition(
string symbol = "", // Specified Symbol
ENUM_POSITION_TYPE type = NULL // Specified Type
)
{
//
ulong result = 0;
//
int age = 0;
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
ulong positionTicket = mPositionInfo.Ticket();
//
string positionSymbol = mPositionInfo.Symbol();
//
double positionProfit = mPositionInfo.Profit();
double positionAbsProfit = MathAbs(positionProfit);
if (positionProfit >= 0)
{
continue;
}
//
ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType();
//
string positionComment = mPositionInfo.Comment();
ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(positionComment);
//
// Calculate Position's Age ...
datetime positionOpenTime = mPositionInfo.Time();
//
// Retrieve Trade Open Bar Index based on Current Period ...
int positionOpenBarIndex = iBarShift(
positionSymbol,
positionPeriod,
positionOpenTime);
//
// Calculate Trade Life ...
int positionAge = MathAbs(0 - positionOpenBarIndex);
//
if (
type == NULL &&
StringLen(symbol) <= 0)
{
//
if (age < positionAge)
{
//
age = positionAge;
result = positionTicket;
}
//
continue;
}
else if (
type != NULL &&
StringLen(symbol) > 0)
{
//
if (type == positionType &&
symbol == positionSymbol)
{
//
if (type == POSITION_TYPE_BUY)
{
//
if (age < positionAge)
{
//
age = positionAge;
result = positionTicket;
}
}
else
{
//
if (age < positionAge)
{
//
age = positionAge;
result = positionTicket;
}
}
//
continue;
}
}
else if (StringLen(symbol) > 0)
{
//
if (positionSymbol == symbol)
{
//
if (age < positionAge)
{
//
age = positionAge;
result = positionTicket;
}
//
continue;
}
}
else if (type != NULL)
{
//
if (type == positionType)
{
//
if (type == POSITION_TYPE_BUY)
{
//
if (age < positionAge)
{
//
age = positionAge;
result = positionTicket;
}
}
else
{
//
if (age < positionAge)
{
//
age = positionAge;
result = positionTicket;
}
}
//
continue;
}
}
}
//
return result;
}
//
// Force Open a Buy/Long Position ...
bool Buy(
string symbol, // Specified Symbol
ENUM_TIMEFRAMES period, // Specified Trade's Period
double volume, // position volume
double price, // execution price
double sl = 0, // stop loss price
double tp = 0, // take profit price
string comment = "" // comment
)
{
//
bool result = false;
//
string mPeriodStr = GeneratePositionPeriodComment(period);
//
comment += mPeriodStr;
//
result = mTrader.Buy(
volume,
symbol,
price,
sl,
tp,
comment);
//
return result;
}
//
// Send BUY LIMIT order ...
bool BuyLimit(
string symbol, // Specified Symbol
ENUM_TIMEFRAMES period, // Specified Trade's Period
double volume, // order volume
double price, // order price
double sl = 0.0, // stop loss price
double tp = 0.0, // take profit price
ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime
datetime expiration = 0, // order expiration time
string comment = "" // comment
)
{
//
bool result = false;
//
string mPeriodStr = GeneratePositionPeriodComment(period);
//
comment += mPeriodStr;
//
result = mTrader.BuyLimit(
volume,
price,
symbol,
sl,
tp,
typeTime,
expiration,
comment);
//
return result;
}
//
// Send BUY STOP order ...
bool BuyStop(
string symbol, // Specified Symbol
ENUM_TIMEFRAMES period, // Specified Trade's Period
double volume, // order volume
double price, // order price
double sl = 0.0, // stop loss price
double tp = 0.0, // take profit price
ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime
datetime expiration = 0, // order expiration time
string comment = "" // comment
)
{
//
bool result = false;
//
string mPeriodStr = GeneratePositionPeriodComment(period);
//
comment += mPeriodStr;
//
result = mTrader.BuyStop(
volume,
price,
symbol,
sl,
tp,
typeTime,
expiration,
comment);
//
return result;
}
//
// Force Open a Sell/Short Position ...
bool Sell(
string symbol, // Specified Symbol
ENUM_TIMEFRAMES period, // Specified Trade's Period
double volume, // position volume
double price, // execution price
double sl = 0, // stop loss price
double tp = 0, // take profit price
string comment = "" // comment
)
{
//
bool result = false;
//
string mPeriodStr = GeneratePositionPeriodComment(period);
//
comment += mPeriodStr;
//
result = mTrader.Sell(
volume,
symbol,
price,
sl,
tp,
comment);
//
return result;
}
//
// Send SELL LIMIT order ...
bool SellLimit(
string symbol, // Specified Symbol
ENUM_TIMEFRAMES period, // Specified Trade's Period
double volume, // order volume
double price, // order price
double sl = 0.0, // stop loss price
double tp = 0.0, // take profit price
ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime
datetime expiration = 0, // order expiration time
string comment = "" // comment
)
{
//
bool result = false;
//
string mPeriodStr = GeneratePositionPeriodComment(period);
//
comment += mPeriodStr;
//
result = mTrader.SellLimit(
volume,
price,
symbol,
sl,
tp,
typeTime,
expiration,
comment);
//
return result;
}
//
// Send SELL STOP order ...
bool SellStop(
string symbol, // Specified Symbol
ENUM_TIMEFRAMES period, // Specified Trade's Period
double volume, // order volume
double price, // order price
double sl = 0.0, // stop loss price
double tp = 0.0, // take profit price
ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime
datetime expiration = 0, // order expiration time
string comment = "" // comment
)
{
//
bool result = false;
//
string mPeriodStr = GeneratePositionPeriodComment(period);
//
comment += mPeriodStr;
//
result = mTrader.SellStop(
volume,
price,
symbol,
sl,
tp,
typeTime,
expiration,
comment);
//
return result;
}
//
// Modify Position ...
bool Modify(
const ulong ticket, // position ticket
double sl = 0, // stop loss price
double tp = 0, // take profit
string comment = "" // comment
)
{
//
bool result = false;
//
// Validate Args ...
if (tp <= 0 && sl <= 0)
{
result = false;
return result;
}
//
// Use Position Comment when there isn't new One ...
if (StringLen(comment) == 0)
{
comment = GetPositionComment(ticket);
}
//
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);
//
return result;
}
//
// Close All Positions ...
void CloseAllPositions(
string comment = "" // Close Position By Specific Comment
)
{
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
ulong positionTicket = mPositionInfo.Ticket();
Close(
positionTicket,
comment);
}
}
//
// 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;
}
//
// Find Position Open Bar Index ...
int GetPositionOpenBarIndex(
const ulong ticket // position ticket
)
{
//
int result = -1;
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
ulong positionTicket = mPositionInfo.Ticket();
if (positionTicket != ticket)
{
continue;
}
//
string symbol = mPositionInfo.Symbol();
datetime openAt = mPositionInfo.Time();
string comment = mPositionInfo.Comment();
ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment);
//
result = iBarShift(
symbol,
period,
openAt);
}
//
return result;
}
//
bool GetPosition(
XPosition &position, // Holds result ...
ulong ticket // Required Position Ticket ...
)
{
//
bool result = false;
//
XPosition positions[];
GetPositions(positions);
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
result = iPosition.ticket == ticket;
if (!result)
{
continue;
}
//
position = iPosition;
break;
}
//
return result;
}
//
// Retrieve Positions as an Array ...
void GetPositions(
XPosition &result[] // Hold Result ...
)
{
//
Clean(result);
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
if (!mPositionInfo.SelectByIndex(i))
{
continue;
}
//
if (mPositionInfo.Magic() != mMagicNumber)
{
continue;
}
//
ulong magic = mPositionInfo.Magic();
ulong ticket = mPositionInfo.Ticket();
string symbol = mPositionInfo.Symbol();
datetime openAt = mPositionInfo.Time();
double swap = mPositionInfo.Swap();
double sl = mPositionInfo.StopLoss();
double tp = mPositionInfo.TakeProfit();
double profit = mPositionInfo.Profit();
double volume = mPositionInfo.Volume();
string comment = mPositionInfo.Comment();
double entry = mPositionInfo.PriceOpen();
double price = mPositionInfo.PriceCurrent();
double commission = mPositionInfo.Commission();
ENUM_POSITION_TYPE type = mPositionInfo.PositionType();
ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment);
//
XPosition iPosition = {};
//
iPosition.tp = tp;
iPosition.sl = sl;
iPosition.swap = swap;
iPosition.type = type;
iPosition.magic = magic;
iPosition.entry = entry;
iPosition.price = price;
iPosition.ticket = ticket;
iPosition.symbol = symbol;
iPosition.period = period;
iPosition.volume = volume;
iPosition.openAt = openAt;
iPosition.profit = profit;
iPosition.comment = comment;
iPosition.commission = commission;
//
Add(
iPosition,
result);
}
}
//
void GetPositions(
XPosition &result[], // Hold Result ...
string symbol, // Trading Symbol ...
ENUM_TIMEFRAMES period // Trading Period ...
)
{
//
Clean(result);
//
bool hasPeriod = period != NULL;
bool hasSymbol = symbol != NULL && StringLen(symbol) > 0;
//
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return;
}
//
XPosition allPositions[];
GetPositions(allPositions);
//
if (!hasPeriod && !hasSymbol)
{
//
Copy(
allPositions,
result);
//
return;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = allPositions[i];
//
if (hasSymbol &&
symbol != iPosition.symbol)
{
continue;
}
//
ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(iPosition.comment);
if (hasPeriod &&
period != positionPeriod)
{
continue;
}
//
Add(
iPosition,
result);
}
}
//
// Execute a Signal ...
bool ExecuteSignal(
XSignal &signal, // Signal ...
string comment = "", // Position Comment ...
ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ...
datetime expiration = 0 // order expiration time
)
{
//
bool result = false;
//
double currentEntry = GetEntry(
signal.symbol,
signal.type);
bool isLong = IsLong(signal.type);
//
ResetLastError();
//
if (signal.mode == X_ORDER_MODE_MARKET)
{
//
// Execute MArket Orders ...
if (isLong)
{
//
result = Buy(
signal.symbol,
signal.period,
signal.volume,
signal.entry,
signal.sl,
signal.tp,
comment);
}
else
{
//
result = Sell(
signal.symbol,
signal.period,
signal.volume,
signal.entry,
signal.sl,
signal.tp,
comment);
}
}
else if (signal.mode == X_ORDER_MODE_LIMIT)
{
//
// Execute Limit Orders ...
//
// Check Conditions ...
//
// Check Price ...
result = isLong
? signal.entry < currentEntry
: signal.entry > currentEntry;
if (!result)
{
return result;
}
//
// Check Expiration Date ...
result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY)
? expiration > 0
: true;
if (!result)
{
return result;
}
//
if (isLong)
{
//
result = BuyLimit(
signal.symbol,
signal.period,
signal.volume,
signal.entry,
signal.sl,
signal.tp,
lifetime,
expiration,
comment);
}
else
{
//
result = SellLimit(
signal.symbol,
signal.period,
signal.volume,
signal.entry,
signal.sl,
signal.tp,
lifetime,
expiration,
comment);
}
}
else if (signal.mode == X_ORDER_MODE_STOP)
{
//
// Execute Stop Orders ...
//
// Check Conditions ...
//
// Check Price ...
result = isLong
? signal.entry > currentEntry
: signal.entry < currentEntry;
if (!result)
{
return result;
}
//
// Check Expiration Date ...
result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY)
? expiration > 0
: true;
if (!result)
{
return result;
}
//
if (isLong)
{
//
result = BuyStop(
signal.symbol,
signal.period,
signal.volume,
signal.entry,
signal.sl,
signal.tp,
lifetime,
expiration,
comment);
}
else
{
//
result = SellStop(
signal.symbol,
signal.period,
signal.volume,
signal.entry,
signal.sl,
signal.tp,
lifetime,
expiration,
comment);
}
}
//
if (!result)
{
LogMessage("Error: " + (string)GetLastError() + ", " + GetErrorDescription(GetLastError()));
}
else
{
//
// Retrieve Last Position Ticket ...
ulong ticket = GetLastOpenPositionTicket();
//
// Check Position have Support Signals or not ...
int supportsCount = ArraySize(signal.supports);
if (supportsCount > 0)
{
//
int executed = 0;
for (int i = 0; i < supportsCount; i++)
{
//
XSignal iSupport = signal.supports[i];
//
int supIndex = i + 1;
string iComment = GenerateSupportSignalComment(
ticket,
supIndex);
//
bool isExecuted = ExecuteSignal(
iSupport,
iComment);
if (isExecuted)
{
executed++;
}
}
//
result = executed == supportsCount;
}
}
//
return result;
}
//
// Execute a Collection of Signals ...
int ExecuteSignals(
const XSignal &signals[], // an Array of Signals ...
string comment = "", // Position Comment ...
ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ...
datetime expiration = 0 // order expiration time
)
{
//
int result = 0;
//
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return result;
}
//
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
if (StringLen(comment) == 0)
{
comment = GenerateProvidersString(iSignal);
}
//
bool isExecuted = ExecuteSignal(
iSignal,
comment,
lifetime,
expiration);
//
if (isExecuted)
{
result++;
}
}
//
return result;
}
//
// Retrieve in Profit Positions ...
void GetInProfitPositions(
XPosition &result[] // Hold Result ...
)
{
//
Clean(result);
//
XPosition allPositions[];
GetPositions(allPositions);
int positionsCount = ArraySize(allPositions);
if (positionsCount <= 0)
{
return;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = allPositions[i];
//
if (iPosition.profit > 0)
{
Add(
iPosition,
result);
}
}
}
//
// Retrieve in Drawdown Positions ...
void GetInDrawdownPositions(
XPosition &result[] // Hold Result ...
)
{
//
Clean(result);
//
XPosition allPositions[];
GetPositions(allPositions);
int positionsCount = ArraySize(allPositions);
if (positionsCount <= 0)
{
return;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = allPositions[i];
//
if (iPosition.profit < 0)
{
Add(
iPosition,
result);
}
}
}
//
// Close a Collection Of Positions ...
int ClosePositions(
XPosition &positions[], // Positions to Close ...
string comment = "" // Specified Comment ...
)
{
//
int result = 0;
int positionsCount = ArraySize(positions);
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
bool isClosed = Close(
iPosition.ticket,
comment);
if (isClosed)
{
result++;
}
}
//
return result;
}
//
// Retrieve All Orders ...
void GetOrders(
XOrder &result[], // Holdes Result ....
string symbol, // Trading Symbol ...
ENUM_TIMEFRAMES period, // Trading TimeFrame ...
ENUM_ORDER_STATE state = NULL // Order State ...
)
{
//
Clean(result);
//
int ordersCount = OrdersTotal();
if (ordersCount <= 0)
{
return;
}
//
// Since Orders may be so more than positions ...
// start Orders Collectiong Loops reverse ...
for (int i = ordersCount - 1; i >= 0; i--)
{
//
if (!mOrderInfo.SelectByIndex(i))
{
continue;
}
//
if (mOrderInfo.Magic() != mMagicNumber)
{
continue;
}
//
// Reading Order Info ...
long magic = mOrderInfo.Magic();
double sl = mOrderInfo.StopLoss();
ulong ticket = mOrderInfo.Ticket();
double tp = mOrderInfo.TakeProfit();
string oSymbol = mOrderInfo.Symbol();
string comment = mOrderInfo.Comment();
long pocitionID = mOrderInfo.PositionId();
double openPrice = mOrderInfo.PriceOpen();
datetime setupAt = mOrderInfo.TimeSetup();
datetime executedAt = mOrderInfo.TimeDone();
ENUM_ORDER_STATE oState = mOrderInfo.State();
ENUM_ORDER_TYPE type = mOrderInfo.OrderType();
double currentPrice = mOrderInfo.PriceCurrent();
datetime expiredAt = mOrderInfo.TimeExpiration();
double initialVolume = mOrderInfo.VolumeInitial();
double currentVolume = mOrderInfo.VolumeCurrent();
double stopLimitPrice = mOrderInfo.PriceStopLimit();
ENUM_ORDER_TYPE_TIME lifetime = mOrderInfo.TypeTime();
ENUM_ORDER_TYPE_FILLING filling = mOrderInfo.TypeFilling();
//
if (StringLen(symbol) > 0 && symbol != oSymbol)
{
continue;
}
//
ENUM_TIMEFRAMES oPeriod = ExtractPositionPeriod(comment);
if (period != NULL && period != oPeriod)
{
continue;
}
//
if (state != NULL && oState != state)
{
continue;
}
//
// Now Create an instance of XOrder struct and fill it by
// retrieved data, and add it to results ...
XOrder iOrder = {};
//
iOrder.sl = sl;
iOrder.tp = tp;
iOrder.type = type;
iOrder.magic = magic;
iOrder.state = oState;
iOrder.ticket = ticket;
iOrder.smybol = oSymbol;
iOrder.period = oPeriod;
iOrder.setupAt = setupAt;
iOrder.comment = comment;
iOrder.filling = filling;
iOrder.lifetime = lifetime;
iOrder.expiredAt = expiredAt;
iOrder.openPrice = openPrice;
iOrder.pocitionID = pocitionID;
iOrder.executedAt = executedAt;
iOrder.currentPrice = currentPrice;
iOrder.initialVolume = initialVolume;
iOrder.currentVolume = currentVolume;
iOrder.stopLimitPrice = stopLimitPrice;
//
Add(
iOrder,
result);
}
}
//
int CountOrders()
{
return OrdersTotal();
}
//
// Cancel Specific Order ...
bool CancelOrder(ulong ticket)
{
return mTrader.OrderDelete(ticket);
}
//
// Cancel Specific Orders ...
bool CancelOrders(
XOrder &orders[])
{
//
bool result = false;
//
int ordersCount = ArraySize(orders);
if (ordersCount <= 0)
{
return result;
}
//
for (int i = 0; i < ordersCount; i++)
{
//
XOrder iOrder = orders[i];
//
bool isDeleted = mTrader.OrderDelete(iOrder.ticket);
if (isDeleted && !result)
{
result = isDeleted;
}
}
//
return result;
}
//
// Retrieve All Deals ...
void GetDeals(XDeal &result[])
{
//
Clean(result);
//
int dealsCount = HistoryDealsTotal();
if (dealsCount <= 0)
{
return;
}
//
for (int i = dealsCount - 1; i >= 0; i--)
{
//
if (!mDealInfo.SelectByIndex(i))
{
continue;
}
//
if (mDealInfo.Magic() != mMagicNumber)
{
continue;
}
//
// Reading Order Info ...
double swap = mDealInfo.Swap();
ulong magic = mDealInfo.Magic();
ulong order = mDealInfo.Order();
ulong ticket = mDealInfo.Ticket();
datetime time = mDealInfo.Time();
double price = mDealInfo.Price();
string symbol = mDealInfo.Symbol();
double profit = mDealInfo.Profit();
double volume = mDealInfo.Volume();
string comment = mDealInfo.Comment();
ulong positionId = mDealInfo.PositionId();
ENUM_DEAL_ENTRY entry = mDealInfo.Entry();
double commission = mDealInfo.Commission();
ENUM_DEAL_TYPE type = mDealInfo.DealType();
ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(
ticket,
DEAL_REASON);
//
XDeal iDeal = {};
//
iDeal.swap = swap;
iDeal.time = time;
iDeal.type = type;
iDeal.magic = magic;
iDeal.entry = entry;
iDeal.order = order;
iDeal.price = price;
iDeal.ticket = ticket;
iDeal.symbol = symbol;
iDeal.profit = profit;
iDeal.volume = volume;
iDeal.reason = reason;
iDeal.comment = comment;
iDeal.positionId = positionId;
iDeal.commission = commission;
//
Add(
iDeal,
result);
}
}
//
// Generate String Representation Of Position's Time Frame ...
string GeneratePositionPeriodComment(ENUM_TIMEFRAMES period)
{
//
string result = mPeriodPrefix + "(" + ToString(period) + ")";
//
return result;
}
//
// Extract Position Time Frame From it's Comment ...
ENUM_TIMEFRAMES ExtractPositionPeriod(string comment)
{
//
ENUM_TIMEFRAMES result = _Period;
//
if (StringLen(comment) <= 0)
{
return result;
}
//
string periodStr = ExtractString(
comment,
mPeriodPrefix + "(",
")");
if (StringLen(periodStr) <= 0)
{
return result;
}
//
result = ToPeriod(periodStr);
//
return result;
}
//
// Retrieve Last Open Position Ticket ...
ulong GetLastOpenPositionTicket()
{
//
ulong result = 0;
int positionsCount = PositionsTotal();
if (positionsCount <= 0)
{
return result;
}
//
result = PositionGetTicket(PositionsTotal() - 1);
//
return result;
}
//
// Retrieve Last Placed Order Ticket ...
ulong GetLastPlacedOrderTicket()
{
//
ulong result = 0;
int ordersCount = OrdersTotal();
if (ordersCount <= 0)
{
return result;
}
//
if (mOrderInfo.SelectByIndex(ordersCount - 1))
{
result = mOrderInfo.Ticket();
}
//
return result;
}
//
// SUPPORT Signals ...
//
// Retrieve a Position if Exists
// by all of it's Supported Positon/Order (s) ...
bool GetPositionPack(
ulong ticket, // Sepcified Position's Ticket
XPositionPack &pack // Hold Result ...
)
{
//
bool result = false;
//
int positionsCount = CountPositions();
int ordersCount = CountOrders();
if (ordersCount <= 0 && positionsCount <= 0)
{
return result;
}
//
XPosition position;
result = GetPosition(
position,
ticket);
if (!result)
{
return result;
}
//
XOrder supportOrders[];
XPosition supportPositions[];
//
XOrder orders[];
GetOrders(
orders,
position.symbol,
position.period,
ORDER_STATE_PLACED);
ordersCount = ArraySize(orders);
//
// Select Orders ...
if (ordersCount > 0)
{
//
for (int i = 0; i < ordersCount; i++)
{
//
XOrder iOrder = orders[i];
//
string params[];
bool hasSupport = ExtractSupportParams(
iOrder.comment,
params);
if (hasSupport)
{
//
ulong parentTicket = ExtractParentTicket(iOrder.comment);
if (parentTicket == ticket)
{
//
Add(
iOrder,
supportOrders);
}
}
}
}
//
XPosition positions[];
GetPositions(
positions,
position.symbol,
position.period);
positionsCount = ArraySize(positions);
//
// Select Positions ...
if (positionsCount > 0)
{
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
string params[];
bool hasSupport = ExtractSupportParams(
iPosition.comment,
params);
if (hasSupport)
{
//
ulong parentTicket = ExtractParentTicket(iPosition.comment);
if (parentTicket == ticket)
{
//
Add(
iPosition,
supportPositions);
}
}
}
}
//
int supportOrdersCount = ArraySize(supportOrders);
int supportPositionsCount = ArraySize(supportPositions);
//
pack.ticket = ticket;
pack.position = position;
//
Copy(supportOrders,
pack.supportOrders);
Copy(supportPositions,
pack.supportPositions);
//
pack.supportOrdersCount = supportOrdersCount;
pack.supportPositionsCount = supportPositionsCount;
//
result = true;
//
return result;
}
//
// END Provided Functions ...
//
//
// Protected ...
protected:
//
// Private ...
//
// EVENTS Handlers Notifiers ...
//
// STATE ...
void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state)
{
//
int count = ArraySize(mTradeStateChangedEventHandlers);
if (count <= 0)
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
TOnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i];
iHandler(state);
}
}
//
// DEALS ...
void NotifyDealsChangeEvent(int changes)
{
//
int count = ArraySize(mDealsChangedEventHandlers);
if (count <= 0)
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
TOnDealsChanged iHandler = mDealsChangedEventHandlers[i];
iHandler(changes);
}
}
//
// ORDERS ...
void NotifyOrdersChangeEvent(int changes)
{
//
int count = ArraySize(mOrdersChangedEventHandlers);
if (count <= 0)
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
TOnOrdersChanged iHandler = mOrdersChangedEventHandlers[i];
iHandler(changes);
}
}
//
// POSITIONS ...
void NotifyPositionsChangeEvent(int changes)
{
//
int count = ArraySize(mPositionsChangedEventHandlers);
if (count <= 0)
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
TOnPositionsChanged iHandler = mPositionsChangedEventHandlers[i];
iHandler(changes);
}
}
//
// TPSL ...
//
void NotifyStopLossEvent(const XDeal &deal)
{
//
int count = ArraySize(mStopLossEventHandlers);
if (count <= 0)
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
TOnStopLoss iHandler = mStopLossEventHandlers[i];
iHandler(deal);
}
}
//
void NotifyTakeProfitEvent(const XDeal &deal)
{
//
int count = ArraySize(mTakeProfitEventHandlers);
if (count <= 0)
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
TOnTakeProfit iHandler = mTakeProfitEventHandlers[i];
iHandler(deal);
}
}
private:
//
// using deviation, it must be in Point ...
int mSlippage;
//
// using magic number ...
ulong mMagicNumber;
//
// using CTrade instance ...
XSCTradeBase mTrader;
//
// Deals Info ...
CDealInfo mDealInfo;
//
// Order Info ...
COrderInfo mOrderInfo;
//
// using PositionInfo instance ...
CPositionInfo mPositionInfo;
//
// ADDITIONAL Data ...
//
string mPeriodPrefix;
//
// START Trade Processing ...
//
//
int mDaysForRead;
//
// set the limits of the trade history on the global scope ...
//
// // start date for trade history in cache ...
datetime mStartDate;
//
// end date for trade history in cache ...
datetime mEndDate;
//
// global OnTrade counters ...
//
// number of active orders ...
int mOrdersCount;
//
// number of open positions ...
int mPositionsCount;
//
// number of deals in the trade history cache ...
int mDealsCount;
//
// number of orders in the trade history cache ...
int mHistoryOrdersCount;
//
// flag of counter relevance ...
bool mScanStarted;
//
// Check Statrt Date In Trade History ...
void CheckStartDateInTradeHistory()
{
//
// initial interval, if we were to start working right now ..
datetime currStart = TimeCurrent() - (mDaysForRead * PeriodSeconds(PERIOD_D1));
//
// make sure that the start limit of the trade history has not gone
// more than 1 day over the intended date ...
if (currStart - mStartDate > PeriodSeconds(PERIOD_D1))
{
//
// correct the start date of history to be loaded in the cache ...
mStartDate = currStart;
//
// now reload the trade history for the updated interval ...
HistorySelect(mStartDate, mEndDate);
//
// correct the deal and order counters in history for further comparison
mHistoryOrdersCount = HistoryOrdersTotal();
mDealsCount = HistoryDealsTotal();
}
}
//
// Process On Trade Context ...
void ProcessOnTradeContext(
XOnTradeHandlerState &result // Hold's Result
)
{
//
mEndDate = TimeCurrent();
//
ResetLastError();
//
// download trading history from the specified interval to the program cache ...
bool selected = HistorySelect(mStartDate, mEndDate);
if (!selected)
{
return;
}
//
// get the current values ...
int currOrders = OrdersTotal();
int currPositions = PositionsTotal();
int currDeals = HistoryDealsTotal();
int currHistoryOrders = HistoryOrdersTotal();
//
// Orders ...
// check if the number of active orders has been changed ...
if (currOrders != mOrdersCount)
{
//
// number of active orders has been changed ...
result.hasNewOrder = true;
result.newOrders = currOrders - mOrdersCount;
//
// update the value ...
mOrdersCount = currOrders;
}
//
// Positions ...
// changes in the number of open positions ...
if (currPositions != mPositionsCount)
{
//
// number of open positions has been changed ...
result.hasNewPosition = true;
result.newPositions = currPositions - mPositionsCount;
//
// update the value ...
mPositionsCount = currPositions;
}
//
// Deals ...
// changes in the number of deals in the trade history cache ...
if (currDeals != mDealsCount)
{
//
// number of deals in the trade history cache has been changed ...
result.hasNewDeal = true;
result.newDeals = currDeals - mDealsCount;
//
// update the value ...
mDealsCount = currDeals;
}
//
// History Orders ...
// changes in the number of history orders in the trade history cache ...
if (currHistoryOrders != mHistoryOrdersCount)
{
//
// number of history orders in the trade history cache has been changed ...
result.hasNewHistoryOrder = true;
result.newHistoryOrders = currHistoryOrders - mHistoryOrdersCount;
//
// update the value ...
mHistoryOrdersCount = currHistoryOrders;
}
//
// checking if it is necessary to change the limits of the trade history to be requested in cache ...
CheckStartDateInTradeHistory();
}
//
// Reset On Trade Scanner Context ...
void ResetOnTradeContext()
{
//
mEndDate = TimeCurrent();
mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1));
}
//
// Initial Context Of Trade Scanner ...
void InitOnTradeContext()
{
//
ResetLastError();
//
mOrdersCount = OrdersTotal();
mPositionsCount = PositionsTotal();
//
// load history ...
bool selected = HistorySelect(mStartDate, mEndDate);
if (!selected)
{
return;
}
//
// get the current value ...
mDealsCount = HistoryDealsTotal();
mHistoryOrdersCount = HistoryOrdersTotal();
//
mScanStarted = true;
}
//
// Deals Changed Event Handlers ...
TOnDealsChanged mDealsChangedEventHandlers[];
//
// Orders Changed Event Handlers ...
TOnOrdersChanged mOrdersChangedEventHandlers[];
//
// Positions Changed Event Handlers ...
TOnPositionsChanged mPositionsChangedEventHandlers[];
//
// Trade State Changed Event Handlers ...
TOnTradeStateChanged mTradeStateChangedEventHandlers[];
//
// TPSL ...
TOnStopLoss mStopLossEventHandlers[];
TOnTakeProfit mTakeProfitEventHandlers[];
//
// END Trade Processing ...
//
};
//
// START Usefull Functions ...
//
//
// Add Specific XPosition to Specified Array ...
void Add(
XDeal &item,
XDeal &buffer[])
{
//
ArrayResize(
buffer,
ArraySize(buffer) + 1);
//
buffer[ArraySize(buffer) - 1] = item;
}
void Add(
XOrder &item,
XOrder &buffer[])
{
//
ArrayResize(
buffer,
ArraySize(buffer) + 1);
//
buffer[ArraySize(buffer) - 1] = item;
}
void Add(
XPosition &item,
XPosition &buffer[])
{
//
ArrayResize(
buffer,
ArraySize(buffer) + 1);
//
buffer[ArraySize(buffer) - 1] = item;
}
//
// Clear All Items Inside Array ...
void Clean(XDeal &buffer[])
{
//
ArrayFree(buffer);
ArrayResize(buffer, 0);
}
void Clean(XOrder &buffer[])
{
//
ArrayFree(buffer);
ArrayResize(buffer, 0);
}
void Clean(XPosition &buffer[])
{
//
ArrayFree(buffer);
ArrayResize(buffer, 0);
}
//
// Generate Identifier Tag ...
string GenerateTag(XSignal &info)
{
//
string result = "";
//
result = info.symbol + "," + ToString(info.period);
//
return result;
}
//
// Convert Position to Signal ...
XSignal ToSignalInfo(
XPosition &position)
{
//
XSignal result;
//
result.tp = position.tp;
result.sl = position.sl;
result.type = position.type;
result.entry = position.entry;
result.symbol = position.symbol;
result.period = position.period;
result.volume = position.volume;
//
return result;
}
//
// AGE Calculations ...
//
//
// Retrieve a Position Age ...
int GetAge(
XPosition &position, // Selected Position ...
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
)
{
//
int result = -1;
//
if (period == NULL)
{
period = _Period;
}
//
result = iBarShift(
position.symbol,
period,
position.openAt);
//
return result;
}
//
// Retrieve an Order Age ...
int GetAge(
XOrder &order, // Selected Order ...
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
)
{
//
int result = -1;
//
if (period == NULL)
{
period = _Period;
}
//
result = iBarShift(
order.smybol,
period,
order.setupAt);
//
return result;
}
//
// Retrieve a Deal Age ...
int GetAge(
XDeal &deal, // Selected Deal ...
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
)
{
//
int result = -1;
//
if (period == NULL)
{
period = _Period;
}
//
result = iBarShift(
deal.symbol,
period,
deal.time);
//
return result;
}
//
// OLDEST Detection ...
//
// Get Oldest Deal ...
int GetOldest(
XDeal &item, // Hold Result ...
XDeal &items[] // Source Array ...
)
{
//
int result = 0;
//
int itemsCount = ArraySize(items);
if (itemsCount <= 0)
{
return result;
}
//
int tmpAge = 0;
XDeal tmpItem;
for (int i = 0; i < itemsCount; i++)
{
//
XDeal iItem = items[i];
//
int iAge = GetAge(iItem);
if (iAge > 0 &&
(tmpAge == 0 || tmpAge < iAge))
{
//
tmpAge = iAge;
tmpItem = iItem;
}
}
//
if (tmpAge > 0)
{
//
result = tmpAge;
item = tmpItem;
}
//
return result;
}
//
// Get Oldest Order ...
int GetOldest(
XOrder &item, // Hold Result ...
XOrder &items[] // Source Array ...
)
{
//
int result = 0;
//
int itemsCount = ArraySize(items);
if (itemsCount <= 0)
{
return result;
}
//
int tmpAge = 0;
XOrder tmpItem;
for (int i = 0; i < itemsCount; i++)
{
//
XOrder iItem = items[i];
//
int iAge = GetAge(iItem);
if (iAge > 0 &&
(tmpAge == 0 || tmpAge < iAge))
{
//
tmpAge = iAge;
tmpItem = iItem;
}
}
//
if (tmpAge > 0)
{
//
result = tmpAge;
item = tmpItem;
}
//
return result;
}
//
// Get Oldes Position ...
int GetOldest(
XPosition &item, // Hold Result ...
XPosition &items[] // Source Array ...
)
{
//
int result = 0;
//
int itemsCount = ArraySize(items);
if (itemsCount <= 0)
{
return result;
}
//
int tmpAge = 0;
XPosition tmpItem;
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = items[i];
//
int iAge = GetAge(iItem);
if (iAge > 0 &&
(tmpAge == 0 || tmpAge < iAge))
{
//
tmpAge = iAge;
tmpItem = iItem;
}
}
//
if (tmpAge > 0)
{
//
result = tmpAge;
item = tmpItem;
}
//
return result;
}
//
// END Usefull Functions ...
//