1806 lines
42 KiB
Plaintext
1806 lines
42 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class Library
|
|
// ----------------------------------------------
|
|
// Name: XSCBaseEA
|
|
// Description: provides all Base EA 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.xalert.class.mq5"
|
|
#include "../Classes/x-saherelm.xtrade.class.mq5"
|
|
|
|
//
|
|
// Define On Signal Event Handler Type ...
|
|
typedef void (*TOnSignal)(XSignal &signal);
|
|
|
|
//
|
|
// Class Definition ...
|
|
|
|
class XSCBaseEA : public XSCBaseAlert
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Trade Class Instance ...
|
|
XSCTrade *mTrader;
|
|
|
|
//
|
|
// Constructor ...
|
|
XSCBaseEA(
|
|
//
|
|
// XTrade Class Requirements ...
|
|
int slippage, // Specify Slippage
|
|
ulong magicNumber, // Specify Magic Number
|
|
//
|
|
// Event Handlers ...
|
|
TOnSignal onSignal = NULL, // On Signal Recieved Event Handler
|
|
TOnModify onModifyPosition = NULL, // On Modify Position Event Handler
|
|
TOnStopLoss onStopLossTriggered = NULL, // On StopLoass Triggered Event Handler
|
|
TOnTakeProfit onTakeProfitTriggered = NULL, // On TakeProfit Triggered Event Handler
|
|
TOnForceClose onForceClosePosition = NULL, // On Force Close Position Event Handler
|
|
TOnPartialClose onPartialClosePosition = NULL, // On Partial Close Position Event Handler
|
|
TOnDealsChanged onDealsChangedHandler = NULL, // On Deals Changed Event Handler
|
|
TOnOrdersChanged onOrdersChangedHandler = NULL, // On Orders Changed Event Handler
|
|
TOnPositionsChanged onPositionsChangedHandler = NULL, // On Positions Changed Event Handler
|
|
TOnTradeStateChanged onTradeStateChangedHandler = NULL // On Trade State Changed Event Handler
|
|
)
|
|
{
|
|
//
|
|
// Instance XSCTrade Class ...
|
|
mTrader = new XSCTrade(
|
|
slippage,
|
|
magicNumber //
|
|
);
|
|
|
|
//
|
|
mIsInTestMode = IsRunningOnTestMode();
|
|
mStaticBalanceForCalculateDrawdown = 0; // Ignore ...
|
|
|
|
//
|
|
// Set Event Handlers ...
|
|
mOnSignal = onSignal;
|
|
mOnModifyPosition = onModifyPosition;
|
|
mOnStopLossTriggered = onStopLossTriggered;
|
|
mOnForceClosePosition = onForceClosePosition;
|
|
mOnTakeProfitTriggered = onTakeProfitTriggered;
|
|
mOnDealsChangedHandler = onDealsChangedHandler;
|
|
mOnPartialClosePosition = onPartialClosePosition;
|
|
mOnOrdersChangedHandler = onOrdersChangedHandler;
|
|
mOnPositionsChangedHandler = onPositionsChangedHandler;
|
|
mOnTradeStateChangedHandler = onTradeStateChangedHandler;
|
|
|
|
//
|
|
if (mOnSignal != NULL)
|
|
{
|
|
AddOnSignalEventHandler(mOnSignal);
|
|
}
|
|
|
|
//
|
|
if (mOnModifyPosition != NULL)
|
|
{
|
|
mTrader.AddOnModifyPositionEventHandler(mOnModifyPosition);
|
|
}
|
|
|
|
//
|
|
if (mOnForceClosePosition != NULL)
|
|
{
|
|
mTrader.AddOnForceClosePositionEventHandler(mOnForceClosePosition);
|
|
}
|
|
|
|
//
|
|
if (mOnPartialClosePosition != NULL)
|
|
{
|
|
mTrader.AddOnPartialClosePositionEventHandler(mOnPartialClosePosition);
|
|
}
|
|
|
|
//
|
|
if (mOnStopLossTriggered != NULL)
|
|
{
|
|
mTrader.AddOnStopLossEventHandler(mOnStopLossTriggered);
|
|
}
|
|
|
|
//
|
|
if (mOnTakeProfitTriggered != NULL)
|
|
{
|
|
mTrader.AddOnTakeProfitEventHandler(mOnTakeProfitTriggered);
|
|
}
|
|
|
|
//
|
|
if (mOnDealsChangedHandler != NULL)
|
|
{
|
|
mTrader.AddOnDealsChangedEventHandler(mOnDealsChangedHandler);
|
|
}
|
|
|
|
//
|
|
if (mOnOrdersChangedHandler != NULL)
|
|
{
|
|
mTrader.AddOnOrdersChangedEventHandler(mOnOrdersChangedHandler);
|
|
}
|
|
|
|
//
|
|
if (mOnPositionsChangedHandler != NULL)
|
|
{
|
|
mTrader.AddOnPositionsChangedEventHandler(mOnPositionsChangedHandler);
|
|
}
|
|
|
|
//
|
|
if (mOnTradeStateChangedHandler != NULL)
|
|
{
|
|
mTrader.AddOnTradeStateChangedEventHandler(mOnTradeStateChangedHandler);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Deconstractor ...
|
|
~XSCBaseEA()
|
|
{
|
|
//
|
|
delete mTrader;
|
|
|
|
//
|
|
Clean(mOnSignalEventHandlers);
|
|
|
|
//
|
|
mOnSignal = NULL;
|
|
mOnModifyPosition = NULL;
|
|
mOnStopLossTriggered = NULL;
|
|
mOnTakeProfitTriggered = NULL;
|
|
mOnForceClosePosition = NULL;
|
|
mOnDealsChangedHandler = NULL;
|
|
mOnPartialClosePosition = NULL;
|
|
mOnOrdersChangedHandler = NULL;
|
|
mOnPositionsChangedHandler = NULL;
|
|
mOnTradeStateChangedHandler = NULL;
|
|
}
|
|
|
|
//
|
|
// Properties Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Retrieve Slippage ...
|
|
int GetSlippage()
|
|
{
|
|
return mTrader.GetSlippage();
|
|
}
|
|
|
|
//
|
|
// Retrieve Magic Number ...
|
|
ulong GetMagicNumber()
|
|
{
|
|
return mTrader.GetMagicNumber();
|
|
}
|
|
|
|
//
|
|
double GetDrawdownPercent()
|
|
{
|
|
//
|
|
CalculateMaxDrawdown();
|
|
return mDrawdownPercent;
|
|
}
|
|
|
|
//
|
|
void AddOnSignalEventHandler(TOnSignal handler)
|
|
{
|
|
//
|
|
Add(
|
|
handler,
|
|
mOnSignalEventHandlers //
|
|
);
|
|
}
|
|
|
|
//
|
|
double MinRequiredProfitPerTrade()
|
|
{
|
|
return mMinRequiredProfitPerTrade;
|
|
}
|
|
|
|
//
|
|
void MinRequiredProfitPerTrade(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mMinRequiredProfitPerTrade = value;
|
|
}
|
|
|
|
//
|
|
double MinRequiredProfitPerVolumeFactor()
|
|
{
|
|
return mMinRequiredProfitPerVolumeFactor;
|
|
}
|
|
|
|
//
|
|
void MinRequiredProfitPerVolumeFactor(double value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
if (value > 0 && value < 0.01)
|
|
{
|
|
value = 0.01;
|
|
}
|
|
|
|
//
|
|
mMinRequiredProfitPerVolumeFactor = value;
|
|
}
|
|
|
|
//
|
|
int RestingAfterHedge()
|
|
{
|
|
return mRestingAfterHedge;
|
|
}
|
|
|
|
//
|
|
void RestingAfterHedge(int value)
|
|
{
|
|
//
|
|
if (value < 0)
|
|
{
|
|
value = 0;
|
|
}
|
|
|
|
//
|
|
mRestingAfterHedge = value;
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
//
|
|
// Customize Token ...
|
|
virtual string GetToken()
|
|
{
|
|
return GetSpecificToken(this);
|
|
}
|
|
|
|
//
|
|
virtual string GetTag()
|
|
{
|
|
return this.GetToken();
|
|
}
|
|
|
|
//
|
|
// Virtual Functions ...
|
|
|
|
//
|
|
// Handle Chart Events ...
|
|
virtual void OnChartEvent(
|
|
const int id, // event ID
|
|
const long &lparam, // long type event parameter
|
|
const double &dparam, // double type event parameter
|
|
const string &sparam // string type event parameter
|
|
)
|
|
{
|
|
}
|
|
|
|
//
|
|
// OnTick Handler ...
|
|
virtual void OnTick()
|
|
{
|
|
//
|
|
CalculateMaxDrawdown();
|
|
|
|
//
|
|
// Draw ...
|
|
Draw();
|
|
|
|
//
|
|
// Check Trade Events ...
|
|
OnTrade();
|
|
|
|
//
|
|
SyncSupports();
|
|
|
|
//
|
|
// First Check For Any Guard Actions ...
|
|
// then Handle Guards if Provided ...
|
|
XGuard guards[];
|
|
bool hasGuard = CheckForGuard(guards);
|
|
if (hasGuard)
|
|
{
|
|
DoGuards(guards);
|
|
}
|
|
|
|
//
|
|
XSignal signals[];
|
|
|
|
//
|
|
// Second Check for Position Management or Equity Management
|
|
// Actions like Supports or etc ...
|
|
bool isIgnored = HandleStateManagement(signals);
|
|
if (isIgnored)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Sleeping State ...
|
|
bool isSlept = IsSlept();
|
|
if (isSlept)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Second Check For Signals ...
|
|
// then Execute Signals if Provided ...
|
|
int signalsCount = RequestForSignal(signals);
|
|
if (signalsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Execute Signals ...
|
|
HandleSignalsExecution(signals);
|
|
|
|
//
|
|
Clean(guards);
|
|
Clean(signals);
|
|
}
|
|
|
|
//
|
|
// These are Some Event Handler ...
|
|
|
|
//
|
|
// Calls whenever a signal Executed ...
|
|
virtual void OnSignalExecuted(const XSignal &signal) {}
|
|
|
|
//
|
|
// Cals whenever a Signal Execution Failed ...
|
|
virtual void OnSignalExecutionFailed(
|
|
const XSignal &signal,
|
|
const ENUM_X_SIGNAL_EXECUTION_RESULT reason //
|
|
)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Calls when a Position Modified ...
|
|
virtual void OnPositionModified(
|
|
const XPosition &position,
|
|
const string comment //
|
|
)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Calls when a Position Closed ...
|
|
virtual void OnPositionClosed(
|
|
const XPosition &position,
|
|
const string comment //
|
|
)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Calls when a Position Partially Closed ...
|
|
virtual void OnPositionPartialyClosed(
|
|
const XPosition &position,
|
|
const string comment //
|
|
)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Handle StopLoss Event ...
|
|
virtual void OnStopLossTriggered(const XDeal &deal) {}
|
|
|
|
//
|
|
// Handle TakeProfit Event ...
|
|
virtual void OnTakeProfitTriggered(const XDeal &deal) {}
|
|
|
|
//
|
|
// Handle Deals Changed Event ...
|
|
virtual void OnDealsChangedHandler(int count) {}
|
|
|
|
//
|
|
// Handle Order Changed Event ...
|
|
virtual void OnOrdersChangedHandler(int count) {}
|
|
|
|
//
|
|
// Handle Position Changed Event ...
|
|
virtual void OnPositionsChangedHandler(int count) {}
|
|
|
|
//
|
|
// Handle Trade State Changed ...
|
|
virtual void OnTradeStateChangedHandler(const XOnTradeHandlerState &state) {}
|
|
|
|
//
|
|
// Handle On Trade ...
|
|
virtual void OnTrade()
|
|
{
|
|
//
|
|
XOnTradeHandlerState state = mTrader.HandleOnTrade();
|
|
|
|
//
|
|
if (
|
|
!state.hasNewDeal &&
|
|
!state.hasNewOrder &&
|
|
!state.hasNewPosition &&
|
|
!state.hasNewHistoryOrder)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// STATE ...
|
|
|
|
//
|
|
// Notfy Trade State Changed Event ...
|
|
OnTradeStateChangedHandler(state);
|
|
|
|
//
|
|
// DEALS ...
|
|
if (state.hasNewDeal)
|
|
{
|
|
//
|
|
// Notfy Deals Changed Event ...
|
|
OnDealsChangedHandler(state.newDeals);
|
|
|
|
//
|
|
// Retrieve Last Deal ...
|
|
XDeal deals[];
|
|
mTrader.GetDeals(deals);
|
|
int dealsCount = ArraySize(deals);
|
|
if (dealsCount > 0)
|
|
{
|
|
//
|
|
XDeal lastDeal = deals[0];
|
|
|
|
//
|
|
if (lastDeal.reason == DEAL_REASON_TP)
|
|
{
|
|
OnTakeProfitTriggered(lastDeal);
|
|
}
|
|
else if (lastDeal.reason == DEAL_REASON_SL)
|
|
{
|
|
OnStopLossTriggered(lastDeal);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// ORDERS ...
|
|
if (state.hasNewOrder || state.hasNewHistoryOrder)
|
|
{
|
|
//
|
|
// Notfy Orders Changed Event ...
|
|
OnOrdersChangedHandler(state.newOrders + state.newHistoryOrders);
|
|
}
|
|
|
|
//
|
|
// POSITIONS ...
|
|
if (state.hasNewPosition)
|
|
{
|
|
//
|
|
// Notfy Positions Changed Event ...
|
|
OnPositionsChangedHandler(state.newPositions);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Retrieve Dept Of Market ...
|
|
virtual void OnBookEvent(const string &symbol)
|
|
{
|
|
//
|
|
// TODO: Implement this ...
|
|
}
|
|
|
|
//
|
|
// Draw On Chart if anything is required ...
|
|
virtual void Draw() {}
|
|
|
|
//
|
|
// Check For any Guard Actions ...
|
|
virtual bool CheckForGuard(XGuard &guards[])
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// When a Guard Notified to Do Support Signal ...
|
|
// this Method Calls For Retrieve Support Signal ...
|
|
// if it's Provided, Execute it ...
|
|
virtual bool RequestForSupport(
|
|
XSignal &support, // Holds Support Signal, if Provided
|
|
string provider, // Positions Provided by Specific Provider
|
|
string symbol, // Trading Symbol
|
|
ENUM_X_POSITION_TYPES type, // Trading Type
|
|
ENUM_TIMEFRAMES period // Specified Time Frame
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Handle Position(s)/ Order(s) or EQM Supporting Action ...
|
|
// if returns true, prevent for process Tick ...
|
|
virtual bool HandleStateManagement(XSignal &signals[])
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Regulary Filtered Signals passed to this
|
|
// and here we can do Additional Signal Filtering
|
|
// for Signal Management such as (Providers and etc) ...
|
|
virtual int HandleSignalManagement(XSignal &signals[])
|
|
{
|
|
//
|
|
int result = ArraySize(signals);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Here we Have to Check Market based
|
|
// on our Strategy for Trading ...
|
|
// and if a Good Entry founded ...
|
|
// model it as an XSignal struct and passed it to result ...
|
|
virtual int RequestForSignal(
|
|
XSignal &signals[] // Holds Signals ...
|
|
)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Execute Provided Signals ...
|
|
virtual void HandleSignalsExecution(XSignal &signals[])
|
|
{
|
|
//
|
|
int signalsCount = ArraySize(signals);
|
|
if (signalsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int managedSignalsCount = HandleSignalManagement(signals);
|
|
if (managedSignalsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Notify Signal Event Handlers for Reciving New Signal ...
|
|
for (int i = 0; i < managedSignalsCount; i++)
|
|
{
|
|
NotifyOnSignalEventHandlers(signals[i]);
|
|
}
|
|
|
|
//
|
|
// Try to Execute Signals ...
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT reasons[];
|
|
int executedSignalsCount = ExecuteSignals(
|
|
signals,
|
|
reasons //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Calculate Max Drawdown and it's Percent ...
|
|
double CalculateMaxDrawdown()
|
|
{
|
|
//
|
|
int positionsCount = PositionsTotal();
|
|
if (IsValidSize(positionsCount))
|
|
{
|
|
double mEquity = mTrader.mAccount.GetEquity();
|
|
if (mEquity > mMaxDrawdown)
|
|
{
|
|
mMaxDrawdown = mEquity;
|
|
}
|
|
|
|
//
|
|
mDrawdownPercent = (mMaxDrawdown - mEquity) / (mStaticBalanceForCalculateDrawdown > 0 ? mStaticBalanceForCalculateDrawdown : mMaxDrawdown) * 100;
|
|
mDrawdownPercent = NormalizeDouble(mDrawdownPercent, 3);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
mMaxDrawdown = 0.0;
|
|
mDrawdownPercent = 0.0;
|
|
}
|
|
|
|
//
|
|
return mDrawdownPercent;
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Check in Test Mode or not ...
|
|
bool mIsInTestMode;
|
|
|
|
//
|
|
// Save Max Drawdown ...
|
|
double mMaxDrawdown;
|
|
double mDrawdownPercent;
|
|
double mStaticBalanceForCalculateDrawdown;
|
|
|
|
//
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Since we need to Calls Some Event Handlers on
|
|
// - Signal Execution;
|
|
// - Modified;
|
|
// - Closed;
|
|
// - Partial Closed;
|
|
// events ...
|
|
// we have to implement thouse Methods here and use them ...
|
|
|
|
//
|
|
// Execute Stand alone Signal ...
|
|
bool ExecuteSignal(
|
|
XSignal &signal, // Signal
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Result
|
|
bool checkPolicies = true, // Check Account Policies
|
|
ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime
|
|
datetime expiration = NULL // order expiration time
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = mTrader.ExecuteSignal(
|
|
signal,
|
|
state,
|
|
lifetime,
|
|
expiration,
|
|
checkPolicies //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
OnSignalExecuted(signal);
|
|
|
|
//
|
|
string message = "Signal Executed (" + ToString(signal.positionId) + ") Successfully ...";
|
|
|
|
//
|
|
Alert(message);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
OnSignalExecutionFailed(signal, state);
|
|
|
|
// //
|
|
// string message = "Signal Execution Failed: " + ToString(state) + " ...";
|
|
|
|
// //
|
|
// Alert(message);
|
|
}
|
|
|
|
//
|
|
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
|
|
bool checkPolicies = true, // Check Account Policies
|
|
ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime
|
|
datetime expiration = NULL // order expiration time
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
int signalsCount = ArraySize(signals);
|
|
if (!IsValidSize(signalsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
Clean(states);
|
|
ArrayResize(states, signalsCount, X_SIGNAL_EXECUTION_UNKNOWN);
|
|
|
|
//
|
|
for (int i = 0; i < signalsCount; i++)
|
|
{
|
|
//
|
|
bool isExecuted = ExecuteSignal(
|
|
signals[i],
|
|
states[i],
|
|
checkPolicies,
|
|
lifetime,
|
|
expiration //
|
|
);
|
|
if (isExecuted)
|
|
{
|
|
result++;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Modify ...
|
|
bool Modify(
|
|
ulong ticket, // position ticket
|
|
double sl = 0, // stop loss price
|
|
double tp = 0, // take profit
|
|
string comment = NULL // comment
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = mTrader.Modify(
|
|
ticket,
|
|
sl,
|
|
tp,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
XPosition position;
|
|
result = mTrader.GetPosition(
|
|
ticket,
|
|
position //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
OnPositionModified(
|
|
position,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
string message = "Position " + ToString(ticket) + " Modified Successfully ...";
|
|
|
|
//
|
|
Alert(message);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Close ...
|
|
bool Close(
|
|
ulong ticket,
|
|
string comment //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XPosition position;
|
|
result = mTrader.GetPosition(
|
|
ticket,
|
|
position //
|
|
);
|
|
|
|
//
|
|
result = mTrader.Close(
|
|
ticket,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
OnPositionClosed(
|
|
position,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
string message = "Position " + ToString(ticket) + " Closed Successfully ...";
|
|
|
|
//
|
|
Alert(message);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Close ...
|
|
int Close(
|
|
XPosition &positions[],
|
|
string comment //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
int count = ArraySize(positions);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
bool isClosed = Close(
|
|
positions[i].ticket,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
if (isClosed)
|
|
{
|
|
result++;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Partial Close ...
|
|
bool PartialClose(
|
|
ulong ticket,
|
|
double volume,
|
|
string comment //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XPosition position;
|
|
result = mTrader.GetPosition(
|
|
ticket,
|
|
position //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = mTrader.ClosePartial(
|
|
ticket,
|
|
volume,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
if (result)
|
|
{
|
|
//
|
|
OnPositionPartialyClosed(
|
|
position,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
string message = "Position " + ToString(ticket) + " Successfully Closed Parital ...";
|
|
|
|
//
|
|
Alert(message);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Partial Close ...
|
|
int PartialClose(
|
|
XPosition &positions[],
|
|
double volume,
|
|
string comment //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
int count = ArraySize(positions);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
bool isClosed = PartialClose(
|
|
positions[i].ticket,
|
|
volume,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
if (isClosed)
|
|
{
|
|
result++;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CancelOrders()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
XOrder supports[];
|
|
int supportsCount = mTrader.GetOrders(
|
|
supports,
|
|
NULL, // All Symbols ...
|
|
XEQMSupportToken, // Only EQM Supports ...
|
|
NULL, // All Periods ...
|
|
X_POSITION_TYPE_ALL, // All Order Types ...
|
|
ORDER_STATE_PLACED, // Untriggered Orders ...
|
|
true // Filter by Magic ...
|
|
);
|
|
if (!IsValidSize(supportsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = mTrader.CancelOrders(
|
|
supports //
|
|
);
|
|
|
|
//
|
|
Clean(supports);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Search Positions and Remove
|
|
// non Exists Positions Support Orders ...
|
|
void SyncSupports()
|
|
{
|
|
//
|
|
XOrder orders[];
|
|
int ordersCount = mTrader.GetOrders(
|
|
orders,
|
|
NULL, // All Symbols ...
|
|
NULL, // All Providers ...
|
|
NULL, // All Periods ...
|
|
X_POSITION_TYPE_ALL, // All Types ...
|
|
ORDER_STATE_PLACED, // Placed Untriggered Orders ...
|
|
true // Filter by Magic ...
|
|
);
|
|
if (!IsValidSize(ordersCount))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XPosition positions[];
|
|
int positionsCount = mTrader.GetPositions(
|
|
positions //
|
|
);
|
|
if (!IsValidSize(positions))
|
|
{
|
|
//
|
|
mTrader.CancelOrders(orders);
|
|
return;
|
|
}
|
|
|
|
//
|
|
XOrder mustCancel[];
|
|
for (int i = 0; i < ordersCount; i++)
|
|
{
|
|
//
|
|
XOrder iOrder = orders[i];
|
|
|
|
//
|
|
// Check Order is Support or not ...
|
|
ulong iParentTicket = ExtractSupportedTicket(iOrder.comment);
|
|
if (iParentTicket <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We Sure it is support Order ...
|
|
XPosition parent;
|
|
bool isParentExists = mTrader.GetPosition(
|
|
iParentTicket,
|
|
parent //
|
|
);
|
|
if (!isParentExists)
|
|
{
|
|
//
|
|
AddRef(
|
|
iOrder,
|
|
mustCancel //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
int mustCancelCount = ArraySize(mustCancel);
|
|
if (!IsValidSize(mustCancelCount))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
mTrader.CancelOrders(mustCancel);
|
|
|
|
//
|
|
Clean(orders);
|
|
Clean(positions);
|
|
Clean(mustCancel);
|
|
}
|
|
|
|
//
|
|
// Hedging ...
|
|
|
|
//
|
|
// Check Required Properties Setted for Hedge or not ...
|
|
bool AllowHedge()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
mMinRequiredProfitPerTrade > 0 &&
|
|
mMinRequiredProfitPerVolumeFactor > 0
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Hedge Conditions is Happens or not ...
|
|
// if true doing Hedge ...
|
|
bool DoHedge()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = AllowHedge();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XPosition positions[];
|
|
int positionsCount = mTrader.GetPositions(positions);
|
|
result = positionsCount > 1;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check At Least One Support Positions Open For Hedging ...
|
|
// XPosition supports[];
|
|
// int supportsCount = ExtractSupports(
|
|
// positions,
|
|
// supports //
|
|
// );
|
|
// result = IsValidSize(supportsCount);
|
|
// if (!result)
|
|
// {
|
|
// return result;
|
|
// }
|
|
|
|
//
|
|
double profits = SpecifiedCalculatePositionsProfit(positions);
|
|
double requiredProfit = SpecifiedCalculateRequiredProfitForHedge(
|
|
positions,
|
|
mMinRequiredProfitPerTrade,
|
|
mMinRequiredProfitPerVolumeFactor //
|
|
);
|
|
|
|
//
|
|
result =
|
|
positionsCount <= 5
|
|
? profits >= requiredProfit
|
|
: profits >= requiredProfit * 0.6;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string comment = XEQMSupportToken + " Hedge ...";
|
|
|
|
//
|
|
int closed = Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
result = IsValidSize(closed);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
SyncSupports();
|
|
|
|
//
|
|
string message = XEQMSupportToken + " Hedge: " + ToString(profits) + " ...";
|
|
|
|
//
|
|
Alert(message);
|
|
|
|
//
|
|
if (mRestingAfterHedge > 0)
|
|
{
|
|
Sleeping(mRestingAfterHedge);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Signal Event Listeners ...
|
|
|
|
//
|
|
void NotifyOnSignalEventHandlers(XSignal &signal)
|
|
{
|
|
//
|
|
int listenersCount = ArraySize(mOnSignalEventHandlers);
|
|
if (listenersCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < listenersCount; i++)
|
|
{
|
|
//
|
|
TOnSignal iListener = mOnSignalEventHandlers[i];
|
|
|
|
//
|
|
iListener(signal);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Guards ...
|
|
|
|
//
|
|
// Do All Provided Guards ...
|
|
void DoGuards(XGuard &guards[])
|
|
{
|
|
//
|
|
int guardsCount = ArraySize(guards);
|
|
if (guardsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < guardsCount; i++)
|
|
{
|
|
//
|
|
XGuard iGuard = guards[i];
|
|
|
|
//
|
|
switch (iGuard.action)
|
|
{
|
|
//
|
|
// Hedge In Profit Specified Positions ...
|
|
case X_GUARD_ACTION_HEDGE:
|
|
HandleGuardHedgeAction(
|
|
iGuard.provider,
|
|
iGuard.symbol,
|
|
iGuard.type,
|
|
iGuard.period);
|
|
break;
|
|
|
|
//
|
|
// Trail Stop Loss in Specified Positions ...
|
|
case X_GUARD_ACTION_TRAIL_STOP:
|
|
HandleGuardTrailingStopAction(
|
|
iGuard.provider,
|
|
iGuard.symbol,
|
|
iGuard.type,
|
|
iGuard.period,
|
|
iGuard.dblPayLoad);
|
|
break;
|
|
|
|
//
|
|
// Force Close Specified Positions ...
|
|
case X_GUARD_ACTION_FORCE_CLOSE:
|
|
HandleGuardForceCloseAction(
|
|
iGuard.provider,
|
|
iGuard.symbol,
|
|
iGuard.type,
|
|
iGuard.period);
|
|
break;
|
|
|
|
//
|
|
// Generate and Place Support Signals ...
|
|
case X_GUARD_ACTION_ADD_SUPPORT_SIGNAL:
|
|
HandleGuardAddSupportPositionAction(
|
|
iGuard.provider,
|
|
iGuard.symbol,
|
|
iGuard.type,
|
|
iGuard.period);
|
|
break;
|
|
|
|
//
|
|
// Delete All Placed Pending Orders ...
|
|
case X_GUARD_ACTION_CANCEL_PENDING_ORDERS:
|
|
HandleGuardCancelPendingOrdersAction(
|
|
iGuard.provider,
|
|
iGuard.symbol,
|
|
iGuard.type,
|
|
iGuard.period);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close All Specified Provider's Positions in Profit Summary ...
|
|
void HandleGuardHedgeAction(
|
|
string provider, // Positions Provided by Specific Provider
|
|
string symbol, // Trading Symbol
|
|
ENUM_X_POSITION_TYPES type, // Trading Type
|
|
ENUM_TIMEFRAMES period, // Specified Time Frame
|
|
double minProfitForHedging = 1, // Specified Profit for Hedge
|
|
double minProfitForHedgingVolumeFactor = 0.01 // Specified Volume Factor for Hedge
|
|
)
|
|
{
|
|
//
|
|
XPosition positions[];
|
|
int positionsCount = mTrader
|
|
.GetPositions(
|
|
positions,
|
|
symbol,
|
|
provider,
|
|
period,
|
|
type
|
|
//
|
|
);
|
|
if (positionsCount <= 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
double profit = SpecifiedCalculatePositionsProfit(positions);
|
|
double requiredProfit = SpecifiedCalculateRequiredProfitForHedge(
|
|
positions,
|
|
minProfitForHedging,
|
|
minProfitForHedgingVolumeFactor //
|
|
);
|
|
|
|
//
|
|
bool isReadyForHedge = profit >= requiredProfit;
|
|
if (!isReadyForHedge)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Guard Hedge " + provider;
|
|
int closed = mTrader.Close(
|
|
positions,
|
|
comment
|
|
//
|
|
);
|
|
if (closed > 0)
|
|
{
|
|
//
|
|
string message = "Guard Hedge " + provider + "'s Positions on Profit: " + ToString(profit);
|
|
|
|
//
|
|
Alert(message);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close Max In Profit Trade Guard Action ...
|
|
void HandleGuardCloseInProfitAction(
|
|
string provider, // Positions Provided by Specific Provider
|
|
string symbol, // Trading Symbol
|
|
ENUM_X_POSITION_TYPES type, // Trading Type
|
|
ENUM_TIMEFRAMES period, // Specified Time Frame
|
|
ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method
|
|
)
|
|
{
|
|
//
|
|
XPosition positions[];
|
|
int positionsCount = mTrader
|
|
.GetInProfitPositions(
|
|
positions,
|
|
symbol,
|
|
provider,
|
|
period,
|
|
type,
|
|
method
|
|
//
|
|
);
|
|
if (positionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Close InProfit ...";
|
|
mTrader.Close(
|
|
positions,
|
|
comment
|
|
//
|
|
);
|
|
|
|
//
|
|
string message = "Guard Close (" + ToString(positionsCount) + ") Postion(s) In Profit ...";
|
|
|
|
//
|
|
Alert(message);
|
|
}
|
|
|
|
//
|
|
// Close Max In Drawdown Trade Guard Action ...
|
|
void HandleGuardCloseInDrawdownAction(
|
|
string provider, // Positions Provided by Specific Provider
|
|
string symbol, // Trading Symbol
|
|
ENUM_X_POSITION_TYPES type, // Trading Type
|
|
ENUM_TIMEFRAMES period, // Specified Time Frame
|
|
ENUM_X_POSITION_SELECT_METHODS method = NULL // Select Method
|
|
)
|
|
{
|
|
//
|
|
XPosition positions[];
|
|
int positionsCount = mTrader
|
|
.GetInDrawdownPositions(
|
|
positions,
|
|
symbol,
|
|
provider,
|
|
period,
|
|
type,
|
|
method
|
|
//
|
|
);
|
|
if (positionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
string comment = "Close InDrawdown ...";
|
|
mTrader.Close(
|
|
positions,
|
|
comment
|
|
//
|
|
);
|
|
|
|
//
|
|
string message = "Guard Close (" + ToString(positionsCount) + ") Position(s) In Drawdown ...";
|
|
|
|
//
|
|
Alert(message);
|
|
}
|
|
|
|
//
|
|
// Force Close Specified Set Of Position ...
|
|
void HandleGuardForceCloseAction(
|
|
string provider, // Positions Provided by Specific Provider
|
|
string symbol, // Trading Symbol
|
|
ENUM_X_POSITION_TYPES type, // Trading Type
|
|
ENUM_TIMEFRAMES period, // Specified Time Frame
|
|
ulong ticket = 0 // Specific Ticket
|
|
)
|
|
{
|
|
//
|
|
string comment = "";
|
|
|
|
//
|
|
// Close All Positions ...
|
|
if (ticket == 0)
|
|
{
|
|
//
|
|
XPosition positions[];
|
|
int positionsCount = mTrader.GetPositions(
|
|
positions,
|
|
symbol,
|
|
provider,
|
|
period,
|
|
type
|
|
//
|
|
);
|
|
if (positionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
comment = provider + " Force Close Guard ...";
|
|
|
|
//
|
|
mTrader.Close(
|
|
positions,
|
|
comment
|
|
//
|
|
);
|
|
}
|
|
//
|
|
// Close Specific Position ...
|
|
else
|
|
{
|
|
//
|
|
XPosition position;
|
|
bool hasPosition = mTrader
|
|
.GetPosition(
|
|
ticket,
|
|
position
|
|
//
|
|
);
|
|
|
|
//
|
|
if (hasPosition)
|
|
{
|
|
//
|
|
comment = provider + "(" + ToString(ticket) + ")" + " Force Close Guard ...";
|
|
|
|
//
|
|
mTrader.Close(
|
|
ticket,
|
|
comment
|
|
//
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
if (IsValid(comment))
|
|
{
|
|
Alert(comment);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Trailing Specified Set Of Positions Stop Losses ...
|
|
void HandleGuardTrailingStopAction(
|
|
string provider, // Positions Provided by Specific Provider
|
|
string symbol, // Trading Symbol
|
|
ENUM_X_POSITION_TYPES type, // Trading Type
|
|
ENUM_TIMEFRAMES period, // Specified Time Frame
|
|
double sl // Desired SL Value ...
|
|
)
|
|
{
|
|
//
|
|
if (sl <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
NormalizePrice(
|
|
sl,
|
|
symbol
|
|
//
|
|
);
|
|
|
|
//
|
|
XPosition positions[];
|
|
int positionsCount = mTrader
|
|
.GetPositions(
|
|
positions,
|
|
symbol,
|
|
provider,
|
|
period,
|
|
type
|
|
//
|
|
);
|
|
if (positionsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int modified = 0;
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
string comment = PrepareSLTrailTag(iPosition.comment);
|
|
|
|
//
|
|
if (iPosition.sl == sl)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isModified = mTrader.Modify(
|
|
iPosition.ticket,
|
|
sl,
|
|
iPosition.tp,
|
|
comment);
|
|
if (isModified)
|
|
{
|
|
modified++;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (modified > 0)
|
|
{
|
|
//
|
|
string message = "(" + ToString(modified) + ") Position's Stop Trailed Successfully ...";
|
|
|
|
//
|
|
Alert(message);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add Support Signal for Specified Positions ...
|
|
void HandleGuardAddSupportPositionAction(
|
|
string provider, // Positions Provided by Specific Provider
|
|
string symbol, // Trading Symbol
|
|
ENUM_X_POSITION_TYPES type, // Trading Type
|
|
ENUM_TIMEFRAMES period // Specified Time Frame
|
|
)
|
|
{
|
|
//
|
|
XSignal support;
|
|
bool hasSupport = RequestForSupport(
|
|
support,
|
|
provider,
|
|
symbol,
|
|
type,
|
|
period
|
|
//
|
|
);
|
|
|
|
//
|
|
if (!hasSupport || !support.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// TODO: May be need to add Support Tag to comments ...
|
|
|
|
//
|
|
ENUM_X_SIGNAL_EXECUTION_RESULT reason = NULL;
|
|
bool isExecuted = ExecuteSignal(
|
|
support,
|
|
reason //
|
|
);
|
|
|
|
//
|
|
string comment = NULL;
|
|
if (!isExecuted)
|
|
{
|
|
comment = "Support Execution Failed doue " + ToString(reason);
|
|
}
|
|
else
|
|
{
|
|
comment = "Guard Support Signal Executed Successfully ...";
|
|
}
|
|
|
|
//
|
|
if (IsValid(comment))
|
|
{
|
|
Alert(comment);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Cancel all Placed Orders ...
|
|
void HandleGuardCancelPendingOrdersAction(
|
|
string provider, // Positions Provided by Specific Provider
|
|
string symbol, // Trading Symbol
|
|
ENUM_X_POSITION_TYPES type, // Trading Type
|
|
ENUM_TIMEFRAMES period // Specified Time Frame
|
|
)
|
|
{
|
|
//
|
|
XOrder orders[];
|
|
int ordersCount = mTrader.GetOrders(
|
|
orders,
|
|
symbol,
|
|
provider,
|
|
period,
|
|
type,
|
|
ORDER_STATE_PLACED,
|
|
true // Filter by Magic ...
|
|
//
|
|
);
|
|
if (ordersCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int canceledOrdersCount = mTrader.CancelOrders(orders);
|
|
|
|
//
|
|
if (canceledOrdersCount > 0)
|
|
{
|
|
//
|
|
string message = "Guard Cancel (" + ToString(canceledOrdersCount) + ") Pending Orders ...";
|
|
|
|
//
|
|
Alert(message);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sleeping Context ...
|
|
|
|
//
|
|
// Sleeping Mode ...
|
|
int mSleepingDuration;
|
|
datetime mSleepingStartAt;
|
|
bool Sleeping(int seconds = -1)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
mSleepingDuration =
|
|
seconds > 0
|
|
? seconds
|
|
: mRestingAfterHedge > 0
|
|
? mRestingAfterHedge
|
|
: 0;
|
|
result = mSleepingDuration > 0;
|
|
if (!result)
|
|
{
|
|
//
|
|
ResetSleeping();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Doesnt Sleep Before ...
|
|
result = mSleepingStartAt == NULL;
|
|
if (!result)
|
|
{
|
|
//
|
|
ResetSleeping();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
datetime cTime = TimeCurrent();
|
|
mSleepingStartAt = cTime;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsSlept()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = mSleepingDuration > 0 &&
|
|
mSleepingStartAt != NULL;
|
|
if (!result)
|
|
{
|
|
//
|
|
ResetSleeping();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
datetime cTime = TimeCurrent();
|
|
result = (int)cTime < (int)mSleepingStartAt + mSleepingDuration;
|
|
if (!result)
|
|
{
|
|
ResetSleeping();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
void ResetSleeping()
|
|
{
|
|
//
|
|
mSleepingDuration = 0;
|
|
mSleepingStartAt = NULL;
|
|
}
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
int mRestingAfterHedge; // Resting Bars After Hedge
|
|
double mMinRequiredProfitPerTrade; // Minimum Required Profit for Hedging
|
|
double mMinRequiredProfitPerVolumeFactor; // Minimum Required Profit for Hedging Per Velume
|
|
|
|
//
|
|
// Signal Event Listeners ...
|
|
TOnSignal mOnSignalEventHandlers[];
|
|
|
|
//
|
|
// Event Handlers ...
|
|
TOnSignal mOnSignal;
|
|
TOnModify mOnModifyPosition;
|
|
TOnStopLoss mOnStopLossTriggered;
|
|
TOnTakeProfit mOnTakeProfitTriggered;
|
|
TOnForceClose mOnForceClosePosition;
|
|
TOnDealsChanged mOnDealsChangedHandler;
|
|
TOnPartialClose mOnPartialClosePosition;
|
|
TOnOrdersChanged mOnOrdersChangedHandler;
|
|
TOnPositionsChanged mOnPositionsChangedHandler;
|
|
TOnTradeStateChanged mOnTradeStateChangedHandler;
|
|
};
|
|
|
|
// |