Files
MQL5Data/Classes/x-saherelm.x121.xtrade.handler.class.mq5
T

1736 lines
34 KiB
Plaintext

///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Class Library
// ----------------------------------------------
// Name: X121SCTradeHandler
// Description: provides all Trade Handling 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.xtrade.class.mq5"
//
// Definitions ...
//
// an Structure for Holding Positions Data ...
struct X121TradeData
{
//
datetime time; // Issue Time (Open Position)
string symbol; // Trading Symbol
double entry; // Entry Price
double volume; // Volume
string provider; // Signaller
ENUM_TIMEFRAMES period; // Trading Timeframe
ENUM_X_POSITION_TYPES type; // Position Type
//
ulong ticket; // Position Ticket
double swap; // Swap
double profit; // Profit on Close
double commission; // Commission
double maxDrawdown; // Max Position Drawdown
string message; // Close Reason
datetime endTime; // End Time
//
XSignal signal; // Signal Object
int pushers; // Signal Pushers
string conditions; // Signal Conditions
//
// Constructor ...
void XTradeInfo()
{
Clean();
}
//
// Filling Trade Handler ...
bool Fill(XSignal &_signal)
{
//
bool result = false;
//
Clean();
//
// Check Signal Validation ...
result = _signal.IsValid();
if (!result)
{
return result;
}
//
signal = _signal;
time = _signal.time;
entry = _signal.entry;
symbol = _signal.symbol;
volume = _signal.volume;
period = _signal.period;
pushers = _signal.pushers;
provider = _signal.provider;
conditions = _signal.conditions;
type = ToPositionType(_signal.type);
//
if (_signal.IsExecuted())
{
ticket = _signal.positionId;
}
//
return result;
}
//
// Filling Trade Handler ...
bool Fill(XPosition &_position)
{
//
bool result = false;
//
Clean();
//
// Check Signal Validation ...
result = _position.IsValid();
if (!result)
{
return result;
}
//
time = _position.openAt;
symbol = _position.symbol;
entry = _position.entry;
volume = _position.volume;
provider = _position.provider;
period = _position.period;
type = ToPositionType(_position.type);
//
ticket = _position.ticket;
//
return result;
}
//
// Update Data ...
bool Update(XPosition &_position)
{
//
bool result = false;
//
result = _position.IsValid();
if (!result)
{
return result;
}
//
profit = _position.profit;
swap = _position.swap;
//
if (profit < 0 &&
(maxDrawdown == 0 ||
MathAbs(profit) > MathAbs(maxDrawdown)))
{
maxDrawdown = profit;
}
//
return result;
}
//
// Tools ...
//
// Cleanup ...
void Clean()
{
//
time = NULL;
type = NULL;
symbol = NULL;
period = NULL;
endTime = NULL;
message = NULL;
provider = NULL;
//
swap = 0;
entry = 0;
ticket = 0;
profit = 0;
volume = 0;
commission = 0;
maxDrawdown = 0;
//
signal.Clean();
}
//
// Validation ...
bool IsValid()
{
//
bool result = false;
//
result =
//
ticket > 0 &&
IsValid(time) &&
IsValid(symbol) &&
IsValid(period)
//
;
//
return result;
}
//
// Retrieve Trade Data Age ...
int GetAge()
{
//
int result = -1;
//
if (!IsValid(symbol) ||
!IsValid(time) ||
!IsValid(endTime) ||
!IsValid(period))
{
return result;
}
//
int startIndex = iBarShift(
symbol,
period,
time,
false //
);
//
int endIndex = iBarShift(
symbol,
period,
endTime,
false //
);
//
result = MathAbs(startIndex - endIndex);
//
return result;
}
//
// Check Own of Trade Data ...
// based on Ticket ...
bool IsOwn(
ulong _ticket //
)
{
//
bool result = false;
//
result = _ticket == ticket;
//
return result;
}
//
// Check Own of Trade Data ...
// based on Symbol/Provider and Period ...
bool IsOwn(
string _symbol,
string _provider,
ENUM_TIMEFRAMES _period,
ENUM_X_POSITION_TYPES _type //
)
{
//
bool result = false;
//
result =
//
IsValid(_symbol) &&
IsValid(_period) &&
IsValid(_provider) &&
type != X_POSITION_TYPE_ALL &&
type != X_POSITION_TYPE_NONE &&
//
type == _type &&
period == _period &&
symbol == _symbol &&
provider == _provider
//
;
//
return result;
}
//
// Data Collector ...
//
// Get Data File Name ...
string GetFileName()
{
//
string result = NULL;
//
if (!IsValid())
{
return result;
}
//
result =
//
symbol + "\\" +
ToString(type) + "\\" +
(profit >= 0 ? "Profit" : "Loss") + "\\" +
ToString(ticket) + "_" +
ToString(period) + "_" +
ToFormatString(time)
//
;
//
return result;
}
//
// Get Signal File Name ...
string GetSignalFileName()
{
//
string result = NULL;
//
result =
//
symbol + "\\" +
ToString(type) + "\\" +
provider + "_" +
ToFormatString(time)
//
;
//
return result;
}
//
// Convert(s) To String Representation(s) ...
string ToString(
bool onlySignals = false //
)
{
//
string result = NULL;
//
int age = GetAge();
//
result =
//
(onlySignals ? "" : ToString("Ticket", ticket)) +
ToString("Symbol", symbol) +
ToString("Period", period) +
ToString("Entry", entry) +
ToString("Provider", provider) +
ToString("Type", ToString(type)) +
ToString("Time", time) +
//
// Attach Trade Info ...
(onlySignals ? "" :
//
"-------------" + "\n" +
ToString("Volume", volume) +
ToString("Profit", profit) +
ToString("Commission", commission) +
ToString("Swap", swap) +
ToString("Max Drawdown", maxDrawdown) +
ToString("End Time", endTime) +
ToString("Age", age) +
ToString("Message", message) +
""
//
) +
//
// Attach Conditions to Signals ...
(!onlySignals ? "" :
//
"-------------" + "\n" +
ToString("Pushers", pushers) +
"Conditions:" + "\n" +
"-------------" + "\n" +
conditions +
""
//
) +
//
""
//
;
//
return result;
}
//
};
//
// Implementation ...
//
// a Class For Read and Write Trade Info Data in Files ...
class X121TradeCollector
{
//
// Public ...
public:
//
// Props ...
//
// Constructor(s) ...
void X121TradeCollector(
string _path = NULL // Base Path
)
{
//
mAccount = new XSCAccount();
//
if (IsValid(_path))
{
mPath = _path;
}
else
{
mPath = "X121TradeData" + "\\" + mAccount.GetCompany();
}
}
//
// Deconstructor ...
void ~X121TradeCollector()
{
}
//
bool IsExists(X121TradeData &item)
{
//
bool result = false;
//
int mHandler = GetFileHandlerForRead(item);
result = mHandler != INVALID_HANDLE;
FileClose(mHandler);
//
return result;
}
//
bool Save(X121TradeData &item)
{
//
bool result = false;
//
// Check info is Valid ...
result = item.IsValid();
if (!result)
{
return result;
}
//
string content = item.ToString();
content += "\n" + "-----------" + "\n" + "Signal: " + "\n" + "-----------" + "\n" + item.ToString(true);
//
result = IsValid(content);
if (!result)
{
return result;
}
//
int mHandler = GetFileHandlerForWrite(item);
result = mHandler != INVALID_HANDLE;
if (!result)
{
return result;
}
//
FileWrite(mHandler, content);
FileFlush(mHandler);
FileClose(mHandler);
//
return result;
}
//
bool SaveSignal(X121TradeData &item)
{
//
bool result = false;
//
string content = item.ToString(true);
result = IsValid(content);
if (!result)
{
return result;
}
//
int mHandler = GetSignalFileHandlerForWrite(item);
result = mHandler != INVALID_HANDLE;
if (!result)
{
return result;
}
//
FileWrite(mHandler, content);
FileFlush(mHandler);
FileClose(mHandler);
//
return result;
}
//
// Conditions only save for Loss Signals ...
// this means the profit must be Lower than Zero ...
// ans also message Contains SL ...
bool SaveConditions(X121TradeData &item)
{
//
bool result = false;
//
// Validate Item ...
result =
//
item.profit < 0 &&
Contains("SL", item.message)
//
;
if (!result)
{
return result;
}
//
string content = item.signal.conditions;
result = IsValid(content);
if (!result)
{
return result;
}
//
int mHandler = GetConditionsFileHandlerForWrite(item);
result = mHandler != INVALID_HANDLE;
if (!result)
{
return result;
}
//
FileSeek(mHandler, 0, SEEK_END);
FileWrite(mHandler, content);
FileFlush(mHandler);
FileClose(mHandler);
//
return result;
}
//
// Protected ...
protected:
//
// Private ...
private:
//
// Props ...
//
string mPath; // Base Path ...
//
XSCAccount *mAccount;
//
string GetFilePath(X121TradeData &item)
{
//
string fileName = item.GetFileName();
//
return GetFilePath(fileName);
}
string GetFilePath(string fileName)
{
//
string result = "";
//
result =
//
mPath + "\\" + "Trades" + "\\" + fileName + ".x121.log"
//
;
//
return result;
}
//
string GetSignalFilePath(X121TradeData &item)
{
//
string fileName = item.GetSignalFileName();
//
return GetSignalFilePath(fileName);
}
string GetSignalFilePath(string fileName)
{
//
string result = "";
//
result =
//
mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log"
//
;
//
return result;
}
//
string GetConditionsFilePath(X121TradeData &item)
{
//
bool isLong = IsLong(item.type);
//
string fileName =
item.symbol + "\\" +
(isLong ? "Longs" : "Shorts");
//
return GetConditionsFilePath(fileName);
}
string GetConditionsFilePath(string fileName)
{
//
string result = "";
//
result =
//
mPath + "\\" + "Conditions" + "\\" + fileName + ".x121.log"
//
;
//
return result;
}
//
int GetFileHandlerForRead(X121TradeData &item)
{
//
int result = INVALID_HANDLE;
//
string filePath = GetFilePath(item);
if (!IsValid(filePath))
{
return result;
}
//
result = FileOpen(
filePath,
FILE_READ | FILE_TXT //
);
//
return result;
}
int GetFileHandlerForWrite(X121TradeData &item)
{
//
int result = INVALID_HANDLE;
//
string filePath = GetFilePath(item);
if (!IsValid(filePath))
{
return result;
}
//
result = FileOpen(
filePath,
FILE_READ | FILE_WRITE | FILE_TXT //
);
//
return result;
}
//
int GetSignalFileHandlerForRead(X121TradeData &item)
{
//
int result = INVALID_HANDLE;
//
string filePath = GetSignalFilePath(item);
if (!IsValid(filePath))
{
return result;
}
//
result = FileOpen(
filePath,
FILE_READ | FILE_TXT //
);
//
return result;
}
int GetSignalFileHandlerForWrite(X121TradeData &item)
{
//
int result = INVALID_HANDLE;
//
string filePath = GetSignalFilePath(item);
if (!IsValid(filePath))
{
return result;
}
//
result = FileOpen(
filePath,
FILE_READ | FILE_WRITE | FILE_TXT //
);
//
return result;
}
//
int GetConditionsFileHandlerForRead(X121TradeData &item)
{
//
int result = INVALID_HANDLE;
//
string filePath = GetConditionsFilePath(item);
if (!IsValid(filePath))
{
return result;
}
//
result = FileOpen(
filePath,
FILE_READ | FILE_TXT //
);
//
return result;
}
int GetConditionsFileHandlerForWrite(X121TradeData &item)
{
//
int result = INVALID_HANDLE;
//
string filePath = GetConditionsFilePath(item);
if (!IsValid(filePath))
{
return result;
}
//
result = FileOpen(
filePath,
FILE_READ | FILE_WRITE | FILE_TXT //
);
//
return result;
}
};
//
// Trade Handler Class ...
class X121SCTradeHandler : public XSCBaseAlert
{
//
// Public ...
public:
//
//
// Constructor(s) ...
void X121SCTradeHandler(XSCTrade *trader)
{
//
mTrader = trader;
mCollector = new X121TradeCollector();
}
//
// Deconstructor ...
void ~X121SCTradeHandler()
{
//
delete mTrader;
delete mCollector;
}
//
// Getter(s) / Setter(s) ...
//
bool SaveSignals()
{
return mSaveSignals;
}
//
void SaveSignals(bool value)
{
mSaveSignals = value;
}
//
bool SaveTrades()
{
return mSaveTrades;
}
//
void SaveTrades(bool value)
{
mSaveTrades = value;
}
//
bool SaveConditions()
{
return mSaveConditions;
}
//
void SaveConditions(bool value)
{
mSaveConditions = value;
}
//
bool AllowLong()
{
return mAllowLong;
}
//
void AllowLong(bool value)
{
mAllowLong = value;
}
//
bool AllowShort()
{
return mAllowShort;
}
//
void AllowShort(bool value)
{
mAllowShort = value;
}
//
int MaxAllowedLongs()
{
return mMaxAllowedLongs;
}
//
void MaxAllowedLongs(int value)
{
//
if (value < 0)
{
value = 0;
}
//
mMaxAllowedLongs = value;
}
//
int MaxAllowedShorts()
{
return mMaxAllowedShorts;
}
//
void MaxAllowedShorts(int value)
{
//
if (value < 0)
{
value = 0;
}
//
mMaxAllowedShorts = value;
}
//
bool UseMaxAllowedTradesPerSymbol()
{
return mUseMaxAllowedTradesPerSymbol;
}
//
void UseMaxAllowedTradesPerSymbol(bool value)
{
mUseMaxAllowedTradesPerSymbol = value;
}
//
double MaxDrawdownPercentForOpenTrades()
{
return mMaxDrawdownPercentForOpenTrades;
}
//
void MaxDrawdownPercentForOpenTrades(double value)
{
//
if (value < 0)
{
value = 0;
}
//
mMaxDrawdownPercentForOpenTrades = value;
}
//
// Read Only Props ...
//
int MaxSameTimeTrades()
{
return maxSameTimeTrades;
}
//
// Calculate Max Drawdown and it's Percent ...
double GetMaxDrawdown()
{
//
XPosition positions[];
int positionsCount = mTrader.GetPositions(positions);
if (IsValidSize(positionsCount))
{
double mEquity = mTrader.mAccount.GetEquity();
if (mEquity > maxDrawdown)
{
maxDrawdown = mEquity;
}
//
drawdownPercent = (maxDrawdown - mEquity) / (staticBalanceForCalculateDrawdown > 0 ? staticBalanceForCalculateDrawdown : maxDrawdown) * 100;
drawdownPercent = NormalizeDouble(drawdownPercent, 3);
}
else
{
//
maxDrawdown = 0.0;
drawdownPercent = 0.0;
}
//
return drawdownPercent;
}
//
// Trade Handling Functions ...
//
// First Step of Trade Handling ...
// Since Must Call when a Signal Executed ...
void AddData(
XSignal &signal, // Executed Signal
double commission = 0 // Commission
)
{
//
// Check Signal Valid ...
if (!signal.IsValid())
{
return;
}
//
// Check Signal Support or Recovery ...
bool isSupport = IsSupport(signal.comment);
bool isRecovery = ExtractRecoveredTicket(signal.comment) > 0;
//
X121TradeData item;
bool isFilled = item.Fill(signal);
if (!isFilled)
{
return;
}
//
item.commission = commission;
//
Add(item);
//
SaveSignal(item);
}
//
void Finish(const XDeal &deal)
{
//
int idx = -1;
bool hasItem = HasItem(
deal.positionId,
idx //
);
if (!hasItem)
{
return;
}
//
// Update Item Info ...
mData[idx].swap = deal.swap;
mData[idx].endTime = deal.time;
mData[idx].profit = deal.profit;
//
mData[idx].message =
deal.reason == DEAL_REASON_TP ? "TP" : "SL";
//
Save(idx);
}
//
void Finish(
const ulong ticket,
const XPosition &position,
const string comment //
)
{
//
int idx = -1;
bool hasItem = HasItem(
ticket,
idx //
);
if (!hasItem)
{
return;
}
//
// Update Item Info ...
mData[idx].swap = position.swap;
mData[idx].endTime = TimeCurrent();
mData[idx].profit = position.profit;
//
mData[idx].message = comment;
//
Save(idx);
}
//
// this Method call's by a Timer,
// or in OnTick for Update Positions,
// Data ...
void UpdateData()
{
//
XPosition positions[];
int count = mTrader.GetPositions(positions);
if (!IsValidSize(count))
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
XPosition iPosition = positions[i];
//
int idx = -1;
bool isExists = HasItem(
iPosition.ticket,
idx //
);
if (!isExists)
{
//
// Add New Data ...
//
// Find Executed Signal Deal History ...
XDeal deals[];
double commission = 0;
int dealsCount = mTrader.GetDeals(
deals,
iPosition.symbol,
iPosition.provider,
iPosition.period,
NULL,
DEAL_ENTRY_IN //
);
if (IsValidSize(dealsCount))
{
//
for (int i = 0; i < dealsCount; i++)
{
//
XDeal iDeal = deals[i];
if (iDeal.positionId == iPosition.ticket)
{
//
commission = iDeal.commission;
break;
}
}
}
//
X121TradeData iData;
iData.Fill(
iPosition //
);
//
iData.ticket = iPosition.ticket;
//
Add(iData);
}
else
{
//
// Update Exists ...
mData[idx].Update(iPosition);
}
}
//
count = Count();
if (count > maxSameTimeTrades)
{
maxSameTimeTrades = count;
}
//
GetMaxDrawdown();
}
//
void UpdateSignal(XSignal &signal)
{
//
if (!signal.IsValid())
{
return;
}
//
int count = Count();
if (!IsValidSize(count))
{
return;
}
//
for (int i = 0; i < count; i++)
{
//
bool isOwn = mData[i].IsOwn(
signal.symbol,
signal.provider,
signal.period,
ToPositionType(signal.type) //
);
if (isOwn)
{
mData[i].Fill(signal);
}
}
}
//
void RemoveSignal(XSignal &signal)
{
//
if (!signal.IsValid())
{
return;
}
//
int signalIDX = -1;
ENUM_X_POSITION_TYPES xType = ToPositionType(signal.type);
bool hasSignal = HasItem(
signal.symbol,
signal.provider,
signal.period,
xType,
signalIDX //
);
if (!hasSignal || !IsValidIndex(signalIDX))
{
return;
}
//
// Remove Item From List ...
ArrayRemove(
mData,
signalIDX,
1 //
);
}
/**
* this Method Synchronize
* all Exists Positions and parse them
* and add them into mData Collection if
* their not Exists ...
*/
void Sync()
{
//
// TODO: Implement here ...
}
/**
* Validate Signal For Execution ...
*/
bool CanExecute(XSignal &signal)
{
//
bool result = false;
//
// Validate Signal ...
result = signal.IsValid();
if (!result)
{
return result;
}
//
// TODO:
// Here we can apply Same type or Opposit Type
// Signals behaviour ...
// also check For Market Open ...
//
// Check Market ...
// TODO: Fix this ...
// result = mSymbolSession.CanTrade(signal.symbol);
// if (!result) {
// return result;
// }
//
return result;
}
/**
* Execute Specific Signal using Trade Handler ...
*/
bool ExecuteSignal(
XSignal &signal, // Signal for Execution
ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State
bool ignorePolicies = false // Ignore Execution Policies
)
{
//
bool result = false;
//
// Check Signal Validation ...
result = signal.IsValid();
if (!result)
{
return result;
}
//
// Filter Signals if Necessary ...
result = CanExecute(signal);
if (!result)
{
//
state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS;
return result;
}
//
// Check Policies ...
if (!ignorePolicies)
{
//
bool isLong = IsLong(signal.type);
//
// Check Allow Trade Type ...
result =
isLong
? mAllowLong
: mAllowShort;
if (!result)
{
//
state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED;
return result;
}
//
// Check Trades Count ...
if (mMaxAllowedLongs > 0 || mMaxAllowedShorts > 0)
{
//
XPosition longs[];
XPosition shorts[];
//
// Counting Positions ...
if (mUseMaxAllowedTradesPerSymbol)
{
//
mTrader.GetPositions(
longs,
shorts,
signal.symbol //
);
}
else
{
//
mTrader.GetPositions(
longs,
shorts,
NULL // All Symbols ...
);
}
//
int longsCount = ArraySize(longs);
int shortsCount = ArraySize(shorts);
//
result =
//
// Long ...
isLong
? mMaxAllowedLongs <= 0
? true
: longsCount < mMaxAllowedLongs
//
// Short ...
: mMaxAllowedShorts <= 0
? true
: shortsCount < mMaxAllowedShorts
//
;
if (!result)
{
//
state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED;
return result;
}
}
//
// Check Drawdown ...
if (mMaxDrawdownPercentForOpenTrades > 0)
{
//
drawdownPercent = GetMaxDrawdown();
//
result =
drawdownPercent <= 0
? true
: drawdownPercent < mMaxDrawdownPercentForOpenTrades;
if (!result)
{
//
state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY;
return result;
}
}
}
//
// Execute Signal ...
result = mTrader.ExecuteSignal(
signal,
state //
);
if (result)
{
//
double commission = mTrader.GetPositionCommission(signal.positionId);
//
// Add Signal to Trade Handler ...
AddData(
signal,
commission //
);
//
string msg = (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") +
" Signal Provided by: " + signal.provider +
(signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") +
" on: " + signal.symbol +
" in: " + ToString(signal.period) +
" Executed Successfully ...";
Alert(msg);
}
//
return result;
}
/**
* Handle Positiona Protections
*/
void HandleProtection()
{
//
// TODO: Implement this ...
}
//
// Protected ...
protected:
//
XSCTrade *mTrader; // Instance of Trader Class
X121TradeCollector *mCollector; // Instance of Trade Collector Class
//
X121TradeData mData[]; // Hold Trade Data
//
// Private ...
private:
//
// Props ...
//
// Read Only ...
int maxSameTimeTrades; // Max Same Time Trades
double maxDrawdown; // Max Drawdown
double drawdownPercent; // Drawdown Percent
double staticBalanceForCalculateDrawdown; // Static Balance for Max Drawdown Calculation
//
bool mSaveSignals; // Save Signals
bool mSaveTrades; // Save Trades
bool mSaveConditions; // Save SL Conditions
//
bool mAllowLong; // Allow Long/Buy Trade Type
bool mAllowShort; // Allow Short/Sell Trade Type
int mMaxAllowedLongs; // Max Allowe Long/Buy Trades
int mMaxAllowedShorts; // Max Allowe Short/Sell Trades
bool mUseMaxAllowedTradesPerSymbol; // Use Max Allowed Trades Per Symbol
double mMaxDrawdownPercentForOpenTrades; // Max Drawdown Percent for Open Trades
//
// Count Data ...
int Count()
{
return ArraySize(mData);
}
//
// Add Item ...
bool Add(X121TradeData &item)
{
//
bool result = false;
//
result = item.IsValid();
if (!result)
{
return result;
}
//
int index = -1;
if (item.ticket > 0)
{
//
result = !HasItem(
item.ticket,
index //
);
}
else
{
//
result = !HasItem(
item.symbol,
item.provider,
item.period,
item.type,
index //
);
}
if (!result || IsValidIndex(index))
{
//
result = false;
return result;
}
//
AddRef(
item,
mData //
);
//
return result;
}
//
// Find Item Index ...
bool HasItem(
ulong ticket,
int &index //
)
{
//
bool result = false;
//
index = -1;
//
int count = Count();
result = IsValidSize(count);
if (!result)
{
return result;
}
//
for (int i = 0; i < count; i++)
{
//
result = mData[i].IsOwn(ticket);
if (result)
{
//
index = i;
break;
}
}
//
return result;
}
//
// Find Item Index ...
bool HasItem(
string symbol,
string provider,
ENUM_TIMEFRAMES period,
ENUM_X_POSITION_TYPES type,
int &index //
)
{
//
bool result = false;
//
index = -1;
//
// Validate ...
result =
//
IsValid(symbol) &&
IsValid(period) &&
IsValid(provider) &&
type != X_POSITION_TYPE_ALL &&
type != X_POSITION_TYPE_NONE
//
;
if (!result)
{
return result;
}
//
int count = Count();
result = IsValidSize(count);
if (!result)
{
return result;
}
//
for (int i = 0; i < count; i++)
{
//
result = mData[i].IsOwn(
symbol,
provider,
period,
type //
);
if (result)
{
//
index = i;
break;
}
}
//
return result;
}
//
void Save(int index)
{
//
int count = Count();
if (!IsValidIndex(index) || index > count - 1)
{
return;
}
//
// Save Trade ...
if (mSaveTrades)
{
mCollector.Save(mData[index]);
}
//
if (mSaveConditions)
{
mCollector.SaveConditions(mData[index]);
}
//
// Remove Item From List ...
ArrayRemove(
mData,
index,
1 //
);
}
//
void SaveSignal(X121TradeData &item)
{
//
if (!mSaveSignals)
{
return;
}
//
// Save Signal ...
mCollector.SaveSignal(item);
}
//
};
//