Files
xMQL5/BKPS/14030316/Classes/x-saherelm.xea.class.mq5
T
2024-06-05 03:56:37 +03:30

3906 lines
81 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 <Generic/HashMap.mqh>
#include "../Classes/x-saherelm.xalert.class.mq5"
#include "../Classes/x-saherelm.xtrade.class.mq5"
//
// Define On Signal Event Handler Type ...
typedef void (*TOnSignal)(XSignal &signals[]);
//
// Tokens ...
string XINProfitToken = "INP";
string XINDrawdownToken = "IND";
string XProfitsToken = "PFS";
string XTimesToken = "TMS";
string XPricessToken = "PCS";
//
enum ENUM_X_PROFIT_TRACK_FIELDS
{
X_PROFIT_TRACK_PROFIT,
X_PROFIT_TRACK_LONGS_PROFIT,
X_PROFIT_TRACK_SHORTS_PROFIT,
};
//
// Model Account Profits ...
struct XProfitTrack
{
//
int longs; // Number of Long ...
int shorts; // Number of Short ...
//
double profit; // Profit of All ...
double longsProfit; // Profits of Longs ...
double shortsProfit; // Profits of Shorts ...
//
double profitFrom; // Profit of All ...
double longsProfitFrom; // Profits of Longs ...
double shortsProfitFrom; // Profits of Shorts ...
//
double volume; // Volume ...
double longsVolume; // Volume of Longs ...
double shortsVolume; // Volume of Shorts ...
//
datetime time; // Check Time ...
//
XProfitTrack()
{
Clean();
}
//
// Tools ...
//
// Initialization ...
bool Init(XSCTrade *mTrader)
{
//
bool result = false;
//
XPosition positions[];
int positionsCount = mTrader.GetPositions(positions);
result = positionsCount > 0;
if (!result)
{
return result;
}
//
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
bool isLong = IsLong(iPosition.type);
//
if (isLong)
{
//
longs++;
longsVolume += iPosition.volume;
longsProfit += iPosition.profit;
}
else
{
//
shorts++;
shortsVolume += iPosition.volume;
shortsProfit += iPosition.profit;
}
//
profit += iPosition.profit;
volume += iPosition.volume;
}
//
result = IsValid();
if (result)
{
time = TimeCurrent();
}
//
return result;
}
//
double SelectField(ENUM_X_PROFIT_TRACK_FIELDS field)
{
//
double result = profit;
//
switch (field)
{
//
case X_PROFIT_TRACK_LONGS_PROFIT:
result = longsProfit;
break;
//
case X_PROFIT_TRACK_SHORTS_PROFIT:
result = shortsProfit;
break;
//
default:
case X_PROFIT_TRACK_PROFIT:
result = profit;
break;
}
//
return result;
}
//
// Cleanup ...
void Clean()
{
//
longs = 0;
shorts = 0;
profit = 0;
volume = 0;
profitFrom = 0;
longsVolume = 0;
longsProfit = 0;
shortsVolume = 0;
shortsProfit = 0;
longsProfitFrom = 0;
shortsProfitFrom = 0;
//
time = NULL;
}
//
// Validate ...
bool IsValid()
{
//
bool result = false;
//
result =
//
(longs > 0 || shorts > 0)
//
&&
//
volume > 0
//
;
//
return result;
}
//
};
//
// Track Specific Position ...
struct XPositionTrack
{
//
ulong ticket; // Position Ticket
string symbol; // Position Symbol
ENUM_POSITION_TYPE type; // Position Type
ENUM_TIMEFRAMES period; // Position Period
//
double price[]; // Check Price ...
double profit[]; // Check Profit ...
datetime time[]; // Check Time ...
//
double tp; // Current TP
double sl; // Current SL
double volume; // Current Volume
double entry; // Position Entry
datetime openAt; // Position Open Time
//
int inProfitCount; // Number of Cross in DrawDown
int inDrawdownCount; // Number of Crossed in Profit
//
// Constructor ...
XPositionTrack()
{
Clean();
}
//
// Tools ...
//
// Initialization ...
bool Init(
XPosition &position // Source Position
)
{
//
bool result = false;
//
Clean();
//
result = position.IsValid();
if (!result)
{
return result;
}
//
ticket = position.ticket;
symbol = position.symbol;
period = position.period;
type = position.type;
tp = position.tp;
sl = position.sl;
entry = position.entry;
volume = position.volume;
openAt = position.openAt;
//
datetime cTime = TimeCurrent();
Add(
cTime,
time //
);
//
Add(
position.profit,
profit //
);
//
Add(
position.price,
price //
);
//
result = IsValid();
//
return result;
}
//
bool Update(
XPosition &position // Source Position
)
{
//
bool result = false;
//
// Check Current Model is Valid or not ...
result = IsValid();
if (!result)
{
return result;
}
//
// Check Position is a Valid Model ...
result = position.IsValid();
if (!result)
{
return result;
}
//
// Check Current Model belongs to Given Position ...
result =
//
entry == position.entry &&
openAt == position.openAt &&
symbol == position.symbol &&
period == position.period &&
type == position.type &&
ticket == position.ticket
//
;
if (!result)
{
return result;
}
//
tp = position.tp;
sl = position.sl;
volume = position.volume;
//
datetime cTime = TimeCurrent();
//
SetArrayStates(false);
//
Add(
cTime,
time //
);
//
Add(
position.profit,
profit //
);
//
Add(
position.price,
price //
);
//
SetArrayStates(true);
//
result = IsValid();
if (!result)
{
return result;
}
//
// Fill In Profit or Drawdown Counters ...
//
bool isCrossInProfit = IsCrossedInProfit();
if (isCrossInProfit)
{
inProfitCount++;
}
//
bool isCrossedInDrawdown = IsCrossedInDrawdown();
if (isCrossedInDrawdown)
{
inDrawdownCount++;
}
//
return result;
}
//
// Cleanup ...
void
Clean()
{
//
ticket = 0;
type = NULL;
symbol = NULL;
period = NULL;
//
tp = 0;
sl = 0;
volume = 0;
entry = 0;
openAt = NULL;
//
inProfitCount = 0;
inDrawdownCount = 0;
//
Clean(price);
Clean(profit);
Clean(time);
}
//
// Validate ...
bool IsValid()
{
//
bool result = false;
//
result =
//
ticket > 0 &&
type != NULL &&
period != NULL &&
volume > 0 &&
entry > 0 &&
openAt > 0
//
;
//
return result;
}
//
void SetArrayStates(bool state)
{
//
ArraySetAsSeries(price, state);
ArraySetAsSeries(profit, state);
ArraySetAsSeries(time, state);
}
//
bool IsCrossedInProfit()
{
//
bool result = false;
//
result = IsValid();
if (!result)
{
return result;
}
//
result = ArraySize(time) > 1;
if (!result)
{
return result;
}
//
result =
//
profit[0] > 0 &&
profit[1] < 0
//
;
//
return result;
}
//
bool IsCrossedInDrawdown()
{
//
bool result = false;
//
result = IsValid();
if (!result)
{
return result;
}
//
result = ArraySize(time) > 1;
if (!result)
{
return result;
}
//
result =
//
profit[0] < 0 &&
profit[1] > 0
//
;
//
return result;
}
//
// Collector Tools ...
//
string GetToken()
{
return GetToken(this);
}
//
bool IsModelValid()
{
return IsValid();
}
//
bool IsSameAs(XPositionTrack &track)
{
//
bool result = false;
//
result =
//
track.IsValid() &&
type == track.type &&
ticket == track.ticket &&
symbol == track.symbol &&
period == track.period &&
openAt == track.openAt
//
;
//
return result;
}
//
int FindIndex(
const XPositionTrack &values[] // Collection
)
{
//
return FindIndex(
this,
values
//
);
}
//
// Converts a Model to String Representation ...
string ToModelString()
{
//
string result = NULL;
//
if (!IsValid())
{
return result;
}
//
// For Modeling a PositionTrack Object ...
// - tp
// - sl
// - type
// - entry
// - ticket
// - symbol
// - period
// - openAt
// - volume
// - inProfitCount
// - inDrawdownCount
// - time[]
// - price[]
// - profit[]
//
// Ticket ...
string ticketStr = Surround(XIDToken, ticket);
//
// Symbol ...
string SymbolStr = Surround(XSymbolToken, symbol);
//
// Type ...
string typeStr = Surround(XTypeToken, type);
//
// Period ...
int iPeriodInt = (int)period;
string periodStr = Surround(XPeriodToken, iPeriodInt);
//
// TP ...
string tpStr = Surround(XTPToken, tp);
//
// SL ...
string slStr = Surround(XSLToken, sl);
//
// Volume ...
string volumeStr = Surround(XVolumeToken, volume);
//
// Entry ...
string entryStr = Surround(XEntryToken, entry);
//
// OpenAt ...
string timeStr = Surround(XTimeToken, openAt);
//
// InProfitCount ...
string inProfitCountStr = Surround(XINProfitToken, inProfitCount);
//
// InDrawdownCount ...
string inDrawdownCountStr = Surround(XINDrawdownToken, inDrawdownCount);
//
// Time(s) ...
string timesContentStr = ToString(time);
string timesStr = Surround(XTimesToken, timesContentStr);
//
// Price(s) ...
string pricesContentStr = ToString(price);
string pricesStr = Surround(XPricessToken, pricesContentStr);
//
// Profit(s) ...
string profitsContentStr = ToString(profit);
string profitsStr = Surround(XProfitsToken, profitsContentStr);
//
string token = GetToken();
//
result =
//
token +
"[" +
//
ticketStr +
SymbolStr +
typeStr +
periodStr +
tpStr +
slStr +
volumeStr +
entryStr +
timeStr +
inProfitCountStr +
inDrawdownCountStr +
timesStr +
pricesStr +
profitsStr +
//
"]"
//
;
//
return result;
}
//
// Pres and Fill Model based on it's String Representation ...
bool ParseModel(string value)
{
//
bool result = false;
//
Clean();
//
result = IsValid(value);
if (!result)
{
return result;
}
//
// For Modeling a PositionTrack Object ...
// - tp
// - sl
// - type
// - entry
// - ticket
// - symbol
// - period
// - openAt
// - volume
// - inProfitCount
// - inDrawdownCount
// - time[]
// - price[]
// - profit[]
//
// TP ...
tp = ParseDoubleSurrounded(value, XTPToken);
//
// SL ...
tp = ParseDoubleSurrounded(value, XSLToken);
//
// Type ...
type = ((ENUM_POSITION_TYPE)ParseIntSurrounded(value, XTypeToken));
//
// Entry ...
entry = ParseDoubleSurrounded(value, XEntryToken);
//
// Ticket ...
ticket = ParseLongSurrounded(value, XIDToken);
//
// Symbol ...
symbol = ParseStringSurrounded(value, XSymbolToken);
//
// Period ...
period = ((ENUM_TIMEFRAMES)ParseIntSurrounded(value, XPeriodToken));
//
// Open At ...
openAt = ParseTimeSurrounded(value, XTimeToken);
//
// Volume ...
volume = ParseDoubleSurrounded(value, XVolumeToken);
//
// InProfitCount ...
inProfitCount = ParseIntSurrounded(value, XINProfitToken);
//
// InDrawdownCount ...
inDrawdownCount = ParseIntSurrounded(value, XINDrawdownToken);
//
// Time(s) ...
ParseTimeArraySurrounded(
time,
value,
XTimesToken
//
);
//
// Price(s) ...
ParseDoubleArraySurrounded(
price,
value,
XPricessToken
//
);
//
// Profit(s) ...
ParseDoubleArraySurrounded(
profit,
value,
XProfitsToken
//
);
//
result = IsValid();
//
return result;
}
};
//
// Type Definitions for XPosition Tracker Events ...
typedef void (*TOnPositionState)(const XPositionTrack &track);
//
// an Struct for Holding Event Handled Items for Position Tracker ...
struct XPositionTrackerState
{
//
XPositionTrack inProfits[];
XPositionTrack inDrawdowns[];
//
XPositionTrack onProfits[];
XPositionTrack onDrawdowns[];
//
XPositionTrackerState()
{
Clean();
}
//
// Tools ...
//
// Cleanup ...
void Clean()
{
//
Clean(inProfits);
Clean(inDrawdowns);
//
Clean(onProfits);
Clean(onDrawdowns);
}
};
//
// Position Tracker Class ...
class XSCPositionTracker
{
//
// Public ...
public:
//
// Props ...
//
// Constructor ...
void XSCPositionTracker(bool cleanStore = false)
{
//
XSCDataCollector<XPositionTrack> mBase;
//
if (cleanStore)
{
mBase.Clear();
}
}
//
// Tools ...
//
// Cleaning Store ...
void Clear()
{
//
XSCDataCollector<XPositionTrack> mBase;
//
mBase.Clear();
}
//
// Collect All Store ...
int Collect(XPositionTrack &result[])
{
//
int mResult = 0;
//
XSCDataCollector<XPositionTrack> mBase;
//
mResult = mBase.Collect(result);
//
return mResult;
}
//
// Add Item To Store ...
bool Add(XPositionTrack &item)
{
//
bool result = false;
//
XSCDataCollector<XPositionTrack> mBase;
//
result = mBase.Add(item);
//
return result;
}
//
// Add Item(s) To Store ...
int Add(XPositionTrack &items[])
{
//
int result = 0;
//
XSCDataCollector<XPositionTrack> mBase;
//
result = mBase.Add(items);
//
return result;
}
//
// Remove an Item from Store ...
bool Remove(XPositionTrack &item)
{
//
bool result = false;
//
XSCDataCollector<XPositionTrack> mBase;
//
result = mBase.Remove(item);
//
return result;
}
//
// Custom Functions ...
//
// Sync all Content using Specific Trader Class ...
int Sync(
XPositionTrackerState &state, // Hold all Changes State ...
XSCTrade *mTrader // XSCTrade Instance for Synchronize ...
)
{
//
int result = 0;
//
XPosition positions[];
int positionsCount = mTrader.GetPositions(positions);
//
ulong trackTickets[];
XPositionTrack trackers[];
int trackersCount = Collect(trackers);
//
// Nothing to Do ...
if (positionsCount <= 0 && trackersCount <= 0)
{
return result;
}
//
// Collect Exists Trackers Ticket's For Managing ...
for (int i = 0; i < trackersCount; i++)
{
//
XPositionTrack iTrack = trackers[i];
//
bool isValid = iTrack.IsValid();
if (isValid)
{
//
AddSpecific(
iTrack.ticket,
trackTickets //
);
}
}
//
// Clear Tracker Store for Update Later ...
Clear();
//
// Collect All Required to Add/Update Trackers here ...
XPositionTrack syncedTracks[];
//
// a Flag for Synchronization Performance ...
bool hasTracker = trackersCount > 0;
//
// Loop through Position for Managing Trackers ...
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
// if there isn't any Track before ...
if (!hasTracker)
{
//
XPositionTrack iTrack;
bool isInited = iTrack.Init(iPosition);
if (isInited)
{
//
AddRef(
iTrack,
syncedTracks //
);
//
FillState(
iTrack,
state //
);
}
//
continue;
}
//
// if there was some tracks ...
//
// Try to Find Position Ticket in Track Tickets ...
int iTicketIdx = FindIndex(
iPosition.ticket,
trackTickets //
);
bool isTrackedBefore = iTicketIdx >= 0;
//
// Add new Track ...
if (!isTrackedBefore)
{
//
XPositionTrack iTrack;
bool isInited = iTrack.Init(iPosition);
if (isInited)
{
//
AddRef(
iTrack,
syncedTracks //
);
//
FillState(
iTrack,
state //
);
}
}
//
// Update Exists Track ...
else
{
//
XPositionTrack iTrack = trackers[iTicketIdx];
bool isUpdated = iTrack.Update(iPosition);
if (isUpdated)
{
//
AddRef(
iTrack,
syncedTracks //
);
//
FillState(
iTrack,
state //
);
}
}
}
//
// Check Synced Tracks ...
int syncedTracksCount = ArraySize(syncedTracks);
if (syncedTracksCount <= 0)
{
return result;
}
//
result = Add(syncedTracks);
//
return result;
}
//
// Event Handlers ...
//
// Add Profit Event Handler ...
void AddOnProfitEventHandler(TOnPositionState handler)
{
//
AddSpecific(
handler,
mOnProfitEventHandlers //
);
}
//
// Add Drawdown Event Handler ...
void AddOnDrawdownEventHandler(TOnPositionState handler)
{
//
AddSpecific(
handler,
mOnDrawdownEventHandlers //
);
}
//
// Protected ...
protected:
//
// Tools ...
//
// Event Handlers ...
//
// OnProfit ...
void NotifyOnProfitEvent(XPositionTrack &track)
{
//
int count = ArraySize(mOnProfitEventHandlers);
if (count <= 0)
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
TOnPositionState iHandler = mOnProfitEventHandlers[i];
iHandler(track);
}
}
//
// OnDrawdown ...
void NotifyOnDrawdownEvent(XPositionTrack &track)
{
//
int count = ArraySize(mOnDrawdownEventHandlers);
if (count <= 0)
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
TOnPositionState iHandler = mOnDrawdownEventHandlers[i];
iHandler(track);
}
}
//
// Private ...
private:
//
// Props ...
//
TOnPositionState mOnProfitEventHandlers[];
TOnPositionState mOnDrawdownEventHandlers[];
//
void FillState(
XPositionTrack &track,
XPositionTrackerState &state //
)
{
//
// In Profit ...
bool isInProfit = track.profit[0] > 0;
if (isInProfit)
{
//
AddRef(
track,
state.inProfits //
);
}
//
// In Drawdown ...
bool isInDrawdown = track.profit[0] < 0;
if (isInDrawdown)
{
//
AddRef(
track,
state.inDrawdowns //
);
}
//
// On Profit ...
bool isOnProfit = track.IsCrossedInProfit();
if (isOnProfit)
{
//
AddRef(
track,
state.onProfits //
);
}
//
// On Drawdown ...
bool isOnDrawdown = track.IsCrossedInDrawdown();
if (isOnDrawdown)
{
//
AddRef(
track,
state.onDrawdowns //
);
}
}
};
//
class XSCPositionHolder
{
//
// Public ...
public:
//
// Props ...
//
// Constructor(s) ...
//
XSCPositionHolder()
{
Clear();
}
//
// Tools ...
//
// Cleanup ...
void Clear()
{
Clean(mItems);
}
//
bool AddItem(XPosition &item)
{
//
bool result = false;
//
result = item.IsValid();
if (!result)
{
return result;
}
//
result = !HasItem(item);
if (!result)
{
return result;
}
//
AddRef(
item,
mItems //
);
//
return result;
}
//
int AddItems(XPosition &items[])
{
//
int result = 0;
//
int itemsCount = ArraySize(items);
if (itemsCount <= 0)
{
return result;
}
//
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = items[i];
//
bool isAdded = AddItem(iItem);
if (isAdded)
{
result++;
}
}
//
return result;
}
//
bool AddOrUpdateItem(XPosition &item)
{
//
bool result = false;
//
result = item.IsValid();
if (!result)
{
return result;
}
//
bool hasItem = HasItem(item);
if (!hasItem)
{
result = AddItem(item);
}
else
{
//
result = RemoveItem(item);
if (result)
{
result = AddItem(item);
}
}
//
return result;
}
//
int AddOrUpdateItem(XPosition &items[])
{
//
int result = 0;
//
int itemsCount = ArraySize(items);
if (itemsCount <= 0)
{
return result;
}
//
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = items[i];
//
bool isAddOrUpdated = AddOrUpdateItem(iItem);
if (isAddOrUpdated)
{
result++;
}
}
//
return result;
}
//
bool HasItem(XPosition &item)
{
//
bool result = false;
//
int itemIDX = FindItem(item);
result = itemIDX >= 0;
//
return result;
}
//
int FindItem(XPosition &item)
{
//
int result = -1;
//
if (!item.IsValid())
{
return result;
}
//
int itemsCount = CountItems();
if (itemsCount <= 0)
{
return result;
}
//
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = mItems[i];
//
bool isSame = IsItemSameAs(item, iItem);
if (isSame)
{
//
result = i;
break;
}
}
//
return result;
}
//
bool GetByIndex(
int index,
XPosition &item //
)
{
//
bool result = false;
//
NormalizeIndex(
index,
mItems //
);
//
item = mItems[index];
//
result = item.IsValid();
//
return result;
}
//
bool RemoveItem(XPosition &item)
{
//
bool result = false;
//
result = HasItem(item);
if (!result)
{
return result;
}
//
int itemIDX = FindItem(item);
result = ArrayRemove(
mItems,
itemIDX,
1 //
);
//
return result;
}
//
int RemoveItems(XPosition &items[])
{
//
int result = 0;
//
int itemsCount = ArraySize(items);
if (itemsCount <= 0)
{
return result;
}
//
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = items[i];
//
bool isRemoved = RemoveItem(iItem);
if (isRemoved)
{
result++;
}
}
//
return result;
}
//
int CountItems()
{
return ArraySize(mItems);
}
//
bool IsItemSameAs(
XPosition &source,
XPosition &dest // Compare Source with this ...
)
{
//
bool result = false;
//
result =
//
dest.IsValid() &&
source.IsValid() &&
source.symbol == dest.symbol &&
source.period == dest.period &&
source.ticket == dest.ticket &&
source.openAt == dest.openAt &&
source.provider == dest.provider
//
;
//
return result;
}
//
// Custom Functions ...
//
bool GetMaxInDrawdown(
XPosition &item // Result
)
{
//
bool result = false;
//
item.Clean();
//
int itemsCount = CountItems();
result = IsValidSize(itemsCount);
if (!result)
{
return result;
}
//
int maxIDX = -1;
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = mItems[i];
//
bool canSelect =
//
iItem.profit < 0
//
&&
//
(
//
(maxIDX == -1 && !item.IsValid())
? true
: item.profit < iItem.profit
//
)
//
;
if (canSelect)
{
//
maxIDX = i;
item = iItem;
}
}
//
result = maxIDX > -1 && item.IsValid();
//
return result;
}
//
bool GetMaxInProfit(
XPosition &item // Result
)
{
//
bool result = false;
//
item.Clean();
//
int itemsCount = CountItems();
result = IsValidSize(itemsCount);
if (!result)
{
return result;
}
//
int maxIDX = -1;
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = mItems[i];
//
bool canSelect =
//
iItem.profit > 0
//
&&
//
(
//
(maxIDX == -1 && !item.IsValid())
? true
: item.profit < iItem.profit
//
)
//
;
if (canSelect)
{
//
maxIDX = i;
item = iItem;
}
}
//
result = maxIDX > -1 && item.IsValid();
//
return result;
}
//
bool GetFarestEntry(
XPosition &item, // Result
string symbol = NULL,
string provider = NULL,
ENUM_TIMEFRAMES period = NULL,
ENUM_POSITION_TYPE type = NULL //
)
{
//
bool result = false;
//
item.Clean();
//
int itemsCount = CountItems();
result = IsValidSize(itemsCount);
if (!result)
{
return result;
}
//
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = mItems[i];
//
bool isFiltersPassed =
//
iItem.IsFiltersPassed(
symbol,
provider,
period,
type //
)
//
;
//
if (!isFiltersPassed)
{
continue;
}
//
// Do Additional Filtering ...
bool isValidEntry =
//
!item.IsValid()
? true
: item.entry < iItem.entry
//
;
if (isValidEntry)
{
//
item = iItem;
}
}
//
result = item.IsValid();
//
return result;
}
//
bool GetNearestEntry(
XPosition &item, // Result
string symbol = NULL,
string provider = NULL,
ENUM_TIMEFRAMES period = NULL,
ENUM_POSITION_TYPE type = NULL //
)
{
//
bool result = false;
//
item.Clean();
//
int itemsCount = CountItems();
result = IsValidSize(itemsCount);
if (!result)
{
return result;
}
//
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = mItems[i];
//
bool isFiltersPassed =
//
iItem.IsFiltersPassed(
symbol,
provider,
period,
type //
)
//
;
//
if (!isFiltersPassed)
{
continue;
}
//
// Do Additional Filtering ...
bool isValidEntry =
//
!item.IsValid()
? true
: item.entry > iItem.entry
//
;
if (isValidEntry)
{
//
item = iItem;
}
}
//
result = item.IsValid();
//
return result;
}
//
bool GetFarestSL(
XPosition &item, // Result
string symbol = NULL,
string provider = NULL,
ENUM_TIMEFRAMES period = NULL,
ENUM_POSITION_TYPE type = NULL //
)
{
//
bool result = false;
//
item.Clean();
//
int itemsCount = CountItems();
result = IsValidSize(itemsCount);
if (!result)
{
return result;
}
//
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = mItems[i];
//
bool isFiltersPassed =
//
iItem.IsFiltersPassed(
symbol,
provider,
period,
type //
)
//
;
//
if (!isFiltersPassed)
{
continue;
}
//
// Do Additional Filtering ...
bool isValidEntry =
//
!item.IsValid()
? true
: item.sl < iItem.sl
//
;
if (isValidEntry)
{
//
item = iItem;
}
}
//
result = item.IsValid();
//
return result;
}
//
bool GetNearestSL(
XPosition &item, // Result
string symbol = NULL,
string provider = NULL,
ENUM_TIMEFRAMES period = NULL,
ENUM_POSITION_TYPE type = NULL //
)
{
//
bool result = false;
//
item.Clean();
//
int itemsCount = CountItems();
result = IsValidSize(itemsCount);
if (!result)
{
return result;
}
//
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = mItems[i];
//
bool isFiltersPassed =
//
iItem.IsFiltersPassed(
symbol,
provider,
period,
type //
)
//
;
//
if (!isFiltersPassed)
{
continue;
}
//
// Do Additional Filtering ...
bool isValidEntry =
//
!item.IsValid()
? true
: item.sl > iItem.sl
//
;
if (isValidEntry)
{
//
item = iItem;
}
}
//
result = item.IsValid();
//
return result;
}
//
bool GetFarestTP(
XPosition &item, // Result
string symbol = NULL,
string provider = NULL,
ENUM_TIMEFRAMES period = NULL,
ENUM_POSITION_TYPE type = NULL //
)
{
//
bool result = false;
//
item.Clean();
//
int itemsCount = CountItems();
result = IsValidSize(itemsCount);
if (!result)
{
return result;
}
//
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = mItems[i];
//
bool isFiltersPassed =
//
iItem.IsFiltersPassed(
symbol,
provider,
period,
type //
)
//
;
//
if (!isFiltersPassed)
{
continue;
}
//
// Do Additional Filtering ...
bool isValidEntry =
//
!item.IsValid()
? true
: item.tp < iItem.tp
//
;
if (isValidEntry)
{
//
item = iItem;
}
}
//
result = item.IsValid();
//
return result;
}
//
bool GetNearestTP(
XPosition &item, // Result
string symbol = NULL,
string provider = NULL,
ENUM_TIMEFRAMES period = NULL,
ENUM_POSITION_TYPE type = NULL //
)
{
//
bool result = false;
//
item.Clean();
//
int itemsCount = CountItems();
result = IsValidSize(itemsCount);
if (!result)
{
return result;
}
//
for (int i = 0; i < itemsCount; i++)
{
//
XPosition iItem = mItems[i];
//
bool isFiltersPassed =
//
iItem.IsFiltersPassed(
symbol,
provider,
period,
type //
)
//
;
//
if (!isFiltersPassed)
{
continue;
}
//
// Do Additional Filtering ...
bool isValidEntry =
//
!item.IsValid()
? true
: item.tp > iItem.tp
//
;
if (isValidEntry)
{
//
item = iItem;
}
}
//
result = item.IsValid();
//
return result;
}
//
// Private ...
private:
//
// Props ...
XPosition mItems[];
};
//
// Class Definition ...
class XSCBaseEA : public XSCBaseAlert
{
//
// Public ...
public:
//
// Props ...
//
// Constructor ...
XSCBaseEA(
//
// XTrade Class Requirements ...
int slippage, // Specify Slippage
ulong magicNumber, // Specify Magic Number
int manageInterval, // Manager Check Intervals Seconds
double maxAllowedSpread, // Max Allowed Spred for Opening Trades
int maxAllowedPositions, // Max Allowed Positions
double maxAllowedDrawdownFactor, // Max Allowed Drawdown Factor
double staticVolume, // Static Volume for Positions
//
// Position Management ...
bool allowLong = true, // Allow Long Trades
bool allowShort = true, // Allow Short Trades
double minProfitPerTrade = 0, // Min Profit Per Trade based On Volume Factor (Hedge)
double minProfitPerVolumeFactor = 0, // Min Volume Factor for Calculating Profit (Hedge)
//
// Event Handlers ...
TOnStopLoss onStopLossTriggered = NULL, // On StopLoass Triggered Event Handler
TOnTakeProfit onTakeProfitTriggered = NULL, // On TakeProfit Triggered 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
//
// Log Handler ...
bool enableAlerts = true, // Enable Alerts
bool logAlerts = true, // Log Alerts
bool terminalAlerts = false, // Terminal Alerts
bool mailAlerts = false, // Mail Alerts
bool pushAlerts = false // Push Alerts
)
{
//
// Instance XSCTrade Class ...
mTrader = new XSCTrade(
slippage,
magicNumber,
manageInterval,
maxAllowedSpread,
maxAllowedPositions,
maxAllowedDrawdownFactor
//
);
//
mIsInTestMode = IsRunningOnTestMode();
//
// Position Management ...
mAllowLong = allowLong;
mAllowShort = allowShort;
mMinProfitPerTrade = minProfitPerTrade;
mMinProfitPerVolumeFactor = minProfitPerVolumeFactor;
mStaticVolume = staticVolume;
//
// Set Event Handlers ...
mOnStopLossTriggered = onStopLossTriggered;
mOnTakeProfitTriggered = onTakeProfitTriggered;
mOnDealsChangedHandler = onDealsChangedHandler;
mOnOrdersChangedHandler = onOrdersChangedHandler;
mOnPositionsChangedHandler = onPositionsChangedHandler;
mOnTradeStateChangedHandler = onTradeStateChangedHandler;
//
// Add Event Listeners to XTrade Class if they Provided ...
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);
}
//
// Instantiate XPositionTracker Class ...
mPositionTracker = new XSCPositionTracker();
//
// Do Synchronisation after Instantiate everything ...
XPositionTrackerState state;
mPositionTracker.Sync(
state,
mTrader //
);
}
//
// Deconstractor ...
~XSCBaseEA()
{
//
delete mTrader;
delete mPositionTracker;
}
//
// Properties Getter(s) / Setter(s) ...
//
// Retrieve Slippage ...
int GetSlippage()
{
return mTrader.GetSlippage();
}
//
// Retrieve Magic Number ...
ulong GetMagicNumber()
{
return mTrader.GetMagicNumber();
}
//
// Retrieve Max Allowed Spread for Trading ...
double GetMaxAllowedSpread()
{
return mTrader.GetMaxAllowedSpread();
}
//
// Retrieve Max Allowed Same Time Positions Count ...
int GetMaxAllowedPositions()
{
return mTrader.GetMaxAllowedPositions();
}
//
// Retrieve Max Allowed Drawdown for Opening new Trades ...
double GetMaxAllowedDrawdownFactor()
{
return mTrader.GetMaxAllowedDrawdownFactor();
}
//
double GetStaticVolume()
{
return mStaticVolume;
}
//
void SetStaticVolume(double value)
{
//
if (value <= 0)
{
value = 0.01;
}
//
mStaticVolume = value;
}
//
bool GetAllowLong()
{
return mAllowLong;
}
//
void SetAllowLong(bool value)
{
mAllowLong = value;
}
//
bool GetAllowShort()
{
return mAllowShort;
}
//
void SetAllowShort(bool value)
{
mAllowShort = value;
}
//
double GetMinProfitPerTrade()
{
return mMinProfitPerTrade;
}
//
void SetMinProfitPerTrade(double value)
{
//
if (value <= 0)
{
value = 0;
}
//
if (value == mMinProfitPerTrade)
{
return;
}
//
mMinProfitPerTrade = value;
}
//
double GetMinProfitPerVolumeFactor()
{
return mMinProfitPerVolumeFactor;
}
//
void SetMinProfitPerVolumeFactor(double value)
{
//
if (value <= 0)
{
value = 0;
}
//
if (value == mMinProfitPerVolumeFactor)
{
return;
}
//
mMinProfitPerVolumeFactor = value;
}
//
bool IsHedgeEnable()
{
//
bool result =
//
mMinProfitPerTrade > 0 &&
mMinProfitPerVolumeFactor > 0
//
;
//
return result;
}
//
// 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()
{
//
// Draw ...
Draw();
//
// Check Trade Events ...
OnTrade();
//
HandleProfitManageMent();
//
// 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;
}
//
// Second Check For Signals ...
// then Execute Signals if Provided ...
int signalsCount = RequestForSignal(signals);
if (signalsCount <= 0)
{
return;
}
//
// Execute Signals ...
HandleSignalsExecution(signals);
}
//
// 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_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period // Specified Time Frame
)
{
return false;
}
//
// Handle Position(s)/ Order(s) or EQM Supporting Action ...
// if returns false, 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;
}
//
// When Some Errors happens in Executing Signals ...
virtual void ManageUnExecutedSignals(
ENUM_X_SIGNAL_EXECUTION_RESULT &states[],
XSignal &unExecutedSignals[] //
)
{
}
//
// Execute Provided Signals ...
virtual void HandleSignalsExecution(XSignal &signals[])
{
//
int signalsCount = ArraySize(signals);
if (signalsCount <= 0)
{
return;
}
//
// Filter Signals Based on their Types ...
XSignal filteredSignals[];
//
// Try to Filter Signals ...
for (int i = 0; i < signalsCount; i++)
{
//
XSignal iSignal = signals[i];
//
bool isLong = IsLong(iSignal.type);
//
if ((isLong && !GetAllowLong()) || (!isLong && !GetAllowShort()))
{
continue;
}
//
AddRef(
iSignal,
filteredSignals //
);
}
//
int filteredSignalsCount = ArraySize(filteredSignals);
if (filteredSignalsCount <= 0)
{
return;
}
//
int managedSignalsCount = HandleSignalManagement(filteredSignals);
if (managedSignalsCount <= 0)
{
return;
}
//
// Try to Execute Signals ...
XSignal notExecuteds[];
ENUM_X_SIGNAL_EXECUTION_RESULT reasons[];
int executedSignalsCount = mTrader.ExecuteSpecifiedSignals(
filteredSignals,
notExecuteds, // Not Executed Signals
reasons
//
);
//
string message = NULL;
if (executedSignalsCount == 0)
{
//
message = "(" + ToString(filteredSignalsCount) + ") Signals Execution Failed ...";
//
for (int j = 0; j < ArraySize(reasons); j++)
{
//
string iReason = ToString(reasons[j]);
//
message += "\n" + ToString(j) + ": " + iReason;
}
}
else if (executedSignalsCount < filteredSignalsCount)
{
//
int diff = filteredSignalsCount - executedSignalsCount;
//
message = "Failed to Execute (" + ToString(diff) + ") Signals ...";
}
else if (executedSignalsCount == filteredSignalsCount)
{
message = "(" + ToString(executedSignalsCount) + ") Signals Executed Successfully ...";
}
//
if (ArraySize(notExecuteds) > 0)
{
//
ManageUnExecutedSignals(
reasons,
notExecuteds //
);
}
//
if (IsValid(message))
{
mAlert.Alert(message);
}
}
//
virtual void OnGoingToProfit(XProfitTrack &track) {}
virtual void OnLongsGoingToProfit(XProfitTrack &track) {}
virtual void OnShortsGoingToProfit(XProfitTrack &track) {}
//
virtual void OnGoingToDrawdown(XProfitTrack &track) {}
virtual void OnLongsGoingToDrawdown(XProfitTrack &track) {}
virtual void OnShortsGoingToDrawdown(XProfitTrack &track) {}
//
virtual void OnPositionGoingInProfit(XPositionTrack &track) {}
virtual void OnPositionGoingToDrawdown(XPositionTrack &track) {}
//
// Protected ...
protected:
//
// Props ...
//
// Trade Class Instance ...
XSCTrade *mTrader;
XSCPositionTracker *mPositionTracker;
//
// Check in Test Mode or not ...
bool mIsInTestMode;
//
// Tools ...
//
// Signal Event Listeners ...
void NotifyOnSignalEventHandlers(XSignal &signals[])
{
//
int listenersCount = ArraySize(mOnSignalEventHandlers);
if (listenersCount <= 0)
{
return;
}
//
for (int i = 0; i < listenersCount; i++)
{
//
TOnSignal iListener = mOnSignalEventHandlers[i];
//
iListener(signals);
}
}
//
// Position Management ...
//
// Calculate Required Profit for Hedging ...
double CalculateRequiredProfitForHedge(
XPosition &positions[] // Source
)
{
//
double result = SpecifiedCalculateRequiredProfitForHedge(
positions,
mMinProfitPerTrade,
mMinProfitPerVolumeFactor //
);
//
return result;
}
//
// Calculate Positions Profit Summary ...
double CalculatePositionsProfit(
XPosition &positions[] // Source
)
{
//
double result = SpecifiedCalculatePositionsProfit(positions);
//
return result;
}
//
// Profit Tracker ...
//
XProfitTrack mProfitTracks[];
//
bool GetProfitTrack(
XProfitTrack &track,
int index = 0 //
)
{
//
bool result = false;
//
if (index < 0)
{
index = 0;
}
//
int tracksCount = CountProfitTracks();
result = tracksCount > 0 && index < tracksCount;
if (!result)
{
return result;
}
//
track.Clean();
//
track = mProfitTracks[index];
//
result = track.IsValid();
//
return result;
}
//
int CountProfitTracks()
{
return ArraySize(mProfitTracks);
}
//
void AddProfitTrack()
{
//
XProfitTrack track;
bool isValid = track.Init(mTrader);
if (!isValid)
{
return;
}
//
ArraySetAsSeries(mProfitTracks, false);
//
AddRef(
track,
mProfitTracks //
);
//
ArraySetAsSeries(mProfitTracks, true);
}
//
// Extract Specified Field Vales of XProfit Track Struct ...
int ExtractProfitTrackField(
double &result[],
ENUM_X_PROFIT_TRACK_FIELDS field,
int start = 0,
int count = 10 //
)
{
//
Clean(result);
//
if (start < 0)
{
start = 0;
}
//
int end = start + count;
//
int tracksCount = CountProfitTracks();
if (end > tracksCount)
{
end = tracksCount;
}
//
for (int i = start; i < end; i++)
{
//
XProfitTrack iTrack;
bool isValid = GetProfitTrack(
iTrack,
i //
);
//
if (!isValid)
{
continue;
}
//
double iValue = iTrack.SelectField(field);
Add(
iValue,
result //
);
}
//
int mResult = ArraySize(result);
//
return mResult;
}
//
double AverageProfitTrackField(
ENUM_X_PROFIT_TRACK_FIELDS field,
int start = 0,
int count = 10 //
)
{
//
double result = EMPTY_VALUE;
//
double items[];
int itemsCount = ExtractProfitTrackField(
items,
field,
start,
count //
);
if (itemsCount <= 0)
{
return result;
}
//
result = GetAverage(items);
//
return result;
}
//
bool IsProfitTrackFieldIncreasing(
ENUM_X_PROFIT_TRACK_FIELDS field,
int start = 0,
int count = 10 //
)
{
//
bool result = false;
//
double items[];
int itemsCount = ExtractProfitTrackField(
items,
field,
start,
count //
);
if (itemsCount <= 0)
{
return result;
}
//
int from = itemsCount - 1;
int to = 0;
//
result = IsIncreasing(
from,
to,
items //
);
//
return result;
}
//
bool IsProfitTrackFieldDecreasing(
ENUM_X_PROFIT_TRACK_FIELDS field,
int start = 0,
int count = 10 //
)
{
//
bool result = false;
//
double items[];
int itemsCount = ExtractProfitTrackField(
items,
field,
start,
count //
);
if (itemsCount <= 0)
{
return result;
}
//
int from = itemsCount - 1;
int to = 0;
//
result = IsDecreasing(
from,
to,
items //
);
//
return result;
}
//
void HandleProfitManageMent()
{
//
// Check Tracking Interval ...
//
static datetime lastProfitTracked = NULL;
datetime cTime = TimeCurrent();
//
int profitManagementInterval = PeriodSeconds(PERIOD_M5);
int timeDiff = (int)cTime - (int)lastProfitTracked;
//
bool canManage =
//
lastProfitTracked == NULL
? true
: timeDiff >= profitManagementInterval
//
;
if (!canManage)
{
return;
}
//
XPosition positions[];
int positionsCount = mTrader.GetPositions(positions);
if (!IsValidSize(positionsCount))
{
//
Clean(mProfitTracks);
return;
}
//
lastProfitTracked = cTime;
//
// Do Track ...
//
AddProfitTrack();
//
int profitsCount = CountProfitTracks();
if (profitsCount <= 1)
{
return;
}
//
XProfitTrack cT;
bool isValid = GetProfitTrack(
cT,
0 //
);
if (!isValid)
{
return;
}
//
XProfitTrack pT;
isValid = GetProfitTrack(
pT,
1 //
);
if (!isValid)
{
return;
}
//
cT.profitFrom = pT.profit;
cT.longsProfitFrom = pT.longsProfit;
cT.shortsProfitFrom = pT.shortsProfit;
//
bool isGoningToProfit =
//
cT.profit > 0 &&
pT.profit <= 0
//
;
if (isGoningToProfit)
{
//
OnGoingToProfit(cT);
}
//
bool isLongsGoningToProfit =
//
cT.longsProfit > 0 &&
pT.longsProfit <= 0
//
;
if (isLongsGoningToProfit)
{
OnLongsGoingToProfit(cT);
}
//
bool isShortsGoningToProfit =
//
cT.shortsProfit > 0 &&
pT.shortsProfit <= 0
//
;
if (isShortsGoningToProfit)
{
OnShortsGoingToProfit(cT);
}
//
bool isGoningToDrawdown =
//
cT.profit < 0 &&
pT.profit >= 0
//
;
if (isGoningToDrawdown)
{
OnGoingToDrawdown(cT);
}
bool isLongsGoningToDrawdown =
//
cT.longsProfit < 0 &&
pT.longsProfit >= 0
//
;
if (isLongsGoningToDrawdown)
{
OnLongsGoingToDrawdown(cT);
}
bool isShortsGoningToDrawdown =
//
cT.shortsProfit < 0 &&
pT.shortsProfit >= 0
//
;
if (isShortsGoningToDrawdown)
{
OnShortsGoingToDrawdown(cT);
}
}
//
// Synchronize Positions and Position Tracker ...
void SyncPositionTracker()
{
//
// Check Syncing Interval ...
//
static datetime lastSyncPositionTracker = NULL;
datetime cTime = TimeCurrent();
//
int syncInterval = PeriodSeconds(PERIOD_M5);
int lastDiff = (int)cTime - (int)lastSyncPositionTracker;
//
bool canSync =
//
lastSyncPositionTracker == NULL
? true
: lastDiff >= syncInterval
//
;
if (!canSync)
{
return;
}
//
lastSyncPositionTracker = cTime;
//
// Do Sync ...
//
XPositionTrackerState state;
int synced = mPositionTracker.Sync(
state,
mTrader //
);
if (synced > 0)
{
//
// Check State and Do What we Want ...
int onProfitsCount = ArraySize(state.onProfits);
int onDrawdownCount = ArraySize(state.onDrawdowns);
//
// Do What we want whe a Position Dropped to Prefit ...
if (onProfitsCount > 0)
{
//
for (int i = 0; i < onProfitsCount; i++)
{
//
XPositionTrack iTrack = state.onProfits[i];
//
OnPositionGoingInProfit(iTrack);
}
}
//
// Do what we want when a Position Dropped to Drawdown ...
if (onDrawdownCount > 0)
{
//
for (int i = 0; i < onDrawdownCount; i++)
{
//
XPositionTrack iTrack = state.onDrawdowns[i];
//
OnPositionGoingToDrawdown(iTrack);
}
}
}
}
//
// 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_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period, // Specified Time Frame
double minProfitForHedging = 1 // Specified Profit for Hedge
)
{
//
XPosition positions[];
int positionsCount = mTrader
.GetPositions(
positions,
symbol,
provider,
period,
type
//
);
if (positionsCount <= 1)
{
return;
}
//
double profit = CalculatePositionsProfit(positions);
double requiredProfit = CalculateRequiredProfitForHedge(positions);
//
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);
//
mAlert.Alert(message);
}
}
//
// Close Max In Profit Trade Guard Action ...
void HandleGuardCloseInProfitAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE 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 ...";
//
mAlert.Alert(message);
}
//
// Close Max In Drawdown Trade Guard Action ...
void HandleGuardCloseInDrawdownAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE 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 ...";
//
mAlert.Alert(message);
}
//
// Force Close Specified Set Of Position ...
void HandleGuardForceCloseAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE 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))
{
mAlert.Alert(comment);
}
}
//
// Trailing Specified Set Of Positions Stop Losses ...
void HandleGuardTrailingStopAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE 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 ...";
//
mAlert.Alert(message);
}
}
//
// Add Support Signal for Specified Positions ...
void HandleGuardAddSupportPositionAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE 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 = mTrader.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))
{
mAlert.Alert(comment);
}
}
//
// Cancel all Placed Orders ...
void HandleGuardCancelPendingOrdersAction(
string provider, // Positions Provided by Specific Provider
string symbol, // Trading Symbol
ENUM_POSITION_TYPE type, // Trading Type
ENUM_TIMEFRAMES period // Specified Time Frame
)
{
//
XOrder orders[];
int ordersCount = mTrader.GetOrders(
orders,
symbol,
provider,
period,
ToOrderType(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 ...";
//
mAlert.Alert(message);
}
}
//
// Position Filter ...
//
int FilterSymbolBasedPositions(
string &symbols[], // Hold Symbols ...
XSCPositionHolder *&holders[] // Holder Class Instances ...
)
{
//
int result = 0;
//
XPosition positions[];
int positionsCount = mTrader.GetPositions(
positions //
);
if (!IsValidSize(positionsCount))
{
return result;
}
//
// Create a HashMap for Holding Positions ...
CHashMap<string, XSCPositionHolder *> symbolMap;
//
// Loop Through Positions ...
for (int i = 0; i < positionsCount; i++)
{
//
XPosition iPosition = positions[i];
//
bool hasIKey = symbolMap.ContainsKey(iPosition.symbol);
//
// Empty Class Pointer ...
XSCPositionHolder *mHolder = NULL;
//
// Add new to Map ...
if (!hasIKey)
{
//
mHolder = new XSCPositionHolder();
if (symbolMap.TrySetValue(iPosition.symbol, mHolder))
{
mHolder.AddOrUpdateItem(iPosition);
}
}
//
// Update Exists in Map ...
else
{
//
if (symbolMap.TryGetValue(iPosition.symbol, mHolder))
{
mHolder.AddOrUpdateItem(iPosition);
}
}
}
//
// Now we Have a Map which Filled Based on Separate Symbols and InDrawDown Positions ...
int mapCount = symbolMap.Count();
if (!IsValidSize(mapCount))
{
return result;
}
//
result = symbolMap.CopyTo(
symbols,
holders //
);
//
return result;
}
//
// Private ...
private:
//
// Props ...
//
// Signal Event Listeners ...
TOnSignal mOnSignalEventHandlers[];
//
// Position Management ...
bool mAllowLong; // Allow Long Trades
bool mAllowShort; // Allow Short Trades
double mMinProfitPerTrade; // Min Profit Per Trade based On Volume Factor (Hedge)
double mMinProfitPerVolumeFactor; // Min Volume Factor for Calculating Profit (Hedge)
double mStaticVolume; // Static Volume for Positions
//
// Event Handlers ...
TOnStopLoss mOnStopLossTriggered;
TOnTakeProfit mOnTakeProfitTriggered;
TOnDealsChanged mOnDealsChangedHandler;
TOnOrdersChanged mOnOrdersChangedHandler;
TOnPositionsChanged mOnPositionsChangedHandler;
TOnTradeStateChanged mOnTradeStateChangedHandler;
};
//