Files
MQL5Data/Classes/x-saherelm.x-target.class.mq5
T

712 lines
16 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// ----------------------------------------------
// Name: XCTarget
// Description: provides all Positions Target 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 "../Classes/x-saherelm.x-trade.class.mq5"
//
// Implementation ...
class XCTarget : public XCBase
{
//
// Public ...
public:
//
XCTrade *trader;
XCAlert *alert;
XSignal signals[];
//
// Constructor ...
XCTarget(
XCTrade *_trader, //
XCAlert *_alert //
) : XCBase()
{
//
alert = _alert;
trader = _trader;
//
XClean(signals);
}
//
// Deconstructor ...
~XCTarget()
{
Destroy();
}
//
void Destroy()
{
//
XClean(signals);
}
//
// Actions ...
/**
* Manage Positions ...
*
* @param barIndex: int, Bar Index ...
*/
void Manage(int barIndex = 0)
{
//
// Normalize ...
barIndex = NormalizeInt(barIndex, 0);
//
// Extract In Profit Positions ...
XPosition positions[];
int count = GetInProfitPositions(positions);
bool has = IsValidIndex(count);
if (!has)
{
return;
}
//
XSignal iSignal;
XTarget iTarget;
int signalIDX = -1;
int targetIDX = -1;
XPosition iPosition;
//
// Loop through Positions ...
for (int i = 0; i < count; i++)
{
//
// Select Positions ...
iPosition = positions[i];
has = FindSignal(
signalIDX,
iPosition.ticket //
);
if (!has)
{
continue;
}
iSignal = signals[signalIDX];
//
// Selecting Target ...
targetIDX = iSignal.appliedTargetIDX;
if (iSignal.isTargetApplied)
{
targetIDX++;
}
//
// Validate Targets Size ...
has = HasChild(iSignal.targets) &&
targetIDX < ArraySize(iSignal.targets);
if (has)
{
//
// Select Target ...
iTarget = iSignal.targets[targetIDX];
//
// Check Can Apply Target and Apply it ...
has = HandleApplyTarget(iTarget, iPosition);
if (has)
{
//
// Update Target IDX ...
iSignal.appliedTargetIDX++;
}
}
//
// Update Signal ...
signals[signalIDX] = iSignal;
//
// Cleanup ...
iSignal.Clean();
iTarget.Clean();
iPosition.Clean();
}
//
// Cleanup Resources ...
iSignal.Clean();
iTarget.Clean();
iPosition.Clean();
}
/**
* Extract in Profit Positions ...
*
* @param positions: XPosition, reference collection to holds result ...
*
* @return ( int )
*/
int GetInProfitPositions(
XPosition &positions[] //
)
{
//
int result = 0;
//
// Prepare ...
XClean(positions);
//
// Validate ...
if (trader == NULL)
{
return result;
}
//
result = trader.GetInProfitPositions(
positions,
NULL, // All Symbols ...
NULL, // All Providers ...
NULL, // All Periods ...
NULL, // All Position Types ...
X_POSITION_SELECT_ALL, // Select Method ...
true, // Filter by Magic ...
true // Force Clean ...
);
if (IsValidSize(result))
{
//
XPosition iPos;
XPosition tmp[];
Copy(
positions,
tmp //
);
XClean(positions);
while (HasChild(tmp))
{
//
iPos = tmp[0];
ArrayRemove(
tmp,
0,
1 //
);
//
int idx = -1;
bool has = FindSignal(
idx,
iPos.ticket //
);
if (has)
{
//
AddRef(
iPos,
positions //
);
}
}
//
XClean(tmp);
iPos.Clean();
//
result = ArraySize(positions);
}
//
return result;
}
/**
* Add Executed Signal ...
*
* @param signal: XSignal, reference to Executed Signal ...
*/
void AddExecutedSignal(XSignal &signal)
{
//
// Validate ...
if (!signal.IsValid() || !signal.IsExecuted())
{
return;
}
//
AddRef(
signal,
signals //
);
}
//
// Trade Event Handlers ...
/**
* Handle Stop Loss Event Triggered ...
*
* @param deal: XDeal instance refrence, provides Triggered Deal info ...
*/
void HandleOnStopLossTriggered(const XDeal &deal)
{
RemoveSignal(deal.positionId);
}
/**
* Handle Take Profit Event Triggered ...
*
* @param deal: XDeal instance refrence, provides Triggered Deal info ...
*/
void HandleOnTakeProfitTriggered(const XDeal &deal)
{
RemoveSignal(deal.positionId);
}
/**
* Handle Position Force Closed Event ...
*
* @param ticket: ulong, triggered Positions ticket ...
* @param position: XPosition instance refrence, Triggered Position ...
* @param comment: string, Comment ...
*/
void HandleOnPositionForceClosed(
const ulong ticket,
const XPosition &position,
const string comment //
)
{
RemoveSignal(ticket);
}
//
// Event Handlers Registration ...
//
void AddOnStopLossEventHandler(TOnStopLoss handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mStopLossEventHandlers
//
);
}
//
void AddOnTakeProfitEventHandler(TOnTakeProfit handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mTakeProfitEventHandlers
//
);
}
//
void AddOnForceClosePositionEventHandler(TOnForceClose handler)
{
//
if (handler == NULL)
{
return;
}
//
Add(
handler,
mOnForceCloseEventHandlers
//
);
}
//
// Protected ...
protected:
//
/**
* Find Specified Signal ...
*
* @param index: int, reference to holds detected index ...
* @param signal: XSignal, reference to Specified Signal ...
*
* @return ( bool )
*/
bool FindSignal(
int &index,
XSignal &signal //
)
{
//
bool result = false;
//
// Prepare ...
index = -1;
//
// Validate ...
result = signal.IsValid() &&
HasChild(signals);
if (!result)
{
return result;
}
//
// Looping Through Signals ...
int count = ArraySize(signals);
for (int i = 0; i < count; i++)
{
//
result = signals[i]
.IsSameAs(signal);
if (result)
{
//
index = i;
break;
}
}
//
result = IsValidIndex(index);
//
return result;
}
/**
* Find Specified Signal ...
*
* @param index: int, reference to holds detected index ...
* @param ticket: ulong, Specified Signal Position ID ...
*
* @return ( bool )
*/
bool FindSignal(
int &index,
ulong ticket //
)
{
//
bool result = false;
//
// Prepare ...
index = -1;
//
// Validate ...
result = NotEmptyZero(ticket) &&
HasChild(signals);
if (!result)
{
return result;
}
//
// Looping Through Signals ...
int count = ArraySize(signals);
for (int i = 0; i < count; i++)
{
//
result = signals[i].IsValid() &&
signals[i].IsExecuted() &&
signals[i].positionId == ticket;
if (result)
{
//
index = i;
break;
}
}
//
result = IsValidIndex(index);
//
return result;
}
/**
* Remove Specified Signal ...
*
* @param ticket: ulong, Specified Ticket ...
*/
void RemoveSignal(ulong ticket)
{
//
bool has = NotEmptyZero(ticket) &&
HasChild(signals);
if (!has)
{
return;
}
//
int idx = -1;
has = FindSignal(
idx,
ticket //
);
if (!has)
{
return;
}
//
ArrayRemove(
signals,
idx,
1 //
);
}
/**
* Check Can Apply Specified Target on Specified Position or not ...
*
* @param target: XTarget, reference to Specified Target for Apply ...
* @param position: XPosition, reference to Specified Position ...
*
* @return ( bool )
*/
bool CanApplyTarget(
XTarget &target,
XPosition &position //
)
{
//
bool result = false;
//
// Validate ...
result =
target.IsValid() &&
position.IsValid();
if (!result)
{
return result;
}
//
// Check Price Reached Targets Value and Distance ...
double targetDistance = (target.actingDistance > 0 ? target.actingDistance : 0) * position.GetPointsValue();
result =
IsLong(position.type)
? position.price >= target.target + targetDistance
: position.price <= target.target - targetDistance;
//
return result;
}
/**
* Apply Specified Target on Specified Position ...
*
* @param target: XTarget, reference to Specified Target for Apply ...
* @param position: XPosition, reference to Specified Position ...
*
* @return ( bool )
*/
bool HandleApplyTarget(
XTarget &target,
XPosition &position //
)
{
//
bool result = false;
//
// Validate ...
result =
target.IsValid() &&
position.IsValid() &&
CanApplyTarget(
target,
position //
);
if (!result)
{
return result;
}
//
// Apply Target ...
string comment = NULL;
string message = NULL;
//
// Do Risk Free if Provided ...
if (result &&
target.doRF)
{
//
comment = "Taregt Manager do RF ...";
result = trader.Modify(
position.ticket,
target.target, // SL ...
position.tp, // TP ...
comment //
);
//
// Handle Alert ...
if (result)
{
//
message = "Target Manager do RF " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") on: " + ToXString(position.price);
alert.SendAlert(message);
}
}
//
// Do Risk Free on Entry if Provided ...
if (result &&
target.doRFOnEntry)
{
//
comment = "Target Manager do RF on Entry ...";
double actingDistance = position.GetPointsValue() * target.actingDistance;
bool isLong = IsLong(position.type);
double sl = position.entry + (isLong
? actingDistance
: (-1 * actingDistance) //
);
result = trader.Modify(
position.ticket,
sl, // SL ...
position.tp, // TP ...
comment //
);
//
// Handle Alert ...
if (result)
{
//
message = "Target Manager do RF " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") on Entry ...";
alert.SendAlert(message);
}
}
//
// Do Partial Close if Provided ...
if (result &&
target.volumeMultiplier > 0)
{
//
double volume = NormalizeVolume((position.volume * target.volumeMultiplier), position.symbol);
if (volume != position.volume)
{
//
comment = "Target Manager do Partial Close ...";
result = trader.ClosePartial(
position.ticket,
volume,
comment //
);
//
// Handle Alert ...
if (result)
{
//
message = "Target Manager do Partial Close " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") by: " + ToXString(volume);
alert.SendAlert(message);
}
}
}
//
// Handle Replace TP ...
if (result &&
target.tpValue > 0)
{
//
// Validate TP Value ...
bool isLong = IsLong(position.type);
bool isValid = isLong
? target.tpValue > position.price &&
target.tpValue > position.tp
: target.tpValue < position.price &&
target.tpValue < position.tp;
if (isValid)
{
//
comment = "Target Manager Change TP ...";
result = trader.Modify(
position.ticket,
position.sl, // SL ...
target.tpValue, // TP ...
comment //
);
//
// Handle Alert ...
if (result)
{
//
message = "Target Manager Change TP of" + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") to: " + ToXString(target.tpValue) + " ...";
alert.SendAlert(message);
}
}
}
//
return result;
}
//
// Private ...
private:
//
//
// Required Event Handlers ...
TOnStopLoss mStopLossEventHandlers[];
TOnTakeProfit mTakeProfitEventHandlers[];
TOnForceClose mOnForceCloseEventHandlers[];
};
//