989 lines
24 KiB
Plaintext
989 lines
24 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Class Library
|
|
// ----------------------------------------------
|
|
// Name: XSCX121EA
|
|
// Description: provides all X121 EA requirements ...
|
|
// - X5 Provider;
|
|
//
|
|
//
|
|
// 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.xea.class.mq5"
|
|
#include "../Classes/x-saherelm.x121.provider.class.mq5"
|
|
|
|
//
|
|
// Define On Signal Event Handler Type Specified for X5 ...
|
|
typedef void (*TX121OnSignal)(X121ProviderDescriptor &descriptor);
|
|
|
|
//
|
|
// Class Definition ...
|
|
|
|
class XSCX121EA : public XSCBaseEA
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Constructors ...
|
|
XSCX121EA(
|
|
//
|
|
// XTrade Class Requirements ...
|
|
int slippage, // Specify Slippage
|
|
ulong magicNumber, // Specify Magic Number
|
|
//
|
|
// Time Management ...
|
|
// TODO: ...
|
|
//
|
|
// XSCTrade 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
|
|
//
|
|
// Custom Event Handler ...
|
|
TOnSignal onSignalHandler = NULL // On Signal Event Handler
|
|
) : XSCBaseEA(slippage,
|
|
magicNumber,
|
|
onStopLossTriggered,
|
|
onTakeProfitTriggered,
|
|
onDealsChangedHandler,
|
|
onOrdersChangedHandler,
|
|
onPositionsChangedHandler,
|
|
onTradeStateChangedHandler //
|
|
)
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
~XSCX121EA() {}
|
|
|
|
//
|
|
// Properties Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Add X5 Specified Signal Event Handler ...
|
|
void AddOnSignalEventHandler(TX121OnSignal listener)
|
|
{
|
|
//
|
|
Add(
|
|
listener,
|
|
mX121OnSignalEventHandlers
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Add Specified X5 Provider ...
|
|
bool AddProvider(X121ProviderDescriptor &descriptor)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Inputs ...
|
|
result = descriptor.Init();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
AddRef(
|
|
descriptor,
|
|
mDescriptors //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
//
|
|
// Customize Token ...
|
|
string GetToken() override
|
|
{
|
|
return GetSpecificToken(this);
|
|
}
|
|
|
|
//
|
|
string GetTag() override
|
|
{
|
|
return this.GetToken();
|
|
}
|
|
|
|
//
|
|
void Draw() override
|
|
{
|
|
//
|
|
int descriptorsCount = CountDescriptors();
|
|
if (descriptorsCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < descriptorsCount; i++)
|
|
{
|
|
//
|
|
X121ProviderDescriptor iDescriptor = mDescriptors[i];
|
|
|
|
//
|
|
iDescriptor.provider.Draw();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Provider for any Guards ...
|
|
bool CheckForGuard(XGuard &guards[]) override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
Clean(guards);
|
|
|
|
//
|
|
int descriptorsCount = CountDescriptors();
|
|
result = descriptorsCount > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < descriptorsCount; i++)
|
|
{
|
|
//
|
|
X121ProviderDescriptor iDescriptor = mDescriptors[i];
|
|
|
|
//
|
|
XGuard iGuards[];
|
|
bool iHasGuard = iDescriptor.HasGuard(iGuards);
|
|
if (iHasGuard)
|
|
{
|
|
//
|
|
Copy(
|
|
iGuards,
|
|
guards,
|
|
false //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(guards) > 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Request Provider to Collect all
|
|
// Potentially Signals and then
|
|
// filters theme here and passed them
|
|
// for Executing ...
|
|
int RequestForSignal(
|
|
XSignal &signals[] // Holds Signals ...
|
|
) override
|
|
{
|
|
//
|
|
bool result = 0;
|
|
|
|
//
|
|
Clean(signals);
|
|
|
|
//
|
|
int descriptorsCount = CountDescriptors();
|
|
if (descriptorsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < descriptorsCount; i++)
|
|
{
|
|
//
|
|
X121ProviderDescriptor iDescriptor = mDescriptors[i];
|
|
|
|
//
|
|
bool iHasSignal = iDescriptor.HasSignal();
|
|
if (iHasSignal)
|
|
{
|
|
//
|
|
// Here we Can double check Signals by Conditions
|
|
// for Score Base Filtering ...
|
|
|
|
//
|
|
AddRef(
|
|
iDescriptor.signal,
|
|
signals
|
|
//
|
|
);
|
|
|
|
//
|
|
NotifyX121OnSignalEventHandlers(iDescriptor);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(signals);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Request for Support Signals using Guard ...
|
|
bool RequestForSupport(
|
|
XSignal &support, // Holds Support Signal, if Provided
|
|
string provider, // Positions Provided by Specific Provider
|
|
string symbol, // Trading Symbol
|
|
ENUM_X_POSITION_TYPE type, // Trading Type
|
|
ENUM_TIMEFRAMES period // Specified Time Frame
|
|
) override
|
|
{
|
|
//
|
|
// TODO: Implement this ...
|
|
|
|
//
|
|
// Support Senario ...
|
|
// Check Support Position Exists or not ...
|
|
// Check Positions for Support based on Types ...
|
|
// Update Untriggered Positions ...
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Here we Manage Signals for Executing ...
|
|
// - Check Policies based on their Signaller ...
|
|
// - Check Same Time Open Positions ...
|
|
// - Check Signal Age for new Trade ...
|
|
// and etc ...
|
|
int HandleSignalManagement(XSignal &signals[]) override
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
int signalsCount = ArraySize(signals);
|
|
if (!IsValidSize(signalsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XSignal tmpSignals[];
|
|
Copy(
|
|
signals,
|
|
tmpSignals //
|
|
);
|
|
|
|
//
|
|
Clean(signals);
|
|
|
|
//
|
|
for (int i = 0; i < signalsCount; i++)
|
|
{
|
|
//
|
|
XSignal iSignal = tmpSignals[i];
|
|
|
|
//
|
|
// Find Provider Descriptor Which Issued this Signal ...
|
|
int iProviderIDX = FindDescriptorIndex(
|
|
iSignal.symbol,
|
|
iSignal.period);
|
|
if (!IsValidIndex(iProviderIDX))
|
|
{
|
|
//
|
|
string message = "Couldn't find Signal Descriptor ...";
|
|
Log(message);
|
|
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Now we Have to Find Signaller Which Issued this Signal ...
|
|
int iSignallerIDX = mDescriptors[iProviderIDX]
|
|
.FindSignallerIndex(iSignal.provider);
|
|
if (!IsValidIndex(iSignallerIDX))
|
|
{
|
|
//
|
|
string message = "Couldn't find Signal Provider ...";
|
|
Log(message);
|
|
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Position Type is Enabled or not ...
|
|
bool isLong = IsLong(iSignal.type);
|
|
bool isAllowedType = isLong
|
|
? mDescriptors[iProviderIDX].signallers[iSignallerIDX].allowLong
|
|
: mDescriptors[iProviderIDX].signallers[iSignallerIDX].allowShort;
|
|
if (!isAllowedType)
|
|
{
|
|
//
|
|
string message = "ignore Signal due Type Policy ...";
|
|
Log(message);
|
|
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Retrieve Long and Short Signals of same Provider ...
|
|
XPosition longs[];
|
|
XPosition shorts[];
|
|
mTrader.GetPositions(
|
|
longs,
|
|
shorts,
|
|
iSignal.symbol,
|
|
iSignal.provider,
|
|
iSignal.period //
|
|
);
|
|
int longsCount = ArraySize(longs);
|
|
int shortsCount = ArraySize(shorts);
|
|
|
|
//
|
|
// Check Max Number of Positions ...
|
|
bool isMaxNumberOfPositionsPassed = isLong
|
|
? mDescriptors[iProviderIDX].signallers[iSignallerIDX].maxAllowedLong <= 0
|
|
? true
|
|
: longsCount < mDescriptors[iProviderIDX].signallers[iSignallerIDX].maxAllowedLong
|
|
: mDescriptors[iProviderIDX].signallers[iSignallerIDX].maxAllowedShort <= 0
|
|
? true
|
|
: shortsCount < mDescriptors[iProviderIDX].signallers[iSignallerIDX].maxAllowedShort;
|
|
if (!isMaxNumberOfPositionsPassed)
|
|
{
|
|
//
|
|
string message = "ignore Signal due Max Allowed Positions Reached ...";
|
|
Log(message);
|
|
|
|
//
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Delay Between Two Same Type Signals ...
|
|
// Check Open Next Behaviour ...
|
|
if (longsCount > 0 || shortsCount > 0)
|
|
{
|
|
//
|
|
// Check if Signaller Configured for Check Delay between Same type Signals ...
|
|
if (mDescriptors[iProviderIDX].signallers[iSignallerIDX].delayBetweenTwoSameTypeSignals > 0)
|
|
{
|
|
//
|
|
bool isDelayPassed = true;
|
|
|
|
//
|
|
if (longsCount > 0)
|
|
{
|
|
//
|
|
XPosition youngestLong;
|
|
int youngestLongAge = GetYoungest(
|
|
youngestLong,
|
|
longs //
|
|
);
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
isDelayPassed = youngestLongAge >= mDescriptors[iProviderIDX].signallers[iSignallerIDX].delayBetweenTwoSameTypeSignals;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (shortsCount > 0)
|
|
{
|
|
//
|
|
XPosition youngestShort;
|
|
int youngetsShortAge = GetYoungest(
|
|
youngestShort,
|
|
shorts //
|
|
);
|
|
|
|
//
|
|
if (!isLong)
|
|
{
|
|
isDelayPassed = youngetsShortAge >= mDescriptors[iProviderIDX].signallers[iSignallerIDX].delayBetweenTwoSameTypeSignals;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (!isDelayPassed)
|
|
{
|
|
//
|
|
string message = "ignore Signal due Delay Between Same Type Policy ...";
|
|
Log(message);
|
|
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Next Position ...
|
|
if (mDescriptors[iProviderIDX].signallers[iSignallerIDX].openNextPositionOnProfit)
|
|
{
|
|
//
|
|
bool isNextPassed = true;
|
|
|
|
//
|
|
if (isLong && longsCount > 0)
|
|
{
|
|
//
|
|
double profit = SpecifiedCalculatePositionsProfit(longs);
|
|
isNextPassed = profit > 0;
|
|
}
|
|
|
|
//
|
|
if (!isLong && shortsCount > 0)
|
|
{
|
|
//
|
|
double profit = SpecifiedCalculatePositionsProfit(shorts);
|
|
isNextPassed = profit > 0;
|
|
}
|
|
|
|
//
|
|
// Check Ignore for Opposit Signals ...
|
|
if (!isNextPassed &&
|
|
((isLong && shortsCount > longsCount) ||
|
|
(!isLong && longsCount > shortsCount)))
|
|
{
|
|
isNextPassed = mDescriptors[iProviderIDX].signallers[iSignallerIDX].ignoreProfitForOppositeSignals;
|
|
}
|
|
|
|
//
|
|
if (!isNextPassed)
|
|
{
|
|
//
|
|
string message = "ignore Signal due Next Must be In Profit Policy ...";
|
|
Log(message);
|
|
|
|
//
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally Add Filtered Signals into Result ...
|
|
AddRef(
|
|
iSignal,
|
|
signals //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(signals);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Handle State Management ....
|
|
// here we can manage current state ...
|
|
// - Check for Long Positions for each Signaller to Close ...
|
|
// - Handle Hedging Signaller's Positions if it's enabled ...
|
|
// - Force Closing Position when Specified Time reached ...
|
|
// - Check Start and End time or Trading Dates ...
|
|
// - handle Trailing or Risk free Signals based on several conditions ...
|
|
// and etc ...
|
|
bool HandleStateManagement(XSignal &signals[]) override
|
|
{
|
|
//
|
|
const bool result = false;
|
|
|
|
//
|
|
// Check Descriptor ...
|
|
int descriptorsCount = CountDescriptors();
|
|
if (!IsValidSize(descriptorsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Loop Through Descriptors ...
|
|
for (int i = 0; i < descriptorsCount; i++)
|
|
{
|
|
//
|
|
// Check Signallers ...
|
|
int signallersCount = mDescriptors[i].CountSignallers();
|
|
if (!IsValidSize(signallersCount))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Loop Through Signallers ...
|
|
for (int j = 0; j < signallersCount; j++)
|
|
{
|
|
//
|
|
// Retrieve Specified Signaller's Position ...
|
|
XPosition positions[];
|
|
int positionsCount = mTrader.GetPositions(
|
|
positions,
|
|
mDescriptors[i].symbol,
|
|
mDescriptors[i].signallers[j].GetName(),
|
|
mDescriptors[i].period);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check Signaller Enable Hedge or not and Handle it if enabled ...
|
|
if (mDescriptors[i].signallers[j].AllowHedge())
|
|
{
|
|
//
|
|
// Check Profits Enough for Hedge or not ...
|
|
double profit = SpecifiedCalculatePositionsProfit(positions);
|
|
bool isReadyForHedge = SpecifiedIsPositionsReadyForHedge(
|
|
positions,
|
|
mDescriptors[i].signallers[j].minRequiredProfitPerTrade,
|
|
mDescriptors[i].signallers[j].minRequiredProfitPerTradeVolumeFactor //
|
|
);
|
|
if (isReadyForHedge)
|
|
{
|
|
//
|
|
string comment = "Close due Hedge ...";
|
|
int closeds = mTrader.Close(
|
|
positions,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
if (closeds > 0)
|
|
{
|
|
//
|
|
string message = "Hedge (" + ToString(closeds) + ") Positions In Profit: " + ToString(profit);
|
|
|
|
//
|
|
Alert(message);
|
|
|
|
//
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Closing Long Age Position's Enabled or not ...
|
|
if (mDescriptors[i].signallers[j].maxAllowedOpenPositionAge > 0)
|
|
{
|
|
//
|
|
// Handle Close Long Time Trades ...
|
|
|
|
//
|
|
// Find Oldest ...
|
|
XPosition oldest;
|
|
int oldestAge = GetOldest(
|
|
oldest,
|
|
positions //
|
|
);
|
|
if (oldestAge >= mDescriptors[i].signallers[j].maxAllowedOpenPositionAge)
|
|
{
|
|
//
|
|
string comment = "Close due Long Age ...";
|
|
bool isClosed = mTrader.Close(
|
|
oldest.ticket,
|
|
comment //
|
|
);
|
|
|
|
//
|
|
if (isClosed)
|
|
{
|
|
//
|
|
string message = "Position (" + ToString(oldest.ticket) + ") Closed due Long Age Policy ...";
|
|
Alert(message);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// if Returns true, Signal Execution failed ...
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
void NotifyX121OnSignalEventHandlers(X121ProviderDescriptor &descriptor)
|
|
{
|
|
//
|
|
int listenersCount = ArraySize(mX121OnSignalEventHandlers);
|
|
if (listenersCount <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < listenersCount; i++)
|
|
{
|
|
//
|
|
TX121OnSignal iListener = mX121OnSignalEventHandlers[i];
|
|
|
|
//
|
|
iListener(descriptor);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Protect Specified Position ...
|
|
void ProtectPosition(XPosition &position)
|
|
{
|
|
//
|
|
// Here i Can Protect Position ...
|
|
// This Protect Include One Position in Market Mode ...
|
|
// If Provided ...
|
|
// the Positions Selection must passed Some conditions ...
|
|
|
|
//
|
|
string message = "For (" + position.symbol + ") Max In Drawdown Position is: (" +
|
|
ToString(position.ticket) + "), by Profit: " + ToString(position.profit);
|
|
|
|
//
|
|
mAlert.Alert(message);
|
|
}
|
|
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Collection of Signal Event Listeners ...
|
|
TX121OnSignal mX121OnSignalEventHandlers[];
|
|
|
|
//
|
|
// a Collection of X5 Provider Descriptors ...
|
|
X121ProviderDescriptor mDescriptors[];
|
|
|
|
//
|
|
int CountDescriptors()
|
|
{
|
|
return ArraySize(mDescriptors);
|
|
}
|
|
|
|
//
|
|
// Find Specifc Descriptor ...
|
|
int FindDescriptorIndex(
|
|
string symbol,
|
|
ENUM_TIMEFRAMES period //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid(symbol) ||
|
|
!IsValid(period))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int descriptorsCount = CountDescriptors();
|
|
if (!IsValidSize(descriptorsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < descriptorsCount; i++)
|
|
{
|
|
//
|
|
X121ProviderDescriptor iDescriptor = mDescriptors[i];
|
|
|
|
//
|
|
bool isPassed =
|
|
//
|
|
iDescriptor.symbol == symbol &&
|
|
iDescriptor.period == period
|
|
//
|
|
;
|
|
if (isPassed)
|
|
{
|
|
//
|
|
result = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
int FindDescriptorIndex(
|
|
T &item //
|
|
)
|
|
{
|
|
return FindDescriptorIndex(
|
|
item.symbol,
|
|
item.period //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Trails Holding ...
|
|
|
|
//
|
|
XTrail mSLTrails[];
|
|
XTrail mTPTrails[];
|
|
|
|
//
|
|
int CountSLTrails()
|
|
{
|
|
return ArraySize(mSLTrails);
|
|
}
|
|
int CountTPTrails()
|
|
{
|
|
return ArraySize(mTPTrails);
|
|
}
|
|
|
|
//
|
|
bool RemoveTrail(ulong ticket)
|
|
{
|
|
//
|
|
bool isSLRemoved = RemoveSLTrail(ticket);
|
|
bool isTPRemoved = RemoveTPTrail(ticket);
|
|
|
|
//
|
|
bool result = isSLRemoved || isTPRemoved;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool RemoveSLTrail(ulong ticket)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int idx = FindSLTrailIndex(ticket);
|
|
result = idx >= 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArrayRemove(
|
|
mSLTrails,
|
|
idx,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool RemoveTPTrail(ulong ticket)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int idx = FindTPTrailIndex(ticket);
|
|
result = idx >= 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArrayRemove(
|
|
mTPTrails,
|
|
idx,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int FindSLTrailIndex(ulong ticket)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int trailsCount = CountSLTrails();
|
|
if (ticket <= 0 || trailsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < trailsCount; i++)
|
|
{
|
|
//
|
|
XTrail iTrail = mSLTrails[i];
|
|
|
|
//
|
|
if (iTrail.ticket == ticket)
|
|
{
|
|
//
|
|
result = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
int FindTPTrailIndex(ulong ticket)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int trailsCount = CountTPTrails();
|
|
if (ticket <= 0 || trailsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < trailsCount; i++)
|
|
{
|
|
//
|
|
XTrail iTrail = mTPTrails[i];
|
|
|
|
//
|
|
if (iTrail.ticket == ticket)
|
|
{
|
|
//
|
|
result = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetSLTrail(
|
|
ulong ticket,
|
|
XTrail &trail //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int idx = FindSLTrailIndex(ticket);
|
|
result = idx >= 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
trail = mSLTrails[idx];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool GetTPTrail(
|
|
ulong ticket,
|
|
XTrail &trail //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int idx = FindTPTrailIndex(ticket);
|
|
result = idx >= 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
trail = mTPTrails[idx];
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
void AddSLTrail(
|
|
XTrail &trail //
|
|
)
|
|
{
|
|
//
|
|
if (!trail.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
AddRef(
|
|
trail,
|
|
mSLTrails //
|
|
);
|
|
}
|
|
void AddTPTrail(
|
|
XTrail &trail //
|
|
)
|
|
{
|
|
//
|
|
if (!trail.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
AddRef(
|
|
trail,
|
|
mTPTrails //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
};
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
// |