6068 lines
111 KiB
Plaintext
6068 lines
111 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Seriallize Library
|
|
// ---------------------------------------
|
|
// Name: XTradeLib
|
|
// Description: All models related to Trade ...
|
|
//
|
|
//
|
|
// 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 "../Libraries/x-saherelm.common.lib.mq5"
|
|
#include "../Libraries/x-saherelm.draw.lib.mq5"
|
|
#include <Trade/Trade.mqh>
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// a List of Used Tokens ...
|
|
|
|
//
|
|
// Common ...
|
|
string XIDToken = "ID";
|
|
string XTicketToken = "TK";
|
|
string XModeToken = "MD";
|
|
string XTypeToken = "TY";
|
|
string XPeriodToken = "PR";
|
|
string XProviderToken = "PRV";
|
|
string XProfitToken = "PF";
|
|
|
|
//
|
|
string XTPToken = "TP";
|
|
string XSLToken = "SL";
|
|
string XTimeToken = "TM";
|
|
string XEntryToken = "EN";
|
|
string XVolumeToken = "VL";
|
|
string XSymbolToken = "SMBL";
|
|
|
|
//
|
|
string XSupportToken = "SP";
|
|
string XEQMSupportToken = "EQM";
|
|
string XEQPToken = "EQP";
|
|
|
|
//
|
|
string XSLTrailToken = "SLT";
|
|
|
|
//
|
|
string XActionToken = "A";
|
|
|
|
//
|
|
string XDirectionalToken = "D";
|
|
string XINDirectionalToken = "IND";
|
|
|
|
//
|
|
string XRecoveryToken = "XRCV";
|
|
|
|
//
|
|
// Available Order Modes ...
|
|
enum ENUM_X_ORDER_MODES
|
|
{
|
|
X_ORDER_MODE_NOTHING, // Nothing
|
|
X_ORDER_MODE_MARKET, // Market Order
|
|
X_ORDER_MODE_STOP, // Pending Stop Order
|
|
X_ORDER_MODE_LIMIT, // Pending Limit Order
|
|
X_ORDER_MODE_STOP_LIMIT, // Pending Stop Limit Order
|
|
};
|
|
|
|
//
|
|
string ToString(ENUM_X_ORDER_MODES value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case X_ORDER_MODE_MARKET:
|
|
result = "Market";
|
|
break;
|
|
|
|
//
|
|
case X_ORDER_MODE_LIMIT:
|
|
result = "Limit";
|
|
break;
|
|
|
|
//
|
|
case X_ORDER_MODE_STOP:
|
|
result = "Stop";
|
|
break;
|
|
|
|
//
|
|
case X_ORDER_MODE_STOP_LIMIT:
|
|
result = "StopLimit";
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Select Positions Type ...
|
|
enum ENUM_X_POSITION_SELECT_METHODS
|
|
{
|
|
X_POSITION_SELECT_NONE, // None
|
|
X_POSITION_SELECT_MAX, // Max
|
|
X_POSITION_SELECT_MIN, // Min
|
|
X_POSITION_SELECT_BOTH, // Min and Max
|
|
X_POSITION_SELECT_ALL, // All
|
|
};
|
|
|
|
//
|
|
// Signal Execution Result ...
|
|
// note that some of them must be handles in
|
|
// EA's ...
|
|
enum ENUM_X_SIGNAL_EXECUTION_RESULT
|
|
{
|
|
//
|
|
X_SIGNAL_EXECUTION_UNKNOWN, // Unknown
|
|
X_SIGNAL_EXECUTION_SUCCEED, // Succed
|
|
X_SIGNAL_EXECUTION_FAILED_SPREAD, // Spread more than Max Allowed
|
|
X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED, // Not Allowed Trade Type
|
|
X_SIGNAL_EXECUTION_FAILED_NO_EQUITY, // No Equity for Trade
|
|
X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR, // Price Error
|
|
X_SIGNAL_EXECUTION_FAILED_MAX_REACHED, // Max Allowed Positions Reached
|
|
X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED, // Same Positions Delay Not Passed
|
|
X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS, // Invalid Params
|
|
};
|
|
|
|
//
|
|
// Available Guard Action ...
|
|
enum ENUM_X_GUARD_ACTIONS
|
|
{
|
|
X_GUARD_ACTION_NOTHING, // Nothing
|
|
X_GUARD_ACTION_HEDGE, // Hedge
|
|
X_GUARD_PARTIAL_CLOSE, // Partial Close
|
|
X_GUARD_ACTION_TRAIL_STOP, // Trail StopLoss
|
|
X_GUARD_ACTION_FORCE_CLOSE, // Force Close
|
|
X_GUARD_ACTION_ADD_SUPPORT_SIGNAL, // Add Support Signal
|
|
X_GUARD_ACTION_CANCEL_PENDING_ORDERS, // Cancel Pending Orders
|
|
};
|
|
|
|
//
|
|
enum ENUM_X_POSITION_TYPES
|
|
{
|
|
X_POSITION_TYPE_NONE = 0,
|
|
X_POSITION_TYPE_ALL = 1,
|
|
X_POSITION_TYPE_LONG = 2,
|
|
X_POSITION_TYPE_SHORT = 3,
|
|
};
|
|
|
|
//
|
|
string ToString(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case X_POSITION_TYPE_ALL:
|
|
result = "All";
|
|
break;
|
|
|
|
//
|
|
case X_POSITION_TYPE_NONE:
|
|
result = "NONE";
|
|
break;
|
|
|
|
//
|
|
case X_POSITION_TYPE_SHORT:
|
|
result = "Short";
|
|
break;
|
|
|
|
//
|
|
case X_POSITION_TYPE_LONG:
|
|
result = "Long";
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool IsLong(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
return value == X_POSITION_TYPE_LONG;
|
|
}
|
|
|
|
//
|
|
bool ToPositionType(
|
|
ENUM_POSITION_TYPE &dest,
|
|
ENUM_X_POSITION_TYPES source //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = source == X_POSITION_TYPE_LONG ||
|
|
source == X_POSITION_TYPE_SHORT;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dest =
|
|
source == X_POSITION_TYPE_LONG
|
|
? POSITION_TYPE_BUY
|
|
: POSITION_TYPE_SELL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_POSITION_TYPES ToPositionType(ENUM_POSITION_TYPE value)
|
|
{
|
|
return IsLong(value)
|
|
? X_POSITION_TYPE_LONG
|
|
: X_POSITION_TYPE_SHORT;
|
|
}
|
|
|
|
//
|
|
ENUM_X_POSITION_TYPES GetOppositPositionType(ENUM_POSITION_TYPE type)
|
|
{
|
|
//
|
|
ENUM_X_POSITION_TYPES result = X_POSITION_TYPE_NONE;
|
|
|
|
//
|
|
bool isLong = IsLong(type);
|
|
bool isShort = IsShort(type);
|
|
|
|
//
|
|
result =
|
|
//
|
|
isLong
|
|
? X_POSITION_TYPE_SHORT
|
|
: isShort
|
|
? X_POSITION_TYPE_LONG
|
|
: X_POSITION_TYPE_NONE
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Structs ...
|
|
|
|
//
|
|
// Model an Open Position ...
|
|
struct XPosition
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
// Magic Number ...
|
|
ulong magic;
|
|
|
|
//
|
|
// Ticket ID ...
|
|
ulong ticket;
|
|
|
|
//
|
|
// Tradinng Symbol ...
|
|
string symbol;
|
|
|
|
//
|
|
// Trading Period ...
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
// Position Type ...
|
|
ENUM_POSITION_TYPE type;
|
|
|
|
//
|
|
// Take Profit ...
|
|
double tp;
|
|
|
|
//
|
|
// Stop Loss ...
|
|
double sl;
|
|
|
|
//
|
|
// Position Current Profit ...
|
|
double profit;
|
|
|
|
//
|
|
// Position Open Price ...
|
|
double entry;
|
|
|
|
//
|
|
// Current Symbol Price ...
|
|
double price;
|
|
|
|
//
|
|
// Position Swap ...
|
|
double swap;
|
|
|
|
//
|
|
// Position Commission ...
|
|
double commission;
|
|
|
|
//
|
|
// Volume ...
|
|
double volume;
|
|
|
|
//
|
|
// Position Open Time ...
|
|
datetime openAt;
|
|
|
|
//
|
|
// Sifnal Provider ...
|
|
string provider;
|
|
|
|
//
|
|
// Position Comment ...
|
|
string comment;
|
|
|
|
//
|
|
// Constructor ...
|
|
XPosition()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Initializers ...
|
|
|
|
bool ByIndex(int index)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
static CPositionInfo mPositionInfo;
|
|
|
|
//
|
|
result = mPositionInfo.SelectByIndex(index);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ulong mTicket = mPositionInfo.Ticket();
|
|
|
|
//
|
|
result = ByTicket(mTicket);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool ByTicket(ulong mTicket)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
static CPositionInfo mPositionInfo;
|
|
|
|
//
|
|
result = mPositionInfo.SelectByTicket(mTicket);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
swap = mPositionInfo.Swap();
|
|
magic = mPositionInfo.Magic();
|
|
openAt = mPositionInfo.Time();
|
|
sl = mPositionInfo.StopLoss();
|
|
ticket = mPositionInfo.Ticket();
|
|
symbol = mPositionInfo.Symbol();
|
|
tp = mPositionInfo.TakeProfit();
|
|
profit = mPositionInfo.Profit();
|
|
volume = mPositionInfo.Volume();
|
|
comment = mPositionInfo.Comment();
|
|
entry = mPositionInfo.PriceOpen();
|
|
type = mPositionInfo.PositionType();
|
|
price = mPositionInfo.PriceCurrent();
|
|
commission = mPositionInfo.Commission();
|
|
|
|
//
|
|
period = ExtractPeriod(comment);
|
|
provider = ExtractProvider(comment);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
magic = 0;
|
|
ticket = 0;
|
|
tp = 0;
|
|
sl = 0;
|
|
swap = 0;
|
|
entry = 0;
|
|
price = 0;
|
|
profit = 0;
|
|
volume = 0;
|
|
openAt = 0;
|
|
commission = 0;
|
|
|
|
//
|
|
type = NULL;
|
|
period = NULL;
|
|
|
|
//
|
|
symbol = NULL;
|
|
comment = NULL;
|
|
provider = NULL;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(symbol) &&
|
|
NotEmpty(ticket)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Entry Price ...
|
|
double GetEntry()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetEntry(
|
|
symbol,
|
|
type
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Exit ...
|
|
double GetExit()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetExit(
|
|
symbol,
|
|
type
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Spread by Point ...
|
|
double GetSpread()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = PriceToPoint(GetSpread(symbol));
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double GetPointsValue()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetPoints(symbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double GetProfitInPoint()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); // Tick size
|
|
double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); // Tick value
|
|
double pointSize = SymbolInfoDouble(symbol, SYMBOL_POINT); // Point size
|
|
double pointValue = tickValue * pointSize / tickSize; // Point value
|
|
|
|
//
|
|
result = profit / (volume * tickValue);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Risk ...
|
|
double GetRisk()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
result = MathAbs(entry - sl);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Reward ...
|
|
double GetReward()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = MathAbs(tp - entry);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double GetRewardInPoint() {
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
result = GetReward() / GetPoints();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Risk Reward Ratio ...
|
|
double GetRiskRewardRatio()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetReward() / GetRisk();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Age ...
|
|
int GetAge(
|
|
ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period
|
|
)
|
|
{
|
|
return GetAge(this, mPeriod);
|
|
}
|
|
|
|
//
|
|
// Check this instance is Same os Given instance or not ...
|
|
bool IsSameAs(
|
|
const XPosition &value // instance for Compare
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
type == value.type &&
|
|
magic == value.magic &&
|
|
entry == value.entry &&
|
|
ticket == value.ticket &&
|
|
volume == value.volume &&
|
|
symbol == value.symbol &&
|
|
provider == value.provider
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find index in a Collection ...
|
|
int FindIndex(
|
|
const XPosition &values[] // Collection to Find
|
|
)
|
|
{
|
|
//
|
|
return FindIndex(
|
|
this,
|
|
values
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Check Items Passed Specific Filters or not ...
|
|
bool IsFiltersPassed(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
string mProvider = NULL, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe
|
|
ENUM_X_POSITION_TYPES mType = NULL, // Long (Buy), Short (Sell)
|
|
ulong mMagic = NULL, // Magic Number
|
|
bool mFilterByMagic = true // Get Only Self Open Positions
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
// Magic Filter ...
|
|
IsMagicFilterPassed(
|
|
mMagic,
|
|
mFilterByMagic,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Symbol Filter ...
|
|
IsSymbolFilterPassed(
|
|
mSymbol,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Provider Filter ...
|
|
IsProviderFilterPassed(
|
|
mProvider,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Period Filter ...
|
|
IsPeriodFilterPassed(
|
|
mPeriod,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Type Filter ...
|
|
IsTypeFilterPassed(
|
|
mType,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model a Signal ...
|
|
struct XSignal
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
ulong positionId; // if Executed this filled ...
|
|
|
|
//
|
|
datetime time; // Issue Time ...
|
|
|
|
//
|
|
double tp; // Take Profit ...
|
|
double sl; // Stop Loss ...
|
|
double entry; // Exntry or Execution Price ...
|
|
double volume; // Position Volume ...
|
|
|
|
//
|
|
string symbol; // Trading Symbol ...
|
|
string comment; // Comment ...
|
|
string provider; // Signaller ...
|
|
|
|
//
|
|
ENUM_TIMEFRAMES period; // Trading TimeFrame ...
|
|
ENUM_POSITION_TYPE type; // Long (Buy) or Short (Sell) ...
|
|
ENUM_X_ORDER_MODES mode; // Execution Mode ...
|
|
|
|
//
|
|
XSignal supports[]; // a Collecion of Support Signals ...
|
|
|
|
//
|
|
int pushers; // Signal Pushers ...
|
|
string conditions; // Signal Conditions ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XSignal()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
bool Prepare(
|
|
string mSymbol, // Trading Symbol
|
|
string mProvider, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame
|
|
ENUM_POSITION_TYPE mType, // Long (Buy) or Short (Sell)
|
|
ENUM_X_ORDER_MODES mMode, // Execution Mode
|
|
double mEntry, // Entry Price
|
|
double mVolume, // Volume
|
|
double mSL = 0, // Stop Loss
|
|
double mTP = 0 // Take Profit
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(mMode) &&
|
|
IsValid(mSymbol) &&
|
|
IsValid(mPeriod) &&
|
|
NotEmpty(mEntry) &&
|
|
NotEmpty(mVolume) &&
|
|
IsValid(mProvider)
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (mTP < 0)
|
|
{
|
|
mTP = 0;
|
|
}
|
|
|
|
//
|
|
if (mSL < 0)
|
|
{
|
|
mSL = 0;
|
|
}
|
|
|
|
//
|
|
type = mType;
|
|
mode = mMode;
|
|
symbol = mSymbol;
|
|
period = mPeriod;
|
|
provider = mProvider;
|
|
|
|
//
|
|
// Normalization Values ...
|
|
sl = NormalizePrice(mSL, mSymbol);
|
|
tp = NormalizePrice(mTP, mSymbol);
|
|
mEntry = NormalizePrice(mEntry, mSymbol);
|
|
mVolume = NormalizeVolume(mVolume, mSymbol);
|
|
|
|
//
|
|
entry = mEntry;
|
|
volume = mVolume;
|
|
|
|
//
|
|
result = Normalize();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool PrepareLong(
|
|
string mSymbol, // Trading Symbol
|
|
string mProvider, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame
|
|
ENUM_X_ORDER_MODES mMode, // Execution Mode
|
|
double mEntry, // Entry Price
|
|
double mVolume, // Volume
|
|
double mSL = 0, // Stop Loss
|
|
double mTP = 0 // Take Profit
|
|
)
|
|
{
|
|
//
|
|
return Prepare(
|
|
mSymbol,
|
|
mProvider,
|
|
mPeriod,
|
|
POSITION_TYPE_BUY,
|
|
mMode,
|
|
mEntry,
|
|
mVolume,
|
|
mSL,
|
|
mTP
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
bool PrepareShort(
|
|
string mSymbol, // Trading Symbol
|
|
string mProvider, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame
|
|
ENUM_X_ORDER_MODES mMode, // Execution Mode
|
|
double mEntry, // Entry Price
|
|
double mVolume, // Volume
|
|
double mSL = 0, // Stop Loss
|
|
double mTP = 0 // Take Profit
|
|
)
|
|
{
|
|
//
|
|
return Prepare(
|
|
mSymbol,
|
|
mProvider,
|
|
mPeriod,
|
|
POSITION_TYPE_SELL,
|
|
mMode,
|
|
mEntry,
|
|
mVolume,
|
|
mSL,
|
|
mTP
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Market Mode ...
|
|
|
|
//
|
|
bool PrepareMarketLong(
|
|
string mSymbol, // Trading Symbol
|
|
string mProvider, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame
|
|
double mEntry, // Entry Price
|
|
double mVolume, // Volume
|
|
double mSL = 0, // Stop Loss
|
|
double mTP = 0 // Take Profit
|
|
)
|
|
{
|
|
//
|
|
return PrepareLong(
|
|
mSymbol,
|
|
mProvider,
|
|
mPeriod,
|
|
X_ORDER_MODE_MARKET,
|
|
mEntry,
|
|
mVolume,
|
|
mSL,
|
|
mTP
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
bool PrepareMarketShort(
|
|
string mSymbol, // Trading Symbol
|
|
string mProvider, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame
|
|
double mEntry, // Entry Price
|
|
double mVolume, // Volume
|
|
double mSL = 0, // Stop Loss
|
|
double mTP = 0 // Take Profit
|
|
)
|
|
{
|
|
//
|
|
return PrepareShort(
|
|
mSymbol,
|
|
mProvider,
|
|
mPeriod,
|
|
X_ORDER_MODE_MARKET,
|
|
mEntry,
|
|
mVolume,
|
|
mSL,
|
|
mTP
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Stop Mode ...
|
|
|
|
//
|
|
bool PrepareStopLong(
|
|
string mSymbol, // Trading Symbol
|
|
string mProvider, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame
|
|
double mEntry, // Entry Price
|
|
double mVolume, // Volume
|
|
double mSL = 0, // Stop Loss
|
|
double mTP = 0 // Take Profit
|
|
)
|
|
{
|
|
//
|
|
return PrepareLong(
|
|
mSymbol,
|
|
mProvider,
|
|
mPeriod,
|
|
X_ORDER_MODE_STOP,
|
|
mEntry,
|
|
mVolume,
|
|
mSL,
|
|
mTP
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
bool PrepareStopShort(
|
|
string mSymbol, // Trading Symbol
|
|
string mProvider, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame
|
|
double mEntry, // Entry Price
|
|
double mVolume, // Volume
|
|
double mSL = 0, // Stop Loss
|
|
double mTP = 0 // Take Profit
|
|
)
|
|
{
|
|
//
|
|
return PrepareShort(
|
|
mSymbol,
|
|
mProvider,
|
|
mPeriod,
|
|
X_ORDER_MODE_STOP,
|
|
mEntry,
|
|
mVolume,
|
|
mSL,
|
|
mTP
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Limit Mode ...
|
|
|
|
//
|
|
bool PrepareLimitLong(
|
|
string mSymbol, // Trading Symbol
|
|
string mProvider, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame
|
|
double mEntry, // Entry Price
|
|
double mVolume, // Volume
|
|
double mSL = 0, // Stop Loss
|
|
double mTP = 0 // Take Profit
|
|
)
|
|
{
|
|
//
|
|
return PrepareLong(
|
|
mSymbol,
|
|
mProvider,
|
|
mPeriod,
|
|
X_ORDER_MODE_LIMIT,
|
|
mEntry,
|
|
mVolume,
|
|
mSL,
|
|
mTP
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
bool PrepareLimitShort(
|
|
string mSymbol, // Trading Symbol
|
|
string mProvider, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod, // Trading TimeFrame
|
|
double mEntry, // Entry Price
|
|
double mVolume, // Volume
|
|
double mSL = 0, // Stop Loss
|
|
double mTP = 0 // Take Profit
|
|
)
|
|
{
|
|
//
|
|
return PrepareShort(
|
|
mSymbol,
|
|
mProvider,
|
|
mPeriod,
|
|
X_ORDER_MODE_LIMIT,
|
|
mEntry,
|
|
mVolume,
|
|
mSL,
|
|
mTP
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Generate Opposit Direction ...
|
|
bool GenerateOpposit(
|
|
XSignal &mSignal // Oppsoit Signal
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_POSITION_TYPE mType = GetOpposit(this.type);
|
|
double mEntry = GetExit(this.symbol, mType);
|
|
|
|
//
|
|
bool isLong = IsLong(mType);
|
|
|
|
//
|
|
// Calculate Risk Reward Ratio ...
|
|
double risk = GetRisk();
|
|
double reward = GetReward();
|
|
|
|
//
|
|
double mSL = isLong
|
|
? mEntry - risk
|
|
: mEntry + risk;
|
|
|
|
//
|
|
double mTP = isLong
|
|
? mEntry + reward
|
|
: mEntry - reward;
|
|
|
|
//
|
|
result = mSignal.Prepare(
|
|
this.symbol,
|
|
this.provider,
|
|
this.period,
|
|
mType,
|
|
this.mode,
|
|
mEntry,
|
|
this.volume,
|
|
mSL,
|
|
mTP //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Prepare Opposit Signal based On a Position ...
|
|
bool PrepareOpposit(
|
|
XPosition &source // Source Data
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
ENUM_POSITION_TYPE mType = GetOpposit(source.type);
|
|
double mEntry = GetEntry(source.symbol, mType);
|
|
|
|
//
|
|
bool isLong = IsLong(mType);
|
|
|
|
//
|
|
double risk = source.GetRisk();
|
|
double reward = source.GetReward();
|
|
|
|
//
|
|
double mSL = isLong
|
|
? mEntry - risk
|
|
: mEntry + risk;
|
|
|
|
//
|
|
double mTP = isLong
|
|
? mEntry + reward
|
|
: mEntry - reward;
|
|
|
|
//
|
|
return Prepare(
|
|
source.symbol,
|
|
source.provider,
|
|
source.period,
|
|
mType,
|
|
X_ORDER_MODE_MARKET,
|
|
mEntry,
|
|
source.volume,
|
|
mSL,
|
|
mTP //
|
|
);
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
entry = 0;
|
|
volume = 0;
|
|
pushers = 0;
|
|
positionId = 0;
|
|
|
|
//
|
|
time = NULL;
|
|
type = NULL;
|
|
mode = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
comment = NULL;
|
|
provider = NULL;
|
|
conditions = NULL;
|
|
|
|
//
|
|
Clean(supports);
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(period) &&
|
|
IsValid(symbol) &&
|
|
NotEmpty(volume) &&
|
|
NotEmpty(entry)
|
|
//
|
|
;
|
|
|
|
//
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// DO All Calculations and Normalizations ...
|
|
bool Normalize()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Normalizations ...
|
|
symbol = NormalizeSymbol(symbol);
|
|
period = NormalizePeriod(period);
|
|
|
|
//
|
|
time = NormalizeTime(time);
|
|
|
|
//
|
|
sl = NormalizePrice(sl, symbol);
|
|
tp = NormalizePrice(tp, symbol);
|
|
entry = NormalizePrice(entry, symbol);
|
|
volume = NormalizeVolume(volume, symbol);
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Signal Executed or not ...
|
|
bool IsExecuted()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid() &&
|
|
NotEmpty(positionId)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Generate Comment for Signal ...
|
|
string GenerateComment()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (IsValid(provider))
|
|
{
|
|
//
|
|
// Generate Provider Tag ...
|
|
result += GenerateProviderTag(provider);
|
|
}
|
|
|
|
//
|
|
if (IsValid(period))
|
|
{
|
|
//
|
|
// Generate Period Tag ...
|
|
result += GeneratePeriodTag(period);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetAge()
|
|
{
|
|
//
|
|
return GetAge(
|
|
this,
|
|
this.period //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Retrieve Entry Price ...
|
|
double GetEntry()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetEntry(
|
|
symbol,
|
|
type
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Exit ...
|
|
double GetExit()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetExit(
|
|
symbol,
|
|
type
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Spread by Point ...
|
|
double GetSpread()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = PriceToPoint(GetSpread(symbol));
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Risk ...
|
|
double GetRisk()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
result = MathAbs(entry - sl);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Reward ...
|
|
double GetReward()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = MathAbs(tp - entry);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Risk Reward Ratio ...
|
|
double GetRiskRewardRatio()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetReward() / GetRisk();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Draw Signal on Chart ...
|
|
bool Draw(
|
|
long chartID,
|
|
int subWindow = 0,
|
|
string prefix = NULL,
|
|
color entryColor = clrGold,
|
|
color bullishColor = clrSpringGreen,
|
|
color bearishColor = clrTomato //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isLong = IsLong(this.type);
|
|
|
|
//
|
|
prefix =
|
|
//
|
|
(!IsValid(prefix) ? "" : prefix) +
|
|
this.symbol + "_" +
|
|
ToString(this.period) + "_" +
|
|
this.provider
|
|
//
|
|
;
|
|
|
|
//
|
|
int age = this.GetAge();
|
|
|
|
//
|
|
// Retrieve Time ...
|
|
datetime time0 = iTime(
|
|
this.symbol,
|
|
this.period,
|
|
age //
|
|
);
|
|
|
|
//
|
|
// Retrieve 3 Time ...
|
|
datetime time3 = iTime(
|
|
this.symbol,
|
|
this.period,
|
|
age + 3 //
|
|
);
|
|
|
|
//
|
|
color posColor = isLong
|
|
? bullishColor
|
|
: bearishColor;
|
|
color tpColor = bullishColor;
|
|
color slColor = bearishColor;
|
|
|
|
//
|
|
ENUM_LINE_STYLE vLineStyle = STYLE_DOT;
|
|
ENUM_LINE_STYLE tpLineStyle = STYLE_SOLID;
|
|
ENUM_LINE_STYLE slLineStyle = STYLE_SOLID;
|
|
ENUM_LINE_STYLE entryLineStyle = STYLE_SOLID;
|
|
|
|
//
|
|
int lineWidth = 2;
|
|
|
|
//
|
|
// Vertical Line ...
|
|
string vlName = prefix + "_" + (string)time;
|
|
|
|
//
|
|
result = DrawVerticalLine(
|
|
chartID,
|
|
vlName,
|
|
subWindow,
|
|
time0,
|
|
posColor,
|
|
vLineStyle,
|
|
lineWidth //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// TP ...
|
|
double profit = (MathAbs(this.tp - this.entry)) * this.volume;
|
|
string tpName = prefix + "_TP_" + (string)profit;
|
|
|
|
//
|
|
result = DrawTrendLine(
|
|
chartID,
|
|
tpName,
|
|
subWindow,
|
|
time3,
|
|
this.tp,
|
|
time0,
|
|
this.tp,
|
|
tpColor,
|
|
tpLineStyle,
|
|
lineWidth //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// SL ...
|
|
double lost = (MathAbs(this.sl - this.entry)) * this.volume;
|
|
string slName = prefix + "_SL_" + (string)lost;
|
|
|
|
//
|
|
result = DrawTrendLine(
|
|
chartID,
|
|
slName,
|
|
subWindow,
|
|
time3,
|
|
this.sl,
|
|
time0,
|
|
this.sl,
|
|
slColor,
|
|
slLineStyle,
|
|
lineWidth //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// ENTRY ...
|
|
string entryName = prefix + "_ENTRY_" + (string)lost;
|
|
|
|
//
|
|
result = DrawTrendLine(
|
|
chartID,
|
|
entryName,
|
|
subWindow,
|
|
time3,
|
|
this.entry,
|
|
time,
|
|
this.entry,
|
|
entryColor,
|
|
entryLineStyle,
|
|
lineWidth //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve String Representation of Signal ...
|
|
string ToString()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
result =
|
|
//
|
|
ToString("Symbol", symbol) +
|
|
ToString("Period", period) +
|
|
ToString("Provider", provider) +
|
|
ToString("Type", type) +
|
|
ToString("Mode", mode) +
|
|
ToString("Volume", volume) +
|
|
ToString("Entry", entry) +
|
|
ToString("TP", tp) +
|
|
ToString("SL", sl) +
|
|
ToString("Time", time) +
|
|
ToString("Comment", comment) +
|
|
//
|
|
""
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model an Order ...
|
|
struct XOrder
|
|
{
|
|
//
|
|
// Time of order placement ...
|
|
datetime setupAt;
|
|
|
|
//
|
|
// Time of order expiration ...
|
|
datetime expiredAt;
|
|
|
|
//
|
|
// Time of order execution or cancellation ...
|
|
datetime executedAt;
|
|
|
|
//
|
|
// Order type ...
|
|
ENUM_ORDER_TYPE type;
|
|
|
|
//
|
|
// Order state ...
|
|
ENUM_ORDER_STATE state;
|
|
|
|
//
|
|
// Type of execution by remainder ...
|
|
ENUM_ORDER_TYPE_FILLING filling;
|
|
|
|
//
|
|
// Order lifetime ...
|
|
ENUM_ORDER_TYPE_TIME lifetime;
|
|
|
|
//
|
|
// Order ticket ...
|
|
ulong ticket;
|
|
|
|
//
|
|
// Magic Number ...
|
|
long magic;
|
|
|
|
//
|
|
// Position id, that is placed on order,
|
|
// when it is executed. Each executed order invokes a
|
|
// deal, that opens new or changes existing
|
|
// position. Id of that position is placed on
|
|
// executed order in this moment.
|
|
long positionId;
|
|
|
|
//
|
|
// Initial volume on order placement ...
|
|
double initialVolume;
|
|
|
|
//
|
|
// Unfilled volume ...
|
|
double currentVolume;
|
|
|
|
//
|
|
// Price, specified in the order ...
|
|
double openPrice;
|
|
|
|
//
|
|
// Current price by order symbol ...
|
|
double currentPrice;
|
|
|
|
//
|
|
// Price of placing Limit order when StopLimit order is triggered ...
|
|
double stopLimitPrice;
|
|
|
|
//
|
|
// Take Profit level ...
|
|
double tp;
|
|
|
|
//
|
|
// Stop Loss level ...
|
|
double sl;
|
|
|
|
//
|
|
// Trading Symbol ...
|
|
string symbol;
|
|
|
|
//
|
|
// Signal Provider ...
|
|
string provider;
|
|
|
|
//
|
|
// Order Comment ...
|
|
string comment;
|
|
|
|
//
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
// Constructor ...
|
|
XOrder()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Initializers ...
|
|
bool ByIndex(
|
|
int index // Fill By Index ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int ordersCount = OrdersTotal();
|
|
if (ordersCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
static COrderInfo mOrderInfo;
|
|
|
|
//
|
|
result = mOrderInfo.SelectByIndex(index);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Order Info ...
|
|
magic = mOrderInfo.Magic();
|
|
sl = mOrderInfo.StopLoss();
|
|
tp = mOrderInfo.TakeProfit();
|
|
ticket = mOrderInfo.Ticket();
|
|
openPrice = mOrderInfo.PriceOpen();
|
|
positionId = mOrderInfo.PositionId();
|
|
currentPrice = mOrderInfo.PriceCurrent();
|
|
initialVolume = mOrderInfo.VolumeInitial();
|
|
currentVolume = mOrderInfo.VolumeCurrent();
|
|
stopLimitPrice = mOrderInfo.PriceStopLimit();
|
|
|
|
//
|
|
symbol = mOrderInfo.Symbol();
|
|
comment = mOrderInfo.Comment();
|
|
|
|
//
|
|
state = mOrderInfo.State();
|
|
type = mOrderInfo.OrderType();
|
|
lifetime = mOrderInfo.TypeTime();
|
|
filling = mOrderInfo.TypeFilling();
|
|
|
|
//
|
|
setupAt = mOrderInfo.TimeSetup();
|
|
executedAt = mOrderInfo.TimeDone();
|
|
expiredAt = mOrderInfo.TimeExpiration();
|
|
|
|
//
|
|
period = ExtractPeriod(comment);
|
|
provider = ExtractProvider(comment);
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve Specific History Order ...
|
|
bool HistoryByIndex(
|
|
int index // Fill By Index ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int ordersCount = HistoryOrdersTotal();
|
|
if (ordersCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
static CHistoryOrderInfo mOrderInfo;
|
|
|
|
//
|
|
result = mOrderInfo.SelectByIndex(index);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Order Info ...
|
|
magic = mOrderInfo.Magic();
|
|
sl = mOrderInfo.StopLoss();
|
|
tp = mOrderInfo.TakeProfit();
|
|
ticket = mOrderInfo.Ticket();
|
|
openPrice = mOrderInfo.PriceOpen();
|
|
positionId = mOrderInfo.PositionId();
|
|
currentPrice = mOrderInfo.PriceCurrent();
|
|
initialVolume = mOrderInfo.VolumeInitial();
|
|
currentVolume = mOrderInfo.VolumeCurrent();
|
|
stopLimitPrice = mOrderInfo.PriceStopLimit();
|
|
|
|
//
|
|
symbol = mOrderInfo.Symbol();
|
|
comment = mOrderInfo.Comment();
|
|
|
|
//
|
|
state = mOrderInfo.State();
|
|
type = mOrderInfo.OrderType();
|
|
lifetime = mOrderInfo.TypeTime();
|
|
filling = mOrderInfo.TypeFilling();
|
|
|
|
//
|
|
setupAt = mOrderInfo.TimeSetup();
|
|
executedAt = mOrderInfo.TimeDone();
|
|
expiredAt = mOrderInfo.TimeExpiration();
|
|
|
|
//
|
|
period = ExtractPeriod(comment);
|
|
provider = ExtractProvider(comment);
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
tp = 0;
|
|
sl = 0;
|
|
magic = 0;
|
|
ticket = 0;
|
|
positionId = 0;
|
|
openPrice = 0;
|
|
currentPrice = 0;
|
|
initialVolume = 0;
|
|
currentVolume = 0;
|
|
stopLimitPrice = 0;
|
|
|
|
//
|
|
setupAt = NULL;
|
|
expiredAt = NULL;
|
|
executedAt = NULL;
|
|
|
|
//
|
|
symbol = NULL;
|
|
comment = NULL;
|
|
provider = NULL;
|
|
|
|
//
|
|
type = NULL;
|
|
state = NULL;
|
|
period = NULL;
|
|
filling = NULL;
|
|
lifetime = NULL;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(symbol) &&
|
|
NotEmpty(ticket) &&
|
|
NotEmpty(positionId)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Age ...
|
|
int GetAge(
|
|
ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period
|
|
)
|
|
{
|
|
return GetAge(this, mPeriod);
|
|
}
|
|
|
|
//
|
|
// Check this instance is Same os Given instance or not ...
|
|
bool IsSameAs(
|
|
const XOrder &value // instance for Compare
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
type == value.type &&
|
|
state == value.state &&
|
|
magic == value.magic &&
|
|
ticket == value.ticket &&
|
|
symbol == value.symbol &&
|
|
provider == value.provider &&
|
|
positionId == value.positionId
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find index in a Collection ...
|
|
int FindIndex(
|
|
const XOrder &values[] // Collection to Find
|
|
)
|
|
{
|
|
//
|
|
return FindIndex(
|
|
this,
|
|
values
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Check Items Passed Specific Filters or not ...
|
|
bool IsFiltersPassed(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
string mProvider = NULL, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe
|
|
ENUM_X_POSITION_TYPES mType = NULL, // Long (Buy), Short (Sell)
|
|
ENUM_ORDER_STATE mState = NULL, // Order State
|
|
ulong mMagic = NULL, // Magic Number
|
|
bool mFilterByMagic = true // Get Only Self Open Positions
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
// Magic Filter ...
|
|
IsMagicFilterPassed(
|
|
mMagic,
|
|
mFilterByMagic,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Symbol Filter ...
|
|
IsSymbolFilterPassed(
|
|
mSymbol,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Provider Filter ...
|
|
IsProviderFilterPassed(
|
|
mProvider,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Period Filter ...
|
|
IsPeriodFilterPassed(
|
|
mPeriod,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Type Filter ...
|
|
IsTypeFilterPassed(
|
|
mType,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// State Filter ...
|
|
IsStateFilterPassed(
|
|
mState,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model a Deal ...
|
|
struct XDeal
|
|
{
|
|
//
|
|
// the ID of the Expert Advisor, that executed the deal ...
|
|
ulong magic;
|
|
|
|
//
|
|
// the ID of position, in which the deal was involved ...
|
|
ulong positionId;
|
|
|
|
//
|
|
// Ticket ...
|
|
ulong ticket;
|
|
|
|
//
|
|
// the name of the deal symbol ...
|
|
string symbol;
|
|
|
|
//
|
|
// order by which the deal is executed ...
|
|
ulong order;
|
|
|
|
//
|
|
// the time of deal execution ...
|
|
datetime time;
|
|
|
|
//
|
|
// Deal price ...
|
|
double price;
|
|
|
|
//
|
|
// the financial result of the deal (in deposit currency) ...
|
|
double profit;
|
|
|
|
//
|
|
// the amount of swap when position is closed ...
|
|
double swap;
|
|
|
|
//
|
|
// the amount of commission of the deal ...
|
|
double commission;
|
|
|
|
//
|
|
// the volume of deal ...
|
|
double volume;
|
|
|
|
//
|
|
// the deal comment ...
|
|
string comment;
|
|
|
|
//
|
|
string provider;
|
|
|
|
//
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
// the deal type ...
|
|
// ------------------------------------------------------------------
|
|
// DEAL_TYPE_BUY => Buy ...
|
|
// DEAL_TYPE_SELL => Sell ...
|
|
// DEAL_TYPE_BUY_CANCELED => Canceled buy deal ...
|
|
// There can be a situation when a previously executed buy deal is canceled. In this case,
|
|
// the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED,
|
|
// and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ...
|
|
//
|
|
// DEAL_TYPE_SELL_CANCELED => Canceled sell deal ...
|
|
// There can be a situation when a previously executed sell deal is canceled. In this case,
|
|
// the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED,
|
|
// and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation
|
|
//
|
|
// DEAL_TYPE_BALANCE => Balance ...
|
|
// DEAL_TYPE_CREDIT => Credit ...
|
|
// DEAL_TYPE_CHARGE => Additional charge ...
|
|
// DEAL_TYPE_CORRECTION => Correction ...
|
|
// DEAL_TAX => Tax charges ...
|
|
// DEAL_TYPE_BONUS => Bonus ...
|
|
// DEAL_TYPE_INTEREST => Interest rate ...
|
|
// DEAL_DIVIDEND => Dividend operations...
|
|
// DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ...
|
|
// DEAL_TYPE_COMMISSION => Additional commission ...
|
|
// DEAL_TYPE_COMMISSION_DAILY => Daily commission ...
|
|
// DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ...
|
|
// DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ...
|
|
// DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission
|
|
ENUM_DEAL_TYPE type;
|
|
|
|
//
|
|
// the deal direction ...
|
|
// ----------------------------------
|
|
// DEAL_ENTRY_IN => Entry in ...
|
|
// DEAL_ENTRY_OUT => Entry out ...
|
|
// DEAL_ENTRY_INOUT => Reverse ...
|
|
// DEAL_ENTRY_OUT_BY => Close a position by an opposite one ...
|
|
ENUM_DEAL_ENTRY entry;
|
|
|
|
//
|
|
// deal reson ...
|
|
// ---------------------
|
|
// DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ...
|
|
// DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ...
|
|
// DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ...
|
|
// DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ...
|
|
// DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ...
|
|
// DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ...
|
|
// DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ...
|
|
// DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ...
|
|
// DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ...
|
|
// DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ...
|
|
ENUM_DEAL_REASON reason;
|
|
|
|
//
|
|
// Constructor ...
|
|
XDeal()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Initializers ...
|
|
bool ByIndex(
|
|
int index // Deal Index
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
int dealsCount = HistoryDealsTotal();
|
|
result = dealsCount > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
static CDealInfo mDealInfo;
|
|
|
|
//
|
|
result = mDealInfo.SelectByIndex(index);
|
|
if (!result)
|
|
{
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Reading Order Info ...
|
|
swap = mDealInfo.Swap();
|
|
magic = mDealInfo.Magic();
|
|
order = mDealInfo.Order();
|
|
ticket = mDealInfo.Ticket();
|
|
time = mDealInfo.Time();
|
|
price = mDealInfo.Price();
|
|
symbol = mDealInfo.Symbol();
|
|
profit = mDealInfo.Profit();
|
|
volume = mDealInfo.Volume();
|
|
comment = mDealInfo.Comment();
|
|
positionId = mDealInfo.PositionId();
|
|
entry = mDealInfo.Entry();
|
|
commission = mDealInfo.Commission();
|
|
type = mDealInfo.DealType();
|
|
reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(
|
|
ticket,
|
|
DEAL_REASON);
|
|
|
|
//
|
|
period = ExtractPeriod(comment);
|
|
provider = ExtractProvider(comment);
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
magic = 0;
|
|
positionId = 0;
|
|
ticket = 0;
|
|
order = 0;
|
|
time = 0;
|
|
price = 0;
|
|
profit = 0;
|
|
swap = 0;
|
|
commission = 0;
|
|
volume = 0;
|
|
|
|
//
|
|
symbol = NULL;
|
|
comment = NULL;
|
|
provider = NULL;
|
|
|
|
//
|
|
type = NULL;
|
|
entry = NULL;
|
|
period = NULL;
|
|
reason = NULL;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(symbol) &&
|
|
NotEmpty(ticket) &&
|
|
NotEmpty(positionId)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Age ...
|
|
int GetAge(
|
|
ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period
|
|
)
|
|
{
|
|
return GetAge(this, mPeriod);
|
|
}
|
|
|
|
//
|
|
// Check this instance is Same os Given instance or not ...
|
|
bool IsSameAs(
|
|
const XDeal &value // instance for Compare
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
type == value.type &&
|
|
magic == value.magic &&
|
|
entry == value.entry &&
|
|
reason == value.reason &&
|
|
ticket == value.ticket &&
|
|
volume == value.volume &&
|
|
symbol == value.symbol &&
|
|
provider == value.provider &&
|
|
positionId == value.positionId
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find index in a Collection ...
|
|
int FindIndex(
|
|
const XDeal &values[] // Collection to Find
|
|
)
|
|
{
|
|
//
|
|
return FindIndex(
|
|
this,
|
|
values
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Check Items Passed Specific Filters or not ...
|
|
bool IsFiltersPassed(
|
|
string mSymbol = NULL, // Trading Symbol
|
|
string mProvider = NULL, // Signal Provider
|
|
ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe
|
|
ENUM_DEAL_TYPE mType = NULL, // Deal Type
|
|
ENUM_DEAL_ENTRY mEntry = NULL, // Deal Entry
|
|
ENUM_DEAL_REASON mReason = NULL, // Deal Reason
|
|
ulong mMagic = NULL, // Magic Number
|
|
bool mFilterByMagic = true // Get Only Self Open Positions
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
// Magic Filter ...
|
|
IsMagicFilterPassed(
|
|
mMagic,
|
|
mFilterByMagic,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Symbol Filter ...
|
|
IsSymbolFilterPassed(
|
|
mSymbol,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Provider Filter ...
|
|
IsProviderFilterPassed(
|
|
mProvider,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Period Filter ...
|
|
IsPeriodFilterPassed(
|
|
mPeriod,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Type Filter ...
|
|
IsTypeFilterPassed(
|
|
mType,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Entry Filter ...
|
|
IsEntryFilterPassed(
|
|
mEntry,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
// Reason Filter ...
|
|
IsReasonFilterPassed(
|
|
mReason,
|
|
this
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model OnTrade Event Handler Result on XCTrade Class ...
|
|
struct XOnTradeHandlerState
|
|
{
|
|
//
|
|
bool hasNewDeal;
|
|
int newDeals;
|
|
|
|
//
|
|
bool hasNewOrder;
|
|
int newOrders;
|
|
|
|
//
|
|
bool hasNewPosition;
|
|
int newPositions;
|
|
|
|
//
|
|
bool hasNewHistoryOrder;
|
|
int newHistoryOrders;
|
|
|
|
//
|
|
// Constructor ...
|
|
XOnTradeHandlerState()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
hasNewDeal = false;
|
|
hasNewOrder = false;
|
|
hasNewPosition = false;
|
|
hasNewHistoryOrder = false;
|
|
|
|
//
|
|
newDeals = 0;
|
|
newOrders = 0;
|
|
newPositions = 0;
|
|
newHistoryOrders = 0;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
(
|
|
//
|
|
hasNewDeal
|
|
? newDeals > 0
|
|
: true
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
//
|
|
hasNewOrder
|
|
? newOrders > 0
|
|
: true
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
//
|
|
hasNewPosition
|
|
? newPositions > 0
|
|
: true
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
//
|
|
hasNewHistoryOrder
|
|
? newHistoryOrders > 0
|
|
: true
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model Guard Info ...
|
|
struct XGuard
|
|
{
|
|
//
|
|
string symbol; // Trading Symbol ...
|
|
string provider; // Signal Provider ...
|
|
ENUM_TIMEFRAMES period; // Trading Timeframe ...
|
|
ENUM_X_POSITION_TYPES type; // Position Type ...
|
|
ENUM_X_GUARD_ACTIONS action; // Which Action to Do ...
|
|
|
|
//
|
|
double dblPayLoad;
|
|
string strPayload;
|
|
|
|
//
|
|
// Constructor ...
|
|
XGuard()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Initialize ...
|
|
|
|
//
|
|
// Global Initializer ...
|
|
bool Init(
|
|
string mSymbol, // Trading Symbol ...
|
|
ENUM_TIMEFRAMES mPeriod, // Trading Timeframe ...
|
|
ENUM_X_GUARD_ACTIONS mAction, // Which Action to Do ...
|
|
ENUM_X_POSITION_TYPES mType = NULL, // Position Type ...
|
|
string mProvider = NULL, // Signal Provider ...
|
|
double mDblPayLoad = NULL,
|
|
string mStrPayload = NULL //
|
|
)
|
|
{
|
|
//
|
|
type = mType;
|
|
symbol = mSymbol;
|
|
period = mPeriod;
|
|
action = mAction;
|
|
provider = mProvider;
|
|
dblPayLoad = mDblPayLoad;
|
|
strPayload = mStrPayload;
|
|
|
|
//
|
|
bool result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
symbol = NULL;
|
|
provider = NULL;
|
|
period = NULL;
|
|
action = X_GUARD_ACTION_NOTHING;
|
|
|
|
//
|
|
strPayload = NULL;
|
|
dblPayLoad = EMPTY_VALUE;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
action != X_GUARD_ACTION_NOTHING
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Model a Position with all of it's Supports ...
|
|
struct XPositionPack
|
|
{
|
|
//
|
|
ulong ticket; // Main Position's Ticket
|
|
|
|
//
|
|
XPosition position; // Main Position (if Exists)
|
|
|
|
//
|
|
int supportOrdersCount; // Supported Orders (Untriggered)
|
|
int supportPositionsCount; // Supported Positions
|
|
|
|
//
|
|
XOrder supportOrders[]; // Supported Orders (Untriggered)
|
|
XPosition supportPositions[]; // Supported Positions
|
|
|
|
//
|
|
// Constructor ...
|
|
XPositionPack()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
ticket = 0;
|
|
|
|
//
|
|
position.Clean();
|
|
|
|
//
|
|
supportOrdersCount = 0;
|
|
supportPositionsCount = 0;
|
|
|
|
//
|
|
Clean(supportOrders);
|
|
Clean(supportPositions);
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
NotEmpty(ticket) &&
|
|
(
|
|
//
|
|
supportOrdersCount > 0
|
|
? ArraySize(supportOrders) == supportOrdersCount
|
|
: true
|
|
//
|
|
)
|
|
//
|
|
&&
|
|
//
|
|
(
|
|
//
|
|
supportPositionsCount > 0
|
|
? ArraySize(supportPositions) == supportPositionsCount
|
|
: true
|
|
//
|
|
)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
// Check Position SL Trails Structure ...
|
|
struct XTrail
|
|
{
|
|
//
|
|
ulong ticket; // Position Ticket ...
|
|
ENUM_POSITION_TYPE type; // Type ...
|
|
datetime time; // Trail Time ...
|
|
double before; // SL Value Before Trailing ...
|
|
double after; // SL Value After Trailing ...
|
|
int level; // Number of Trails SL ...
|
|
double profit; // Profit in SL Time ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XTrail()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
bool Init(
|
|
ulong mTicket, // Ticket
|
|
ENUM_POSITION_TYPE mType, // Type
|
|
double mProfit, // Profit
|
|
double mBefore, // Before
|
|
double mAfter // After
|
|
)
|
|
{
|
|
//
|
|
Clean();
|
|
|
|
//
|
|
type = mType;
|
|
after = mAfter;
|
|
ticket = mTicket;
|
|
before = mBefore;
|
|
profit = mProfit;
|
|
|
|
//
|
|
level++;
|
|
|
|
//
|
|
time = TimeCurrent();
|
|
|
|
//
|
|
return IsValid();
|
|
}
|
|
|
|
//
|
|
bool Update(
|
|
double mSl, // new SL ...
|
|
double mProfit // Profit
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
time = TimeCurrent();
|
|
|
|
//
|
|
double cAfter = after;
|
|
after = mSl;
|
|
before = cAfter;
|
|
profit = mProfit;
|
|
|
|
//
|
|
level++;
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string GenerateTag()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
string ticketLevelStr = ToString(ticket) + "," + ToString(level);
|
|
|
|
//
|
|
result = Surround(
|
|
XSLTrailToken,
|
|
ticketLevelStr //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
ticket = 0;
|
|
time = 0;
|
|
before = 0;
|
|
after = 0;
|
|
level = 0;
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
ticket > 0 &&
|
|
time > 0 &&
|
|
level > 0
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
//
|
|
struct XSymbolPositions
|
|
{
|
|
//
|
|
string symbol;
|
|
|
|
//
|
|
double profit;
|
|
double volume;
|
|
|
|
//
|
|
double longsProfit;
|
|
double longSupportsProfit;
|
|
|
|
//
|
|
double shortsProfit;
|
|
double shortSupportsProfit;
|
|
|
|
//
|
|
double longsVolume;
|
|
double longSupportsVolume;
|
|
|
|
//
|
|
double shortsVolume;
|
|
double shortSupportsVolume;
|
|
|
|
//
|
|
double requiredProfitForHedge;
|
|
|
|
//
|
|
XPosition longs[];
|
|
XPosition shorts[];
|
|
XPosition supports[];
|
|
XPosition positions[];
|
|
XPosition longSupports[];
|
|
XPosition shortSupports[];
|
|
|
|
//
|
|
bool forceHedge;
|
|
|
|
//
|
|
XSymbolPositions()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
bool Update(
|
|
double mMinProfitPerTrade,
|
|
double mMinProfitPerVolumeFactor //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool hasChild = HasChild();
|
|
if (!hasChild)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XPosition _supports[];
|
|
XPosition _positions[];
|
|
|
|
//
|
|
XPosition _tmp[];
|
|
|
|
//
|
|
Copy(
|
|
positions,
|
|
_tmp //
|
|
);
|
|
|
|
//
|
|
Clean(positions);
|
|
|
|
//
|
|
int tmpsCount = ArraySize(_tmp);
|
|
for (int i = 0; i < tmpsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = _tmp[i];
|
|
|
|
//
|
|
bool isSupport = IsSupport(iPosition.comment);
|
|
if (!isSupport)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
_positions //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
_supports //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
Clean(_tmp);
|
|
|
|
//
|
|
Copy(
|
|
_positions,
|
|
positions //
|
|
);
|
|
Clean(_positions);
|
|
|
|
//
|
|
// Extract Types ...
|
|
ExtractPositions(
|
|
positions,
|
|
longs,
|
|
shorts //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
_supports,
|
|
supports //
|
|
);
|
|
Clean(_supports);
|
|
|
|
//
|
|
// Extract Types ...
|
|
ExtractPositions(
|
|
supports,
|
|
longSupports,
|
|
shortSupports //
|
|
);
|
|
|
|
//
|
|
int numOfLongs = 0;
|
|
int numOfShorts = 0;
|
|
CountPositions(
|
|
positions,
|
|
numOfLongs,
|
|
longsProfit,
|
|
longsVolume,
|
|
numOfShorts,
|
|
shortsProfit,
|
|
shortsVolume //
|
|
);
|
|
|
|
//
|
|
numOfLongs = 0;
|
|
numOfShorts = 0;
|
|
CountPositions(
|
|
supports,
|
|
numOfLongs,
|
|
longSupportsProfit,
|
|
longSupportsVolume,
|
|
numOfShorts,
|
|
shortSupportsProfit,
|
|
shortSupportsVolume //
|
|
);
|
|
|
|
//
|
|
XPosition _allPositions[];
|
|
Copy(
|
|
positions,
|
|
_allPositions,
|
|
false //
|
|
);
|
|
Copy(
|
|
supports,
|
|
_allPositions,
|
|
false //
|
|
);
|
|
|
|
//
|
|
profit = longsProfit + shortsProfit + longSupportsProfit + shortSupportsProfit;
|
|
volume = longsVolume + shortsVolume + longSupportsVolume + shortSupportsVolume;
|
|
requiredProfitForHedge = SpecifiedCalculateRequiredProfitForHedge(
|
|
_allPositions,
|
|
mMinProfitPerTrade,
|
|
mMinProfitPerVolumeFactor //
|
|
);
|
|
|
|
//
|
|
Clean(_allPositions);
|
|
|
|
//
|
|
result = true;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Cleanup ...
|
|
void Clean()
|
|
{
|
|
//
|
|
symbol = NULL;
|
|
forceHedge = false;
|
|
|
|
//
|
|
profit = 0;
|
|
longsProfit = 0;
|
|
shortsProfit = 0;
|
|
|
|
//
|
|
volume = 0;
|
|
longsVolume = 0;
|
|
shortsVolume = 0;
|
|
|
|
//
|
|
requiredProfitForHedge = 0;
|
|
|
|
//
|
|
Clean(longs);
|
|
Clean(shorts);
|
|
Clean(positions);
|
|
}
|
|
|
|
//
|
|
// Validate ...
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid(symbol);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Has Child ...
|
|
bool HasChild()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = Count();
|
|
result = IsValidSize(count);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Count ...
|
|
int Count()
|
|
{
|
|
return ArraySize(positions);
|
|
}
|
|
|
|
//
|
|
int CountSupports()
|
|
{
|
|
return ArraySize(supports);
|
|
}
|
|
|
|
//
|
|
int CountLongs()
|
|
{
|
|
return ArraySize(longs);
|
|
}
|
|
|
|
//
|
|
int CountShorts()
|
|
{
|
|
return ArraySize(shorts);
|
|
}
|
|
|
|
//
|
|
int CountLongSupports()
|
|
{
|
|
return ArraySize(longSupports);
|
|
}
|
|
|
|
//
|
|
int CountShortSupports()
|
|
{
|
|
return ArraySize(shortSupports);
|
|
}
|
|
|
|
//
|
|
int GetOldest(
|
|
XPosition &_oldest, //
|
|
ENUM_POSITION_TYPE _type //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
bool isLong = IsLong(_type);
|
|
|
|
//
|
|
int count =
|
|
isLong
|
|
? CountLongs()
|
|
: CountShorts();
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
//
|
|
result = GetOldest(
|
|
_oldest,
|
|
longs //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
result = GetOldest(
|
|
_oldest,
|
|
shorts //
|
|
);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetYoungest(
|
|
XPosition &_youngest, //
|
|
ENUM_POSITION_TYPE _type //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
bool isLong = IsLong(_type);
|
|
|
|
//
|
|
int count =
|
|
isLong
|
|
? CountLongs()
|
|
: CountShorts();
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
//
|
|
result = GetYoungest(
|
|
_youngest,
|
|
longs //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
result = GetYoungest(
|
|
_youngest,
|
|
shorts //
|
|
);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetMaxInProfit(
|
|
XPosition &_position,
|
|
ENUM_POSITION_TYPE _type //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
bool isLong = IsLong(_type);
|
|
|
|
//
|
|
int count =
|
|
isLong
|
|
? CountLongs()
|
|
: CountShorts();
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
//
|
|
result = FindMaxProfitIndex(
|
|
longs //
|
|
);
|
|
|
|
//
|
|
if (IsValidIndex(result))
|
|
{
|
|
_position = longs[result];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
result = FindMaxProfitIndex(
|
|
shorts //
|
|
);
|
|
|
|
//
|
|
if (IsValidIndex(result))
|
|
{
|
|
_position = shorts[result];
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetMinInProfit(
|
|
XPosition &_position,
|
|
ENUM_POSITION_TYPE _type //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
bool isLong = IsLong(_type);
|
|
|
|
//
|
|
int count =
|
|
isLong
|
|
? CountLongs()
|
|
: CountShorts();
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
//
|
|
result = FindMinProfitIndex(
|
|
longs //
|
|
);
|
|
|
|
//
|
|
if (IsValidIndex(result))
|
|
{
|
|
_position = longs[result];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
result = FindMinProfitIndex(
|
|
shorts //
|
|
);
|
|
|
|
//
|
|
if (IsValidIndex(result))
|
|
{
|
|
_position = shorts[result];
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetMaxInDrawdown(
|
|
XPosition &_position,
|
|
ENUM_POSITION_TYPE _type //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
bool isLong = IsLong(_type);
|
|
|
|
//
|
|
int count =
|
|
isLong
|
|
? CountLongs()
|
|
: CountShorts();
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
//
|
|
result = FindMaxInDrawdownIndex(
|
|
longs //
|
|
);
|
|
|
|
//
|
|
if (IsValidIndex(result))
|
|
{
|
|
_position = longs[result];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
result = FindMaxInDrawdownIndex(
|
|
shorts //
|
|
);
|
|
|
|
//
|
|
if (IsValidIndex(result))
|
|
{
|
|
_position = shorts[result];
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int GetMinInDrawdown(
|
|
XPosition &_position,
|
|
ENUM_POSITION_TYPE _type //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
bool isLong = IsLong(_type);
|
|
|
|
//
|
|
int count =
|
|
isLong
|
|
? CountLongs()
|
|
: CountShorts();
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (isLong)
|
|
{
|
|
//
|
|
result = FindMinInDrawdownIndex(
|
|
longs //
|
|
);
|
|
|
|
//
|
|
if (IsValidIndex(result))
|
|
{
|
|
_position = longs[result];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
result = FindMinInDrawdownIndex(
|
|
shorts //
|
|
);
|
|
|
|
//
|
|
if (IsValidIndex(result))
|
|
{
|
|
_position = shorts[result];
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// an Structure for Holding Positions Data ...
|
|
struct XTradeData
|
|
{
|
|
//
|
|
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();
|
|
|
|
//
|
|
ResetTrail();
|
|
ResetRecovery();
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// There are some Controlling Situations for each Trade
|
|
// which implemented here ...
|
|
|
|
//
|
|
// Trailing Stop ....
|
|
|
|
//
|
|
bool allowTrailStop; // Specified Position Can Trail Stop or not
|
|
bool ignoreTPOnTrail; // Ignore TP when SL Trailed
|
|
bool trailBasedOnProfit; // Do Trail Based on Profit Points
|
|
int trailLevel; // Last Trail Level
|
|
double trailStartInPoint; // Trail Starts When Profits Growing in Point
|
|
double trailStepInPoint; // Profit Must Grows Point to do Trailling
|
|
|
|
//
|
|
// Reset all Trailing Configurations ....
|
|
void ResetTrail()
|
|
{
|
|
//
|
|
trailLevel = 0;
|
|
trailStepInPoint = 0;
|
|
trailStartInPoint = 0;
|
|
allowTrailStop = false;
|
|
ignoreTPOnTrail = false;
|
|
trailBasedOnProfit = false;
|
|
}
|
|
|
|
//
|
|
// Recovery ...
|
|
|
|
//
|
|
bool allowRecover; // Allow Recover Specified Position
|
|
double recoveryTPPoint; // Recovery TP Point
|
|
double recoverySLPoint; // Recovery SL Point
|
|
int maxAllowedRecover; // Max Allowed Recovery
|
|
int recoveryLevel; // Number of Recovery Signals
|
|
double recoveryVolumeMultiplier; // Recovery Volume Multiplier
|
|
double recoveryVolume; // Next Recovery Positioin Volume
|
|
ENUM_X_POSITION_TYPES recoveryLookingType; // Looking for Next Recovery Type
|
|
|
|
//
|
|
void ResetRecovery()
|
|
{
|
|
//
|
|
allowRecover = false;
|
|
recoveryLevel = 0;
|
|
recoveryVolume = 0;
|
|
recoveryTPPoint = 0;
|
|
recoverySLPoint = 0;
|
|
recoveryVolumeMultiplier = 0;
|
|
recoveryLookingType = X_POSITION_TYPE_NONE;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// TypeDefs ...
|
|
|
|
//
|
|
typedef void (*TOnSignal)(XSignal &signal);
|
|
|
|
//
|
|
typedef void (*TOnDealsChanged)(int count);
|
|
|
|
//
|
|
typedef void (*TOnOrdersChanged)(int count);
|
|
|
|
//
|
|
typedef void (*TOnPositionsChanged)(int count);
|
|
|
|
//
|
|
typedef void (*TOnStopLoss)(const XDeal &deal);
|
|
typedef void (*TOnTakeProfit)(const XDeal &deal);
|
|
|
|
//
|
|
typedef void (*TOnTradeStateChanged)(const XOnTradeHandlerState &state);
|
|
|
|
//
|
|
typedef void (*TOnForceClose)(
|
|
const ulong ticket,
|
|
const XPosition &position,
|
|
const string comment //
|
|
);
|
|
|
|
//
|
|
typedef void (*TOnPartialClose)(
|
|
const ulong ticket,
|
|
const double profit,
|
|
const string comment //
|
|
);
|
|
|
|
//
|
|
typedef void (*TOnModify)(
|
|
const ulong ticket,
|
|
const double profit,
|
|
const string comment //
|
|
);
|
|
|
|
//
|
|
// Classes ...
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
bool IsValid(ENUM_X_ORDER_MODES value)
|
|
{
|
|
return value != X_ORDER_MODE_NOTHING;
|
|
}
|
|
|
|
//
|
|
// Ages ...
|
|
|
|
//
|
|
// Retrieve a Position Age ...
|
|
int GetAge(
|
|
XSignal &signal, // Selected Signal ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (period == NULL)
|
|
{
|
|
period = _Period;
|
|
}
|
|
|
|
//
|
|
result = iBarShift(
|
|
signal.symbol,
|
|
period,
|
|
signal.time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve a Position Age ...
|
|
int GetAge(
|
|
XPosition &position, // Selected Position ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (period == NULL)
|
|
{
|
|
period = _Period;
|
|
}
|
|
|
|
//
|
|
result = iBarShift(
|
|
position.symbol,
|
|
period,
|
|
position.openAt);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve an Order Age ...
|
|
int GetAge(
|
|
XOrder &order, // Selected Order ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (period == NULL)
|
|
{
|
|
period = _Period;
|
|
}
|
|
|
|
//
|
|
result = iBarShift(
|
|
order.symbol,
|
|
period,
|
|
order.setupAt);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve a Deal Age ...
|
|
int GetAge(
|
|
XDeal &deal, // Selected Deal ...
|
|
ENUM_TIMEFRAMES period = NULL // Dest Time Frame ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (period == NULL)
|
|
{
|
|
period = _Period;
|
|
}
|
|
|
|
//
|
|
result = iBarShift(
|
|
deal.symbol,
|
|
period,
|
|
deal.time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Oldest Deal ...
|
|
int GetOldest(
|
|
XDeal &item, // Hold Result ...
|
|
XDeal &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XDeal tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XDeal iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge < iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Youngest Deal ...
|
|
int GetYoungest(
|
|
XDeal &item, // Hold Result ...
|
|
XDeal &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XDeal tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XDeal iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge > iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Oldest Order ...
|
|
int GetOldest(
|
|
XOrder &item, // Hold Result ...
|
|
XOrder &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XOrder tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XOrder iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge < iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Youngest Order ...
|
|
int GetYoungest(
|
|
XOrder &item, // Hold Result ...
|
|
XOrder &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XOrder tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XOrder iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge > iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Oldes Position ...
|
|
int GetOldest(
|
|
XPosition &item, // Hold Result ...
|
|
XPosition &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XPosition tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XPosition iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge < iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Get Youngest Position ...
|
|
int GetYoungest(
|
|
XPosition &item, // Hold Result ...
|
|
XPosition &items[] // Source Array ...
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int tmpAge = 0;
|
|
XPosition tmpItem;
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
XPosition iItem = items[i];
|
|
|
|
//
|
|
int iAge = GetAge(iItem);
|
|
if (iAge > 0 &&
|
|
(tmpAge == 0 || tmpAge > iAge))
|
|
{
|
|
//
|
|
tmpAge = iAge;
|
|
tmpItem = iItem;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (tmpAge > 0)
|
|
{
|
|
//
|
|
result = tmpAge;
|
|
item = tmpItem;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int FindMaxProfitIndex(
|
|
XPosition &positions[] // Position Collection
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double max = 0;
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
if (iPosition.profit <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
if (max == 0 ||
|
|
max < iPosition.profit)
|
|
{
|
|
//
|
|
result = i;
|
|
max = iPosition.profit;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int FindMinProfitIndex(
|
|
XPosition &positions[] // Position Collection
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double min = 0;
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
if (iPosition.profit <= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
if (min == 0 ||
|
|
min > iPosition.profit)
|
|
{
|
|
//
|
|
result = i;
|
|
min = iPosition.profit;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int ExtractInProfitPositions(
|
|
XPosition &positions[], // Position Collection
|
|
XPosition &inProfits[] // Result
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(inProfits);
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (iPosition.profit > 0)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
inProfits //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(inProfits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int FindMaxInDrawdownIndex(
|
|
XPosition &positions[] // Position Collection
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double max = 0;
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
if (iPosition.profit >= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
if (max == 0 ||
|
|
MathAbs(max) < MathAbs(iPosition.profit))
|
|
{
|
|
//
|
|
result = i;
|
|
max = iPosition.profit;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int FindMinInDrawdownIndex(
|
|
XPosition &positions[] // Position Collection
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double min = 0;
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
if (iPosition.profit >= 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
if (min == 0 ||
|
|
min > iPosition.profit)
|
|
{
|
|
//
|
|
result = i;
|
|
min = iPosition.profit;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int ExtractInDrawdownPositions(
|
|
XPosition &positions[], // Position Collection
|
|
XPosition &inDradowns[] // Result
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(inDradowns);
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (iPosition.profit < 0)
|
|
{
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
inDradowns //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(inDradowns);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Check Filters ...
|
|
|
|
//
|
|
// Magic Filter ...
|
|
template <typename T>
|
|
bool IsMagicFilterPassed(
|
|
ulong magic,
|
|
bool filterByMagic,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return !filterByMagic
|
|
? true
|
|
: !NotEmpty(magic)
|
|
? false
|
|
: magic == item.magic;
|
|
}
|
|
|
|
//
|
|
// Symbol Filter ...
|
|
template <typename T>
|
|
bool IsSymbolFilterPassed(
|
|
string symbol,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return !IsValid(symbol)
|
|
? true
|
|
: symbol == item.symbol;
|
|
}
|
|
|
|
//
|
|
// Provider Filter ...
|
|
template <typename T>
|
|
bool IsProviderFilterPassed(
|
|
string provider,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return !IsValid(provider)
|
|
? true
|
|
: provider == item.provider;
|
|
}
|
|
|
|
//
|
|
// Period Filter ...
|
|
template <typename T>
|
|
bool IsPeriodFilterPassed(
|
|
ENUM_TIMEFRAMES period,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return !IsValid(period)
|
|
? true
|
|
: period == item.period;
|
|
}
|
|
|
|
//
|
|
// Type Filter ...
|
|
template <typename T>
|
|
bool IsTypeFilterPassed(
|
|
ENUM_POSITION_TYPE type,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
bool result = type == item.type;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
template <typename T>
|
|
bool IsTypeFilterPassed(
|
|
ENUM_X_POSITION_TYPES type,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
bool result = type == NULL || type == X_POSITION_TYPE_ALL
|
|
? true
|
|
: ((type == X_POSITION_TYPE_LONG && ((int)item.type == (int)POSITION_TYPE_BUY || (int)item.type == (int)ORDER_TYPE_BUY)) ||
|
|
(type == X_POSITION_TYPE_SHORT && ((int)item.type == (int)POSITION_TYPE_SELL || (int)item.type == (int)ORDER_TYPE_SELL)));
|
|
|
|
//
|
|
return result;
|
|
}
|
|
template <typename T>
|
|
bool IsTypeFilterPassed(
|
|
ENUM_ORDER_TYPE type,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return type == NULL
|
|
? true
|
|
: type == item.type;
|
|
}
|
|
template <typename T>
|
|
bool IsTypeFilterPassed(
|
|
ENUM_DEAL_TYPE type,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return type == NULL
|
|
? true
|
|
: type == item.type;
|
|
}
|
|
|
|
//
|
|
// Mode Filter ...
|
|
template <typename T>
|
|
bool IsModeFilterPassed(
|
|
ENUM_X_ORDER_MODES mode,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return mode == NULL
|
|
? true
|
|
: mode == item.mode;
|
|
}
|
|
|
|
//
|
|
// Entry Filter ...
|
|
template <typename T>
|
|
bool IsEntryFilterPassed(
|
|
ENUM_DEAL_ENTRY entry,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return entry == NULL
|
|
? true
|
|
: entry == item.entry;
|
|
}
|
|
|
|
//
|
|
// Reason Filter ...
|
|
template <typename T>
|
|
bool IsReasonFilterPassed(
|
|
ENUM_DEAL_REASON reason,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return reason == NULL
|
|
? true
|
|
: reason == item.reason;
|
|
}
|
|
|
|
//
|
|
// State Filter ...
|
|
template <typename T>
|
|
bool IsStateFilterPassed(
|
|
ENUM_ORDER_STATE state,
|
|
T &item
|
|
//
|
|
)
|
|
{
|
|
//
|
|
return state == NULL
|
|
? true
|
|
: state == item.state;
|
|
}
|
|
|
|
//
|
|
|
|
//
|
|
// Find Specific Item Index inside a Collection ...
|
|
template <typename T>
|
|
int FindIndex(
|
|
T &item, // Item to Find
|
|
const T &items[] // Items for Search
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
// Check Item Validation ...
|
|
if (!item.IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int itemsCount = ArraySize(items);
|
|
if (itemsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < itemsCount; i++)
|
|
{
|
|
//
|
|
T iItem = items[i];
|
|
|
|
//
|
|
// Validate Item ...
|
|
if (!iItem.IsValid())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isSame = item.IsSameAs(iItem);
|
|
if (isSame && result <= -1)
|
|
{
|
|
//
|
|
result = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//
|
|
// Calculate Positions Profit Summary ...
|
|
double SpecifiedCalculatePositionsProfit(
|
|
XPosition &positions[] // Source
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (positionsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
result += iPosition.profit;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Required Profit for Hedging ...
|
|
double SpecifiedCalculateRequiredProfitForHedge(
|
|
XPosition &positions[], // Source
|
|
double mMinProfitPerTrade,
|
|
double mMinProfitPerVolumeFactor //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (positionsCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isHedgingEnable = mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0;
|
|
if (!isHedgingEnable)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0)
|
|
{
|
|
//
|
|
result +=
|
|
((iPosition.volume / mMinProfitPerVolumeFactor) *
|
|
mMinProfitPerTrade) +
|
|
(-1 * iPosition.swap);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool SpecifiedIsPositionsReadyForHedge(
|
|
XPosition &positions[], // Source
|
|
double mMinProfitPerTrade,
|
|
double mMinProfitPerVolumeFactor //
|
|
)
|
|
{
|
|
//
|
|
double profit = SpecifiedCalculatePositionsProfit(positions);
|
|
double requiredProfit = SpecifiedCalculateRequiredProfitForHedge(
|
|
positions,
|
|
mMinProfitPerTrade,
|
|
mMinProfitPerVolumeFactor //
|
|
);
|
|
|
|
//
|
|
bool result = requiredProfit > 0
|
|
? profit >= requiredProfit
|
|
: profit > requiredProfit;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int FindCoverageDrawdownPosition(
|
|
XPosition &position, // In Drawdown Position
|
|
XPosition &inProfits[], // In Profit Positions
|
|
XPosition &coverage[], // Coverage Positons
|
|
double mMinProfitPerTrade,
|
|
double mMinProfitPerVolumeFactor //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(coverage);
|
|
|
|
//
|
|
if (!position.IsValid() || position.profit >= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int inProfitsCount = ArraySize(inProfits);
|
|
if (!IsValidSize(inProfitsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Copy in Profits to TMP ...
|
|
XPosition tmp[];
|
|
Copy(
|
|
inProfits,
|
|
tmp //
|
|
);
|
|
|
|
//
|
|
bool isCoverPassed = false;
|
|
while (!isCoverPassed || ArraySize(tmp) > 0)
|
|
{
|
|
//
|
|
XPosition max;
|
|
int idx = FindMaxProfitIndex(tmp);
|
|
if (idx >= 0)
|
|
{
|
|
//
|
|
if (tmp[idx].profit > 0)
|
|
{
|
|
AddRef(
|
|
tmp[idx],
|
|
coverage //
|
|
);
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmp,
|
|
idx,
|
|
1 //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check Cover Passed ...
|
|
XPosition tmpPositions[];
|
|
Copy(
|
|
coverage,
|
|
tmpPositions //
|
|
);
|
|
AddRef(
|
|
position,
|
|
tmpPositions //
|
|
);
|
|
|
|
//
|
|
double profits = SpecifiedCalculatePositionsProfit(tmpPositions);
|
|
double requiredProfit = SpecifiedCalculateRequiredProfitForHedge(
|
|
tmpPositions,
|
|
mMinProfitPerTrade,
|
|
mMinProfitPerVolumeFactor //
|
|
);
|
|
isCoverPassed = profits >= requiredProfit;
|
|
if (isCoverPassed)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
if (!isCoverPassed && ArraySize(tmp) == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(coverage);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract a Collection of Positions SL ...
|
|
int ExtractSLs(
|
|
XPosition &positions[],
|
|
double &sls[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(sls);
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (iPosition.sl > 0)
|
|
{
|
|
//
|
|
Add(
|
|
iPosition.sl,
|
|
sls //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(sls);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract a Colletion of Positions TP ...
|
|
int ExtractTPs(
|
|
XPosition &positions[],
|
|
double &tps[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(tps);
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (iPosition.tp > 0)
|
|
{
|
|
//
|
|
Add(
|
|
iPosition.tp,
|
|
tps //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(tps);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Retrieve String Representation ...
|
|
string ToString(ENUM_X_SIGNAL_EXECUTION_RESULT value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case X_SIGNAL_EXECUTION_UNKNOWN:
|
|
result = "Unknown";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_SUCCEED:
|
|
result = "Succed";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_SPREAD:
|
|
result = "Spread more than Max Allowed";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_NO_EQUITY:
|
|
result = "No Equity for Trade";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR:
|
|
result = "Price Error";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_MAX_REACHED:
|
|
result = "Max Allowed Positions Reached";
|
|
break;
|
|
|
|
//
|
|
case X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS:
|
|
result = "Invalid Params";
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Converts Position Type to Order Type ...
|
|
ENUM_ORDER_TYPE ToOrderType(ENUM_POSITION_TYPE value)
|
|
{
|
|
//
|
|
bool isLong = IsLong(value);
|
|
|
|
//
|
|
ENUM_ORDER_TYPE result =
|
|
isLong
|
|
? ORDER_TYPE_BUY
|
|
: ORDER_TYPE_SELL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
ENUM_ORDER_TYPE ToOrderType(ENUM_X_POSITION_TYPES value)
|
|
{
|
|
//
|
|
ENUM_POSITION_TYPE mType =
|
|
value == X_POSITION_TYPE_SHORT
|
|
? POSITION_TYPE_SELL
|
|
: POSITION_TYPE_BUY;
|
|
|
|
//
|
|
bool isLong = IsLong(mType);
|
|
|
|
//
|
|
ENUM_ORDER_TYPE result =
|
|
isLong
|
|
? ORDER_TYPE_BUY
|
|
: ORDER_TYPE_SELL;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tagging ...
|
|
|
|
//
|
|
// Generate Specified Tag for Using in Comments ...
|
|
string GeneratePeriodTag(ENUM_TIMEFRAMES period)
|
|
{
|
|
//
|
|
string strPeriod = ToString(period);
|
|
return Surround(
|
|
XPeriodToken,
|
|
strPeriod
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract Period from a Tagged string ...
|
|
ENUM_TIMEFRAMES ExtractPeriod(string value)
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
string pStr = ParseStringSurrounded(
|
|
value,
|
|
XPeriodToken
|
|
//
|
|
);
|
|
if (!IsValid(pStr))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ToPeriod(pStr);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
// Generate Specified Tag for Using in Comments ...
|
|
string GenerateProviderTag(string provider)
|
|
{
|
|
//
|
|
return Surround(
|
|
XProviderToken,
|
|
provider
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract Provider from a Tagged string ...
|
|
string ExtractProvider(string value)
|
|
{
|
|
//
|
|
return ParseStringSurrounded(
|
|
value,
|
|
XProviderToken
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Generate Support Comment Tag ...
|
|
string GenerateSupportTag(ulong ticket)
|
|
{
|
|
//
|
|
return Surround(
|
|
XSupportToken,
|
|
ticket
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract Support Positions from a Tagged string ...
|
|
ulong ExtractSupportedTicket(string value)
|
|
{
|
|
//
|
|
return ParseLongSurrounded(
|
|
value,
|
|
XSupportToken
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract Support ...
|
|
template <typename T>
|
|
int ExtractSupports(
|
|
T &source[],
|
|
T &dest[] // Result ...
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(dest);
|
|
|
|
//
|
|
int sourceCount = ArraySize(source);
|
|
if (!IsValidSize(sourceCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
T iSource = source[i];
|
|
|
|
//
|
|
ulong isSupport = ExtractSupportedTicket(iSource.comment) > 0;
|
|
ulong iEQMSupport = ExtractEQMSupportedTicket(iSource.comment) > 0;
|
|
if (isSupport || iEQMSupport)
|
|
{
|
|
//
|
|
AddRef(
|
|
iSource,
|
|
dest //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(dest);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Generate EQM Support Comment Tag ...
|
|
string GenerateEQMSupportTag(ulong ticket)
|
|
{
|
|
//
|
|
return Surround(
|
|
XEQMSupportToken,
|
|
ticket
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract EQM Support Positions from a Tagged string ...
|
|
ulong ExtractEQMSupportedTicket(string value)
|
|
{
|
|
//
|
|
return ParseLongSurrounded(
|
|
value,
|
|
XEQMSupportToken
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
bool IsSupport(string value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool isSupport = ExtractSupportedTicket(value) > 0;
|
|
bool isEQMSupport = ExtractEQMSupportedTicket(value) > 0;
|
|
|
|
//
|
|
result =
|
|
//
|
|
isSupport
|
|
//
|
|
||
|
|
//
|
|
isEQMSupport
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ulong ExtractParentTicket(string value)
|
|
{
|
|
//
|
|
ulong result = 0;
|
|
|
|
//
|
|
if (!IsSupport(value))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ExtractSupportedTicket(value);
|
|
if (result > 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ExtractEQMSupportedTicket(value);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// XRecovery ...
|
|
|
|
//
|
|
string GenerateRecoveryTag(ulong ticket)
|
|
{
|
|
//
|
|
return Surround(
|
|
XRecoveryToken,
|
|
ticket //
|
|
);
|
|
}
|
|
|
|
//
|
|
ulong ExtractRecoveredTicket(string value)
|
|
{
|
|
//
|
|
return ParseLongSurrounded(
|
|
value,
|
|
XRecoveryToken //
|
|
);
|
|
}
|
|
|
|
//
|
|
// Extract Recoveries ...
|
|
template <typename T>
|
|
int ExtractRecoveries(
|
|
T &source[],
|
|
T &dest[] // Result ...
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(dest);
|
|
|
|
//
|
|
int sourceCount = ArraySize(source);
|
|
if (!IsValidSize(sourceCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
T iSource = source[i];
|
|
|
|
//
|
|
ulong isRecovery = ExtractRecoveredTicket(iSource.comment) > 0;
|
|
if (isRecovery)
|
|
{
|
|
//
|
|
AddRef(
|
|
iSource,
|
|
dest //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(dest);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Extract Specified Position's Recoveries ...
|
|
int ExtractRecoveries(
|
|
ulong ticket,
|
|
XPosition &source[],
|
|
XPosition &dest[] // Result ...
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(dest);
|
|
|
|
//
|
|
int sourceCount = ArraySize(source);
|
|
if (!IsValidSize(sourceCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < sourceCount; i++)
|
|
{
|
|
//
|
|
XPosition iSource = source[i];
|
|
|
|
//
|
|
ulong parentTicket = ExtractRecoveredTicket(iSource.comment);
|
|
bool isRecovery = parentTicket > 0;
|
|
if (isRecovery && parentTicket == ticket)
|
|
{
|
|
//
|
|
AddRef(
|
|
iSource,
|
|
dest //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ArraySize(dest);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// SL Trails ...
|
|
|
|
//
|
|
// Extract SL Trail Level ...
|
|
int ExtractSLTrailLevel(string comment)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid(comment))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ParseIntSurrounded(
|
|
comment,
|
|
XSLTrailToken
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Generate SL Trail Comment Tag ...
|
|
string GenerateSLTrailTag(int level)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (level <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = Surround(
|
|
XSLTrailToken,
|
|
level
|
|
//
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Prepare SL Trail Comment ...
|
|
string PrepareSLTrailTag(
|
|
const string comment // Original Position Comment ...
|
|
)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
int level = 0;
|
|
result = comment;
|
|
|
|
//
|
|
// Check Comment Contains SL Trailing or not ...
|
|
int lastTrailLevel = ExtractSLTrailLevel(comment);
|
|
if (lastTrailLevel <= 0)
|
|
{
|
|
level++;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
level = lastTrailLevel + 1;
|
|
string lastLevelStr = GenerateSLTrailTag(lastTrailLevel);
|
|
StringReplace(
|
|
result,
|
|
lastLevelStr,
|
|
""
|
|
//
|
|
);
|
|
}
|
|
|
|
//
|
|
// Generate level Comment ...
|
|
string levelStr = GenerateSLTrailTag(level);
|
|
result += levelStr;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Count Positions from a Collection ...
|
|
void CountPositions(
|
|
const XPosition &positions[],
|
|
int &longs,
|
|
double &longProfits,
|
|
double &longVolumes, //
|
|
//
|
|
int &shorts,
|
|
double &shortProfits,
|
|
double &shortVolumes //
|
|
)
|
|
{
|
|
//
|
|
longs = 0;
|
|
longProfits = 0;
|
|
longVolumes = 0;
|
|
|
|
//
|
|
shorts = 0;
|
|
shortProfits = 0;
|
|
shortVolumes = 0;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
bool isLong = IsLong(iPosition.type);
|
|
if (isLong)
|
|
{
|
|
//
|
|
longs++;
|
|
longProfits += iPosition.profit;
|
|
longVolumes += iPosition.volume;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
shorts++;
|
|
shortProfits += iPosition.profit;
|
|
shortVolumes += iPosition.volume;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Extract Positions based On Type ...
|
|
void ExtractPositions(
|
|
XPosition &positions[],
|
|
XPosition &longs[],
|
|
XPosition &shorts[] //
|
|
)
|
|
{
|
|
//
|
|
int count = ArraySize(positions);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
Clean(longs);
|
|
Clean(shorts);
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
bool isLong = IsLong(iPosition.type);
|
|
if (isLong)
|
|
{
|
|
AddRef(
|
|
iPosition,
|
|
longs //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
AddRef(
|
|
iPosition,
|
|
shorts //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
int FindSymbolIndex(
|
|
string mSymbol,
|
|
XSymbolPositions &mItems[] //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
if (!IsValid(mSymbol))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = ArraySize(mItems);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XSymbolPositions iItem = mItems[i];
|
|
|
|
//
|
|
if (iItem.symbol == mSymbol)
|
|
{
|
|
//
|
|
result = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int ExtractSymbolPositions(
|
|
XPosition &positions[],
|
|
XSymbolPositions &items[], // Holds Result
|
|
double mMinProfitPerTrade,
|
|
double mMinProfitPerVolumeFactor //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
int positionsCount = ArraySize(positions);
|
|
if (!IsValidSize(positionsCount))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
Clean(items);
|
|
|
|
//
|
|
for (int i = 0; i < positionsCount; i++)
|
|
{
|
|
//
|
|
XPosition iPosition = positions[i];
|
|
|
|
//
|
|
if (!iPosition.IsValid())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
int itemIDX = FindSymbolIndex(
|
|
iPosition.symbol,
|
|
items //
|
|
);
|
|
if (!IsValidIndex(itemIDX))
|
|
{
|
|
//
|
|
// Add New One ...
|
|
XSymbolPositions item;
|
|
item.symbol = iPosition.symbol;
|
|
|
|
//
|
|
AddRef(
|
|
item,
|
|
items //
|
|
);
|
|
itemIDX = FindSymbolIndex(iPosition.symbol, items);
|
|
}
|
|
|
|
//
|
|
AddRef(
|
|
iPosition,
|
|
items[itemIDX].positions //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(items);
|
|
if (IsValidSize(result))
|
|
{
|
|
//
|
|
for (int i = 0; i < result; i++)
|
|
{
|
|
//
|
|
items[i].Update(
|
|
mMinProfitPerTrade,
|
|
mMinProfitPerVolumeFactor //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Custom Drawings ...
|
|
bool DrawTrendState(
|
|
long chartId,
|
|
string _prefix,
|
|
XOHCL &_bar,
|
|
double &support,
|
|
double &resistance,
|
|
int shoulders = 10,
|
|
int subWindow = 0,
|
|
color resistanceColor = clrRed,
|
|
color supportColor = clrGreen,
|
|
color swingHighColor = clrAqua,
|
|
color swingLowColor = clrMagenta //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(_prefix) &&
|
|
_bar.IsValid()
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find Low Swings ...
|
|
|
|
//
|
|
int firstSwingLowIndex = FindSwing(
|
|
_bar.symbol,
|
|
_bar.period,
|
|
X_SWING_LOW,
|
|
shoulders,
|
|
_bar.Index() + 1 //
|
|
);
|
|
XOHCL firstSwingLowBar;
|
|
result = firstSwingLowBar.Init(
|
|
_bar.symbol,
|
|
_bar.period,
|
|
firstSwingLowIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int secondSwingLowIndex = FindSwing(
|
|
_bar.symbol,
|
|
_bar.period,
|
|
X_SWING_LOW,
|
|
shoulders,
|
|
firstSwingLowIndex + 1 //
|
|
);
|
|
XOHCL secondSwingLowBar;
|
|
result = secondSwingLowBar.Init(
|
|
_bar.symbol,
|
|
_bar.period,
|
|
secondSwingLowIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
support = secondSwingLowBar.low;
|
|
|
|
//
|
|
string lowSwingTrendLineName = _prefix + "_Low_Swing_Trend";
|
|
|
|
//
|
|
result = DrawTrendLine(
|
|
chartId,
|
|
lowSwingTrendLineName,
|
|
subWindow,
|
|
secondSwingLowBar.time,
|
|
secondSwingLowBar.low,
|
|
firstSwingLowBar.time,
|
|
firstSwingLowBar.low,
|
|
swingLowColor,
|
|
STYLE_SOLID,
|
|
2,
|
|
false,
|
|
false,
|
|
true // Ray Right ...
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string lowSwingSupportLineName = _prefix + "_Low_Swing_Support";
|
|
|
|
//
|
|
result = DrawTrendLine(
|
|
chartId,
|
|
lowSwingSupportLineName,
|
|
subWindow,
|
|
secondSwingLowBar.time,
|
|
secondSwingLowBar.low,
|
|
firstSwingLowBar.time,
|
|
secondSwingLowBar.low,
|
|
supportColor,
|
|
STYLE_SOLID,
|
|
2,
|
|
false,
|
|
false,
|
|
true // Ray Right ...
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Find High Swings ...
|
|
|
|
//
|
|
int firstSwingHighIndex = FindSwing(
|
|
_bar.symbol,
|
|
_bar.period,
|
|
X_SWING_HIGH,
|
|
shoulders,
|
|
_bar.Index() + 1 //
|
|
);
|
|
XOHCL firstSwingHighBar;
|
|
result = firstSwingHighBar.Init(
|
|
_bar.symbol,
|
|
_bar.period,
|
|
firstSwingHighIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int secondSwingHighIndex = FindSwing(
|
|
_bar.symbol,
|
|
_bar.period,
|
|
X_SWING_HIGH,
|
|
shoulders,
|
|
firstSwingHighIndex + 1 //
|
|
);
|
|
XOHCL secondSwingHighBar;
|
|
result = secondSwingHighBar.Init(
|
|
_bar.symbol,
|
|
_bar.period,
|
|
secondSwingHighIndex //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
resistance = secondSwingHighBar.high;
|
|
|
|
//
|
|
string highSwingTrendLineName = _prefix + "_High_Swing_Trend";
|
|
|
|
//
|
|
result = DrawTrendLine(
|
|
chartId,
|
|
highSwingTrendLineName,
|
|
subWindow,
|
|
secondSwingHighBar.time,
|
|
secondSwingHighBar.high,
|
|
firstSwingHighBar.time,
|
|
firstSwingHighBar.high,
|
|
swingHighColor,
|
|
STYLE_SOLID,
|
|
2,
|
|
false,
|
|
false,
|
|
true // Ray Right ...
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string highSwingResistanceLineName = _prefix + "_High_Swing_Resistance";
|
|
|
|
//
|
|
result = DrawTrendLine(
|
|
chartId,
|
|
highSwingResistanceLineName,
|
|
subWindow,
|
|
secondSwingHighBar.time,
|
|
secondSwingHighBar.high,
|
|
firstSwingHighBar.time,
|
|
secondSwingHighBar.high,
|
|
resistanceColor,
|
|
STYLE_SOLID,
|
|
2,
|
|
false,
|
|
false,
|
|
true // Ray Right ...
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
// |