7059 lines
123 KiB
Plaintext
7059 lines
123 KiB
Plaintext
//
|
|
// All Available POI(s) ...
|
|
enum ENUM_XPOIS
|
|
{
|
|
//
|
|
X_POI_NONE,
|
|
//
|
|
X_POI_TICKS_ZONES, // Ticks Zone ...
|
|
//
|
|
// Trading Day ...
|
|
X_POI_TRADING_DAY, // Trading Day ...
|
|
//
|
|
// Market Session ...
|
|
X_POI_MARKET_SESSION, // Market Session ...
|
|
//
|
|
// Momentum Bar ...
|
|
X_POI_MOMENTUM_BAR, // Momentum Bar ...
|
|
//
|
|
// Rejection Bar ...
|
|
X_POI_REJECTION_BAR, // Rejection Bar ...
|
|
//
|
|
// Swings ...
|
|
X_POI_SWING_HIGH, // Simple Swing High ...
|
|
X_POI_SWING_LOW, // Simple Swing Low ...
|
|
//
|
|
// Support nad Resistance ...
|
|
X_POI_SUPPORT_ZONE, // Support Zone ...
|
|
X_POI_RESISTANCE_ZONE, // Resistance Zone ...
|
|
//
|
|
// Supply and Demand Zones ...
|
|
X_POI_SUPPLY_ZONE, // Supply Zone ...
|
|
X_POI_DEMAND_ZONE, // Demand Zone ...
|
|
//
|
|
// Order Blocks ...
|
|
X_POI_BULLISH_ORDERBLOCK, // Bullish Order Block ...
|
|
X_POI_BEARISH_ORDERBLOCK, // Bearish Order Block ...
|
|
//
|
|
// Fair Value Gaps ...
|
|
X_POI_BULLISH_FVG, // Bullish Order Block ...
|
|
X_POI_BEARISH_FVG, // Bearish Order Block ...
|
|
//
|
|
X_BULLISH_CONSOLIDATION_ZONE,
|
|
X_BEARISH_CONSOLIDATION_ZONE,
|
|
//
|
|
X_BULLISH_SHARP,
|
|
X_BEARISH_SHARP,
|
|
//
|
|
X_BULLISH_SPIKE,
|
|
X_BEARISH_SPIKE,
|
|
//
|
|
X_BULLISH_PULLBACK,
|
|
X_BEARISH_PULLBACK,
|
|
};
|
|
|
|
//
|
|
// Event Types ...
|
|
enum ENUM_XPOI_EVENTS
|
|
{
|
|
//
|
|
X_POI_EVENT_NONE,
|
|
//
|
|
// Trading Days ...
|
|
X_TRADE_DAY_FIRST_BAR, // Trading Day First Bar ...
|
|
X_TRADE_DAY_LAST_BAR, // Trading Day Last Bar ...
|
|
//
|
|
// Session ...
|
|
X_SESSION_FIRST_BAR, // Session First Bar ...
|
|
X_SESSION_LAST_BAR, // Session Last Bar ...
|
|
//
|
|
// Momentum Bar ...
|
|
X_BULLISH_MOMENTUM_BAR_DETECTED,
|
|
X_BEARISH_MOMENTUM_BAR_DETECTED,
|
|
//
|
|
// Rejection Bar ...
|
|
X_BULLISH_REJECTION_BAR_DETECTED,
|
|
X_BEARISH_REJECTION_BAR_DETECTED,
|
|
//
|
|
// Swings ...
|
|
X_SWING_HIGH_DETECTED,
|
|
X_SWING_LOW_DETECTED,
|
|
//
|
|
// Support nad Resistance ...
|
|
X_SUPPORT_ZONE_DETECTED, // Support Zone ...
|
|
X_RESISTANCE_ZONE_DETECTED, // Resistance Zone ...
|
|
//
|
|
// Supply nad Demand ...
|
|
X_SUPPLY_ZONE_DETECTED, // Supply Zone ...
|
|
X_DEMAND_ZONE_DETECTED, // Demand Zone ...
|
|
//
|
|
// Order Blocks ...
|
|
X_BULLISH_ORDERBLOCK_DETECTED, // Bullish Order Block ...
|
|
X_BEARISH_ORDERBLOCK_DETECTED, // Bearish Order Block ...
|
|
//
|
|
// Fair Value Gaps ...
|
|
X_BULLISH_FVG_DETECTED, // Bullish Fair Value Gapّ ...
|
|
X_BEARISH_FVG_DETECTED, // Bearish Fair Value Gapّ ...
|
|
X_BULLISH_CONSOLIDATION_ZONE_DETECTED,
|
|
X_BEARISH_CONSOLIDATION_ZONE_DETECTED,
|
|
X_BULLISH_SHARP_DETECTED,
|
|
X_BEARISH_SHARP_DETECTED,
|
|
X_BULLISH_SPIKE_DETECTED,
|
|
X_BEARISH_SPIKE_DETECTED,
|
|
X_BULLISH_PULLBACK_DETECTED,
|
|
X_BEARISH_PULLBACK_DETECTED,
|
|
};
|
|
|
|
//
|
|
enum ENUM_XZONE_STATE
|
|
{
|
|
XZONE_STATE_NONE,
|
|
XZONE_STATE_PASSED,
|
|
XZONE_STATE_FAILED,
|
|
XZONE_STATE_IGNORED,
|
|
};
|
|
|
|
//
|
|
// Forext Sessions ...
|
|
enum ENUM_XSESSION
|
|
{
|
|
X_TOKYO,
|
|
X_SYDNEY,
|
|
X_LONDON,
|
|
X_NEW_YORK,
|
|
X_FRANKFORT,
|
|
};
|
|
|
|
/**
|
|
* Converts ENUM_XPOI value to String Representation ...
|
|
*
|
|
* @param value: ENUM_XPOI member ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string ToString(ENUM_XPOIS value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case X_POI_TRADING_DAY:
|
|
result = "XTDAY";
|
|
break;
|
|
|
|
//
|
|
case X_POI_MARKET_SESSION:
|
|
result = "XMSESS";
|
|
break;
|
|
|
|
//
|
|
case X_POI_MOMENTUM_BAR:
|
|
result = "XMNTMB";
|
|
break;
|
|
|
|
//
|
|
case X_POI_REJECTION_BAR:
|
|
result = "XRJCTB";
|
|
break;
|
|
|
|
//
|
|
case X_POI_SWING_HIGH:
|
|
result = "XSPH";
|
|
break;
|
|
|
|
//
|
|
case X_POI_SWING_LOW:
|
|
result = "XSPL";
|
|
break;
|
|
|
|
//
|
|
case X_POI_SUPPORT_ZONE:
|
|
result = "XSUP";
|
|
break;
|
|
|
|
//
|
|
case X_POI_RESISTANCE_ZONE:
|
|
result = "XRES";
|
|
break;
|
|
|
|
//
|
|
case X_POI_SUPPLY_ZONE:
|
|
result = "XSUPPLY";
|
|
break;
|
|
|
|
//
|
|
case X_POI_DEMAND_ZONE:
|
|
result = "XDEMAND";
|
|
break;
|
|
|
|
//
|
|
case X_POI_BULLISH_ORDERBLOCK:
|
|
result = "XBULLOB";
|
|
break;
|
|
|
|
//
|
|
case X_POI_BEARISH_ORDERBLOCK:
|
|
result = "XBEAROB";
|
|
break;
|
|
|
|
//
|
|
case X_POI_BULLISH_FVG:
|
|
result = "XBULLFVG";
|
|
break;
|
|
|
|
//
|
|
case X_POI_BEARISH_FVG:
|
|
result = "XBEARFVG";
|
|
break;
|
|
|
|
//
|
|
case X_POI_TICKS_ZONES:
|
|
result = "XTKSZ";
|
|
break;
|
|
|
|
//
|
|
case X_BULLISH_CONSOLIDATION_ZONE:
|
|
result = "XBULLCZ";
|
|
break;
|
|
|
|
//
|
|
case X_BEARISH_CONSOLIDATION_ZONE:
|
|
result = "XBEARCZ";
|
|
break;
|
|
|
|
//
|
|
case X_BULLISH_SPIKE:
|
|
result = "XBULLSPK";
|
|
break;
|
|
|
|
//
|
|
case X_BEARISH_SPIKE:
|
|
result = "XBEARSPK";
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Converts ENUM_XSESSION value to String Representation ...
|
|
*
|
|
* @param value: ENUM_XSESSION member ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string ToString(ENUM_XSESSION value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case X_SYDNEY:
|
|
result = "Sydney";
|
|
break;
|
|
|
|
//
|
|
case X_TOKYO:
|
|
result = "Tokyo";
|
|
break;
|
|
|
|
//
|
|
case X_FRANKFORT:
|
|
result = "FrankGurt";
|
|
break;
|
|
|
|
//
|
|
case X_LONDON:
|
|
result = "London";
|
|
break;
|
|
|
|
//
|
|
case X_NEW_YORK:
|
|
result = "NewYork";
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Generate General Event Messages ...
|
|
*
|
|
* @param value: ENUM_XPOI_EVENTS member ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string ToString(ENUM_XPOI_EVENTS value)
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
switch (value)
|
|
{
|
|
//
|
|
case X_TRADE_DAY_FIRST_BAR:
|
|
result = "First Bar of Day";
|
|
break;
|
|
|
|
//
|
|
case X_TRADE_DAY_LAST_BAR:
|
|
result = "Last Bar of Day";
|
|
break;
|
|
|
|
//
|
|
case X_SESSION_FIRST_BAR:
|
|
result = "First Bar of Session";
|
|
break;
|
|
|
|
//
|
|
case X_SESSION_LAST_BAR:
|
|
result = "Last Bar of Session";
|
|
break;
|
|
|
|
//
|
|
case X_BULLISH_MOMENTUM_BAR_DETECTED:
|
|
result = "Bullish Momentum Bar Detected";
|
|
break;
|
|
|
|
//
|
|
case X_BEARISH_MOMENTUM_BAR_DETECTED:
|
|
result = "Bearish Momentum Bar Detected";
|
|
break;
|
|
|
|
//
|
|
case X_BULLISH_REJECTION_BAR_DETECTED:
|
|
result = "Bullish Rejection Bar Detected";
|
|
break;
|
|
|
|
//
|
|
case X_BEARISH_REJECTION_BAR_DETECTED:
|
|
result = "Bearish Rejection Bar Detected";
|
|
break;
|
|
|
|
//
|
|
case X_SWING_HIGH_DETECTED:
|
|
result = "Swing High Detected";
|
|
break;
|
|
|
|
//
|
|
case X_SWING_LOW_DETECTED:
|
|
result = "Swing Low Detected";
|
|
break;
|
|
|
|
//
|
|
case X_SUPPORT_ZONE_DETECTED:
|
|
result = "Support Zone Detected";
|
|
break;
|
|
|
|
//
|
|
case X_RESISTANCE_ZONE_DETECTED:
|
|
result = "Resistance Zone Detected";
|
|
break;
|
|
|
|
//
|
|
case X_SUPPLY_ZONE_DETECTED:
|
|
result = "Supply Zone Detected";
|
|
break;
|
|
|
|
//
|
|
case X_DEMAND_ZONE_DETECTED:
|
|
result = "Demand Zone Detected";
|
|
break;
|
|
|
|
//
|
|
case X_BULLISH_ORDERBLOCK_DETECTED:
|
|
result = "Bullish Order Block Detected";
|
|
break;
|
|
|
|
//
|
|
case X_BEARISH_ORDERBLOCK_DETECTED:
|
|
result = "Bearish Orer Block Detected";
|
|
break;
|
|
|
|
//
|
|
case X_BULLISH_FVG_DETECTED:
|
|
result = "Bullish FVG Detected";
|
|
break;
|
|
|
|
//
|
|
case X_BEARISH_FVG_DETECTED:
|
|
result = "Bearish FVg Detected";
|
|
break;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Implementation ...
|
|
|
|
//
|
|
// Base POI Model Class ...
|
|
class XCBasePOI : public XCBase
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCBasePOI()
|
|
{
|
|
//
|
|
Clean();
|
|
|
|
//
|
|
mSep = "_";
|
|
mLineSep = "\n";
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCBasePOI()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Virtual ...
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
virtual void Clean()
|
|
{
|
|
mType = X_POI_NONE;
|
|
}
|
|
|
|
/**
|
|
* Validate ...
|
|
*
|
|
* @return ( virtual bool )
|
|
*/
|
|
virtual bool IsValid()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Retrieve POI Type ...
|
|
*
|
|
* @return ( virtual ENUM_XPOIS member )
|
|
*/
|
|
virtual ENUM_XPOIS Type()
|
|
{
|
|
return mType;
|
|
}
|
|
|
|
/**
|
|
* Retrieve POI Type ...
|
|
*
|
|
* @return ( virtual string )
|
|
*/
|
|
virtual string TypeAsString()
|
|
{
|
|
return ToString(mType);
|
|
}
|
|
|
|
/**
|
|
* Retrieve POI Tag ...
|
|
*
|
|
* @return ( virtual string )
|
|
*/
|
|
virtual string GetTag()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Retrieve POI Tooltip ...
|
|
*
|
|
* @return ( virtual string )
|
|
*/
|
|
virtual string GetTooltip()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
// Props ...
|
|
string mSep; // Separator ...
|
|
string mLineSep; // Line Separator ...
|
|
ENUM_XPOIS mType; // Type ...
|
|
|
|
//
|
|
private:
|
|
//
|
|
};
|
|
|
|
//
|
|
typedef void (*TOnPOIEvent)(ENUM_XPOI_EVENTS event,
|
|
XCBasePOI *param //
|
|
);
|
|
|
|
//
|
|
// Zone POI Class ...
|
|
class XCZone : public XCBasePOI
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Get Zone Upper Boundary ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double Upper()
|
|
{
|
|
return mUpper;
|
|
}
|
|
|
|
/**
|
|
* Set Zone Upper Boundary ...
|
|
*/
|
|
void Upper(double value)
|
|
{
|
|
mUpper = value;
|
|
}
|
|
|
|
/**
|
|
* Get Zone Lower Boundary ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double Lower()
|
|
{
|
|
return mLower;
|
|
}
|
|
|
|
/**
|
|
* Set Zone Lower Boundary ...
|
|
*/
|
|
void Lower(double value)
|
|
{
|
|
mLower = value;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Zone Range ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double Range()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
double upper = Upper();
|
|
double lower = Lower();
|
|
|
|
//
|
|
if (upper > 0 && lower > 0 && upper > lower)
|
|
{
|
|
result = upper - lower;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
double RangePercent()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
double range = Range();
|
|
if (range > 0)
|
|
{
|
|
result = range / 100;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Virtuals ...
|
|
|
|
/**
|
|
* Get Zone Start Date ...
|
|
*
|
|
* @return ( virtual datetime )
|
|
*/
|
|
virtual datetime From()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Get Zone End Date ...
|
|
*
|
|
* @return ( virtual datetime )
|
|
*/
|
|
virtual datetime To()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
//
|
|
// Validators ...
|
|
|
|
/**
|
|
* Validate Upper and Lower of Zone ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValidBoundary()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
mUpper > 0 &&
|
|
mLower > 0 &&
|
|
mUpper >= mLower
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check From Date of Zone is Valid ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValidFrom()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
datetime from = From();
|
|
result = IsSpecifiedValid(from);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
// Props ...
|
|
double mUpper; // Zone Upper ...
|
|
double mLower; // Zone Lower ...
|
|
|
|
//
|
|
private:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// From To Zone ...
|
|
class XCFromToZone : public XCBasePOI
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCFromToZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCFromToZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
bool InitFromTo(
|
|
ENUM_XPOIS type,
|
|
string title,
|
|
datetime from //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = type != X_POI_NONE &&
|
|
IsSpecifiedValid(from) &&
|
|
IsSpecifiedValid(title);
|
|
|
|
//
|
|
mType = type;
|
|
mFrom = from;
|
|
mTitle = title;
|
|
mTo = TimeCurrent();
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool InitFromTo(
|
|
ENUM_XPOIS type,
|
|
string title,
|
|
datetime from,
|
|
datetime to //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
result = InitFromTo(
|
|
type,
|
|
title,
|
|
from //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
to = NormalizeTime(to);
|
|
mTo = to;
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Get Zone Start Time ...
|
|
*
|
|
* @return ( datetime )
|
|
*/
|
|
datetime From()
|
|
{
|
|
return mFrom;
|
|
}
|
|
|
|
/**
|
|
* Set Zone Start Time ...
|
|
*
|
|
* @param value: Datetime
|
|
*/
|
|
void From(datetime value)
|
|
{
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
mFrom = value;
|
|
}
|
|
|
|
/**
|
|
* Get Zone End Time ...
|
|
*
|
|
* @return ( datetime )
|
|
*/
|
|
datetime To()
|
|
{
|
|
return mTo;
|
|
}
|
|
|
|
/**
|
|
* Set Zone End Time ...
|
|
*
|
|
* @param value: Datetime
|
|
*/
|
|
void To(datetime value)
|
|
{
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
mTo = value;
|
|
}
|
|
|
|
/**
|
|
* Get Title ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string Title()
|
|
{
|
|
return mTitle;
|
|
}
|
|
|
|
/**
|
|
* Set Title ...
|
|
*
|
|
* @param value: String ...
|
|
*/
|
|
// void Title(string value)
|
|
// {
|
|
// mTitle = value;
|
|
// }
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
void Clean() override
|
|
{
|
|
//
|
|
mTo = NULL;
|
|
mFrom = NULL;
|
|
mType = X_POI_NONE;
|
|
}
|
|
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
mType != X_POI_NONE &&
|
|
IsSpecifiedValid(mTo) &&
|
|
IsSpecifiedValid(mFrom) &&
|
|
IsSpecifiedValid(mTitle)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
string GetTag() override
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string hash = TypeAsString() + mSep + ToString(From()) + mSep + Title();
|
|
hash = ToMD5(hash);
|
|
|
|
//
|
|
result = TypeAsString() + "[" + Title() + "]" + mSep + hash;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
// Props ...
|
|
datetime mFrom; // Start Date
|
|
datetime mTo; // End Date
|
|
string mTitle; // Zone Title
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Bar Zone ...
|
|
class XCBarZone : public XCZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCBarZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCBarZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param type: ENUM_XPOIS member ...
|
|
* @param upperPrice: ENUM_X_PRICE member ...
|
|
* @param lowerPrice: ENUM_X_PRICE member ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool InitBarZone(
|
|
XOHCL &bar,
|
|
ENUM_XPOIS type,
|
|
ENUM_X_PRICE upperPrice,
|
|
ENUM_X_PRICE lowerPrice //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid() &&
|
|
type != X_POI_NONE &&
|
|
upperPrice != lowerPrice;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mBar = bar;
|
|
mType = type;
|
|
mUpperPrice = upperPrice;
|
|
mLowerPrice = lowerPrice;
|
|
mUpper = bar.GetPrice(upperPrice);
|
|
mLower = bar.GetPrice(lowerPrice);
|
|
|
|
//
|
|
result = IsValidBarZone();
|
|
if (result)
|
|
{
|
|
//
|
|
From(bar.time);
|
|
To(TimeCurrent());
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Fill Bar as XOHCL struct ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool FillBar(
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bar = mBar;
|
|
result = mBar.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Set From Date ...
|
|
*
|
|
* @param value: DateTime ...
|
|
*/
|
|
void From(datetime value)
|
|
{
|
|
//
|
|
if (!IsValidBarZone())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
mFrom = value;
|
|
}
|
|
|
|
/**
|
|
* Set To Date ...
|
|
*
|
|
* @param value: DateTime ...
|
|
*/
|
|
void To(datetime value)
|
|
{
|
|
//
|
|
if (!IsValidBarZone())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
mTo = value;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Bar Time ...
|
|
*
|
|
* @return ( datetime )
|
|
*/
|
|
datetime BarTime()
|
|
{
|
|
return mBar.time;
|
|
}
|
|
|
|
/**
|
|
* Get Symbol ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetSymbol()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!mBar.IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return mBar.symbol;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Period ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
ENUM_TIMEFRAMES GetPeriod()
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
if (!mBar.IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return mBar.period;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zone Started or not ...
|
|
* First Exit in Direction of Zone after From ...
|
|
*
|
|
* @param forDir: exit direction ...
|
|
* @param startedBar: specified Start Bar ...
|
|
* @param isBodyOut: specified Start Bar Close is Out of Zone or not ...
|
|
* @param forPeriod: specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsStarted(
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &startedBar,
|
|
bool &isBodyOut,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
isBodyOut = false;
|
|
startedBar.Clean();
|
|
|
|
//
|
|
result = HasDirection(forDir) &&
|
|
IsValidBarZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
// Detect From Bar Index ...
|
|
int fromIndex = iBarShift(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
From() //
|
|
);
|
|
|
|
//
|
|
for (int i = fromIndex; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
result = isInited;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isBreakedFromUpper =
|
|
//
|
|
iBar.low > Upper() ||
|
|
(iBar.low <= Upper() &&
|
|
iBar.high > Upper() &&
|
|
iBar.close > Upper())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreakedFromLower =
|
|
//
|
|
iBar.low < Lower() ||
|
|
(iBar.high >= Lower() &&
|
|
iBar.low < Lower() &&
|
|
iBar.close < Lower())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreaked =
|
|
isBreakedFromUpper ||
|
|
isBreakedFromLower;
|
|
if (isBreaked)
|
|
{
|
|
//
|
|
result = isBreaked &&
|
|
isBullish
|
|
? isBreakedFromUpper
|
|
: isBreakedFromLower;
|
|
if (result)
|
|
{
|
|
//
|
|
startedBar = iBar;
|
|
iBar.Clean();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
|
|
//
|
|
result = startedBar.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
isBodyOut =
|
|
isBullish
|
|
? startedBar.IsBullish() &&
|
|
startedBar.GetUp() > Upper()
|
|
: startedBar.IsBearish() &&
|
|
startedBar.GetDown() < Lower();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zone Activated or not ...
|
|
* First Enter in Opposit Direction of Zone after Start ...
|
|
*
|
|
* @param forDir: exit direction ...
|
|
* @param activatedBar: specified Activation Bar ...
|
|
* @param isBodyIn: specified Activation Bar Close is Inside of Zone or not ...
|
|
* @param forPeriod: specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsActivated(
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &activatedBar,
|
|
bool &isBodyIn,
|
|
bool forceBodyOutStarted = true,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
isBodyIn = false;
|
|
activatedBar.Clean();
|
|
|
|
//
|
|
result = HasDirection(forDir) &&
|
|
IsValidBarZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
XOHCL startedBar;
|
|
bool isBodyOut = false;
|
|
bool isStarted = IsStarted(
|
|
forDir,
|
|
startedBar,
|
|
isBodyOut,
|
|
forPeriod //
|
|
);
|
|
result =
|
|
!forceBodyOutStarted
|
|
? isStarted
|
|
: isStarted &&
|
|
isBodyOut;
|
|
if (!result)
|
|
{
|
|
//
|
|
startedBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int fromIndex = startedBar.Index() - 1;
|
|
|
|
//
|
|
for (int i = fromIndex; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
result = isInited;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isInsideFromUpper =
|
|
//
|
|
iBar.high < Upper() ||
|
|
(iBar.high > Upper() &&
|
|
iBar.low <= Upper() &&
|
|
iBar.close <= Upper())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isInsideFromLower =
|
|
//
|
|
iBar.low > Lower() ||
|
|
(iBar.low < Lower() &&
|
|
iBar.high >= Lower() &&
|
|
iBar.close >= Lower())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isInside =
|
|
isInsideFromUpper ||
|
|
isInsideFromLower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
result = isInside &&
|
|
isBullish
|
|
? isInsideFromUpper
|
|
: isInsideFromLower;
|
|
if (result)
|
|
{
|
|
//
|
|
activatedBar = iBar;
|
|
iBar.Clean();
|
|
startedBar.Clean();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
startedBar.Clean();
|
|
}
|
|
|
|
//
|
|
result = activatedBar.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
isBodyIn =
|
|
isBullish
|
|
? activatedBar.IsBearish() &&
|
|
activatedBar.GetDown() < Upper()
|
|
: activatedBar.IsBullish() &&
|
|
activatedBar.GetUp() > Lower();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zone Breaked or not ...
|
|
*
|
|
* @param forDir: exit direction ...
|
|
* @param breakedBar: specified Breaked Bar ...
|
|
* @param isBodyOut: specified Breaked Bar Close is Out of Zone or not ...
|
|
* @param ignoreStart: Ignore Zone Start (Calculate from From()) ...
|
|
* @param startedBodyOut: Started Bar Body Close State, if use Start for Calculation ...
|
|
* @param forPeriod: specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBreaked(
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &breakedBar,
|
|
bool &isBodyOut,
|
|
bool ignoreStart = false,
|
|
bool startedBodyOut = false,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
isBodyOut = false;
|
|
breakedBar.Clean();
|
|
|
|
//
|
|
result = HasDirection(forDir) &&
|
|
IsValidBarZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
int fromIndex = -1;
|
|
if (!ignoreStart)
|
|
{
|
|
//
|
|
XOHCL startedBar;
|
|
bool isBodyOut = false;
|
|
bool isStarted = IsStarted(
|
|
forDir,
|
|
startedBar,
|
|
isBodyOut,
|
|
forPeriod //
|
|
);
|
|
|
|
//
|
|
bool isStartPassed =
|
|
!startedBodyOut
|
|
? isStarted
|
|
: isStarted &&
|
|
isBodyOut;
|
|
if (isStartPassed)
|
|
{
|
|
fromIndex = startedBar.Index() - 1;
|
|
}
|
|
|
|
//
|
|
startedBar.Clean();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
fromIndex = iBarShift(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
From() //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(fromIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = fromIndex; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
result = isInited;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isBreakedFromUpper =
|
|
//
|
|
iBar.low > Upper() ||
|
|
(iBar.low <= Upper() &&
|
|
iBar.high > Upper() &&
|
|
iBar.close > Upper())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreakedFromLower =
|
|
//
|
|
iBar.low < Lower() ||
|
|
(iBar.high >= Lower() &&
|
|
iBar.low < Lower() &&
|
|
iBar.close < Lower())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreaked =
|
|
isBreakedFromUpper ||
|
|
isBreakedFromLower;
|
|
if (isBreaked)
|
|
{
|
|
//
|
|
result = isBreaked &&
|
|
(isBullish
|
|
? isBreakedFromLower
|
|
: isBreakedFromUpper);
|
|
if (result)
|
|
{
|
|
//
|
|
breakedBar = iBar;
|
|
iBar.Clean();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
|
|
//
|
|
result = breakedBar.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
isBodyOut =
|
|
isBullish
|
|
? breakedBar.IsBearish() &&
|
|
breakedBar.GetDown() < Lower()
|
|
: breakedBar.IsBullish() &&
|
|
breakedBar.GetUp() > Upper();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zone Worked or not ...
|
|
*
|
|
* @param forDir: exit direction ...
|
|
* @param workedBar: specified Worked Bar ...
|
|
* @param isBodyOut: specified Worked Bar Close is Out of Zone or not ...
|
|
* @param ignoreActivation: Ignore Zone Activation (Calculate from From()) ...
|
|
* @param activationStartedOut: Specified Zone Start Bar State ...
|
|
* @param activationBodyIn: Specified Zone Activation Bar State ...
|
|
* @param forPeriod: specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsWorked(
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &workedBar,
|
|
bool &isBodyOut,
|
|
bool ignoreActivation = false,
|
|
bool activationStartedOut = false,
|
|
bool activationBodyIn = false,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
isBodyOut = false;
|
|
workedBar.Clean();
|
|
|
|
//
|
|
result = HasDirection(forDir) &&
|
|
IsValidBarZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
int fromIndex = -1;
|
|
if (!ignoreActivation)
|
|
{
|
|
//
|
|
XOHCL activatedBar;
|
|
bool isBodyIn = false;
|
|
bool isActivated = IsActivated(
|
|
forDir,
|
|
activatedBar,
|
|
isBodyIn,
|
|
activationStartedOut,
|
|
forPeriod //
|
|
);
|
|
|
|
//
|
|
bool isActivationPassed =
|
|
!activationBodyIn
|
|
? isActivated
|
|
: isActivated &&
|
|
isBodyIn;
|
|
if (isActivationPassed)
|
|
{
|
|
fromIndex = activatedBar.Index() - 1;
|
|
}
|
|
|
|
//
|
|
activatedBar.Clean();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
fromIndex = iBarShift(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
From() //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(fromIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = fromIndex; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
result = isInited;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isBreakedFromUpper =
|
|
//
|
|
iBar.low > Upper() ||
|
|
(iBar.low <= Upper() &&
|
|
iBar.high > Upper() &&
|
|
iBar.close > Upper())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreakedFromLower =
|
|
//
|
|
iBar.low < Lower() ||
|
|
(iBar.high >= Lower() &&
|
|
iBar.low < Lower() &&
|
|
iBar.close < Lower())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreaked =
|
|
isBreakedFromUpper ||
|
|
isBreakedFromLower;
|
|
if (isBreaked)
|
|
{
|
|
//
|
|
result = isBreaked &&
|
|
isBullish
|
|
? isBreakedFromUpper
|
|
: isBreakedFromLower;
|
|
if (result)
|
|
{
|
|
//
|
|
workedBar = iBar;
|
|
iBar.Clean();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
|
|
//
|
|
result = workedBar.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
isBodyOut =
|
|
isBullish
|
|
? workedBar.IsBullish() &&
|
|
workedBar.GetUp() > Upper()
|
|
: workedBar.IsBearish() &&
|
|
workedBar.GetDown() < Lower();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check to Find Nearest Bar which Breakes Upper ...
|
|
*
|
|
* @param bar: XOHCL instance Reference, Breaker Bar ...
|
|
* @param forPeriod: ENUM_TIMEFRAMES member, Breaker Bar Detection Period, default is Zone Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool FindNearestInsideBarFromUpper(
|
|
XOHCL &bar,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int from = 1;
|
|
int to = iBarShift(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
From() //
|
|
);
|
|
|
|
//
|
|
for (int i = from; i < to; i++)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
bool isInside = iBar.low < Upper();
|
|
if (isInside)
|
|
{
|
|
//
|
|
bar = iBar;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check to Find Nearest Bar which Breakes Lower ...
|
|
*
|
|
* @param bar: XOHCL instance Reference, Breaker Bar ...
|
|
* @param forPeriod: ENUM_TIMEFRAMES member, Breaker Bar Detection Period, default is Zone Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool FindNearestInsideBarFromLower(
|
|
XOHCL &bar,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int from = 1;
|
|
int to = iBarShift(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
From() //
|
|
);
|
|
|
|
//
|
|
for (int i = from; i < to; i++)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
bool isInside = iBar.high > Lower();
|
|
if (isInside)
|
|
{
|
|
//
|
|
bar = iBar;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
void Clean() override
|
|
{
|
|
//
|
|
mBar.Clean();
|
|
mUpper = 0;
|
|
mLower = 0;
|
|
mType = X_POI_NONE;
|
|
}
|
|
|
|
datetime From() override
|
|
{
|
|
return mFrom;
|
|
}
|
|
|
|
datetime To() override
|
|
{
|
|
return mTo;
|
|
}
|
|
|
|
string GetTag() override
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValidBarZone())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string hash = ToMD5(mBar.GetTag());
|
|
|
|
//
|
|
result =
|
|
//
|
|
TypeAsString() + mSep +
|
|
ToString(mBar.period) + mSep +
|
|
hash
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
string GetTooltip() override
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValidBarZone())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
// Props ...
|
|
XOHCL mBar; // Bar ...
|
|
ENUM_X_PRICE mUpperPrice; // Upper Price Selection
|
|
ENUM_X_PRICE mLowerPrice; // Lower Price Selection
|
|
|
|
/**
|
|
* Check Bar Zone Validation ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValidBarZone()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = mBar.IsValid() &&
|
|
mType != X_POI_NONE &&
|
|
IsValidBoundary();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
private:
|
|
//
|
|
// Props ...
|
|
datetime mFrom;
|
|
datetime mTo;
|
|
|
|
//
|
|
};
|
|
class XCTwoBarZone : public XCZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCTwoBarZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCTwoBarZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param type: ENUM_XPOIS member ...
|
|
* @param upperPrice: ENUM_X_PRICE member ...
|
|
* @param lowerPrice: ENUM_X_PRICE member ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool InitTwoBarZone(
|
|
XOHCL &startBar,
|
|
XOHCL &endBar,
|
|
ENUM_XPOIS type,
|
|
ENUM_X_PRICE startPrice,
|
|
ENUM_X_PRICE endPrice //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = startBar.IsValid() &&
|
|
endBar.IsValid() &&
|
|
startBar.symbol == endBar.symbol &&
|
|
startBar.period == endBar.period &&
|
|
startBar.time < endBar.time &&
|
|
type != X_POI_NONE;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mType = type;
|
|
mEndBar = endBar;
|
|
mStartBar = startBar;
|
|
|
|
//
|
|
int startIndex = startBar.Index();
|
|
int endIndex = endBar.Index();
|
|
|
|
//
|
|
double mStartPrice = startBar.GetPrice(startPrice);
|
|
double mEndPrice = endBar.GetPrice(endPrice);
|
|
bool isStartOverEnd = mStartPrice > mEndPrice;
|
|
|
|
//
|
|
if (isStartOverEnd)
|
|
{
|
|
//
|
|
mUpperPrice = startPrice;
|
|
mLowerPrice = endPrice;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
mUpperPrice = endPrice;
|
|
mLowerPrice = startPrice;
|
|
}
|
|
|
|
//
|
|
mUpper = MathMax(mStartPrice, mEndPrice);
|
|
mLower = MathMin(mStartPrice, mEndPrice);
|
|
|
|
//
|
|
result = IsValidTwoBarZone();
|
|
if (result)
|
|
{
|
|
//
|
|
From(startBar.time);
|
|
To(endBar.time);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Set From Date ...
|
|
*
|
|
* @param value: DateTime ...
|
|
*/
|
|
void From(datetime value)
|
|
{
|
|
//
|
|
if (!IsValidTwoBarZone())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
mFrom = value;
|
|
}
|
|
|
|
/**
|
|
* Set To Date ...
|
|
*
|
|
* @param value: DateTime ...
|
|
*/
|
|
void To(datetime value)
|
|
{
|
|
//
|
|
if (!IsValidTwoBarZone())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
mTo = value;
|
|
}
|
|
|
|
/**
|
|
* Fill Start Bar ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool FillStartBar(XOHCL &bar)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValidTwoBarZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bar = mStartBar;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Fill End Bar ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool FillEndBar(XOHCL &bar)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValidTwoBarZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bar = mEndBar;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Symbol ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetSymbol()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!mStartBar.IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return mStartBar.symbol;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Period ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
ENUM_TIMEFRAMES GetPeriod()
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
if (!mStartBar.IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return mStartBar.period;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zone Started or not ...
|
|
* First Exit in Direction of Zone after From ...
|
|
*
|
|
* @param forDir: exit direction ...
|
|
* @param startedBar: specified Start Bar ...
|
|
* @param isBodyOut: specified Start Bar Close is Out of Zone or not ...
|
|
* @param forPeriod: specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsStarted(
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &startedBar,
|
|
bool &isBodyOut,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
isBodyOut = false;
|
|
startedBar.Clean();
|
|
|
|
//
|
|
result = HasDirection(forDir) &&
|
|
IsValidTwoBarZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
// Detect From Bar Index ...
|
|
int fromIndex = iBarShift(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
From() //
|
|
);
|
|
|
|
//
|
|
for (int i = fromIndex; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
result = isInited;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isBreakedFromUpper =
|
|
//
|
|
iBar.low > Upper() ||
|
|
(iBar.low <= Upper() &&
|
|
iBar.high > Upper() &&
|
|
iBar.close > Upper())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreakedFromLower =
|
|
//
|
|
iBar.low < Lower() ||
|
|
(iBar.high >= Lower() &&
|
|
iBar.low < Lower() &&
|
|
iBar.close < Lower())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreaked =
|
|
isBreakedFromUpper ||
|
|
isBreakedFromLower;
|
|
if (isBreaked)
|
|
{
|
|
//
|
|
result = isBreaked &&
|
|
isBullish
|
|
? isBreakedFromUpper
|
|
: isBreakedFromLower;
|
|
if (result)
|
|
{
|
|
//
|
|
startedBar = iBar;
|
|
iBar.Clean();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
|
|
//
|
|
result = startedBar.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
isBodyOut =
|
|
isBullish
|
|
? startedBar.IsBullish() &&
|
|
startedBar.GetUp() > Upper()
|
|
: startedBar.IsBearish() &&
|
|
startedBar.GetDown() < Lower();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zone Activated or not ...
|
|
* First Enter in Opposit Direction of Zone after Start ...
|
|
*
|
|
* @param forDir: exit direction ...
|
|
* @param activatedBar: specified Activation Bar ...
|
|
* @param isBodyIn: specified Activation Bar Close is Inside of Zone or not ...
|
|
* @param forPeriod: specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsActivated(
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &activatedBar,
|
|
bool &isBodyIn,
|
|
bool forceBodyOutStarted = true,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
isBodyIn = false;
|
|
activatedBar.Clean();
|
|
|
|
//
|
|
result = HasDirection(forDir) &&
|
|
IsValidTwoBarZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
XOHCL startedBar;
|
|
bool isBodyOut = false;
|
|
bool isStarted = IsStarted(
|
|
forDir,
|
|
startedBar,
|
|
isBodyOut,
|
|
forPeriod //
|
|
);
|
|
result =
|
|
!forceBodyOutStarted
|
|
? isStarted
|
|
: isStarted &&
|
|
isBodyOut;
|
|
if (!result)
|
|
{
|
|
//
|
|
startedBar.Clean();
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int fromIndex = startedBar.Index() - 1;
|
|
|
|
//
|
|
for (int i = fromIndex; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
result = isInited;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isInsideFromUpper =
|
|
//
|
|
iBar.high < Upper() ||
|
|
(iBar.high > Upper() &&
|
|
iBar.low <= Upper() &&
|
|
iBar.close <= Upper())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isInsideFromLower =
|
|
//
|
|
iBar.low > Lower() ||
|
|
(iBar.low < Lower() &&
|
|
iBar.high >= Lower() &&
|
|
iBar.close >= Lower())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isInside =
|
|
isInsideFromUpper ||
|
|
isInsideFromLower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
result = isInside &&
|
|
isBullish
|
|
? isInsideFromUpper
|
|
: isInsideFromLower;
|
|
if (result)
|
|
{
|
|
//
|
|
activatedBar = iBar;
|
|
iBar.Clean();
|
|
startedBar.Clean();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
startedBar.Clean();
|
|
}
|
|
|
|
//
|
|
result = activatedBar.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
isBodyIn =
|
|
isBullish
|
|
? activatedBar.IsBearish() &&
|
|
activatedBar.GetDown() < Upper()
|
|
: activatedBar.IsBullish() &&
|
|
activatedBar.GetUp() > Lower();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zone reaked or not ...
|
|
*
|
|
* @param forDir: exit direction ...
|
|
* @param breakedBar: specified Breaked Bar ...
|
|
* @param isBodyOut: specified Breaked Bar Close is Out of Zone or not ...
|
|
* @param ignoreStart: Ignore Zone Start (Calculate from From()) ...
|
|
* @param startedBodyOut: Started Bar Body Close State, if use Start for Calculation ...
|
|
* @param forPeriod: specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBreaked(
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &breakedBar,
|
|
bool &isBodyOut,
|
|
bool ignoreStart = false,
|
|
bool startedBodyOut = false,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
isBodyOut = false;
|
|
breakedBar.Clean();
|
|
|
|
//
|
|
result = HasDirection(forDir) &&
|
|
IsValidTwoBarZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
int fromIndex = -1;
|
|
if (!ignoreStart)
|
|
{
|
|
//
|
|
XOHCL startedBar;
|
|
bool isBodyOut = false;
|
|
bool isStarted = IsStarted(
|
|
forDir,
|
|
startedBar,
|
|
isBodyOut,
|
|
forPeriod //
|
|
);
|
|
|
|
//
|
|
bool isStartPassed =
|
|
!startedBodyOut
|
|
? isStarted
|
|
: isStarted &&
|
|
isBodyOut;
|
|
if (isStartPassed)
|
|
{
|
|
fromIndex = startedBar.Index() - 1;
|
|
}
|
|
|
|
//
|
|
startedBar.Clean();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
fromIndex = iBarShift(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
From() //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(fromIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = fromIndex; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
result = isInited;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isBreakedFromUpper =
|
|
//
|
|
iBar.low > Upper() ||
|
|
(iBar.low <= Upper() &&
|
|
iBar.high > Upper() &&
|
|
iBar.close > Upper())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreakedFromLower =
|
|
//
|
|
iBar.low < Lower() ||
|
|
(iBar.high >= Lower() &&
|
|
iBar.low < Lower() &&
|
|
iBar.close < Lower())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreaked =
|
|
isBreakedFromUpper ||
|
|
isBreakedFromLower;
|
|
if (isBreaked)
|
|
{
|
|
//
|
|
result = isBreaked &&
|
|
(isBullish
|
|
? isBreakedFromLower
|
|
: isBreakedFromUpper);
|
|
if (result)
|
|
{
|
|
//
|
|
breakedBar = iBar;
|
|
iBar.Clean();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
|
|
//
|
|
result = breakedBar.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
isBodyOut =
|
|
isBullish
|
|
? breakedBar.IsBearish() &&
|
|
breakedBar.GetDown() < Lower()
|
|
: breakedBar.IsBullish() &&
|
|
breakedBar.GetUp() > Upper();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zone Worked or not ...
|
|
*
|
|
* @param forDir: exit direction ...
|
|
* @param workedBar: specified Worked Bar ...
|
|
* @param isBodyOut: specified Worked Bar Close is Out of Zone or not ...
|
|
* @param ignoreActivation: Ignore Zone Activation (Calculate from From()) ...
|
|
* @param activationStartedOut: Specified Zone Start Bar State ...
|
|
* @param activationBodyIn: Specified Zone Activation Bar State ...
|
|
* @param forPeriod: specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsWorked(
|
|
ENUM_X_DIRECTION forDir,
|
|
XOHCL &workedBar,
|
|
bool &isBodyOut,
|
|
bool ignoreActivation = false,
|
|
bool activationStartedOut = false,
|
|
bool activationBodyIn = false,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
isBodyOut = false;
|
|
workedBar.Clean();
|
|
|
|
//
|
|
result = HasDirection(forDir) &&
|
|
IsValidTwoBarZone();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
int fromIndex = -1;
|
|
if (!ignoreActivation)
|
|
{
|
|
//
|
|
XOHCL activatedBar;
|
|
bool isBodyIn = false;
|
|
bool isActivated = IsActivated(
|
|
forDir,
|
|
activatedBar,
|
|
isBodyIn,
|
|
activationStartedOut,
|
|
forPeriod //
|
|
);
|
|
|
|
//
|
|
bool isActivationPassed =
|
|
!activationBodyIn
|
|
? isActivated
|
|
: isActivated &&
|
|
isBodyIn;
|
|
if (isActivationPassed)
|
|
{
|
|
fromIndex = activatedBar.Index() - 1;
|
|
}
|
|
|
|
//
|
|
activatedBar.Clean();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
fromIndex = iBarShift(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
From() //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(fromIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = fromIndex; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
result = isInited;
|
|
if (!result)
|
|
{
|
|
//
|
|
iBar.Clean();
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isBreakedFromUpper =
|
|
//
|
|
iBar.low > Upper() ||
|
|
(iBar.low <= Upper() &&
|
|
iBar.high > Upper() &&
|
|
iBar.close > Upper())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreakedFromLower =
|
|
//
|
|
iBar.low < Lower() ||
|
|
(iBar.high >= Lower() &&
|
|
iBar.low < Lower() &&
|
|
iBar.close < Lower())
|
|
//
|
|
;
|
|
|
|
//
|
|
bool isBreaked =
|
|
isBreakedFromUpper ||
|
|
isBreakedFromLower;
|
|
if (isBreaked)
|
|
{
|
|
//
|
|
result = isBreaked &&
|
|
isBullish
|
|
? isBreakedFromUpper
|
|
: isBreakedFromLower;
|
|
if (result)
|
|
{
|
|
//
|
|
workedBar = iBar;
|
|
iBar.Clean();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
|
|
//
|
|
result = workedBar.IsValid();
|
|
if (result)
|
|
{
|
|
//
|
|
isBodyOut =
|
|
isBullish
|
|
? workedBar.IsBullish() &&
|
|
workedBar.GetUp() > Upper()
|
|
: workedBar.IsBearish() &&
|
|
workedBar.GetDown() < Lower();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check to Find Nearest Bar which Breakes Upper ...
|
|
*
|
|
* @param bar: XOHCL instance Reference, Breaker Bar ...
|
|
* @param forPeriod: ENUM_TIMEFRAMES member, Breaker Bar Detection Period, default is Zone Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool FindNearestInsideBarFromUpper(
|
|
XOHCL &bar,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int from = 1;
|
|
int to = iBarShift(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
From() //
|
|
);
|
|
|
|
//
|
|
for (int i = from; i < to; i++)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
bool isInside = iBar.low < Upper();
|
|
if (isInside)
|
|
{
|
|
//
|
|
bar = iBar;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check to Find Nearest Bar which Breakes Lower ...
|
|
*
|
|
* @param bar: XOHCL instance Reference, Breaker Bar ...
|
|
* @param forPeriod: ENUM_TIMEFRAMES member, Breaker Bar Detection Period, default is Zone Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool FindNearestInsideBarFromLower(
|
|
XOHCL &bar,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = GetPeriod();
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int from = 1;
|
|
int to = iBarShift(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
From() //
|
|
);
|
|
|
|
//
|
|
for (int i = from; i < to; i++)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
GetSymbol(),
|
|
forPeriod,
|
|
i //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
bool isInside = iBar.high > Lower();
|
|
if (isInside)
|
|
{
|
|
//
|
|
bar = iBar;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
void Clean() override
|
|
{
|
|
//
|
|
mStartBar.Clean();
|
|
mEndBar.Clean();
|
|
mUpper = 0;
|
|
mLower = 0;
|
|
mUseStartBarForUpper = false;
|
|
mType = X_POI_NONE;
|
|
}
|
|
|
|
datetime From() override
|
|
{
|
|
return mFrom;
|
|
}
|
|
|
|
datetime To() override
|
|
{
|
|
return mTo;
|
|
}
|
|
|
|
string GetTag() override
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValidTwoBarZone())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string hash = ToMD5(mStartBar.GetTag() + mSep + mEndBar.GetTag());
|
|
|
|
//
|
|
result =
|
|
//
|
|
TypeAsString() + mSep +
|
|
ToString(mStartBar.period) + mSep +
|
|
hash
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
string GetTooltip() override
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValidTwoBarZone())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
// Props ...
|
|
XOHCL mStartBar; // Start (Oldest) Bar ...
|
|
XOHCL mEndBar; // End (Newest) Bar ...
|
|
bool mUseStartBarForUpper; // Use Start Bar for Upper Calculation ...
|
|
ENUM_X_PRICE mUpperPrice; // Upper Price Selection
|
|
ENUM_X_PRICE mLowerPrice; // Lower Price Selection
|
|
|
|
/**
|
|
* Check Two Bar Zone Validation ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValidTwoBarZone()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = mStartBar.IsValid() &&
|
|
mEndBar.IsValid() &&
|
|
mStartBar.symbol == mEndBar.symbol &&
|
|
mStartBar.period == mEndBar.period &&
|
|
mStartBar.time < mEndBar.time &&
|
|
mType != X_POI_NONE &&
|
|
IsValidBoundary();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
private:
|
|
//
|
|
// Props ...
|
|
datetime mFrom;
|
|
datetime mTo;
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Swing Class ...
|
|
class XCSwing : public XCBasePOI
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCSwing()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCSwing()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param type: ENUM_XPOIS member ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
XOHCL &bar,
|
|
ENUM_XPOIS type //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid() &&
|
|
(type == X_POI_SWING_HIGH ||
|
|
type == X_POI_SWING_LOW);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
mBar = bar;
|
|
mType = type;
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Fill Bar as XOHCL struct ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool FillBar(
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bar = mBar;
|
|
result = mBar.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Time of Swing ...
|
|
*
|
|
* @return ( datetime )
|
|
*/
|
|
datetime GetTime()
|
|
{
|
|
//
|
|
datetime result = NULL;
|
|
|
|
//
|
|
if (!IsValid() || !mBar.IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = mBar.time;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
ENUM_TIMEFRAMES GetPeriod()
|
|
{
|
|
//
|
|
ENUM_TIMEFRAMES result = NULL;
|
|
|
|
//
|
|
XOHCL bar;
|
|
bool isFilled = FillBar(bar);
|
|
if (!isFilled)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = bar.period;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Swing High or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSwingHigh()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
Type() == X_POI_SWING_HIGH;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Swing Low or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSwingLow()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
Type() == X_POI_SWING_LOW;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Swing Value ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double GetValue()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
IsSwingHigh()
|
|
? mBar.high
|
|
: mBar.low;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
void Clean() override
|
|
{
|
|
//
|
|
mBar.Clean();
|
|
mType = X_POI_NONE;
|
|
}
|
|
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = mBar.IsValid() &&
|
|
(mType == X_POI_SWING_HIGH ||
|
|
mType == X_POI_SWING_LOW);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
string GetTag() override
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string hash = ToMD5(mBar.GetTag());
|
|
|
|
//
|
|
string subType = IsSwingHigh()
|
|
? "High"
|
|
: "Low";
|
|
|
|
//
|
|
result =
|
|
//
|
|
TypeAsString() + mSep +
|
|
subType + mSep +
|
|
ToString(mBar.period) + mSep +
|
|
hash
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
string GetTooltip() override
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
// Props ...
|
|
XOHCL mBar; // Swing Bar ...
|
|
|
|
//
|
|
private:
|
|
//
|
|
};
|
|
|
|
//
|
|
// Supply Zone ...
|
|
class XCSupplyZone : public XCBarZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCSupplyZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCSupplyZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param range: Integer, Detection Range ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
XOHCL &bar,
|
|
int range = 0,
|
|
bool useRangeAsStart = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = InitBarZone(
|
|
bar,
|
|
X_POI_SUPPLY_ZONE,
|
|
X_PRICE_HIGH,
|
|
X_PRICE_LOW //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
if (result &&
|
|
range > 0)
|
|
{
|
|
//
|
|
datetime time = bar.time;
|
|
int periodSeconds = PeriodSeconds(bar.period);
|
|
|
|
//
|
|
datetime from =
|
|
!useRangeAsStart
|
|
? (datetime)((int)time - (range * periodSeconds))
|
|
: time;
|
|
datetime to = (datetime)((int)time + (range * periodSeconds));
|
|
|
|
//
|
|
From(from);
|
|
To(to);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValidBarZone() &&
|
|
mType == X_POI_SUPPLY_ZONE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Demand Zone ...
|
|
class XCDemandZone : public XCBarZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCDemandZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCDemandZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param range: Integer, Detection Range ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
XOHCL &bar,
|
|
int range = 0,
|
|
bool useRangeAsStart = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = InitBarZone(
|
|
bar,
|
|
X_POI_DEMAND_ZONE,
|
|
X_PRICE_HIGH,
|
|
X_PRICE_LOW //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
if (result &&
|
|
range > 0)
|
|
{
|
|
//
|
|
datetime time = bar.time;
|
|
int periodSeconds = PeriodSeconds(bar.period);
|
|
|
|
//
|
|
datetime from =
|
|
!useRangeAsStart
|
|
? (datetime)((int)time - (range * periodSeconds))
|
|
: time;
|
|
datetime to = (datetime)((int)time + (range * periodSeconds));
|
|
|
|
//
|
|
From(from);
|
|
To(to);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValidBarZone() &&
|
|
mType == X_POI_DEMAND_ZONE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Support Zone ...
|
|
class XCSupportZone : public XCBarZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCSupportZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCSupportZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param range: Integer, Detection Range ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
XOHCL &bar,
|
|
int range = 0,
|
|
bool useRangeAsStart = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = InitBarZone(
|
|
bar,
|
|
X_POI_SUPPORT_ZONE,
|
|
X_PRICE_DOWN,
|
|
X_PRICE_LOW //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
if (result &&
|
|
range > 0)
|
|
{
|
|
//
|
|
datetime time = bar.time;
|
|
int periodSeconds = PeriodSeconds(bar.period);
|
|
|
|
//
|
|
datetime from =
|
|
!useRangeAsStart
|
|
? (datetime)((int)time - (range * periodSeconds))
|
|
: time;
|
|
datetime to = (datetime)((int)time + (range * periodSeconds));
|
|
|
|
//
|
|
From(from);
|
|
To(to);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValidBarZone() &&
|
|
mType == X_POI_SUPPORT_ZONE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Resistance Zone ...
|
|
class XCResistanceZone : public XCBarZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCResistanceZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCResistanceZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param range: Integer, Detection Range ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
XOHCL &bar,
|
|
int range = 0,
|
|
bool useRangeAsStart = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = InitBarZone(
|
|
bar,
|
|
X_POI_RESISTANCE_ZONE,
|
|
X_PRICE_HIGH,
|
|
X_PRICE_UP //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
if (result &&
|
|
range > 0)
|
|
{
|
|
//
|
|
datetime time = bar.time;
|
|
int periodSeconds = PeriodSeconds(bar.period);
|
|
|
|
//
|
|
datetime from =
|
|
!useRangeAsStart
|
|
? (datetime)((int)time - (range * periodSeconds))
|
|
: time;
|
|
datetime to = (datetime)((int)time + (range * periodSeconds));
|
|
|
|
//
|
|
From(from);
|
|
To(to);
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValidBarZone() &&
|
|
mType == X_POI_RESISTANCE_ZONE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Order Block ...
|
|
class XCOrderBlock : public XCBarZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCOrderBlock()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCOrderBlock()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
* @param dir: ENUM_X_DIRECTION member ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
XOHCL &bar,
|
|
ENUM_X_DIRECTION dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid() &&
|
|
(dir == X_DIRECTION_BULLISH ||
|
|
dir == X_DIRECTION_BEARISH);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_XPOIS mTT =
|
|
IsSpecifiedBullish(dir)
|
|
? X_POI_BULLISH_ORDERBLOCK
|
|
: X_POI_BEARISH_ORDERBLOCK;
|
|
|
|
//
|
|
result = InitBarZone(
|
|
bar,
|
|
mTT,
|
|
X_PRICE_HIGH,
|
|
X_PRICE_LOW //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Check is Bullish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBullish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
Type() == X_POI_BULLISH_ORDERBLOCK;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check is Bearish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBearish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
Type() == X_POI_BEARISH_ORDERBLOCK;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
ENUM_X_DIRECTION GetDirection()
|
|
{
|
|
//
|
|
ENUM_X_DIRECTION result = X_DIRECTION_NONE;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
IsBullish()
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValidBarZone() &&
|
|
(mType == X_POI_BULLISH_ORDERBLOCK ||
|
|
mType == X_POI_BEARISH_ORDERBLOCK);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Rejection Bar ...
|
|
class XCRejectionBar : public XCBarZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCRejectionBar()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCRejectionBar()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish =
|
|
bar.GetLowShadow() > bar.GetHighShadow();
|
|
bool isBearish =
|
|
bar.GetHighShadow() > bar.GetLowShadow();
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_PRICE upPrice = isBullish
|
|
? X_PRICE_HIGH
|
|
: X_PRICE_DOWN;
|
|
//
|
|
ENUM_X_PRICE loPrice = isBullish
|
|
? X_PRICE_UP
|
|
: X_PRICE_LOW;
|
|
|
|
//
|
|
result = InitBarZone(
|
|
bar,
|
|
X_POI_REJECTION_BAR,
|
|
upPrice,
|
|
loPrice //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Check is Bullish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBullish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
Type() == X_POI_REJECTION_BAR &&
|
|
mBar.GetLowShadow() > mBar.GetHighShadow();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check is Bearish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBearish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
Type() == X_POI_REJECTION_BAR &&
|
|
mBar.GetHighShadow() > mBar.GetLowShadow();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValidBarZone() &&
|
|
mType == X_POI_REJECTION_BAR;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Momentum Bar ...
|
|
class XCMomentumBar : public XCBarZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCMomentumBar()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCMomentumBar()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param bar: XOHCL instance ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = bar.IsBullish();
|
|
bool isBearish = bar.IsBearish();
|
|
result = isBullish ||
|
|
isBearish;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = InitBarZone(
|
|
bar,
|
|
X_POI_MOMENTUM_BAR,
|
|
X_PRICE_HIGH,
|
|
X_PRICE_LOW //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Check is Bullish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBullish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
mBar.IsBullish() &&
|
|
Type() == X_POI_MOMENTUM_BAR;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check is Bearish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBearish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
mBar.IsBearish() &&
|
|
Type() == X_POI_MOMENTUM_BAR;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValidBarZone() &&
|
|
mType == X_POI_MOMENTUM_BAR;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Fair Value Gap ...
|
|
class XCFVG : public XCTwoBarZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCFVG()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCFVG()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param startBar: XOHCL instance ...
|
|
* @param endBar: XOHCL instance ...
|
|
* @param dir: ENUM_X_DIRECTION member ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
XOHCL &startBar,
|
|
XOHCL &endBar,
|
|
ENUM_X_DIRECTION dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = endBar.IsValid() &&
|
|
startBar.IsValid() &&
|
|
(dir == X_DIRECTION_BULLISH ||
|
|
dir == X_DIRECTION_BEARISH);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isDirBullish = IsSpecifiedBullish(dir);
|
|
ENUM_XPOIS mTT =
|
|
isDirBullish
|
|
? X_POI_BULLISH_FVG
|
|
: X_POI_BEARISH_FVG;
|
|
|
|
//
|
|
ENUM_X_PRICE startPrice = isDirBullish
|
|
? X_PRICE_HIGH
|
|
: X_PRICE_LOW;
|
|
ENUM_X_PRICE endPrice = isDirBullish
|
|
? X_PRICE_LOW
|
|
: X_PRICE_HIGH;
|
|
|
|
//
|
|
result = InitTwoBarZone(
|
|
startBar,
|
|
endBar,
|
|
mTT,
|
|
startPrice,
|
|
endPrice //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Check is Bullish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBullish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
Type() == X_POI_BULLISH_FVG;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check is Bearish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBearish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
Type() == X_POI_BEARISH_FVG;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
ENUM_X_DIRECTION GetDirection()
|
|
{
|
|
//
|
|
ENUM_X_DIRECTION result = X_DIRECTION_NONE;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
IsBullish()
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValidTwoBarZone() &&
|
|
(mType == X_POI_BULLISH_FVG ||
|
|
mType == X_POI_BEARISH_FVG);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Ticks Zones ...
|
|
|
|
//
|
|
class XCTickZone : public CObject
|
|
{
|
|
//
|
|
// Public ...
|
|
public:
|
|
//
|
|
// Props ...
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
double high;
|
|
double low;
|
|
int ticks;
|
|
double percent;
|
|
|
|
//
|
|
ulong volume;
|
|
double volumePercent;
|
|
|
|
//
|
|
// Compare Two Zone With Each Other ...
|
|
virtual int Compare(
|
|
const CObject *node,
|
|
const int mode = 0 //
|
|
) const
|
|
{
|
|
//
|
|
const XCTickZone *other = (XCTickZone *)node;
|
|
|
|
//
|
|
return other.ticks - ticks;
|
|
}
|
|
|
|
//
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = high > 0 &&
|
|
low > 0 &&
|
|
high > low &&
|
|
ticks > 0 &&
|
|
percent > 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Protected ...
|
|
protected:
|
|
//
|
|
// Private ...
|
|
private:
|
|
//
|
|
};
|
|
|
|
//
|
|
class XCTicksZone : public XCTwoBarZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCTicksZone()
|
|
{
|
|
Default();
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCTicksZone()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Get Number of Ticks Levels ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int Levels()
|
|
{
|
|
return mLevels;
|
|
}
|
|
|
|
/**
|
|
* Set Number of Ticks Levels ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
void Levels(int value)
|
|
{
|
|
//
|
|
if (value < 2)
|
|
{
|
|
value = 2;
|
|
}
|
|
|
|
//
|
|
mLevels = value;
|
|
}
|
|
|
|
/**
|
|
* Apply Default Config ...
|
|
*/
|
|
virtual void Default()
|
|
{
|
|
//
|
|
Levels(10);
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @param startBar: XOHCL instance ...
|
|
* @param endBar: XOHCL instance ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
XOHCL &startBar,
|
|
XOHCL &endBar,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = endBar.IsValid() &&
|
|
startBar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (!IsSpecifiedValid(forPeriod))
|
|
{
|
|
forPeriod = endBar.period;
|
|
}
|
|
|
|
//
|
|
// Calculate Start and End Time ...
|
|
datetime from = startBar.time;
|
|
datetime to = endBar.time;
|
|
ulong fromM = ((ulong)to * 1000);
|
|
ulong toM = ((ulong)from * 1000);
|
|
|
|
//
|
|
// Symbol and Period ...
|
|
string symbol = startBar.symbol;
|
|
ENUM_TIMEFRAMES period = startBar.period;
|
|
|
|
//
|
|
// Prepare Zones Array ...
|
|
mZones.Clear();
|
|
|
|
//
|
|
// Retrieve Ticks between Times ...
|
|
SpecificClean(mTicks);
|
|
int res = CopyTicksRange(
|
|
symbol,
|
|
mTicks,
|
|
COPY_TICKS_ALL,
|
|
fromM,
|
|
toM //
|
|
);
|
|
|
|
//
|
|
// Ticks Volumes ...
|
|
int ticksVolumeCount = CopyTickVolume(
|
|
symbol,
|
|
forPeriod,
|
|
from,
|
|
to,
|
|
mTickVolumes //
|
|
);
|
|
if (IsValidSize(ticksVolumeCount))
|
|
{
|
|
//
|
|
mVolumes = 0;
|
|
for (int i = 0; i < ticksVolumeCount; i++)
|
|
{
|
|
mVolumes += mTickVolumes[i];
|
|
}
|
|
}
|
|
|
|
//
|
|
// Retrieve Highs ...
|
|
SpecificClean(mHighs);
|
|
CopyHigh(
|
|
symbol,
|
|
period,
|
|
from,
|
|
to,
|
|
mHighs //
|
|
);
|
|
|
|
//
|
|
// Retrieve Lows ...
|
|
SpecificClean(mLows);
|
|
CopyLow(
|
|
symbol,
|
|
period,
|
|
from,
|
|
to,
|
|
mLows //
|
|
);
|
|
|
|
//
|
|
// Find Highest Value in Range ...
|
|
int highIDX = ArrayMaximum(mHighs);
|
|
mRangeHigh = mHighs[highIDX];
|
|
|
|
//
|
|
// Find Lowest Value in Range ...
|
|
int lowIDX = ArrayMinimum(mLows);
|
|
mRangeLow = mLows[lowIDX];
|
|
|
|
//
|
|
datetime mTimes[];
|
|
CopyTime(
|
|
symbol,
|
|
period,
|
|
from,
|
|
to,
|
|
mTimes //
|
|
);
|
|
mRangeHighTime = mTimes[highIDX];
|
|
mRangeLowTime = mTimes[lowIDX];
|
|
|
|
//
|
|
double mRangeSize = mRangeHigh - mRangeLow;
|
|
|
|
//
|
|
// Create Zones ...
|
|
for (int i = 0; i < Levels(); i++)
|
|
{
|
|
//
|
|
// Instance a New Zone ...
|
|
XCTickZone *iZone = new XCTickZone();
|
|
|
|
//
|
|
iZone.symbol = symbol;
|
|
iZone.period = period;
|
|
|
|
//
|
|
// Calculate Each Zones High / Low based on Range ...
|
|
double iH = mRangeHigh - mRangeSize * i / Levels();
|
|
double iL = mRangeHigh - mRangeSize * (i + 1) / Levels();
|
|
|
|
//
|
|
// Set Zone High Low Properties ...
|
|
iZone.low = iL;
|
|
iZone.high = iH;
|
|
|
|
//
|
|
// Add Zone to Zone Array Objects ...
|
|
mZones.Add(iZone);
|
|
}
|
|
|
|
//
|
|
// Calculate Each Zone Ticks ...
|
|
int ticksCount = ArraySize(mTicks);
|
|
for (int i = 0; i < ticksCount; i++)
|
|
{
|
|
//
|
|
// Retrieve Tick ...
|
|
MqlTick iTick = mTicks[i];
|
|
|
|
//
|
|
// Loop through Zones ...
|
|
for (int j = 0; j < Levels(); j++)
|
|
{
|
|
//
|
|
// Rejrieve j indexed Zone Object ...
|
|
XCTickZone *jZone = mZones.At(j);
|
|
|
|
//
|
|
bool isInRange = IsTickInZoneRange(
|
|
iTick,
|
|
jZone //
|
|
);
|
|
if (isInRange)
|
|
{
|
|
//
|
|
jZone.ticks++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculating Zone Percents ...
|
|
for (int i = 0; i < Levels(); i++)
|
|
{
|
|
//
|
|
XCTickZone *iZone = mZones.At(i);
|
|
|
|
//
|
|
double percent = CalculateZoneTickPercent(iZone);
|
|
iZone.percent = percent;
|
|
}
|
|
|
|
//
|
|
// Sort Zones Based on Percents ...
|
|
mZones.Sort();
|
|
|
|
//
|
|
mUpper = mRangeHigh;
|
|
mLower = mRangeLow;
|
|
mType = X_POI_TICKS_ZONES;
|
|
mEndBar = endBar;
|
|
mStartBar = startBar;
|
|
From(endBar.time);
|
|
To(startBar.time);
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Try to Find Out PERIOD_1M times in each zone ...
|
|
datetime to1M = (datetime)((int)endBar.time + PeriodSeconds(period) - 60);
|
|
int to1MIndex = iBarShift(
|
|
symbol,
|
|
forPeriod,
|
|
to1M //
|
|
);
|
|
int from1MIndex = iBarShift(
|
|
symbol,
|
|
forPeriod,
|
|
from //
|
|
);
|
|
for (int i = from1MIndex; i > to1MIndex; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
symbol,
|
|
forPeriod,
|
|
i //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
continue;
|
|
}
|
|
ulong iVolume = iTickVolume(
|
|
symbol,
|
|
forPeriod,
|
|
i //
|
|
);
|
|
|
|
//
|
|
// Loop through Zones ...
|
|
for (int j = 0; j < Levels(); j++)
|
|
{
|
|
//
|
|
XCTickZone *jZone = mZones.At(j);
|
|
if (!jZone.IsValid())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Check iBar is Inside jZone ...
|
|
bool isIBarInside =
|
|
iBar.GetUp() < jZone.high &&
|
|
iBar.GetDown() > jZone.low;
|
|
// iBar.low < jZone.high ||
|
|
// iBar.high > jZone.low;
|
|
if (isIBarInside)
|
|
{
|
|
jZone.volume += iVolume;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculate Volume Percent ...
|
|
for (int i = 0; i < Levels(); i++)
|
|
{
|
|
//
|
|
XCTickZone *iZone = mZones.At(i);
|
|
|
|
//
|
|
if (mVolumes > 0)
|
|
{
|
|
iZone.volumePercent = (double)(iZone.volume * 100 / mVolumes);
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
/**
|
|
* Retrieve Zones Count ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int Count()
|
|
{
|
|
return mZones.Total();
|
|
}
|
|
|
|
/**
|
|
* Retrieve Specified Sorted Zones ...
|
|
*
|
|
* @param index: Integer ...
|
|
*
|
|
* @return ( XCTickZone * )
|
|
*/
|
|
XCTickZone *GetZone(int index)
|
|
{
|
|
//
|
|
if (!IsValidIndex(index))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
return mZones.At(index);
|
|
}
|
|
|
|
/**
|
|
* Calculate Liquidity Percent for Specified Direction ...
|
|
*
|
|
* @param forDirection: ENUM_X_DIRECTION member, Specified Liquidity ...
|
|
* @param price: Double, Specified Price ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double CalculateLiquidityPercent(
|
|
ENUM_X_DIRECTION forDirection,
|
|
double price //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
int count = Count();
|
|
if (price <= 0 ||
|
|
!IsValid() ||
|
|
!IsValidSize(count) ||
|
|
forDirection == X_DIRECTION_ALL ||
|
|
forDirection == X_DIRECTION_NONE)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = forDirection == X_DIRECTION_BULLISH;
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCTickZone *iZone = GetZone(i);
|
|
|
|
//
|
|
if (iZone.IsValid())
|
|
{
|
|
//
|
|
result += !isBullish &&
|
|
price > iZone.high
|
|
? iZone.percent
|
|
: isBullish &&
|
|
price < iZone.low
|
|
? iZone.percent
|
|
: 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Overrides ...
|
|
bool IsValid() override
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
IsValidFrom() &&
|
|
IsValidTwoBarZone() &&
|
|
Levels() > 0 &&
|
|
mZones.Total() == Levels() &&
|
|
mRangeHigh > 0 &&
|
|
mRangeLow > 0;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetMaxTickZone(XCTickZone *&zone)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zone = NULL;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = Count();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCTickZone *iZone = GetZone(i);
|
|
|
|
//
|
|
bool canSet =
|
|
zone == NULL
|
|
? true
|
|
: zone.ticks < iZone.ticks
|
|
? true
|
|
: false;
|
|
if (canSet)
|
|
{
|
|
zone = iZone;
|
|
}
|
|
|
|
//
|
|
ZeroMemory(iZone);
|
|
}
|
|
|
|
//
|
|
result = zone != NULL &&
|
|
zone.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetMinTickZone(XCTickZone *&zone)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zone = NULL;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = Count();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCTickZone *iZone = GetZone(i);
|
|
|
|
//
|
|
bool canSet =
|
|
zone == NULL
|
|
? true
|
|
: zone.ticks > iZone.ticks
|
|
? true
|
|
: false;
|
|
if (canSet)
|
|
{
|
|
zone = iZone;
|
|
}
|
|
|
|
//
|
|
ZeroMemory(iZone);
|
|
}
|
|
|
|
//
|
|
result = zone != NULL &&
|
|
zone.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetMaxVolumeZone(XCTickZone *&zone)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zone = NULL;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = Count();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCTickZone *iZone = GetZone(i);
|
|
|
|
//
|
|
bool canSet =
|
|
zone == NULL
|
|
? true
|
|
: zone.volume < iZone.volume
|
|
? true
|
|
: false;
|
|
if (canSet)
|
|
{
|
|
zone = iZone;
|
|
}
|
|
|
|
//
|
|
ZeroMemory(iZone);
|
|
}
|
|
|
|
//
|
|
result = zone != NULL &&
|
|
zone.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool GetMinVolumeZone(XCTickZone *&zone)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zone = NULL;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = Count();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCTickZone *iZone = GetZone(i);
|
|
|
|
//
|
|
bool canSet =
|
|
zone == NULL
|
|
? true
|
|
: zone.volume > iZone.volume
|
|
? true
|
|
: false;
|
|
if (canSet)
|
|
{
|
|
zone = iZone;
|
|
}
|
|
|
|
//
|
|
ZeroMemory(iZone);
|
|
}
|
|
|
|
//
|
|
result = zone != NULL &&
|
|
zone.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
MqlTick mTicks[];
|
|
double mHighs[];
|
|
double mLows[];
|
|
ulong mVolumes;
|
|
ulong mTickVolumes[];
|
|
double mRangeHigh;
|
|
datetime mRangeHighTime;
|
|
double mRangeLow;
|
|
datetime mRangeLowTime;
|
|
|
|
//
|
|
int mLevels; // Number of Ticks Levels ...
|
|
|
|
//
|
|
CArrayObj mZones;
|
|
|
|
/**
|
|
* Check a Tick is in a Zone rage or not ...
|
|
*
|
|
* @param tick: MqlTick instance ...
|
|
* @param zone: XCTickZone instance ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsTickInZoneRange(
|
|
MqlTick &tick,
|
|
XCTickZone *zone //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
tick.bid >= zone.low &&
|
|
tick.bid <= zone.high
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Zone Tick Percent ...
|
|
*
|
|
* @param zone: XCTickZone instance ...
|
|
* @param normalizationDigits: Integer ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double CalculateZoneTickPercent(
|
|
XCTickZone *zone,
|
|
int normalizationDigits = 2 //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (normalizationDigits < 2 || normalizationDigits > 5)
|
|
{
|
|
normalizationDigits = 2;
|
|
}
|
|
|
|
//
|
|
int ticksCount = ArraySize(mTicks);
|
|
if (ticksCount <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = (double)zone.ticks / ticksCount * 100;
|
|
result = NormalizeDouble(result, normalizationDigits);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Trading Day ...
|
|
class XCDay : public XCFromToZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCDay()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCDay()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Trading Session ...
|
|
class XCSession : public XCFromToZone
|
|
{
|
|
//
|
|
public:
|
|
//
|
|
|
|
//
|
|
// Constructor ...
|
|
void XCSession()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Deconstructor ...
|
|
void ~XCSession()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize POI ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Getter(s) / Setter(s) ...
|
|
|
|
//
|
|
// Overrides ...
|
|
|
|
//
|
|
protected:
|
|
//
|
|
|
|
//
|
|
private:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
template <typename T>
|
|
bool ToBox(
|
|
T *&source[],
|
|
XBoxZone &dest[] //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
Clean(dest);
|
|
|
|
//
|
|
int count = ArraySize(source);
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
T *item = source[i];
|
|
|
|
//
|
|
if (item != NULL)
|
|
{
|
|
//
|
|
XBoxZone iBox;
|
|
bool hasBox = ToBox(
|
|
iBox,
|
|
item //
|
|
);
|
|
|
|
//
|
|
if (hasBox)
|
|
{
|
|
//
|
|
AddRef(
|
|
iBox,
|
|
dest //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
int destCount = ArraySize(dest);
|
|
result = IsValidSize(destCount);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
int GetOldest(
|
|
T *&source[] //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int count = ArraySize(source);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone boxes[];
|
|
bool isConverted = ToBox(
|
|
source,
|
|
boxes //
|
|
);
|
|
if (!isConverted)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int boxesCount = ArraySize(boxes);
|
|
|
|
//
|
|
if (count != boxesCount)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetOldest(boxes);
|
|
|
|
//
|
|
Clean(boxes);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
int GetYoungest(
|
|
T *&source[] //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int count = ArraySize(source);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone boxes[];
|
|
bool isConverted = ToBox(
|
|
source,
|
|
boxes //
|
|
);
|
|
if (!isConverted)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int boxesCount = ArraySize(boxes);
|
|
|
|
//
|
|
if (count != boxesCount)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetYoungest(boxes);
|
|
|
|
//
|
|
Clean(boxes);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
int GetLowest(
|
|
T *&source[] //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int count = ArraySize(source);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone boxes[];
|
|
bool isConverted = ToBox(
|
|
source,
|
|
boxes //
|
|
);
|
|
if (!isConverted)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int boxesCount = ArraySize(boxes);
|
|
|
|
//
|
|
if (count != boxesCount)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetLowest(boxes);
|
|
|
|
//
|
|
Clean(boxes);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
int GetHighest(
|
|
T *&source[] //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int count = ArraySize(source);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone boxes[];
|
|
bool isConverted = ToBox(
|
|
source,
|
|
boxes //
|
|
);
|
|
if (!isConverted)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int boxesCount = ArraySize(boxes);
|
|
|
|
//
|
|
if (count != boxesCount)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = GetHighest(boxes);
|
|
|
|
//
|
|
Clean(boxes);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
bool IsSame(
|
|
T *source,
|
|
T *dest //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XBoxZone sourceBox;
|
|
result = ToBox(
|
|
sourceBox,
|
|
source //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone destBox;
|
|
result = ToBox(
|
|
destBox,
|
|
dest //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = sourceBox.IsSameAs(destBox);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
bool IsBelow(
|
|
T *source,
|
|
T *dest,
|
|
bool ignoreInside = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XBoxZone sourceBox;
|
|
result = ToBox(
|
|
sourceBox,
|
|
source //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone destBox;
|
|
result = ToBox(
|
|
destBox,
|
|
dest //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsBoxBelow(
|
|
sourceBox,
|
|
destBox,
|
|
ignoreInside //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
bool IsAbove(
|
|
T *source,
|
|
T *dest,
|
|
bool ignoreInside = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XBoxZone sourceBox;
|
|
result = ToBox(
|
|
sourceBox,
|
|
source //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone destBox;
|
|
result = ToBox(
|
|
destBox,
|
|
dest //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsBoxAbove(
|
|
sourceBox,
|
|
destBox,
|
|
ignoreInside //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
bool IsInside(
|
|
T *source,
|
|
T *dest //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XBoxZone sourceBox;
|
|
result = ToBox(
|
|
sourceBox,
|
|
source //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone destBox;
|
|
result = ToBox(
|
|
destBox,
|
|
dest //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsBoxInside(
|
|
sourceBox,
|
|
destBox //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
bool IsInsideOr(
|
|
T *source,
|
|
T *dest //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XBoxZone sourceBox;
|
|
result = ToBox(
|
|
sourceBox,
|
|
source //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone destBox;
|
|
result = ToBox(
|
|
destBox,
|
|
dest //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsBoxInsideOr(
|
|
sourceBox,
|
|
destBox //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
bool FindIndex(
|
|
int &index,
|
|
T *item,
|
|
T *&items[] //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
XBoxZone itemBox;
|
|
result = ToBox(
|
|
itemBox,
|
|
item //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XBoxZone itemsBox[];
|
|
result = ToBox(
|
|
items,
|
|
itemsBox //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = FindBoxIndex(
|
|
index,
|
|
itemBox,
|
|
itemsBox //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
bool IsInside(
|
|
double value,
|
|
T *source //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XBoxZone sourceBox;
|
|
result = ToBox(
|
|
sourceBox,
|
|
source //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsInsideBox(
|
|
value,
|
|
sourceBox //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
bool IsAbove(
|
|
double value,
|
|
T *source //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XBoxZone sourceBox;
|
|
result = ToBox(
|
|
sourceBox,
|
|
source //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsAboveBox(
|
|
value,
|
|
sourceBox //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
bool IsBelow(
|
|
double value,
|
|
T *source //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
XBoxZone sourceBox;
|
|
result = ToBox(
|
|
sourceBox,
|
|
source //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = IsBelowBox(
|
|
value,
|
|
sourceBox //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
template <typename T>
|
|
void SortZones(
|
|
T *&source[],
|
|
ENUM_X_DIRECTION forDir,
|
|
bool ignoreInside = true //
|
|
)
|
|
{
|
|
//
|
|
int idx = -1;
|
|
int count = 0;
|
|
bool has = false;
|
|
|
|
//
|
|
has = HasDirection(forDir);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
count = ArraySize(source);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
T *tmpItems[];
|
|
T *last = NULL;
|
|
bool hasLast = false;
|
|
while (HasChild(source))
|
|
{
|
|
//
|
|
if (!hasLast)
|
|
{
|
|
//
|
|
idx = GetOldest(source);
|
|
hasLast = IsValidIndex(idx);
|
|
if (hasLast)
|
|
{
|
|
//
|
|
last = source[idx];
|
|
ArrayRemove(
|
|
source,
|
|
idx,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
Add(
|
|
last,
|
|
tmpItems //
|
|
);
|
|
}
|
|
|
|
//
|
|
count = ArraySize(source);
|
|
has = IsValidSize(count);
|
|
if (!has)
|
|
{
|
|
//
|
|
ZeroMemory(last);
|
|
break;
|
|
}
|
|
}
|
|
if (!hasLast)
|
|
{
|
|
//
|
|
ZeroMemory(last);
|
|
break;
|
|
}
|
|
|
|
//
|
|
T *item = NULL;
|
|
idx = GetOldest(source);
|
|
has = IsValidIndex(idx);
|
|
if (!has)
|
|
{
|
|
//
|
|
ZeroMemory(last);
|
|
ZeroMemory(item);
|
|
break;
|
|
}
|
|
item = source[idx];
|
|
ArrayRemove(
|
|
source,
|
|
idx,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
bool isAbove = IsAbove(
|
|
item,
|
|
last,
|
|
ignoreInside //
|
|
);
|
|
|
|
//
|
|
bool isBelow = IsBelow(
|
|
item,
|
|
last,
|
|
ignoreInside //
|
|
);
|
|
|
|
//
|
|
has =
|
|
isBullish
|
|
? isAbove
|
|
: isBelow;
|
|
if (has)
|
|
{
|
|
//
|
|
Add(
|
|
item,
|
|
tmpItems //
|
|
);
|
|
|
|
//
|
|
last = item;
|
|
hasLast = item != NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
Clean(source);
|
|
Copy(
|
|
tmpItems,
|
|
source //
|
|
);
|
|
|
|
//
|
|
Clean(tmpItems);
|
|
}
|
|
|
|
/**
|
|
* Extract all Zones Which provided bar is Inside it ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
template <typename T>
|
|
int ExtractInsideZones(
|
|
XOHCL &bar, // Bar ...
|
|
T *&zones[], // Source of Zones ...
|
|
T *&dest[] // Dest (all inside Zones) ...
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(dest);
|
|
|
|
//
|
|
int count = ArraySize(zones);
|
|
bool isValid = bar.IsValid() &&
|
|
IsValidSize(count);
|
|
if (!isValid)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
T *iZone = zones[i];
|
|
|
|
//
|
|
bool isHighInside = IsInside(
|
|
bar.high,
|
|
iZone //
|
|
);
|
|
|
|
//
|
|
bool isLowInside = IsInside(
|
|
bar.low,
|
|
iZone //
|
|
);
|
|
|
|
//
|
|
bool isInside =
|
|
isLowInside &&
|
|
isHighInside;
|
|
|
|
//
|
|
if (isInside)
|
|
{
|
|
//
|
|
Add(
|
|
iZone,
|
|
dest //
|
|
);
|
|
}
|
|
|
|
//
|
|
ZeroMemory(iZone);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(dest);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Add Specific Item into a Collection Reference only if it's not Exists ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
template <typename T>
|
|
bool AddIfNotExists(
|
|
T *item,
|
|
T *&items[] //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = item != NULL;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int before = ArraySize(items);
|
|
|
|
//
|
|
int idx = FindIndex(
|
|
item,
|
|
items //
|
|
);
|
|
bool has = IsValidIndex(idx);
|
|
result = !has;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
Add(
|
|
item,
|
|
items //
|
|
);
|
|
|
|
//
|
|
int after = ArraySize(items);
|
|
|
|
//
|
|
result = after > before;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Add items Collection reference Members into source Collection only if it's not Exists ...alignas
|
|
* @return ( int )
|
|
*/
|
|
template <typename T>
|
|
int AddIfNotExists(
|
|
T *&items[],
|
|
T *&sources[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
bool has = HasChild(items);
|
|
if (!has)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int before = ArraySize(sources);
|
|
|
|
//
|
|
int count = ArraySize(items);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
has = AddIfNotExists(
|
|
items[i],
|
|
sources //
|
|
);
|
|
}
|
|
|
|
//
|
|
int after = ArraySize(sources);
|
|
|
|
//
|
|
result = after > before;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Update to Time of Specifiex Collection ...
|
|
*
|
|
* @param items: XOBFVG instance Collection ...
|
|
* @param value: datetime ...
|
|
*/
|
|
template <typename T>
|
|
void SpecifiedUpdateTo(
|
|
T *&items[],
|
|
datetime value = NULL //
|
|
)
|
|
{
|
|
//
|
|
value = NormalizeTime(value);
|
|
|
|
//
|
|
int count = ArraySize(items);
|
|
bool has = HasChild(items);
|
|
if (!has)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
items[i].To(value);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Check a Box is Used or not ...
|
|
*
|
|
* @param box: XBoxZone instance Reference ...
|
|
* @param fromIndex: int ...
|
|
* @param toIndex: int
|
|
* @param forPeriod: Specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBoxUsed(
|
|
XBoxZone &box,
|
|
int fromIndex,
|
|
int toIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (toIndex < 0)
|
|
{
|
|
toIndex = 0;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
box.IsValid() &&
|
|
fromIndex > 0 &&
|
|
fromIndex > toIndex
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = box.period;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION forDir = box.dir;
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
bool isTouched = false;
|
|
for (int i = fromIndex; i >= toIndex; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
box.symbol,
|
|
forPeriod,
|
|
i //
|
|
);
|
|
|
|
//
|
|
isTouched =
|
|
isInited &&
|
|
(isBullish
|
|
? iBar.low > box.upper
|
|
: iBar.high < box.lower);
|
|
if (!isTouched)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = isTouched;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Validate Box ...
|
|
*
|
|
* @param box: XBoxZone instance ...
|
|
* @param barIndex: int, Current Bar Index ...
|
|
* @param forPeriod: Testing Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBoxValid(
|
|
XBoxZone &box,
|
|
int barIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = box.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = box.period;
|
|
}
|
|
|
|
//
|
|
int toIndex = iBarShift(
|
|
box.symbol,
|
|
forPeriod,
|
|
box.to //
|
|
);
|
|
result = IsValidIndex(toIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL iBar;
|
|
bool isBullish = box.IsBullish();
|
|
for (int i = barIndex; i < toIndex; i++)
|
|
{
|
|
//
|
|
result = iBar.Init(
|
|
box.symbol,
|
|
forPeriod,
|
|
i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result =
|
|
isBullish
|
|
? iBar.low > box.upper
|
|
: iBar.high < box.lower;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Box Breaked ...
|
|
*
|
|
* @param box: XBoxZone instance ...
|
|
* @param barIndex: int, Current Bar Index ...
|
|
* @param forPeriod: Testing Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBoxBreaked(
|
|
XBoxZone &box,
|
|
int barIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = box.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (barIndex < 0)
|
|
{
|
|
barIndex = 0;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = box.period;
|
|
}
|
|
|
|
//
|
|
int toIndex = iBarShift(
|
|
box.symbol,
|
|
forPeriod,
|
|
box.to //
|
|
);
|
|
result = IsValidIndex(toIndex);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL iBar;
|
|
bool isBullish = box.IsBullish();
|
|
for (int i = barIndex; i < toIndex; i++)
|
|
{
|
|
//
|
|
result = iBar.Init(
|
|
box.symbol,
|
|
forPeriod,
|
|
i //
|
|
);
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
result =
|
|
isBullish
|
|
? iBar.high < box.lower
|
|
: iBar.low > box.upper;
|
|
if (!result)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a Box is Breaked or not ...
|
|
*
|
|
* @param box: XBoxZone instance Reference ...
|
|
* @param fromIndex: int ...
|
|
* @param toIndex: int
|
|
* @param forPeriod: Specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBoxBreaked(
|
|
XBoxZone &box,
|
|
int fromIndex,
|
|
int toIndex = 0,
|
|
ENUM_TIMEFRAMES forPeriod = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
if (toIndex < 0)
|
|
{
|
|
toIndex = 0;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
box.IsValid() &&
|
|
fromIndex > 0 &&
|
|
fromIndex > toIndex
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (!IsValid(forPeriod))
|
|
{
|
|
forPeriod = box.period;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION forDir = box.dir;
|
|
bool isBullish = IsBullish(forDir);
|
|
|
|
//
|
|
bool isBreaked = false;
|
|
for (int i = fromIndex; i >= toIndex; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
box.symbol,
|
|
forPeriod,
|
|
i //
|
|
);
|
|
|
|
//
|
|
isBreaked =
|
|
isInited &&
|
|
(isBullish
|
|
? iBar.high <= box.lower
|
|
: iBar.low >= box.upper);
|
|
if (!isBreaked)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
iBar.Clean();
|
|
break;
|
|
}
|
|
|
|
//
|
|
result = isBreaked;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check a BaxHas Valid Place for Specified Bar ...
|
|
*
|
|
* @param bar: XOHCL instance reference, Specified Bar ...
|
|
* #param box: XBoxZone instance reference, Specified Box ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBoxPlaceValidForBar(
|
|
XOHCL &bar,
|
|
XBoxZone &box //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = bar.IsValid() &&
|
|
box.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
box.IsBullish()
|
|
? bar.low > box.upper
|
|
: bar.high < box.upper;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
|
|
/**
|
|
* Check Source Box is Below Dest ...
|
|
*
|
|
* @param source: XBoxZone instance Reference ...
|
|
* @param dest: XBoxZone instance Reference ...
|
|
* @param ignoreInside: bool ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBoxBelow(
|
|
XBoxZone &source,
|
|
XBoxZone &dest,
|
|
bool ignoreInside = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = source.IsValid() &&
|
|
dest.IsValid() &&
|
|
!source.IsSameAs(dest);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (!ignoreInside)
|
|
{
|
|
result = source.upper < dest.lower;
|
|
}
|
|
else
|
|
{
|
|
result = (source.upper < dest.lower ||
|
|
source.upper >= dest.upper) &&
|
|
source.lower < dest.lower;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Source Box is Above Dest ...
|
|
*
|
|
* @param source: XBoxZone instance Reference ...
|
|
* @param dest: XBoxZone instance Reference ...
|
|
* @param ignoreInside: bool ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBoxAbove(
|
|
XBoxZone &source,
|
|
XBoxZone &dest,
|
|
bool ignoreInside = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = source.IsValid() &&
|
|
dest.IsValid() &&
|
|
!source.IsSameAs(dest);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
if (!ignoreInside)
|
|
{
|
|
result = source.lower > dest.upper;
|
|
}
|
|
else
|
|
{
|
|
result = (source.lower > dest.upper ||
|
|
source.lower <= dest.upper) &&
|
|
source.upper > dest.upper;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Source Box is Inside Dest ...
|
|
*
|
|
* @param source: XBoxZone instance Reference ...
|
|
* @param dest: XBoxZone instance Reference ...
|
|
* @param forceSideOut: bool, force check Box has One Side Out ...
|
|
* @param ignoreSideOut: bool, Accept if source Box one Side is out of Dest Box ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBoxInside(
|
|
XBoxZone &source,
|
|
XBoxZone &dest,
|
|
bool forceSideOut = false, //
|
|
bool ignoreSideOut = true //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = source.IsValid() &&
|
|
dest.IsValid() &&
|
|
!source.IsSameAs(dest);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(dest.dir);
|
|
|
|
//
|
|
if (!forceSideOut)
|
|
{
|
|
//
|
|
if (ignoreSideOut)
|
|
{
|
|
//
|
|
result = source.lower >= dest.lower &&
|
|
source.upper <= dest.upper;
|
|
}
|
|
else
|
|
{
|
|
result = source.lower >= dest.lower ||
|
|
source.upper <= dest.upper;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
bool hasSideIn =
|
|
isBullish
|
|
? source.lower >= dest.lower
|
|
: source.upper <= dest.upper;
|
|
bool hasSideOut =
|
|
isBullish
|
|
? source.upper >= dest.upper
|
|
: source.lower <= dest.lower;
|
|
result =
|
|
hasSideIn &&
|
|
hasSideOut;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect source BoX is Inside Dest Box or Have a Side Out on it ...
|
|
*
|
|
* @param source: XBoxZone instance, source box which checks by dest ...
|
|
* @param dest: XBoxZone instance, dest Box which compares source with it ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBoxInsideOr(
|
|
XBoxZone &source,
|
|
XBoxZone &dest,
|
|
bool forceInside = false //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = source.IsValid() &&
|
|
dest.IsValid() &&
|
|
!source.IsSameAs(dest);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isInside =
|
|
source.upper <= dest.upper &&
|
|
source.upper >= dest.lower &&
|
|
source.lower >= dest.lower &&
|
|
source.lower <= dest.upper;
|
|
bool isUpperInside =
|
|
source.upper <= dest.upper &&
|
|
source.upper >= dest.lower;
|
|
bool isLowerInside =
|
|
source.lower >= dest.lower &&
|
|
source.lower <= dest.upper;
|
|
|
|
//
|
|
result =
|
|
forceInside
|
|
? isInside
|
|
: (isInside ||
|
|
isLowerInside ||
|
|
isUpperInside);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Value is Inside Specified Box ...
|
|
*
|
|
* @param value: double ...
|
|
* @param box: XCBozZone instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsInsideBox(
|
|
double value,
|
|
XBoxZone &box //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = value > 0 &&
|
|
box.IsValid() &&
|
|
value <= box.upper &&
|
|
value >= box.lower;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Bar is Inside Specified Box ...
|
|
*
|
|
* @param bar: XOHCL instance reference, Specified Bar ...
|
|
* @param box: XCBozZone instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsInsideBox(
|
|
XOHCL &bar,
|
|
XBoxZone &box //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
// Validate Args ...
|
|
result = bar.IsValid() &&
|
|
box.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
bar.close <= box.upper &&
|
|
bar.close >= box.lower;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Value is Above Specified Box ...
|
|
*
|
|
* @param value: double ...
|
|
* @param box: XCBozZone instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsAboveBox(
|
|
double value,
|
|
XBoxZone &box //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = value > 0 &&
|
|
box.IsValid() &&
|
|
value > box.upper;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Value is Below Specified Box ...
|
|
*
|
|
* @param value: double ...
|
|
* @param box: XCBozZone instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBelowBox(
|
|
double value,
|
|
XBoxZone &box //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = value > 0 &&
|
|
box.IsValid() &&
|
|
value < box.lower;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Find an Inside Box of source in a Collection ...
|
|
*
|
|
* @param index: int, Founded Index ...
|
|
* @param source: XBoxZone instance ...
|
|
* @param dest: XBoxZone instance Collection ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasInsideBox(
|
|
int &index,
|
|
XBoxZone &source,
|
|
XBoxZone &dest[] //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
index = -1;
|
|
|
|
//
|
|
result = source.IsValid() &&
|
|
HasChild(dest);
|
|
|
|
//
|
|
int count = ArraySize(dest);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XBoxZone iBox = dest[i];
|
|
|
|
//
|
|
bool isInside = !iBox.IsSameAs(source) &&
|
|
IsBoxInsideOr(
|
|
iBox,
|
|
source //
|
|
);
|
|
if (isInside)
|
|
{
|
|
//
|
|
index = i;
|
|
iBox.Clean();
|
|
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
iBox.Clean();
|
|
}
|
|
|
|
//
|
|
result = IsValidIndex(index);
|
|
|
|
//
|
|
return result;
|
|
}
|