Files
xMQL5/MQLTestWorkspace/BKPS/14030322/Classes/x-saherelm.xtrade.class.mq5
T

3745 lines
88 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
//
// Imports ...
#include "../Classes/x-saherelm.base.class.mq5"
#include "../Libraries/x-saherelm.xtrade.lib.mq5"
#include "../Classes/x-saherelm.xaccount.class.mq5"
//
// Definitions ...
//
// 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));
}
};
//
// Implementation ...
//
// a Class For Manage Trades and Handle Trading Actions ...
class XSCTrade : public XSCBase
{
//
// Public ...
public:
//
// Props ...
XSCAccount *mAccount; // Account Info Provider
//
// Constructors ...
void XSCTrade(
int slippage, // Specify Slippage
ulong magicNumber, // Specify Magic Number
double maxAllowedSpread = 0, // Max Allowed Spred for Opening Trades
int maxAllowedPositions = 0, // Max Allowed Positions
double maxAllowedDrawdownFactor = 0 // Max Allowed Drawdown Factor
)
{
//
// Setting Props ...
mSlippage = slippage;
mMagicNumber = magicNumber;
//
mMaxAllowedSpread = maxAllowedSpread;
mMaxAllowedPositions = maxAllowedPositions;
mMaxAllowedDrawdownFactor = maxAllowedDrawdownFactor;
//
mAccount = new XSCAccount();
//
// Instance Base Trader Class ...
mTrader = new XSCTradeBase();
//
// Configuring Base Trader Class ...
mTrader.SetAsyncMode(false);
mTrader.SetDeviationInPoints(mSlippage);
mTrader.SetExpertMagicNumber(mMagicNumber);
//
// Setting Log Level ...
mTrader.LogLevel(LOG_LEVEL_ERRORS);
//
// OnTrade Context ...
//
mDaysForRead = 1;
mScanStarted = false;
//
// Reset On Trade Counter ...
ResetOnTradeContext();
//
// Init On Trade Context ...
InitOnTradeContext();
}
//
// Deconstructor ...
~XSCTrade()
{
//
// Remove Pointer ...
delete mTrader;
delete mAccount;
}
//
// Props ...
//
// Retrieve Slippage ...
int GetSlippage()
{
return mSlippage;
}
//
// Retrieve Magic Number ...
ulong GetMagicNumber()
{
return mMagicNumber;
}
//
int GetManageInterval()
{
return mManageInterval;
}
//
double GetMaxAllowedSpread()
{
return mMaxAllowedSpread;
}
//
int GetMaxAllowedPositions()
{
return mMaxAllowedPositions;
}
//
double GetMaxAllowedDrawdownFactor()
{
return mMaxAllowedDrawdownFactor;
}
//
// Add Event Listeners ...
//
// Add New Deals Changed Event Handler ...
void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler)
{
//
Add(
handler,
mTradeStateChangedEventHandlers
//
);
}
//
// Add New Deals Changed Event Handler ...
void AddOnDealsChangedEventHandler(TOnDealsChanged handler)
{
//
Add(
handler,
mDealsChangedEventHandlers
//
);
}
//
// Add New Orders Changed Event Handler ...
void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler)
{
//
Add(
handler,
mOrdersChangedEventHandlers
//
);
}
//
// Add New Positions Changed Event Handler ...
void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler)
{
//
Add(
handler,
mPositionsChangedEventHandlers
//
);
}
//
// Add New Stop Loss Event Handler ...
void AddOnStopLossEventHandler(TOnStopLoss handler)
{
//
Add(
handler,
mStopLossEventHandlers
//
);
}
//
// Add New Stop Loss Event Handler ...
void AddOnTakeProfitEventHandler(TOnTakeProfit handler)
{
//
Add(
handler,
mTakeProfitEventHandlers
//
);
}
//
// Functions ...
//
// Handlers ...
//
// Process On Trade Requirement ...
// this Only Used when we Have to Proccess OnTrade Event in EA(s) ...
void HandleOnTradeEvent(
XOnTradeHandlerState &result // Hold's Result
)
{
//
result.Clean();
//
if (mScanStarted)
{
//
ProcessOnTradeContext(result);
}
else
{
//
// Init Trade Context ...
InitOnTradeContext();
//
return;
}
//
// Here we Can Check the Start ...
bool isValid =
//
result.IsValid() &&
//
!result.hasNewDeal &&
!result.hasNewOrder &&
!result.hasNewPosition &&
!result.hasNewHistoryOrder
//
;
if (!isValid)
{
return;
}
//
// State ...
//
// Notfy Trade State Changed Event ...
NotifyTradeStateChangeEvent(result);
//
// Deals ...
if (result.hasNewDeal)
{
//
// Notfy Deals Changed Event ...
NotifyDealsChangeEvent(result.newDeals);
//
// Retrieve Last Deal ...
XDeal deals[];
int dealsCount = GetDeals(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 (result.hasNewOrder || result.hasNewHistoryOrder)
{
//
// Notfy Orders Changed Event ...
NotifyOrdersChangeEvent(result.newOrders + result.newHistoryOrders);
}
//
// Positions ...
if (result.hasNewPosition)
{
//
// Notfy Positions Changed Event ...
NotifyPositionsChangeEvent(result.newPositions);
}
}
//
// This Must be Called Every time OnTrade Event Happening ...
// this Used for Implementing Custom Senarios ...
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;
}
//
// Trade Actions ...
//
// Main ...
//
// Policies ...
//
// Check Acocunt Balance is Allow new Trades or not ...
bool CheckEquityForTrade()
{
//
bool result = false;
//
if (mMaxAllowedDrawdownFactor <= 0)
{
//
result = true;
return result;
}
//
double equity = mAccount.GetEquity();
double balance = mAccount.GetBalance();
//
double selectedBalance = MathMax(equity, balance) - MathMin(equity, balance);
//
double maxAllowedBalanceDrawDown = GetMaxAllowedEquity();
//
result = equity > balance ||
(equity <= balance &&
selectedBalance <= maxAllowedBalanceDrawDown);
//
return result;
}
//
// Check Max Allowed Positions Policy for Trade ...
bool CheckPositionsForTrade()
{
//
bool result = false;
//
if (mMaxAllowedPositions <= 0)
{
//
result = true;
return result;
}
//
XPosition positions[];
int positionsCount = GetPositions(positions);
if (positionsCount <= 0)
{
//
result = true;
return result;
}
//
result = positionsCount < mMaxAllowedPositions;
//
return result;
}
//
// Check Spread is Ok for Executing Specific Signal ...
bool CheckSpreadForSignalExecution(XSignal &mSignal)
{
//
bool result = false;
//
bool isSpreadCheckEnable = mMaxAllowedSpread > 0;
if (!isSpreadCheckEnable)
{
result = true;
}
else
{
//
// Retrieve Signal Spread ...
double spread = mSignal.GetSpread();
result = spread <= mMaxAllowedSpread;
}
//
return result;
}
//
// Check Account Policy ...
bool CheckAccountPolicy(
XSignal &mSignal, // For Executing Signal
ENUM_X_SIGNAL_EXECUTION_RESULT &state // State Holder
)
{
//
bool result = false;
//
// Check Positions For Trade ...
result = CheckPositionsForTrade();
if (!result)
{
//
state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED;
return result;
}
//
// Check Equity For Trade ...
result = CheckEquityForTrade();
if (!result)
{
//
state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY;
return result;
}
//
// Check Spread for Trade ...
result = CheckSpreadForSignalExecution(mSignal);
if (!result)
{
//
state = X_SIGNAL_EXECUTION_FAILED_SPREAD;
return result;
}
//
return result;
}
//
// Manage ...
// this must be Call on OnTick for Manage
// Positions ...
// NOTE: Call this Before Checking IsNewBar ...
void Manage()
{
// //
// // All required Position Managements Actions implemented here ...
// datetime tmc = TimeCurrent();
// bool canManage = !IsValid(mLastManageOn)
// ? true
// : mLastManageOn + mManageInterval >= tmc;
// if (!canManage)
// {
// return;
// }
// //
// mLastManageOn = tmc;
//
// - [] Partial Close;
// - [] Risk Free;
// - [] Trail Stop;
// - [] SLS;
// - [] TPS;
//
// - [] Data Collector;
// - [] Profit Management;
//
// TODO: Implement them ...
//
// Implement Signal Collector Inside this Class
// and Manipulate Signals when SL/TP/Partial Close/Trail Stop/Profit/Close/ Modify and etc Happens ...
}
//
// Execute a Signal ...
bool ExecuteSignal(
XSignal &mSignal, // Signal
ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Result
ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime
datetime expiration = NULL, // order expiration time
bool checkPolicies = true // Check Account Policies
)
{
//
bool result = false;
state = X_SIGNAL_EXECUTION_UNKNOWN;
//
double currentEntry = GetEntry(
mSignal.symbol,
mSignal.type
//
);
bool isLong = IsLong(mSignal.type);
//
if (!mSignal.IsValid())
{
//
state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS;
return result;
}
//
// Prepare Signal Comment ...
string mSComment = mSignal.GenerateComment();
mSignal.comment += mSComment;
//
// Handle Market Execution ...
if (mSignal.mode == X_ORDER_MODE_MARKET)
{
//
// Do Apply Policies here ...
bool hasPolicy = !checkPolicies
? true
: CheckAccountPolicy(mSignal, state);
if (!hasPolicy)
{
result = false;
}
else
{
//
if (isLong)
{
//
result = Buy(
mSignal.symbol,
mSignal.period,
mSignal.volume,
mSignal.entry,
mSignal.sl,
mSignal.tp,
mSignal.comment
//
);
}
else
{
//
result = Sell(
mSignal.symbol,
mSignal.period,
mSignal.volume,
mSignal.entry,
mSignal.sl,
mSignal.tp,
mSignal.comment
//
);
}
}
}
//
// Handle Stop Execution ...
else if (mSignal.mode == X_ORDER_MODE_STOP)
{
//
// Check Conditions ...
//
// Check Price ...
result = isLong
? mSignal.entry > currentEntry
: mSignal.entry < currentEntry;
if (!result)
{
//
state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR;
return result;
}
//
// Execute Order ...
if (isLong)
{
//
result = BuyStop(
mSignal.symbol,
mSignal.period,
mSignal.volume,
mSignal.entry,
mSignal.sl,
mSignal.tp,
lifetime,
expiration,
mSignal.comment
//
);
}
else
{
//
result = SellStop(
mSignal.symbol,
mSignal.period,
mSignal.volume,
mSignal.entry,
mSignal.sl,
mSignal.tp,
lifetime,
expiration,
mSignal.comment
//
);
}
}
//
// Handle Limit Execution ...
else if (mSignal.mode == X_ORDER_MODE_LIMIT)
{
//
// Check Conditions ...
//
// Check Price ...
result = isLong
? mSignal.entry < currentEntry
: mSignal.entry > currentEntry;
if (!result)
{
//
state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR;
return result;
}
//
// Execute Order ...
if (isLong)
{
//
result = BuyLimit(
mSignal.symbol,
mSignal.period,
mSignal.volume,
mSignal.entry,
mSignal.sl,
mSignal.tp,
lifetime,
expiration,
mSignal.comment
//
);
}
else
{
//
result = SellLimit(
mSignal.symbol,
mSignal.period,
mSignal.volume,
mSignal.entry,
mSignal.sl,
mSignal.tp,
lifetime,
expiration,
mSignal.comment
//
);
}
}
//
// Handle Ticket ...
if (result)
{
//
state = X_SIGNAL_EXECUTION_SUCCEED;
//
ulong ticket;
if (mSignal.mode == X_ORDER_MODE_MARKET)
{
ticket = GetLastOpenPositionTicket();
}
else
{
ticket = GetLastPlacedOrderTicket();
}
//
mSignal.positionId = ticket;
//
// Handle Store XPositionInfo ...
if (mSignal.mode == X_ORDER_MODE_MARKET)
{
//
// TODO: Implement this ...
}
//
// Handle Executing Support Signals ...
int supportsCount = ArraySize(mSignal.supports);
if (supportsCount > 0)
{
//
int executed = 0;
for (int i = 0; i < supportsCount; i++)
{
//
XSignal iSupport = mSignal.supports[i];
//
int supIndex = i + 1;
string iComment = GenerateSupportTag(ticket);
//
bool isExecuted = ExecuteSignal(
iSupport,
state,
lifetime,
expiration
//
);
if (isExecuted)
{
executed++;
}
}
//
result = executed == supportsCount;
}
}
//
return result;
}
//
// Execute a Collection Of Signals ...
int ExecuteSignals(
XSignal &signals[], // Collection of Signal for Execution
ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result
ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime
datetime expiration = NULL, // order expiration time
bool checkPolicies = true // Check Account Policies
)
{
//
int result = 0;
//
Clean(states);
//
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return result;
}
//
ArrayResize(states, signalsCount);
ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN);
for (int i = 0; i < signalsCount; i++)
{
//
bool isExecuted = ExecuteSignal(
signals[i],
states[i],
lifetime,
expiration,
checkPolicies
//
);
//
if (isExecuted)
{
result++;
}
}
//
return result;
}
//
int ExecuteSpecifiedSignals(
XSignal &signals[], // Collection of Signal for Execution
XSignal &notExecuteds[], // Not Executed Signal
ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result
ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime
datetime expiration = NULL, // order expiration time
bool checkPolicies = true // Check Account Policies
)
{
//
int result = 0;
//
Clean(states);
Clean(notExecuteds);
//
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return result;
}
//
ArrayResize(states, signalsCount);
ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN);
for (int i = 0; i < signalsCount; i++)
{
//
bool isExecuted = ExecuteSignal(
signals[i],
states[i],
lifetime,
expiration
//
);
//
if (isExecuted)
{
result++;
}
else
{
//
AddRef(
signals[i],
notExecuteds //
);
}
}
//
return result;
}
//
// Regular Trade Actions ...
//
// Buy ...
//
// 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 = NULL // comment
)
{
//
bool result = false;
//
ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment);
if (!IsValid(comment) ||
!IsValid(mPeriod))
{
//
string mPeriodStr = GeneratePeriodTag(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 = NULL // comment
)
{
//
bool result = false;
//
ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment);
if (!IsValid(comment) ||
!IsValid(mPeriod))
{
//
string mPeriodStr = GeneratePeriodTag(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 = NULL // comment
)
{
//
bool result = false;
//
ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment);
if (!IsValid(comment) ||
!IsValid(mPeriod))
{
//
string mPeriodStr = GeneratePeriodTag(period);
//
comment += mPeriodStr;
}
//
result = mTrader.BuyStop(
volume,
price,
symbol,
sl,
tp,
typeTime,
expiration,
comment
//
);
//
return result;
}
//
// Sell ...
//
// 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 = NULL // comment
)
{
//
bool result = false;
//
ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment);
if (!IsValid(comment) ||
!IsValid(mPeriod))
{
//
string mPeriodStr = GeneratePeriodTag(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 = NULL // comment
)
{
//
bool result = false;
//
ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment);
if (!IsValid(comment) ||
!IsValid(mPeriod))
{
//
string mPeriodStr = GeneratePeriodTag(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 = NULL // comment
)
{
//
bool result = false;
//
ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment);
if (!IsValid(comment) ||
!IsValid(mPeriod))
{
//
string mPeriodStr = GeneratePeriodTag(period);
//
comment += mPeriodStr;
}
//
result = mTrader.SellStop(
volume,
price,
symbol,
sl,
tp,
typeTime,
expiration,
comment
//
);
//
return result;
}
//
// Check a Position is Exists Open or not ...
bool IsOpen(
ulong ticket // Specified Position Ticket
)
{
//
bool result = false;
//
result = mPositionInfo
.SelectByTicket(ticket);
//
return result;
}
//
// Modify Position ...
bool Modify(
const ulong ticket, // position ticket
double sl = 0, // stop loss price
double tp = 0, // take profit
string comment = NULL // comment
)
{
//
bool result = false;
//
// Validate Args ...
result =
IsOpen(ticket) &&
(tp >= 0 || sl >= 0);
if (!result)
{
return result;
}
//
// Use Position Comment when there isn't new One ...
if (!IsValid(comment) == 0)
{
//
// if there isn't provided Comment
// Use Position Comment for default ...
comment = "Modify " + GetPositionComment(ticket);
}
//
result = mTrader.PositionModify(
ticket,
sl,
tp,
comment
//
);
//
return result;
}
//
// Close Position By Ticket ...
bool Close(
ulong ticket, // Position Ticket
string comment = NULL // Close Position By Specific Comment
)
{
//
bool result = false;
//
// Check Position Open ...
result = IsOpen(ticket);
if (!result)
{
return result;
}
//
// Use Default Position Comment if it's Not Provided ...
if (!IsValid(comment))
{
comment = "Close " + GetPositionComment(ticket);
}
//
// Close Position By Specific Comment ...
result = mTrader.PositionClose(
ticket,
mSlippage,
comment
//
);
//
return result;
}
//
// Close Specified Positions ...
int Close(
string comment = NULL, // Close Position By Specific Comment
string symbol = NULL, // Trading Symbol
string provider = NULL, // Signal Provider
ENUM_TIMEFRAMES period = NULL, // Trading Period
ENUM_X_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell)
bool filterByMagic = true // Get Only Self Open Positions
)
{
//
int result = 0;
//
XPosition positions[];
int positionsCount = GetPositions(
positions,
symbol,
provider,
period,
type,
filterByMagic);
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;
}
//
// Close a Collection of Positions ...
int Close(
XPosition &positions[], // Collection of Positions
string comment // Close 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;
}
//
// Close Partial By Ticket ...
bool ClosePartial(
ulong ticket, // Position Ticket
double volume, // Volume Size for Partial Closing
string comment = NULL // Close Position By Specific Comment
)
{
//
bool result = false;
//
result = IsOpen(ticket);
if (!result)
{
return result;
}
//
// Use Default Partial Close Comment ...
if (!IsValid(comment))
{
//
comment += "PClose " + GetPositionComment(ticket);
}
//
result = mTrader.PositionClosePartial(
ticket,
volume,
mSlippage,
comment
//
);
//
return result;
}
//
// Cancel Specific Order ...
bool CancelOrder(ulong ticket)
{
return mTrader
.OrderDelete(ticket);
}
//
// Cancel Specific Orders ...
int CancelOrders(
XOrder &orders[] // Specified Orders ...
)
{
//
int result = 0;
//
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++;
}
}
//
return result;
}
//
// Extractors ...
//
// Positions ...
//
// Calculate Positions Profit ...
double Profit(
string symbol = NULL, // Trading Symbol
string provider = NULL, // Signal Provider
ENUM_TIMEFRAMES period = NULL, // Trading Period
ENUM_X_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell)
bool filterByMagic = true // Get Only Self Open Positions
)
{
//
double result = 0;
//
// Retrieve Positions ...
XPosition positions[];
int positionsCount = GetPositions(
positions,
symbol,
provider,
period,
type,
filterByMagic
//
);
if (positionsCount <= 0)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
result += positions[i].profit;
}
//
return result;
}
//
// Retrieve Specific Position by Index ...
bool GetPosition(
int index, // Specified Index
XPosition &result // Hold's Result
)
{
//
return result
.ByIndex(index);
}
//
// Retrieve Specific Position by Ticket ...
bool GetPosition(
ulong ticket, // Specified Ticket
XPosition &result // Hold's Result
)
{
//
return result
.ByTicket(ticket);
}
//
// Retrieve Positions ...
int GetPositions(
XPosition &result[], // Hold's Result
string symbol = NULL, // Trading Symbol
string provider = NULL, // Signal Provider
ENUM_TIMEFRAMES period = NULL, // Trading Period
ENUM_X_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell)
bool filterByMagic = true, // Get Only Self Open Positions
bool forceClean = true // Clean Result Array
)
{
//
int mResult = 0;
//
int before = ArraySize(result);
//
if (forceClean)
{
Clean(result);
}
//
// Count Positions ...
int itemsCount = PositionsTotal();
if (itemsCount <= 0)
{
return mResult;
}
//
// Loop Through all Positions ...
for (int i = itemsCount - 1; i >= 0; i--)
{
//
XPosition iItem;
bool isLoaded = iItem.ByIndex(i);
if (!isLoaded)
{
continue;
}
//
// Now we have to Check Given Filters ...
bool isFiltersPassed =
iItem.IsFiltersPassed(
symbol,
provider,
period,
type,
mMagicNumber,
filterByMagic
//
);
if (!isFiltersPassed)
{
continue;
}
//
// Add Filtered Item into Result ...
AddRef(
iItem,
result
//
);
}
//
int after = ArraySize(result);
//
mResult = after - before;
//
return mResult;
}
//
void GetPositions(
XPosition &longs[], // Hold's Longs Result
XPosition &shorts[], // Hold's Shorts Result
string symbol = NULL, // Trading Symbol
string provider = NULL, // Signal Provider
ENUM_TIMEFRAMES period = NULL, // Trading Period
bool filterByMagic = true, // Get Only Self Open Positions
bool forceClean = true // Clean Result Array
)
{
//
// Retrieve Long Positions ...
GetPositions(
longs,
symbol,
provider,
period,
X_POSITION_TYPE_LONG,
filterByMagic,
forceClean //
);
//
// Retrieve Short Positions ...
GetPositions(
shorts,
symbol,
provider,
period,
X_POSITION_TYPE_SHORT,
filterByMagic,
forceClean //
);
}
//
// Select In Profit Positions ...
int GetInProfitPositions(
XPosition &result[], // Hold's Result
string symbol = NULL, // Trading Symbol
string provider = NULL, // Signal Provider
ENUM_TIMEFRAMES period = NULL, // Trading Period
ENUM_X_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell)
ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method
bool filterByMagic = true, // Get Only Self Open Positions
bool forceClean = true // Clean Result Array
)
{
//
int mResult = 0;
//
int before = ArraySize(result);
//
if (forceClean)
{
Clean(result);
}
//
XPosition positions[];
int positionsCount = GetPositions(
positions,
symbol,
provider,
period,
type,
filterByMagic,
forceClean);
if (positionsCount <= 0)
{
return mResult;
}
//
XPosition min;
XPosition max;
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
if (iPosition.profit <= 0)
{
continue;
}
//
// Calculate Min and Max ...
//
// Min ...
if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit)
{
min = iPosition;
}
//
// Max ...
if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit)
{
max = iPosition;
}
//
bool isSelectionMethodFilterPassed =
//
(method == NULL ||
method == X_POSITION_SELECT_ALL)
? true
: false;
//
;
if (!isSelectionMethodFilterPassed)
{
continue;
}
//
AddRef(
iPosition,
result
//
);
}
//
if (min.IsValid() &&
(method == X_POSITION_SELECT_MIN ||
method == X_POSITION_SELECT_BOTH))
{
//
AddRef(
min,
result
//
);
}
//
if (max.IsValid() &&
(method == X_POSITION_SELECT_MAX ||
method == X_POSITION_SELECT_BOTH))
{
//
AddRef(
max,
result
//
);
}
//
int after = ArraySize(result);
//
mResult = after - before;
//
return mResult;
}
//
// Select In Drawdown Positions ...
int GetInDrawdownPositions(
XPosition &result[], // Hold's Result
string symbol = NULL, // Trading Symbol
string provider = NULL, // Signal Provider
ENUM_TIMEFRAMES period = NULL, // Trading Period
ENUM_X_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell)
ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method
bool filterByMagic = true, // Get Only Self Open Positions
bool forceClean = true // Clean Result Array
)
{
//
int mResult = 0;
//
int before = ArraySize(result);
//
if (forceClean)
{
Clean(result);
}
//
XPosition positions[];
int positionsCount = GetPositions(
positions,
symbol,
provider,
period,
type,
filterByMagic,
forceClean);
if (positionsCount <= 0)
{
return mResult;
}
//
XPosition min;
XPosition max;
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
if (iPosition.profit >= 0)
{
continue;
}
//
// Calculate Min and Max ...
//
// Min ...
if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit)
{
min = iPosition;
}
//
// Max ...
if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit)
{
max = iPosition;
}
//
bool isSelectionMethodFilterPassed =
//
(method == NULL ||
method == X_POSITION_SELECT_ALL)
? true
: false;
//
;
if (!isSelectionMethodFilterPassed)
{
continue;
}
//
AddRef(
iPosition,
result
//
);
}
//
if (min.IsValid() &&
(method == X_POSITION_SELECT_MIN ||
method == X_POSITION_SELECT_BOTH))
{
//
AddRef(
min,
result
//
);
}
//
if (max.IsValid() &&
(method == X_POSITION_SELECT_MAX ||
method == X_POSITION_SELECT_BOTH))
{
//
AddRef(
max,
result
//
);
}
//
int after = ArraySize(result);
//
mResult = after - before;
//
return mResult;
}
//
// Orders ...
//
// Retrieve Specific Order by Index ...
bool GetOrder(
int index, // Specified Index
XOrder &result // Hold's Result
)
{
//
return result
.ByIndex(index);
}
//
// Retrieve Specific Positions Orders ...
int GetOrders(
ulong ticket, // Positions Ticket
XOrder &result[], // Hold's Result
bool forceClean = true // Clean Result Array
)
{
//
int mResult = 0;
//
// Select History by Specified Ticket ...
bool isHistorySelected = HistorySelectByPosition(ticket);
if (!isHistorySelected)
{
return mResult;
}
//
int ordersCount = HistoryOrdersTotal();
if (ordersCount <= 0)
{
return mResult;
}
//
int before = ArraySize(result);
//
if (forceClean)
{
Clean(result);
}
//
for (int i = 0; i < ordersCount; i++)
{
//
XOrder iOrder;
bool isLoaded = iOrder.HistoryByIndex(i);
if (!isLoaded)
{
continue;
}
//
bool isTicketFilterPassed =
//
iOrder.ticket = ticket
//
;
if (!isTicketFilterPassed)
{
continue;
}
//
AddRef(
iOrder,
result
//
);
}
//
int after = ArraySize(result);
//
mResult = after - before;
//
return mResult;
}
//
// Retrieve All Orders ...
int GetOrders(
XOrder &result[], // Hold's Result
string symbol = NULL, // Trading Symbol
string provider = NULL, // Signal Provider
ENUM_TIMEFRAMES period = NULL, // Trading Period
ENUM_ORDER_TYPE type = NULL, // Long (Buy) or Short (Sell)
ENUM_ORDER_STATE state = NULL, // Order State
bool filterByMagic = true, // Get Only Self Open Positions
bool forceClean = true // Clean Result Array
)
{
//
int mResult = 0;
//
int before = ArraySize(result);
//
if (forceClean)
{
Clean(result);
}
//
// Count Positions ...
int itemsCount = OrdersTotal();
if (itemsCount <= 0)
{
return mResult;
}
//
// Loop Through all Positions ...
for (int i = itemsCount - 1; i >= 0; i--)
{
//
XOrder iItem;
bool isLoaded = iItem.ByIndex(i);
if (!isLoaded)
{
continue;
}
//
// Now we have to Check Given Filters ...
bool isFiltersPassed =
iItem.IsFiltersPassed(
symbol,
provider,
period,
type,
state,
mMagicNumber,
filterByMagic
//
);
if (!isFiltersPassed)
{
continue;
}
//
// Add Filtered Item into Result ...
AddRef(
iItem,
result
//
);
}
//
int after = ArraySize(result);
//
mResult = after - before;
//
return mResult;
}
//
// Retrieve Historical Orders ...
int GetOrders(
XOrder &result[], // Hold's Result
string symbol = NULL, // Trading Symbol
string provider = NULL, // Signal Provider
ENUM_TIMEFRAMES period = NULL, // Trading Period
ENUM_ORDER_TYPE type = NULL, // Long (Buy) or Short (Sell)
ENUM_ORDER_STATE state = NULL, // Order State
datetime startDate = NULL, // Specify Start Date
datetime endDate = NULL, // Specify End Date
bool filterByMagic = true, // Get Only Self Open Positions
bool forceClean = true // Clean Result Array
)
{
//
int mResult = 0;
//
endDate = NormalizeTime(endDate);
//
if (!IsValid(startDate))
{
startDate = endDate - PeriodSeconds(PERIOD_D1);
}
//
bool isHistorySelected = HistorySelect(
startDate,
endDate);
if (!isHistorySelected)
{
return mResult;
}
//
int before = ArraySize(result);
//
if (forceClean)
{
Clean(result);
}
//
// Count Positions ...
int itemsCount = OrdersTotal();
if (itemsCount <= 0)
{
return mResult;
}
//
// Loop Through all Positions ...
for (int i = itemsCount - 1; i >= 0; i--)
{
//
XOrder iItem;
bool isLoaded = iItem.HistoryByIndex(i);
if (!isLoaded)
{
continue;
}
//
// Now we have to Check Given Filters ...
bool isFiltersPassed =
iItem.IsFiltersPassed(
symbol,
provider,
period,
type,
state,
mMagicNumber,
filterByMagic
//
);
if (!isFiltersPassed)
{
continue;
}
//
// Add Filtered Item into Result ...
AddRef(
iItem,
result
//
);
}
//
int after = ArraySize(result);
//
mResult = after - before;
//
return mResult;
}
//
// Deals ...
//
// Retrieve Specific Deal by Index ...
bool GetDeal(
int index, // Specified Index
XDeal &result // Hold's Result
)
{
//
return result
.ByIndex(index);
}
//
bool GetLastDeal(
XDeal &result // Hold's Result
)
{
//
bool mResult = false;
//
mResult = HistorySelect(0, TimeCurrent());
if (!mResult)
{
return mResult;
}
//
int lastDealIndex = HistoryDealsTotal() - 1;
//
mResult = GetDeal(
lastDealIndex,
result //
);
//
return mResult;
}
//
// Retrieve Specified Deal's History ...
int GetDealsHistory(
XDeal &deal, // Specified Deal
XOrder &history[], // Deals History
bool forceClean = true // Clean Result Array
)
{
//
int result = 0;
//
if (!deal.IsValid())
{
return result;
}
//
result = GetOrders(
deal.positionId,
history,
forceClean);
//
return result;
}
//
// Retrieve All Deals ...
int GetDeals(
XDeal &result[], // Hold's Result
string symbol = NULL, // Trading Symbol
string provider = NULL, // Signal Provider
ENUM_TIMEFRAMES period = NULL, // Trading Period
ENUM_DEAL_TYPE type = NULL, // Deal Type
ENUM_DEAL_ENTRY entry = NULL, // Deal Entry
ENUM_DEAL_REASON reason = NULL, // Deal Reason
datetime startDate = NULL, // Specify Start Date
datetime endDate = NULL, // Specify End Date
bool filterByMagic = true, // Get Only Self Open Positions
bool forceClean = true // Clean Result Array
)
{
//
int mResult = 0;
//
endDate = NormalizeTime(endDate);
//
if (!IsValid(startDate))
{
startDate = endDate - PeriodSeconds(PERIOD_D1);
}
//
bool isHistorySelected = HistorySelect(
startDate,
endDate);
if (!isHistorySelected)
{
return mResult;
}
//
int before = ArraySize(result);
//
if (forceClean)
{
Clean(result);
}
//
// Count Positions ...
int itemsCount = HistoryDealsTotal();
if (itemsCount <= 0)
{
return mResult;
}
//
// Loop Through all Positions ...
for (int i = itemsCount - 1; i >= 0; i--)
{
//
XDeal iItem;
bool isLoaded = iItem.ByIndex(i);
if (!isLoaded)
{
continue;
}
//
// Now we have to Check Given Filters ...
bool isFiltersPassed =
iItem.IsFiltersPassed(
symbol,
provider,
period,
type,
entry,
reason,
mMagicNumber,
filterByMagic
//
);
if (!isFiltersPassed)
{
continue;
}
//
// Add Filtered Item into Result ...
AddRef(
iItem,
result
//
);
}
//
int after = ArraySize(result);
//
mResult = after - before;
//
return mResult;
}
//
// XPosition Pack ...
//
// Extract specific Positions Pack ...
// in this senario there is no need to Position exists itself ...
bool GetPositionPack(
ulong ticket, // Specified Positions Ticket
string symbol, // Specified Position Symbol
ENUM_TIMEFRAMES period, // Specified Position Period
XPositionPack &pack // Hold Result
)
{
//
bool result = false;
//
pack.Clean();
//
XPosition position;
bool hasPosition = GetPosition(
ticket,
position
//
);
if (hasPosition)
{
pack.position = position;
}
//
XOrder supportOrders[];
XPosition supportPositions[];
//
XOrder orders[];
GetOrders(
orders,
symbol, // Specified Symbol
NULL, // All Providers
period, // Specified Period
NULL, // All Types
ORDER_STATE_PLACED, // Just UnTriggered Orders
true // Filter by Magic
);
int ordersCount = ArraySize(orders);
//
// Select Orders ...
if (ordersCount > 0)
{
//
for (int i = 0; i < ordersCount; i++)
{
//
XOrder iOrder = orders[i];
//
// Retrieve Order Supported Ticket ...
ulong parentTicket = ExtractSupportedTicket(iOrder.comment);
if (NotEmpty(parentTicket) && parentTicket == ticket)
{
//
AddRef(
iOrder,
supportOrders
//
);
}
}
}
//
int supportOrdersCount = ArraySize(supportOrders);
if (supportOrdersCount > 0)
{
//
pack.supportOrdersCount = supportOrdersCount;
//
Copy(
supportOrders,
pack.supportOrders);
}
//
XPosition positions[];
GetPositions(
positions,
symbol, // Specified Symbol ...
NULL, // All Providers ...
period // Specified Period ...
);
int positionsCount = ArraySize(positions);
//
// Select Positions ...
if (positionsCount > 0)
{
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
ulong parentTicket = ExtractSupportedTicket(iPosition.comment);
if (NotEmpty(parentTicket) && parentTicket == ticket)
{
//
AddRef(
iPosition,
supportPositions
//
);
}
}
}
//
int supportPositionsCount = ArraySize(supportPositions);
if (supportPositionsCount > 0)
{
//
pack.supportPositionsCount = supportPositionsCount;
//
Copy(
supportPositions,
pack.supportPositions);
}
//
result = pack.IsValid();
//
return result;
}
//
// Close Position Pack ...
bool ClosePositionPack(
XPositionPack &pack, // Specified Position Pack
string comment, // Specified Close Comment
bool inProfit = false, // if it's true only close Pack if in profit
double minProfitPerTrade = 0, // Min Profit based On Volume Factor ...
double minProfitPerVolumeFactor = 0 // Min Volume Factor ...
)
{
//
bool result = false;
//
ulong ticket = pack.ticket;
//
XPosition positions[];
//
XPosition pPosition;
result = GetPosition(
ticket,
pPosition //
);
if (result)
{
//
AddRef(
pPosition,
positions //
);
}
//
if (pack.supportPositionsCount > 0)
{
//
for (int i = 0; i < pack.supportPositionsCount; i++)
{
//
XPosition iPosition = pack.supportPositions[i];
//
AddRef(
iPosition,
positions //
);
}
}
//
// Force Close ...
if (!inProfit)
{
//
int closed = Close(
positions,
comment //
);
//
int cancelled = 0;
if (pack.supportOrdersCount > 0)
{
cancelled = CancelOrders(pack.supportOrders);
}
//
result = (closed + cancelled) == (pack.supportPositionsCount + pack.supportOrdersCount + 1);
}
else
{
//
bool canHedge = SpecifiedIsPositionsReadyForHedge(
positions,
minProfitPerTrade,
minProfitPerVolumeFactor //
);
if (canHedge)
{
//
int closed = Close(
positions,
comment //
);
//
int cancelled = 0;
if (pack.supportOrdersCount > 0)
{
cancelled = CancelOrders(pack.supportOrders);
}
//
result = (closed + cancelled) == (pack.supportPositionsCount + pack.supportOrdersCount + 1);
}
else
{
result = false;
}
}
//
return result;
}
bool ClosePositionPack(
ulong ticket, // Specified Position Pack
string symbol, // Specified Position Symbol
ENUM_TIMEFRAMES period, // Specified Position Period
string comment, // Specified Close Comment
bool inProfit = false, // if it's true only close Pack if in profit
double minProfitPerTrade = 0, // Min Profit based On Volume Factor ...
double minProfitPerVolumeFactor = 0 // Min Volume Factor ...
)
{
//
bool result = false;
//
XPositionPack pack;
result = GetPositionPack(
ticket,
symbol,
period,
pack //
);
if (!result)
{
return result;
}
//
result = ClosePositionPack(
pack,
comment,
inProfit,
minProfitPerTrade,
minProfitPerVolumeFactor //
);
//
return result;
}
//
// Close Positions Pack ...
int ClosePositionsPack(
XPosition &positions[], // Positions ...
string comment, // Specified Close Comment
bool inProfit = false, // if it's true only close Pack if in profit
double minProfitPerTrade = 0, // Min Profit based On Volume Factor ...
double minProfitPerVolumeFactor = 0 // Min Volume Factor ...
)
{
//
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 = ClosePositionPack(
iPosition.ticket,
iPosition.symbol,
iPosition.period,
comment,
inProfit,
minProfitPerTrade,
minProfitPerVolumeFactor //
);
if (isClosed)
{
result++;
}
}
//
return result;
}
//
// Tools ...
//
// 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;
}
//
// Protected ...
protected:
//
// Props ...
//
// Event Listener 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);
}
}
//
// StopLoss ...
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);
}
}
//
// Take Profit ...
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);
}
}
//
// Tools ...
//
// Retrieve Specified Position Comment ...
string GetPositionComment(ulong ticket)
{
//
string result = NULL;
//
if (!IsOpen(ticket))
{
return result;
}
//
XPosition position;
bool isLoaded = position.ByTicket(ticket);
if (!isLoaded)
{
return result;
}
//
result = position.comment;
//
return result;
}
//
// Extract Specific Deals Position's Pack ...
// this used when a Position SL or TP triggered and we want to close
// all it's Supported Packs ...
bool GetDealPack(
XDeal &deal,
XPositionPack &pack //
)
{
//
bool result = false;
//
ulong ticket = deal.positionId;
ENUM_TIMEFRAMES dealPeriod = GetDealPeriod(deal);
string dealSymbol = deal.symbol;
//
// So We Have to Get Positions Pack ...
result = GetPositionPack(
ticket,
dealSymbol,
dealPeriod,
pack
//
);
//
return result;
}
//
ENUM_TIMEFRAMES GetDealPeriod(XDeal &deal)
{
//
ENUM_TIMEFRAMES result = NULL;
//
XOrder orders[];
int ordersCount = GetDealsHistory(
deal,
orders);
if (!ordersCount)
{
return result;
}
//
for (int i = 0; i < ordersCount; i++)
{
//
XOrder iOrder = orders[i];
//
if (IsValid(iOrder.comment))
{
//
ENUM_TIMEFRAMES iPeriod = ExtractPeriod(iOrder.comment);
if (IsValid(iPeriod))
{
result = iPeriod;
break;
}
}
}
//
return result;
}
//
double GetMaxAllowedEquity()
{
//
double equity = mAccount.GetEquity();
double balance = mAccount.GetBalance();
//
double balanceForFactor = MathAbs(equity - balance);
if (balanceForFactor <= 0)
{
balanceForFactor = balance;
}
else
{
balanceForFactor = equity;
}
//
double result = balanceForFactor * mMaxAllowedDrawdownFactor;
//
return result;
}
//
// Private ...
private:
//
// Props ...
//
int mSlippage; // Slippage ...
ulong mMagicNumber; // Magic Number (Unique Identifier) ...
//
datetime mLastManageOn; // Last Manager Check
int mManageInterval; // Manager Check Intervals Seconds
//
double mMaxAllowedSpread; // Max Allowed Spred for Opening Trades
int mMaxAllowedPositions; // Max Allowed Same Positions
double mMaxAllowedDrawdownFactor; // Max Allowed Drawdown Factor
//
XSCTradeBase *mTrader; // Base CTrade Manipulated Instance ...
//
CDealInfo mDealInfo; // Deals Info ...
COrderInfo mOrderInfo; // Order Info ...
CPositionInfo mPositionInfo; // Positions Info
CHistoryOrderInfo mHistoryOrderInfo; // History Orders Info ...
//
// Position Info Collector ...
//
// Tools ...
//
// OnTrade Event Handlers Section ...
//
// Props ...
//
int mDaysForRead; // Reading Dates for Trade History Checker ...
datetime mEndDate; // End Date for Trade history Checking ...
datetime mStartDate; // Start Date for Trade history Checking ... ...
int mOrdersCount; // Number of Active orders ...
int mPositionsCount; // Number of Open positions ...
int mDealsCount; // Number of Deals in the Trade History Checking ...
int mHistoryOrdersCount; // Number of Orders in the Trade History Checking ...
bool mScanStarted; // a Flag of counter relevance ...
//
// Event Listeners ...
//
// 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[];
//
// 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;
}
//
// 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();
}
};
//