9751 lines
177 KiB
Plaintext
9751 lines
177 KiB
Plaintext
///////////////////////////////////////////////////////
|
|
//
|
|
// SaherElm IT Center MQL5 Seriallize Library
|
|
// ---------------------------------------
|
|
// Name: XPOILib
|
|
// Description: All models related to POIs ...
|
|
//
|
|
//
|
|
// Maintainer:
|
|
// ------------
|
|
// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com)
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// Global Properties ...
|
|
#property library
|
|
#property copyright "Copyright `023, SaherElm IT Center"
|
|
#property link "https://www.saherelm.ir"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//
|
|
// Imports ...
|
|
#include "../Classes/x-saherelm.base.class.mq5"
|
|
#include <Arrays/ArrayObj.mqh>
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// Definitions ...
|
|
|
|
//
|
|
// 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 ...
|
|
};
|
|
|
|
//
|
|
// Event Types ...
|
|
enum ENUM_XPOI_EVENTS
|
|
{
|
|
//
|
|
// 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ّ ...
|
|
};
|
|
|
|
//
|
|
// Forext Sessions ...
|
|
enum ENUM_XSESSION
|
|
{
|
|
X_TOKYO,
|
|
X_SYDNEY,
|
|
X_LONDON,
|
|
X_NEW_YORK,
|
|
X_FRANKFORT,
|
|
};
|
|
|
|
//
|
|
// 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:
|
|
//
|
|
};
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// 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,
|
|
bool useStartBarForUpper,
|
|
ENUM_X_PRICE upperPrice,
|
|
ENUM_X_PRICE lowerPrice //
|
|
)
|
|
{
|
|
//
|
|
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;
|
|
mUpperPrice = upperPrice;
|
|
mLowerPrice = lowerPrice;
|
|
mUseStartBarForUpper = useStartBarForUpper;
|
|
|
|
mUpper =
|
|
useStartBarForUpper
|
|
? startBar.GetPrice(upperPrice)
|
|
: endBar.GetPrice(upperPrice);
|
|
mLower =
|
|
useStartBarForUpper
|
|
? endBar.GetPrice(lowerPrice)
|
|
: startBar.GetPrice(lowerPrice);
|
|
|
|
//
|
|
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;
|
|
}
|
|
|
|
//
|
|
// 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 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 = (datetime)((int)time - (range * periodSeconds));
|
|
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 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 = (datetime)((int)time - (range * periodSeconds));
|
|
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 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 = (datetime)((int)time - (range * periodSeconds));
|
|
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 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 = (datetime)((int)time - (range * periodSeconds));
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Detect Order Blocks Breaker Bar ...
|
|
*
|
|
* @param breakerBar: XOHCL instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool DetectBreakerBar(XOHCL &breakerBar)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
breakerBar.Clean();
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL fromBar;
|
|
result = FillBar(fromBar);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int fromIndex = fromBar.Index();
|
|
result = fromIndex > 0;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish();
|
|
ENUM_X_DIRECTION dir =
|
|
isBullish
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
double value =
|
|
isBullish
|
|
? Upper()
|
|
: Lower();
|
|
|
|
//
|
|
for (int i = fromIndex - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
fromBar.symbol,
|
|
fromBar.period,
|
|
i //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
isInited = IsBarBreak(
|
|
value,
|
|
dir,
|
|
iBar //
|
|
);
|
|
if (isInited)
|
|
{
|
|
//
|
|
breakerBar = iBar;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = breakerBar.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Order Block is Hunted or not ...
|
|
*
|
|
* @param huntedBar: XOHCL instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsHunted(XOHCL &huntedBar)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
huntedBar.Clean();
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL breakerBar;
|
|
result = DetectBreakerBar(breakerBar);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish();
|
|
|
|
//
|
|
int breakerIndex = breakerBar.Index();
|
|
for (int i = breakerIndex - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
result = iBar.Init(
|
|
breakerBar.symbol,
|
|
breakerBar.period,
|
|
i //
|
|
);
|
|
|
|
//
|
|
double price =
|
|
isBullish
|
|
? iBar.low
|
|
: iBar.high;
|
|
|
|
//
|
|
result = IsPriceInsideZone(
|
|
price,
|
|
Upper(),
|
|
Lower() //
|
|
);
|
|
if (result)
|
|
{
|
|
//
|
|
huntedBar = iBar;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = huntedBar.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Order Block Validation ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValidOrderBlock()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL breakerBar;
|
|
result = DetectBreakerBar(breakerBar);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
int breakerBarIndex = breakerBar.Index();
|
|
|
|
//
|
|
XOHCL huntedBar;
|
|
bool isHunted = IsHunted(huntedBar);
|
|
result = !isHunted;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish();
|
|
|
|
//
|
|
for (int i = breakerBarIndex - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
result = iBar.Init(
|
|
breakerBar.symbol,
|
|
breakerBar.period,
|
|
i //
|
|
);
|
|
if (!result)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
double price =
|
|
isBullish
|
|
? iBar.low
|
|
: iBar.high;
|
|
|
|
//
|
|
result =
|
|
isBullish
|
|
? price > Upper()
|
|
: price < Lower();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
//
|
|
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;
|
|
|
|
//
|
|
bool useFistForUpper = isDirBullish
|
|
? false
|
|
: true;
|
|
ENUM_X_PRICE upPrice = isDirBullish
|
|
? X_PRICE_LOW
|
|
: X_PRICE_HIGH;
|
|
ENUM_X_PRICE loPrice = isDirBullish
|
|
? X_PRICE_HIGH
|
|
: X_PRICE_LOW;
|
|
|
|
//
|
|
result = InitTwoBarZone(
|
|
startBar,
|
|
endBar,
|
|
mTT,
|
|
useFistForUpper,
|
|
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_BULLISH_FVG;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check is Bearish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBearish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
Type() == X_POI_BEARISH_FVG;
|
|
|
|
//
|
|
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 //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = endBar.IsValid() &&
|
|
startBar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Calculate Start and End Time ...
|
|
datetime from = startBar.time;
|
|
datetime to = endBar.time;
|
|
ulong fromM = ((ulong)startBar.time * 1000);
|
|
ulong toM = ((ulong)endBar.time * 1000);
|
|
|
|
//
|
|
// Symbol and Period ...
|
|
string symbol = startBar.symbol;
|
|
ENUM_TIMEFRAMES period = startBar.period;
|
|
|
|
//
|
|
// Prepare Zones Array ...
|
|
mZones.Clear();
|
|
|
|
//
|
|
// Retrieve Ticks between Times ...
|
|
SpecificClean(mTicks);
|
|
CopyTicksRange(
|
|
symbol,
|
|
mTicks,
|
|
COPY_TICKS_ALL,
|
|
fromM,
|
|
toM //
|
|
);
|
|
|
|
//
|
|
// Ticks Volumes ...
|
|
int ticksVolumeCount = CopyTickVolume(
|
|
symbol,
|
|
PERIOD_M1,
|
|
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(startBar.time);
|
|
To(endBar.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,
|
|
PERIOD_M1,
|
|
to1M //
|
|
);
|
|
int from1MIndex = iBarShift(
|
|
symbol,
|
|
PERIOD_M1,
|
|
from //
|
|
);
|
|
for (int i = from1MIndex; i > to1MIndex; i--)
|
|
{
|
|
//
|
|
XOHCL iBar;
|
|
bool isInited = iBar.Init(
|
|
symbol,
|
|
PERIOD_M1,
|
|
i //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
continue;
|
|
}
|
|
ulong iVolume = iTickVolume(
|
|
symbol,
|
|
PERIOD_M1,
|
|
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);
|
|
|
|
//
|
|
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;
|
|
}
|
|
|
|
//
|
|
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:
|
|
//
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
//
|
|
// Model Exists Founded POIs ...
|
|
struct XPOIState
|
|
{
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
datetime time;
|
|
|
|
//
|
|
XCTicksZone *ticksZone; // Ticks Zone ...
|
|
|
|
//
|
|
XCSwing *swingHighs[]; // Holds Founded Swing Highs ...
|
|
XCSwing *swingLows[]; // Holds Founded Swing Lows ...
|
|
XCMomentumBar *bullishMomentumBars[]; // Holds Founded Bullish Momentum Bars ...
|
|
XCMomentumBar *bearishMomentumBars[]; // Holds Founded Bearish Momentum Bars ...
|
|
XCRejectionBar *bullishRejectionBars[]; // Holds Founded Bullish Rejection Bars ...
|
|
XCRejectionBar *bearishRejectionBars[]; // Holds Founded Bearish Rejection Bars ...
|
|
XCSupportZone *supportZones[]; // Holds Founded Support Zones ...
|
|
XCResistanceZone *resistanceZones[]; // Holds Founded Resistance Zones ...
|
|
XCSupplyZone *supplyZones[]; // Holds Founded Supply Zones ...
|
|
XCDemandZone *demandZones[]; // Holds Founded Demand Zones ...
|
|
XCOrderBlock *bullishOrderBlocks[]; // Holds Founded Bullish Order Blocks ...
|
|
XCOrderBlock *bearishOrderBlocks[]; // Holds Founded Bearish Order Blocks ...
|
|
XCFVG *bullishFairValueGaps[]; // Holds Founded Bullish Fair Value Gaps ...
|
|
XCFVG *bearishFairValueGaps[]; // Holds Founded Bearish Fair Value Gaps ...
|
|
|
|
//
|
|
// Constructor ...
|
|
void XPOIState()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Actions ...
|
|
|
|
/**
|
|
* Cleanup all props ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
symbol = NULL;
|
|
period = NULL;
|
|
time = NULL;
|
|
|
|
//
|
|
ticksZone = NULL;
|
|
|
|
//
|
|
Clean(swingHighs);
|
|
Clean(swingLows);
|
|
Clean(bullishMomentumBars);
|
|
Clean(bearishMomentumBars);
|
|
Clean(bullishRejectionBars);
|
|
Clean(bearishRejectionBars);
|
|
Clean(supportZones);
|
|
Clean(resistanceZones);
|
|
Clean(supplyZones);
|
|
Clean(demandZones);
|
|
Clean(bullishOrderBlocks);
|
|
Clean(bearishOrderBlocks);
|
|
Clean(bullishFairValueGaps);
|
|
Clean(bearishFairValueGaps);
|
|
}
|
|
|
|
/**
|
|
* Validate ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
IsSpecifiedValid(symbol) &&
|
|
IsSpecifiedValid(period) &&
|
|
IsSpecifiedValid(time);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check State has Childs or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasChild()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValidSize(CountSwingHighs()) ||
|
|
IsValidSize(CountSwingLows()) ||
|
|
IsValidSize(CountBullishMomentumBars()) ||
|
|
IsValidSize(CountBearishMomentumBars()) ||
|
|
IsValidSize(CountBullishRejectionBars()) ||
|
|
IsValidSize(CountBearishRejectionBars()) ||
|
|
IsValidSize(CountSupportZones()) ||
|
|
IsValidSize(CountResistanceZones()) ||
|
|
IsValidSize(CountSupplyZones()) ||
|
|
IsValidSize(CountDemandZones()) ||
|
|
IsValidSize(CountBullishOrderBlocks()) ||
|
|
IsValidSize(CountBearishOrderBlocks()) ||
|
|
IsValidSize(CountBullishFairValueGaps()) ||
|
|
IsValidSize(CountBearishFairValueGaps())
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Fill Dest State by Current State's Data ...
|
|
*
|
|
* @param dest: XPOIState instance, reference to specified dest ...
|
|
*
|
|
*/
|
|
void Fill(XPOIState &dest)
|
|
{
|
|
//
|
|
if (!IsValid() ||
|
|
!HasChild())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
dest.symbol = symbol;
|
|
dest.period = period;
|
|
dest.time = time;
|
|
|
|
//
|
|
Copy(
|
|
swingHighs,
|
|
dest.swingHighs,
|
|
false //
|
|
);
|
|
Copy(
|
|
swingLows,
|
|
dest.swingLows,
|
|
false //
|
|
);
|
|
Copy(
|
|
bullishMomentumBars,
|
|
dest.bullishMomentumBars,
|
|
false //
|
|
);
|
|
Copy(
|
|
bearishMomentumBars,
|
|
dest.bearishMomentumBars,
|
|
false //
|
|
);
|
|
Copy(
|
|
bullishRejectionBars,
|
|
dest.bullishRejectionBars,
|
|
false //
|
|
);
|
|
Copy(
|
|
bearishRejectionBars,
|
|
dest.bearishRejectionBars,
|
|
false //
|
|
);
|
|
Copy(
|
|
supportZones,
|
|
dest.supportZones,
|
|
false //
|
|
);
|
|
Copy(
|
|
resistanceZones,
|
|
dest.resistanceZones,
|
|
false //
|
|
);
|
|
Copy(
|
|
supplyZones,
|
|
dest.supplyZones,
|
|
false //
|
|
);
|
|
Copy(
|
|
demandZones,
|
|
dest.demandZones,
|
|
false //
|
|
);
|
|
Copy(
|
|
bullishOrderBlocks,
|
|
dest.bullishOrderBlocks,
|
|
false //
|
|
);
|
|
Copy(
|
|
bearishOrderBlocks,
|
|
dest.bearishOrderBlocks,
|
|
false //
|
|
);
|
|
Copy(
|
|
bullishFairValueGaps,
|
|
dest.bullishFairValueGaps,
|
|
false //
|
|
);
|
|
Copy(
|
|
bearishFairValueGaps,
|
|
dest.bearishFairValueGaps,
|
|
false //
|
|
);
|
|
|
|
//
|
|
}
|
|
|
|
/**
|
|
* 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 = 0 //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid() ||
|
|
ticksZone == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Normalize Price for Actions ...
|
|
if (price <= 0)
|
|
{
|
|
//
|
|
MqlTick mTick;
|
|
bool isTickRetrieved = GetTick(
|
|
symbol,
|
|
mTick //
|
|
);
|
|
if (isTickRetrieved)
|
|
{
|
|
price = mTick.bid;
|
|
}
|
|
}
|
|
|
|
//
|
|
result = ticksZone
|
|
.CalculateLiquidityPercent(
|
|
forDirection,
|
|
price //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Counters ...
|
|
|
|
//
|
|
int CountSwingHighs()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(swingHighs);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountSwingLows()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(swingLows);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBullishMomentumBars()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bullishMomentumBars);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBearishMomentumBars()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bearishMomentumBars);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBullishRejectionBars()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bullishRejectionBars);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBearishRejectionBars()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bearishRejectionBars);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountSupportZones()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(supportZones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountResistanceZones()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(resistanceZones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountSupplyZones()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(supplyZones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountDemandZones()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(demandZones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBullishOrderBlocks()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bullishOrderBlocks);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBearishOrderBlocks()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bearishOrderBlocks);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBullishFairValueGaps()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bullishFairValueGaps);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBearishFairValueGaps()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bearishFairValueGaps);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
// Pivot Types ...
|
|
enum ENUM_XPV_PIVOTS
|
|
{
|
|
XPV_NONE,
|
|
XPV_PEAK,
|
|
XPV_VALE,
|
|
};
|
|
|
|
//
|
|
// Model a Pivot structure ...
|
|
struct XPVPivot
|
|
{
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
double upper;
|
|
double lower;
|
|
|
|
//
|
|
datetime from;
|
|
datetime to;
|
|
|
|
//
|
|
int repetition;
|
|
|
|
//
|
|
ENUM_XPV_PIVOTS type;
|
|
|
|
//
|
|
// Combined all States ...
|
|
XPOIState state;
|
|
|
|
//
|
|
XPVPivot()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
upper = 0;
|
|
lower = 0;
|
|
|
|
//
|
|
to = NULL;
|
|
from = NULL;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
|
|
//
|
|
repetition = 0;
|
|
|
|
//
|
|
type = XPV_NONE;
|
|
|
|
//
|
|
state.Clean();
|
|
}
|
|
|
|
/**
|
|
* Validation ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(to) &&
|
|
IsValid(from) &&
|
|
IsValid(symbol) &&
|
|
IsValid(period) &&
|
|
repetition > 0 &&
|
|
type != XPV_NONE &&
|
|
(upper > 0 || lower > 0)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Pivot is Peak ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPeak()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
type == XPV_PEAK;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Pivot is Vale ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsVale()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
type == XPV_VALE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Lower for Peaks ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double CalculateLower()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid() ||
|
|
!IsPeak())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int fromIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
from //
|
|
);
|
|
|
|
//
|
|
int toIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
to //
|
|
);
|
|
|
|
//
|
|
int count =
|
|
fromIndex - toIndex;
|
|
|
|
//
|
|
int llIDX = iLowest(
|
|
symbol,
|
|
period,
|
|
MODE_LOW,
|
|
count,
|
|
toIndex //
|
|
);
|
|
|
|
//
|
|
result =
|
|
iLow(
|
|
symbol,
|
|
period,
|
|
llIDX //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Upper for Vales ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double CalculateUpper()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid() ||
|
|
!IsVale())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int fromIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
from //
|
|
);
|
|
|
|
//
|
|
int toIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
to //
|
|
);
|
|
|
|
//
|
|
int count =
|
|
fromIndex - toIndex;
|
|
|
|
//
|
|
int hhIDX = iHighest(
|
|
symbol,
|
|
period,
|
|
MODE_HIGH,
|
|
count,
|
|
toIndex //
|
|
);
|
|
|
|
//
|
|
result =
|
|
iHigh(
|
|
symbol,
|
|
period,
|
|
hhIDX //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Range of Pivot ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double CalculateRange()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid() ||
|
|
upper <= 0 ||
|
|
lower <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = upper - lower;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Middle of Pivot ...
|
|
* Used for
|
|
* @return ( double )
|
|
*/
|
|
double CalculateMid()
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
double range = CalculateRange();
|
|
if (range <= 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = lower + (range / 2);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* 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 = 0 //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = state
|
|
.CalculateLiquidityPercent(
|
|
forDirection,
|
|
price //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Price in Premium or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPriceInPremium()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double ask = GetAsk(symbol);
|
|
double bid = GetBid(symbol);
|
|
|
|
//
|
|
double mid = CalculateMid();
|
|
|
|
//
|
|
result =
|
|
//
|
|
ask > mid &&
|
|
bid > mid
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Price in Discount or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPriceInDiscount()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
double ask = GetAsk(symbol);
|
|
double bid = GetBid(symbol);
|
|
|
|
//
|
|
double mid = CalculateMid();
|
|
|
|
//
|
|
result =
|
|
//
|
|
ask > mid &&
|
|
bid > mid
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
|
|
/**
|
|
* Get Unique Identifier ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetTag()
|
|
{
|
|
//
|
|
string result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
string hash = symbol + "_" +
|
|
ToString(period) + "_" +
|
|
ToString(upper) + "," +
|
|
ToString(lower) + "_" +
|
|
ToString(from) + "," +
|
|
ToString(to);
|
|
hash = ToMD5(hash);
|
|
|
|
//
|
|
string typeStr =
|
|
type == XPV_PEAK
|
|
? "Peak"
|
|
: "Vale";
|
|
|
|
//
|
|
result =
|
|
//
|
|
"XPV_" +
|
|
typeStr + "_" +
|
|
symbol + "_" +
|
|
ToString(period) +
|
|
"_" + hash
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Pivots ...
|
|
struct XPVPivotPoint
|
|
{
|
|
//
|
|
// Props ...
|
|
double value;
|
|
int repetition;
|
|
datetime time;
|
|
ENUM_XPV_PIVOTS type;
|
|
|
|
//
|
|
// Constructor ...
|
|
XPVPivotPoint()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
value = 0;
|
|
time = NULL;
|
|
repetition = 0;
|
|
type = XPV_NONE;
|
|
}
|
|
|
|
/**
|
|
* Validate ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
value > 0 &&
|
|
IsValid(time) &&
|
|
repetition > 0 &&
|
|
type != XPV_NONE
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check current Pivot Point is Peak or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPeak()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
type == XPV_PEAK;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check current Pivot Point is Vale or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsVale()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
type == XPV_VALE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
//
|
|
// Consolidation Zone ...
|
|
struct XConsolidationZone
|
|
{
|
|
//
|
|
// Props ...
|
|
|
|
//
|
|
string symbol; // Symbol ...
|
|
ENUM_TIMEFRAMES period; // Period ...
|
|
|
|
//
|
|
double upper; // Upper ...
|
|
double lower; // Lower ...
|
|
|
|
//
|
|
datetime initTime;
|
|
int loopback; // Loopback ...
|
|
|
|
//
|
|
ENUM_X_DIRECTION breakDirection; // Break Direction ...
|
|
XOHCL breakerBar; // Breaker Bar ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XConsolidationZone()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize Zone ...
|
|
*
|
|
* @param _symbol: String ...
|
|
* @param _period: ENUM_TIMEFRAMES member ...
|
|
* @param _upper: Double ...
|
|
* @param _lower: Double ...
|
|
* @param _loopback: Integer ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
string _symbol,
|
|
ENUM_TIMEFRAMES _period,
|
|
double _upper,
|
|
double _lower,
|
|
int _loopback //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
_symbol = NormalizeSymbol(_symbol);
|
|
_period = NormalizePeriod(_period);
|
|
|
|
//
|
|
result =
|
|
//
|
|
_upper > 0 &&
|
|
_lower > 0 &&
|
|
_loopback > 0
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
upper = _upper;
|
|
lower = _lower;
|
|
symbol = _symbol;
|
|
period = _period;
|
|
loopback = _loopback;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (result)
|
|
{
|
|
initTime = TimeCurrent();
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Update Breaked State ...
|
|
*/
|
|
void Update()
|
|
{
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
if (IsBreaked())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XOHCL cBar;
|
|
bool isInited = cBar.Init(
|
|
symbol,
|
|
period,
|
|
0 //
|
|
);
|
|
if (!isInited)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
XOHCL pBar;
|
|
isInited = cBar.GetPreviousBar(pBar);
|
|
if (!isInited)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Consolidation Hounts ...
|
|
bool isHountTop = cBar.high > upper &&
|
|
cBar.low < upper &&
|
|
cBar.GetUp() < upper;
|
|
bool isHountBottom = cBar.low < lower &&
|
|
cBar.high > lower &&
|
|
cBar.GetDown() > lower;
|
|
bool isHounted = isHountTop ||
|
|
isHountBottom;
|
|
if (isHounted)
|
|
{
|
|
//
|
|
if (isHountTop)
|
|
{
|
|
upper = cBar.high;
|
|
}
|
|
|
|
//
|
|
if (isHountBottom)
|
|
{
|
|
lower = cBar.low;
|
|
}
|
|
|
|
//
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check Consolidation Breaks ...
|
|
bool isBreakTop = (cBar.GetUp() > upper &&
|
|
cBar.GetDown() < upper) ||
|
|
(cBar.low > upper &&
|
|
cBar.high > upper);
|
|
bool isBreakBottom = (cBar.GetDown() < lower &&
|
|
cBar.GetUp() > lower) ||
|
|
(cBar.high < lower &&
|
|
cBar.low < lower);
|
|
bool isBreaked = isBreakTop ||
|
|
isBreakBottom;
|
|
if (!isBreaked)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Calculate Break Direction ...
|
|
breakerBar = cBar;
|
|
breakDirection = isBreakTop
|
|
? X_DIRECTION_BULLISH
|
|
: isBreakBottom
|
|
? X_DIRECTION_BEARISH
|
|
: X_DIRECTION_NONE;
|
|
}
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
upper = 0;
|
|
lower = 0;
|
|
loopback = 0;
|
|
symbol = NULL;
|
|
period = NULL;
|
|
initTime = NULL;
|
|
breakerBar.Clean();
|
|
breakDirection = X_DIRECTION_NONE;
|
|
}
|
|
|
|
/**
|
|
* Validate ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid(symbol) &&
|
|
IsValid(period) &&
|
|
upper > 0 &&
|
|
lower > 0 &&
|
|
loopback > 0
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zone is Breaked or not ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBreaked()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = breakerBar.IsValid() &&
|
|
HasDirection(breakDirection);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect Supply Zone if Exists ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasSupplyZone(
|
|
XCSupplyZone *&zone //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsBreaked() &&
|
|
breakDirection == X_DIRECTION_BEARISH;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Implment Zone Finding ...
|
|
int index = breakerBar.Index();
|
|
int hhIDX = iHighest(
|
|
symbol,
|
|
period,
|
|
MODE_HIGH,
|
|
loopback,
|
|
index //
|
|
);
|
|
result = IsValidIndex(hhIDX);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL hhBar;
|
|
result = hhBar.Init(
|
|
symbol,
|
|
period,
|
|
hhIDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
zone = new XCSupplyZone();
|
|
result = zone.Init(
|
|
hhBar,
|
|
loopback //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect Demand Zone if Exists ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasDemandZone(
|
|
XCDemandZone *&zone //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsBreaked() &&
|
|
breakDirection == X_DIRECTION_BULLISH;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Implment Zone Finding ...
|
|
int index = breakerBar.Index();
|
|
int llIDX = iLowest(
|
|
symbol,
|
|
period,
|
|
MODE_LOW,
|
|
loopback,
|
|
index //
|
|
);
|
|
result = IsValidIndex(llIDX);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XOHCL llBar;
|
|
result = llBar.Init(
|
|
symbol,
|
|
period,
|
|
llIDX //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
zone = new XCDemandZone();
|
|
result = zone.Init(
|
|
llBar,
|
|
loopback //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Start Time ...
|
|
*
|
|
* @return ( datetime )
|
|
*/
|
|
datetime From()
|
|
{
|
|
//
|
|
datetime result = NULL;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int startIndex = iBarShift(
|
|
symbol,
|
|
period,
|
|
initTime //
|
|
);
|
|
|
|
//
|
|
result = iTime(
|
|
symbol,
|
|
period,
|
|
loopback + startIndex //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Unique Identifier ...
|
|
*
|
|
* @return ( string )
|
|
*/
|
|
string GetTag()
|
|
{
|
|
//
|
|
string result =
|
|
//
|
|
GetTypeName(this) + "_" +
|
|
symbol + "_" +
|
|
ToString(period) + "_" +
|
|
ToString(upper) + "_" +
|
|
ToString(lower)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
/**
|
|
* Converts a Consolidation Zone ...
|
|
*
|
|
* @param zone: XConsolidationZone instance Reference ...
|
|
* @param dest: XCZone pointer Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool ToZone(
|
|
XConsolidationZone &zone,
|
|
XCZone *&dest //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dest = NULL;
|
|
|
|
//
|
|
result = zone.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dest = new XCZone();
|
|
dest.Upper(zone.upper);
|
|
dest.Lower(zone.lower);
|
|
result = dest.IsValidBoundary();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Model Value Changed ...
|
|
struct XValueChange
|
|
{
|
|
//
|
|
// Props ...
|
|
double before; // Before Change Value ...
|
|
double after; // After Change Value ...
|
|
datetime time; // Change Time ...
|
|
ENUM_X_DIRECTION dir; // Change Direction ...
|
|
|
|
//
|
|
// Constructor ...
|
|
XValueChange()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
/**
|
|
* Initialize ...
|
|
*
|
|
* @param _before: Double, Value Before Change ...
|
|
* @param _after: Double, Value After Change ...
|
|
* @param _time: Datetime, Change Time ...
|
|
* @param _dir: ENUM_X_DIRECTION member, Specified Changed Direction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool Init(
|
|
double _before, // Before Change Value ...
|
|
double _after, // After Change Value ...
|
|
ENUM_X_DIRECTION _dir, // Change Direction ...
|
|
datetime _time = NULL // Change Time ...
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
_time = NormalizeTime(_time);
|
|
|
|
//
|
|
// Validate Inputs ...
|
|
result =
|
|
//
|
|
_after > 0 &&
|
|
_before > 0 &&
|
|
IsValid(_time) &&
|
|
_after != _before &&
|
|
HasDirection(_dir)
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Set Validated Values ...
|
|
dir = _dir;
|
|
time = _time;
|
|
after = _after;
|
|
before = _before;
|
|
|
|
//
|
|
result = IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Cleaning Up ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
after = 0;
|
|
before = 0;
|
|
time = NULL;
|
|
dir = X_DIRECTION_NONE;
|
|
}
|
|
|
|
/**
|
|
* Validate Model ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
after > 0 &&
|
|
before > 0 &&
|
|
IsValid(time) &&
|
|
after != before &&
|
|
HasDirection(dir)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Fill Change Bar ...
|
|
*
|
|
* @param bar: XOHCL instance Reference, holds Change Bar ...
|
|
* @param _symbol: String, Specified Symbol ...
|
|
* @param _period: ENUM_TIMEFRAMES _period member, Specified Period ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool FillBar(
|
|
XOHCL &bar,
|
|
string _symbol = NULL,
|
|
ENUM_TIMEFRAMES _period = NULL //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bar.Clean();
|
|
_symbol = NormalizeSymbol(_symbol);
|
|
_period = NormalizePeriod(_period);
|
|
|
|
//
|
|
result = IsValid() &&
|
|
IsValid(_symbol) &&
|
|
IsValid(_period);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = bar.Init(
|
|
_symbol,
|
|
_period,
|
|
time //
|
|
);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Price Zones Model ...
|
|
struct XPriceZones
|
|
{
|
|
//
|
|
XOHCL bar; // if Based On Bar it's Filled ...
|
|
double price; // if Based on Price, it's Filled ...
|
|
|
|
//
|
|
int count; // Exists Zones Count ...
|
|
|
|
//
|
|
XCFVG *fairValueGap; // Exists Fair Value Gap ...
|
|
XCSupplyZone *supplyZone; // Exists Supply Zone ...
|
|
XCDemandZone *demandZone; // Exists Demand Zone ...
|
|
XCOrderBlock *orderBlock; // Exists Order Block ...
|
|
XCSupportZone *supportZone; // Exists Support Zone ...
|
|
XCResistanceZone *resistanceZone; // Exists Resistance Zone ...ّ
|
|
|
|
//
|
|
// Constructor ...
|
|
XPriceZones()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
bar.Clean();
|
|
price = 0;
|
|
|
|
//
|
|
supplyZone = NULL;
|
|
demandZone = NULL;
|
|
orderBlock = NULL;
|
|
supportZone = NULL;
|
|
fairValueGap = NULL;
|
|
resistanceZone = NULL;
|
|
}
|
|
|
|
/**
|
|
* Check Zone is Valid ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
(IsBasedOnBar() ||
|
|
IsBasedOnPrice()) &&
|
|
IsValidSize(count)
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zones Base on Bar ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBasedOnBar()
|
|
{
|
|
return bar.IsValid();
|
|
}
|
|
|
|
/**
|
|
* Check Zones Based on Price ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBasedOnPrice()
|
|
{
|
|
return price > 0;
|
|
}
|
|
|
|
/**
|
|
* Check Has Supply Zone ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasSupplyZone()
|
|
{
|
|
//
|
|
return IsValidSize(count) &&
|
|
supplyZone != NULL &&
|
|
supplyZone.IsValid();
|
|
}
|
|
|
|
/**
|
|
* Check Has Demand Zone ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasDemandZone()
|
|
{
|
|
//
|
|
return IsValidSize(count) &&
|
|
demandZone != NULL &&
|
|
demandZone.IsValid();
|
|
}
|
|
|
|
/**
|
|
* Check Has OrderBlock ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasOrderBlock()
|
|
{
|
|
//
|
|
return IsValidSize(count) &&
|
|
orderBlock != NULL &&
|
|
orderBlock.IsValid();
|
|
}
|
|
|
|
/**
|
|
* Check Has Support Zone ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasSupportZone()
|
|
{
|
|
//
|
|
return IsValidSize(count) &&
|
|
supportZone != NULL &&
|
|
supportZone.IsValid();
|
|
}
|
|
|
|
/**
|
|
* Check Has FairValueGap ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasFairValueGap()
|
|
{
|
|
//
|
|
return IsValidSize(count) &&
|
|
fairValueGap != NULL &&
|
|
fairValueGap.IsValid();
|
|
}
|
|
|
|
/**
|
|
* Check Has Resistance Zone ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasResistanceZone()
|
|
{
|
|
//
|
|
return IsValidSize(count) &&
|
|
resistanceZone != NULL &&
|
|
resistanceZone.IsValid();
|
|
}
|
|
|
|
/**
|
|
* Check Zones are Overal Bullish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBullish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
HasDemandZone()
|
|
//
|
|
||
|
|
//
|
|
HasSupportZone()
|
|
//
|
|
||
|
|
//
|
|
(HasOrderBlock() &&
|
|
orderBlock.IsBullish())
|
|
//
|
|
||
|
|
//
|
|
(HasFairValueGap() &&
|
|
fairValueGap.IsBullish())
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Zones are Overal Bearish ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBearish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
HasSupplyZone()
|
|
//
|
|
||
|
|
//
|
|
HasResistanceZone()
|
|
//
|
|
||
|
|
//
|
|
(HasOrderBlock() &&
|
|
orderBlock.IsBearish())
|
|
//
|
|
||
|
|
//
|
|
(HasFairValueGap() &&
|
|
fairValueGap.IsBearish())
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Fill Zones Based On required Direction ...
|
|
*
|
|
* @param dir: ENUM_X_DIRECTION member ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int FillZones(
|
|
ENUM_X_DIRECTION dir,
|
|
XCZone *&zones[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
Clean(zones);
|
|
|
|
//
|
|
bool isBullish = IsBullish(dir);
|
|
bool isBoth = dir == X_DIRECTION_ALL ||
|
|
dir == X_DIRECTION_NONE;
|
|
|
|
//
|
|
if (isBoth || isBullish)
|
|
{
|
|
//
|
|
if (HasSupportZone())
|
|
{
|
|
//
|
|
Add(
|
|
(XCZone *)supportZone,
|
|
zones //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (HasDemandZone())
|
|
{
|
|
//
|
|
Add(
|
|
(XCZone *)demandZone,
|
|
zones //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (HasOrderBlock() &&
|
|
orderBlock.IsBullish())
|
|
{
|
|
//
|
|
Add(
|
|
(XCZone *)orderBlock,
|
|
zones //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (HasFairValueGap() &&
|
|
fairValueGap.IsBullish())
|
|
{
|
|
//
|
|
Add(
|
|
(XCZone *)fairValueGap,
|
|
zones //
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
if (isBoth || !isBullish)
|
|
{
|
|
//
|
|
if (HasResistanceZone())
|
|
{
|
|
//
|
|
Add(
|
|
(XCZone *)resistanceZone,
|
|
zones //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (HasSupplyZone())
|
|
{
|
|
//
|
|
Add(
|
|
(XCZone *)supplyZone,
|
|
zones //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (HasOrderBlock() &&
|
|
orderBlock.IsBearish())
|
|
{
|
|
//
|
|
Add(
|
|
(XCZone *)orderBlock,
|
|
zones //
|
|
);
|
|
}
|
|
|
|
//
|
|
if (HasFairValueGap() &&
|
|
fairValueGap.IsBearish())
|
|
{
|
|
//
|
|
Add(
|
|
(XCZone *)fairValueGap,
|
|
zones //
|
|
);
|
|
}
|
|
}
|
|
|
|
// s
|
|
result = ArraySize(zones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Boundary of Zones ...
|
|
*
|
|
* @param dir: ENUM_X_DIRECTION Member, Specified Direction ...
|
|
* @param upper: Double ...
|
|
* @param lower: Double ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetBoundary(
|
|
ENUM_X_DIRECTION dir,
|
|
double &upper,
|
|
double &lower //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
upper = 0;
|
|
lower = 0;
|
|
|
|
//
|
|
XCZone *zones[];
|
|
int mCount = FillZones(dir, zones);
|
|
result = IsValidSize(mCount);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < mCount; i++)
|
|
{
|
|
//
|
|
XCZone *iZone = zones[i];
|
|
|
|
//
|
|
double iUpper = iZone.Upper();
|
|
double iLower = iZone.Lower();
|
|
|
|
//
|
|
upper =
|
|
upper == 0
|
|
? iUpper
|
|
: iUpper > upper
|
|
? iUpper
|
|
: upper;
|
|
|
|
//
|
|
lower =
|
|
lower == 0
|
|
? iLower
|
|
: iLower < lower
|
|
? iLower
|
|
: lower;
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Lifetime of Zones ...
|
|
*
|
|
* @param dir: ENUM_X_DIRECTION Member, Specified Direction ...
|
|
* @param from: DateTime ...
|
|
* @param to: DateTime ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetLifetime(
|
|
ENUM_X_DIRECTION dir,
|
|
datetime &from,
|
|
datetime &to //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
to = NULL;
|
|
from = NULL;
|
|
|
|
//
|
|
XCZone *zones[];
|
|
int mCount = FillZones(dir, zones);
|
|
result = IsValidSize(mCount);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool isBullish = IsBullish(dir);
|
|
bool isAll = dir == X_DIRECTION_NONE ||
|
|
dir == X_DIRECTION_ALL;
|
|
|
|
//
|
|
if (isAll || isBullish)
|
|
{
|
|
//
|
|
// Support Zone ...
|
|
bool hasSupportZone = HasSupportZone();
|
|
if (hasSupportZone)
|
|
{
|
|
//
|
|
XCSupportZone *zone = supportZone;
|
|
|
|
//
|
|
from =
|
|
!IsValid(from) ||
|
|
from > zone.From()
|
|
? zone.From()
|
|
: from;
|
|
|
|
//
|
|
to =
|
|
!IsValid(to) ||
|
|
to < zone.To()
|
|
? zone.To()
|
|
: from;
|
|
}
|
|
|
|
//
|
|
// Demand Zone ...
|
|
bool hasDemandZone = HasDemandZone();
|
|
if (hasDemandZone)
|
|
{
|
|
//
|
|
XCDemandZone *zone = demandZone;
|
|
|
|
//
|
|
from =
|
|
!IsValid(from) ||
|
|
from > zone.From()
|
|
? zone.From()
|
|
: from;
|
|
|
|
//
|
|
to =
|
|
!IsValid(to) ||
|
|
to < zone.To()
|
|
? zone.To()
|
|
: from;
|
|
}
|
|
|
|
//
|
|
// Order Block ...
|
|
bool hasOrderBlock = HasOrderBlock() &&
|
|
orderBlock.IsBullish();
|
|
if (hasOrderBlock)
|
|
{
|
|
//
|
|
XCOrderBlock *zone = orderBlock;
|
|
|
|
//
|
|
from =
|
|
!IsValid(from) ||
|
|
from > zone.From()
|
|
? zone.From()
|
|
: from;
|
|
|
|
//
|
|
to =
|
|
!IsValid(to) ||
|
|
to < zone.To()
|
|
? zone.To()
|
|
: from;
|
|
}
|
|
|
|
//
|
|
// Fair Value Gap ...
|
|
bool hasFairValueGap = HasFairValueGap() &&
|
|
fairValueGap.IsBullish();
|
|
if (hasFairValueGap)
|
|
{
|
|
//
|
|
XCFVG *zone = fairValueGap;
|
|
|
|
//
|
|
from =
|
|
!IsValid(from) ||
|
|
from > zone.From()
|
|
? zone.From()
|
|
: from;
|
|
|
|
//
|
|
to =
|
|
!IsValid(to) ||
|
|
to < zone.To()
|
|
? zone.To()
|
|
: from;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (isAll || !isBullish)
|
|
{
|
|
//
|
|
// Resistance Zone ...
|
|
bool hasResistanceZone = HasResistanceZone();
|
|
if (hasResistanceZone)
|
|
{
|
|
//
|
|
XCResistanceZone *zone = resistanceZone;
|
|
|
|
//
|
|
from =
|
|
!IsValid(from) ||
|
|
from > zone.From()
|
|
? zone.From()
|
|
: from;
|
|
|
|
//
|
|
to =
|
|
!IsValid(to) ||
|
|
to < zone.To()
|
|
? zone.To()
|
|
: from;
|
|
}
|
|
|
|
//
|
|
// Supply Zone ...
|
|
bool hasSupplyZone = HasSupplyZone();
|
|
if (hasSupplyZone)
|
|
{
|
|
//
|
|
XCSupplyZone *zone = supplyZone;
|
|
|
|
//
|
|
from =
|
|
!IsValid(from) ||
|
|
from > zone.From()
|
|
? zone.From()
|
|
: from;
|
|
|
|
//
|
|
to =
|
|
!IsValid(to) ||
|
|
to < zone.To()
|
|
? zone.To()
|
|
: from;
|
|
}
|
|
|
|
//
|
|
// Order Block ...
|
|
bool hasOrderBlock = HasOrderBlock() &&
|
|
orderBlock.IsBearish();
|
|
if (hasOrderBlock)
|
|
{
|
|
//
|
|
XCOrderBlock *zone = orderBlock;
|
|
|
|
//
|
|
from =
|
|
!IsValid(from) ||
|
|
from > zone.From()
|
|
? zone.From()
|
|
: from;
|
|
|
|
//
|
|
to =
|
|
!IsValid(to) ||
|
|
to < zone.To()
|
|
? zone.To()
|
|
: from;
|
|
}
|
|
|
|
//
|
|
// Fair Value Gap ...
|
|
bool hasFairValueGap = HasFairValueGap() &&
|
|
fairValueGap.IsBearish();
|
|
if (hasFairValueGap)
|
|
{
|
|
//
|
|
XCFVG *zone = fairValueGap;
|
|
|
|
//
|
|
from =
|
|
!IsValid(from) ||
|
|
from > zone.From()
|
|
? zone.From()
|
|
: from;
|
|
|
|
//
|
|
to =
|
|
!IsValid(to) ||
|
|
to < zone.To()
|
|
? zone.To()
|
|
: from;
|
|
}
|
|
}
|
|
|
|
//
|
|
result =
|
|
to > from &&
|
|
IsValid(to) &&
|
|
IsValid(from);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Box Model Data ...
|
|
*
|
|
* @param dir: ENUM_X_DIRECTION Member, Specified Direction ...
|
|
* @param upper: Double ...
|
|
* @param lower: Double ...
|
|
* @param from: DateTime ...
|
|
* @param to: DateTime ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetBoxData(
|
|
ENUM_X_DIRECTION dir,
|
|
double &upper,
|
|
double &lower,
|
|
datetime &from,
|
|
datetime &to //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
bool hasBoundary = GetBoundary(
|
|
dir,
|
|
upper,
|
|
lower //
|
|
);
|
|
|
|
//
|
|
bool hasLifetime = GetLifetime(
|
|
dir,
|
|
from,
|
|
to //
|
|
);
|
|
|
|
//
|
|
result =
|
|
hasBoundary &&
|
|
hasLifetime;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
//
|
|
// Market Strucutre Model ...
|
|
struct XMarketStructure
|
|
{
|
|
//
|
|
string symbol;
|
|
ENUM_TIMEFRAMES period;
|
|
|
|
//
|
|
ENUM_X_DIRECTION bias;
|
|
|
|
//
|
|
XPVPivotPoint vales[];
|
|
XPriceZones valePriceZones[];
|
|
|
|
//
|
|
XPVPivotPoint peaks[];
|
|
XPriceZones peakPriceZones[];
|
|
|
|
//
|
|
XOHCL lowestValeBar;
|
|
XOHCL lowestValePeakBreakeUpBar;
|
|
XOHCL valeAboveLowestValePeakBar;
|
|
|
|
//
|
|
XOHCL highestPeakBar;
|
|
XOHCL peakBelowHighestPeakValeBar;
|
|
XOHCL highestPeakValeBreakeDownBar;
|
|
|
|
//
|
|
XMarketStructure()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
/**
|
|
* Cleanup ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
symbol = NULL;
|
|
period = NULL;
|
|
bias = X_DIRECTION_NONE;
|
|
|
|
//
|
|
Clean(vales);
|
|
Clean(peaks);
|
|
Clean(valePriceZones);
|
|
Clean(peakPriceZones);
|
|
|
|
//
|
|
lowestValeBar.Clean();
|
|
lowestValePeakBreakeUpBar.Clean();
|
|
valeAboveLowestValePeakBar.Clean();
|
|
|
|
//
|
|
highestPeakBar.Clean();
|
|
peakBelowHighestPeakValeBar.Clean();
|
|
highestPeakValeBreakeDownBar.Clean();
|
|
}
|
|
|
|
/**
|
|
* Validate Model ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
IsValid(symbol) &&
|
|
IsValid(period) &&
|
|
bias != X_DIRECTION_NONE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Bullish Trend ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBullish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid() &&
|
|
IsBullish(bias) &&
|
|
HasChild(peaks) &&
|
|
HasDirection(bias) &&
|
|
lowestValeBar.IsValid() &&
|
|
HasChild(peakPriceZones) &&
|
|
lowestValePeakBreakeUpBar.IsValid() &&
|
|
valeAboveLowestValePeakBar.IsValid()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Bearish Trend ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsBearish()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValid() &&
|
|
IsBearish(bias) &&
|
|
HasChild(vales) &&
|
|
HasDirection(bias) &&
|
|
highestPeakBar.IsValid() &&
|
|
HasChild(valePriceZones) &&
|
|
peakBelowHighestPeakValeBar.IsValid() &&
|
|
highestPeakValeBreakeDownBar.IsValid()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Has Trend ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool HasTrend()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = IsValid() &&
|
|
(IsBullish() ||
|
|
IsBearish());
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
};
|
|
|
|
struct XStateZones
|
|
{
|
|
//
|
|
XCSupportZone *supportZones[]; // Holds Founded Support Zones ...
|
|
XCResistanceZone *resistanceZones[]; // Holds Founded Resistance Zones ...
|
|
XCSupplyZone *supplyZones[]; // Holds Founded Supply Zones ...
|
|
XCDemandZone *demandZones[]; // Holds Founded Demand Zones ...
|
|
XCOrderBlock *bullishOrderBlocks[]; // Holds Founded Bullish Order Blocks ...
|
|
XCOrderBlock *bearishOrderBlocks[]; // Holds Founded Bearish Order Blocks ...
|
|
XCFVG *bullishFairValueGaps[]; // Holds Founded Bullish Fair Value Gaps ...
|
|
XCFVG *bearishFairValueGaps[]; // Holds Founded Bearish Fair Value Gaps ...
|
|
|
|
//
|
|
XStateZones()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
/**
|
|
* Cleaning Model ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
Clean(supportZones);
|
|
Clean(resistanceZones);
|
|
Clean(supplyZones);
|
|
Clean(demandZones);
|
|
Clean(bullishOrderBlocks);
|
|
Clean(bearishOrderBlocks);
|
|
Clean(bullishFairValueGaps);
|
|
Clean(bearishFairValueGaps);
|
|
}
|
|
|
|
/**
|
|
* Validate Model ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
IsValidSize(CountSupportZones()) ||
|
|
IsValidSize(CountResistanceZones()) ||
|
|
IsValidSize(CountSupplyZones()) ||
|
|
IsValidSize(CountDemandZones()) ||
|
|
IsValidSize(CountBullishOrderBlocks()) ||
|
|
IsValidSize(CountBearishOrderBlocks()) ||
|
|
IsValidSize(CountBullishFairValueGaps()) ||
|
|
IsValidSize(CountBearishFairValueGaps())
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// Tools ...
|
|
|
|
//
|
|
int CountSupportZones()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(supportZones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountResistanceZones()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(resistanceZones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountSupplyZones()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(supplyZones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountDemandZones()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(demandZones);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBullishOrderBlocks()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bullishOrderBlocks);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBearishOrderBlocks()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bearishOrderBlocks);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBullishFairValueGaps()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bullishFairValueGaps);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int CountBearishFairValueGaps()
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
if (!IsValid())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result = ArraySize(bearishFairValueGaps);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
};
|
|
|
|
struct XFVGOrderBlock
|
|
{
|
|
//
|
|
// Props ...
|
|
XCOrderBlock *orderBlock;
|
|
XCFVG *fairValueGap;
|
|
// XStateZones stateZones;
|
|
|
|
//
|
|
XFVGOrderBlock()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
/**
|
|
* Cleanup Model ...
|
|
*/
|
|
void Clean()
|
|
{
|
|
//
|
|
orderBlock = NULL;
|
|
fairValueGap = NULL;
|
|
}
|
|
|
|
/**
|
|
* Validate Model ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsValid()
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
//
|
|
orderBlock != NULL &&
|
|
fairValueGap != NULL &&
|
|
// stateZones.IsValid() &&
|
|
((orderBlock.IsBullish() &&
|
|
fairValueGap.IsBullish()) ||
|
|
((orderBlock.IsBearish() &&
|
|
fairValueGap.IsBearish())))
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Get Model Direction ...
|
|
*
|
|
* @param dir: ENUM_X_DIRECTION member ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool GetDirection(
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
dir = orderBlock.IsBullish()
|
|
? X_DIRECTION_BULLISH
|
|
: X_DIRECTION_BEARISH;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieve Boundary of Zone ...
|
|
*
|
|
* @param upper: Upper Boundary ...ّ
|
|
* @param lower: Lower Bondary ...
|
|
* @return ( bool )
|
|
*/
|
|
bool GetBoundary(
|
|
double &upper,
|
|
double &lower //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
upper = 0;
|
|
lower = 0;
|
|
|
|
//
|
|
result = IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
upper = orderBlock.Upper();
|
|
upper = MathMax(upper, fairValueGap.Upper());
|
|
|
|
//
|
|
lower = orderBlock.Lower();
|
|
lower = MathMax(lower, fairValueGap.Lower());
|
|
|
|
//
|
|
result = lower > 0 &&
|
|
upper > 0 &&
|
|
upper > lower;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Model is same as another Istance ...
|
|
*
|
|
* @param value: XFVGOrderBlock instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsSameAs(XFVGOrderBlock &value)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
IsValid() &&
|
|
value.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION dir;
|
|
result = GetDirection(dir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
ENUM_X_DIRECTION valueDir;
|
|
result = value.GetDirection(valueDir);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
dir = valueDir
|
|
//
|
|
&&
|
|
//
|
|
orderBlock.From() == value.orderBlock.From() &&
|
|
orderBlock.Upper() == value.orderBlock.Upper() &&
|
|
orderBlock.Lower() == value.orderBlock.Lower()
|
|
//
|
|
&&
|
|
//
|
|
fairValueGap.From() == value.fairValueGap.From() &&
|
|
fairValueGap.Upper() == value.fairValueGap.Upper() &&
|
|
fairValueGap.Lower() == value.fairValueGap.Lower()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
//
|
|
};
|
|
|
|
//
|
|
// Extensions ...
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
//
|
|
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;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
/**
|
|
* Find Oldest Pivot Index ...
|
|
*
|
|
* @param pivots: XPVPivot instance ...
|
|
* @return ( int )
|
|
*/
|
|
int FindOldestPivotIndex(
|
|
XPVPivot &pivots[] //
|
|
)
|
|
{
|
|
//
|
|
int result = -1;
|
|
|
|
//
|
|
int count = ArraySize(pivots);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPVPivot iPivot = pivots[i];
|
|
|
|
//
|
|
bool isOldest = true;
|
|
for (int j = 0; j < count; j++)
|
|
{
|
|
//
|
|
XPVPivot jPivot = pivots[j];
|
|
|
|
//
|
|
isOldest = iPivot.from <= jPivot.from;
|
|
if (!isOldest)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
if (isOldest)
|
|
{
|
|
//
|
|
result = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Sort Pivots Based On From Date ...
|
|
*
|
|
* @param pivots: XPVPivot instance Collection reference ...
|
|
*/
|
|
void SortPivots(
|
|
XPVPivot &pivots[] //
|
|
)
|
|
{
|
|
//
|
|
XPVPivot tmp[];
|
|
Copy(
|
|
pivots,
|
|
tmp //
|
|
);
|
|
|
|
//
|
|
Clean(pivots);
|
|
|
|
//
|
|
while (ArraySize(tmp) > 0)
|
|
{
|
|
//
|
|
if (ArraySize(tmp) == 1)
|
|
{
|
|
//
|
|
AddRef(
|
|
tmp[0],
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
1);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
int idx = FindOldestPivotIndex(tmp);
|
|
if (IsValidIndex(idx))
|
|
{
|
|
//
|
|
AddRef(
|
|
tmp[idx],
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmp,
|
|
idx,
|
|
1 //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
Clean(tmp);
|
|
}
|
|
|
|
bool IsPivotBreaked(
|
|
XPVPivot &pivot,
|
|
XPVPivot &pivots[] //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result = pivot.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = ArraySize(pivots);
|
|
result = IsValidSize(pivots);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// For Peaks Highs Must not Broked ...
|
|
// For Vales Lows Must not Broked ...
|
|
bool isPeak = pivot.IsPeak();
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPVPivot iPivot = pivots[i];
|
|
|
|
//
|
|
result = isPeak
|
|
? iPivot.upper > pivot.upper
|
|
: iPivot.lower < pivot.lower;
|
|
if (result)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Filter Broken Pivots for Detect Order Flow ...
|
|
*
|
|
* @param pivots: XPVPivot instance Collection reference ...
|
|
*/
|
|
void FilterBrokenPivots(
|
|
XPVPivot &pivots[] //
|
|
)
|
|
{
|
|
//
|
|
XPVPivot tmp[];
|
|
Copy(
|
|
pivots,
|
|
tmp //
|
|
);
|
|
|
|
//
|
|
Clean(pivots);
|
|
|
|
//
|
|
while (ArraySize(tmp) > 0)
|
|
{
|
|
//
|
|
if (ArraySize(tmp) == 1)
|
|
{
|
|
//
|
|
AddRef(
|
|
tmp[0],
|
|
pivots //
|
|
);
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
1 //
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
XPVPivot pivot = tmp[0];
|
|
|
|
//
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
1 //
|
|
);
|
|
|
|
//
|
|
bool isBreaked = IsPivotBreaked(
|
|
pivot,
|
|
tmp //
|
|
);
|
|
if (!isBreaked)
|
|
{
|
|
//
|
|
AddRef(
|
|
pivot,
|
|
pivots //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
Clean(tmp);
|
|
}
|
|
|
|
/**
|
|
* Calculate Order Flow Direction ...
|
|
*
|
|
* @param orderFlow: XPVPivot instance Collection reference ...
|
|
* @param dir: ENUM_X_DIRECTION member reference, Hold's Calculated Direction ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool DetectPivotDirection(
|
|
XPVPivot &orderFlow[],
|
|
ENUM_X_DIRECTION &dir //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
dir = X_DIRECTION_NONE;
|
|
|
|
//
|
|
int count = ArraySize(orderFlow);
|
|
result = IsValidSize(count);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
// For Bullish Direction all Exists lowers must be Greater or Equal Prev ...
|
|
bool isBullish = false;
|
|
bool canLookupForBullish = true;
|
|
|
|
//
|
|
// For Bearish Direction all Exists uppers must be Lesser or Equal Prev ...
|
|
bool isBearish = false;
|
|
bool canLookupForBearish = true;
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPVPivot iPivot = orderFlow[i];
|
|
|
|
//
|
|
XPVPivot tmp[];
|
|
Copy(
|
|
orderFlow,
|
|
tmp //
|
|
);
|
|
ArrayRemove(
|
|
tmp,
|
|
0,
|
|
i + 1 //
|
|
);
|
|
|
|
//
|
|
int tmpCount = ArraySize(tmp);
|
|
if (IsValidSize(tmpCount))
|
|
{
|
|
//
|
|
for (int j = 0; j < tmpCount; j++)
|
|
{
|
|
//
|
|
XPVPivot jPivot = tmp[j];
|
|
|
|
//
|
|
// Check Bullish Direction ...
|
|
isBullish =
|
|
canLookupForBullish &&
|
|
jPivot.lower >= iPivot.lower;
|
|
if (!isBullish)
|
|
{
|
|
canLookupForBullish = false;
|
|
}
|
|
|
|
//
|
|
// Check Bearish Direction ...
|
|
isBearish =
|
|
canLookupForBearish &&
|
|
jPivot.upper <= iPivot.upper;
|
|
if (!isBearish)
|
|
{
|
|
canLookupForBearish = false;
|
|
}
|
|
|
|
//
|
|
if (!canLookupForBullish &&
|
|
!canLookupForBearish)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Clean(tmp);
|
|
}
|
|
|
|
//
|
|
if (isBullish &&
|
|
!isBearish)
|
|
{
|
|
dir = X_DIRECTION_BULLISH;
|
|
}
|
|
else if (isBearish &&
|
|
!isBullish)
|
|
{
|
|
dir = X_DIRECTION_BEARISH;
|
|
}
|
|
|
|
//
|
|
result = dir != X_DIRECTION_NONE;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect all POIs which inside a Pivot ...
|
|
*
|
|
* @param pivot: XPVPivot instance, Specified Pivot ...
|
|
* @param source: XPOIState instance, Reference to Source State ...
|
|
* @param state: XPOIState instance, Reference to Detected Pivots ...
|
|
* @param lookupSwingHighs: Boolean ...
|
|
* @param lookupSwingLows: Boolean ...
|
|
* @param lookupSupportZones: Boolean ...
|
|
* @param lookupResistanceZones: Boolean ...
|
|
* @param lookupSupplyZones: Boolean ...
|
|
* @param lookupDemandZones: Boolean ...
|
|
* @param lookupBullishOrderBlocks: Boolean ...
|
|
* @param lookupBearishOrderBlocks: Boolean ...
|
|
* @param lookupBullishFairValueGaps: Boolean ...
|
|
* @param lookupBearishFairValueGaps: Boolean ...
|
|
* @param lookupBullishRejectionBars: Boolean ...
|
|
* @param lookupBearishRejectionBars: Boolean ...
|
|
* @param lookupBullishMomentumBars: Boolean ...
|
|
* @param lookupBearishMomentumBars: Boolean ...
|
|
*/
|
|
void DetectPivotPOIs(
|
|
XPVPivot &pivot,
|
|
XPOIState &source,
|
|
XPOIState &state,
|
|
bool lookupSwingHighs = true,
|
|
bool lookupSwingLows = true,
|
|
bool lookupSupportZones = true,
|
|
bool lookupResistanceZones = true,
|
|
bool lookupSupplyZones = true,
|
|
bool lookupDemandZones = true,
|
|
bool lookupBullishOrderBlocks = true,
|
|
bool lookupBearishOrderBlocks = true,
|
|
bool lookupBullishFairValueGaps = true,
|
|
bool lookupBearishFairValueGaps = true,
|
|
bool lookupBullishRejectionBars = true,
|
|
bool lookupBearishRejectionBars = true,
|
|
bool lookupBullishMomentumBars = true,
|
|
bool lookupBearishMomentumBars = true //
|
|
)
|
|
{
|
|
//
|
|
state.Clean();
|
|
|
|
//
|
|
if (!pivot.IsValid())
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
int count = 0;
|
|
|
|
//
|
|
state.symbol = pivot.symbol;
|
|
state.period = pivot.period;
|
|
state.time = TimeCurrent();
|
|
|
|
//
|
|
// Swings ...
|
|
|
|
//
|
|
// Swing High ...
|
|
if (lookupSwingHighs)
|
|
{
|
|
//
|
|
count = ArraySize(source.swingHighs);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCSwing *iSwing = source.swingHighs[i];
|
|
|
|
//
|
|
XOHCL iBar;
|
|
bool isFilled = iSwing.FillBar(iBar);
|
|
if (!isFilled)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isInside = iBar.high <= pivot.upper;
|
|
if (isInside)
|
|
{
|
|
//
|
|
// iSwing.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iSwing,
|
|
state.swingHighs //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Swing Low ...
|
|
if (lookupSwingLows)
|
|
{
|
|
//
|
|
count = ArraySize(source.swingLows);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCSwing *iSwing = source.swingLows[i];
|
|
|
|
//
|
|
XOHCL iBar;
|
|
bool isFilled = iSwing.FillBar(iBar);
|
|
if (!isFilled)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isInside = iBar.low >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
// iSwing.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iSwing,
|
|
state.swingLows //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Support and Resistance Zones ...
|
|
|
|
//
|
|
// Support Zones ...
|
|
if (lookupSupportZones)
|
|
{
|
|
//
|
|
count = ArraySize(source.supportZones);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCSupportZone *iZone = source.supportZones[i];
|
|
|
|
//
|
|
bool isInside =
|
|
iZone.Upper() <= pivot.upper &&
|
|
iZone.Lower() >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iZone.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iZone,
|
|
state.supportZones //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Resistance Zones ...
|
|
if (lookupResistanceZones)
|
|
{
|
|
//
|
|
count = ArraySize(source.resistanceZones);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCResistanceZone *iZone = source.resistanceZones[i];
|
|
|
|
//
|
|
bool isInside =
|
|
iZone.Upper() <= pivot.upper &&
|
|
iZone.Lower() >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iZone.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iZone,
|
|
state.resistanceZones //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Supply and Demand Zones ...
|
|
|
|
//
|
|
// Supply Zones ...
|
|
if (lookupSupplyZones)
|
|
{
|
|
//
|
|
count = ArraySize(source.supplyZones);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCSupplyZone *iZone = source.supplyZones[i];
|
|
|
|
//
|
|
bool isInside =
|
|
iZone.Upper() <= pivot.upper &&
|
|
iZone.Lower() >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iZone.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iZone,
|
|
state.supplyZones //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Demand Zones ...
|
|
if (lookupDemandZones)
|
|
{
|
|
//
|
|
count = ArraySize(source.demandZones);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCDemandZone *iZone = source.demandZones[i];
|
|
|
|
//
|
|
bool isInside =
|
|
iZone.Upper() <= pivot.upper &&
|
|
iZone.Lower() >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iZone.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iZone,
|
|
state.demandZones //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Order Blocks ...
|
|
|
|
//
|
|
// Bullish Order Blocks ...
|
|
if (lookupBullishOrderBlocks)
|
|
{
|
|
//
|
|
count = ArraySize(source.bullishOrderBlocks);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCOrderBlock *iZone = source.bullishOrderBlocks[i];
|
|
|
|
//
|
|
bool isInside =
|
|
iZone.Upper() <= pivot.upper &&
|
|
iZone.Lower() >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iZone.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iZone,
|
|
state.bullishOrderBlocks //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bearish Order Blocks ...
|
|
if (lookupBearishOrderBlocks)
|
|
{
|
|
//
|
|
count = ArraySize(source.bearishOrderBlocks);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCOrderBlock *iZone = source.bearishOrderBlocks[i];
|
|
|
|
//
|
|
bool isInside =
|
|
iZone.Upper() <= pivot.upper &&
|
|
iZone.Lower() >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iZone.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iZone,
|
|
state.bearishOrderBlocks //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fair Value Gaps ...
|
|
|
|
//
|
|
// Bullish Fair Value Gaps ...
|
|
if (lookupBullishFairValueGaps)
|
|
{
|
|
//
|
|
count = ArraySize(source.bullishFairValueGaps);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCFVG *iZone = source.bullishFairValueGaps[i];
|
|
|
|
//
|
|
bool isInside =
|
|
iZone.Upper() <= pivot.upper &&
|
|
iZone.Lower() >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iZone.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iZone,
|
|
state.bullishFairValueGaps //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bearish Fair Value Gaps ...
|
|
if (lookupBearishFairValueGaps)
|
|
{
|
|
//
|
|
count = ArraySize(source.bearishFairValueGaps);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCFVG *iZone = source.bearishFairValueGaps[i];
|
|
|
|
//
|
|
bool isInside =
|
|
iZone.Upper() <= pivot.upper &&
|
|
iZone.Lower() >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iZone.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iZone,
|
|
state.bearishFairValueGaps //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Rejection Bars ...
|
|
|
|
//
|
|
// Bullish Rejection Bars ...
|
|
if (lookupBullishRejectionBars)
|
|
{
|
|
//
|
|
count = ArraySize(source.bullishRejectionBars);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCRejectionBar *iRejection = source.bullishRejectionBars[i];
|
|
|
|
//
|
|
XOHCL iBar;
|
|
bool isFilled = iRejection.FillBar(iBar);
|
|
if (!isFilled)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isInside = iBar.low <= pivot.upper &&
|
|
iBar.low >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iRejection.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iRejection,
|
|
state.bullishRejectionBars //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bearish Rejection Bars ...
|
|
if (lookupBearishRejectionBars)
|
|
{
|
|
//
|
|
count = ArraySize(source.bearishRejectionBars);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCRejectionBar *iRejection = source.bearishRejectionBars[i];
|
|
|
|
//
|
|
XOHCL iBar;
|
|
bool isFilled = iRejection.FillBar(iBar);
|
|
if (!isFilled)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isInside = iBar.high <= pivot.upper &&
|
|
iBar.high >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iRejection.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iRejection,
|
|
state.bearishRejectionBars //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Momentum Bars ...
|
|
|
|
//
|
|
// Bullish Momentum Bars ...
|
|
if (lookupBullishMomentumBars)
|
|
{
|
|
//
|
|
count = ArraySize(source.bullishMomentumBars);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCMomentumBar *iMomentum = source.bullishMomentumBars[i];
|
|
|
|
//
|
|
XOHCL iBar;
|
|
bool isFilled = iMomentum.FillBar(iBar);
|
|
if (!isFilled)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isInside = iBar.low <= pivot.upper &&
|
|
iBar.low >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iMomentum.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iMomentum,
|
|
state.bullishMomentumBars //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bearish Momenum Bars ...
|
|
if (lookupBearishMomentumBars)
|
|
{
|
|
//
|
|
count = ArraySize(source.bearishMomentumBars);
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCMomentumBar *iMomentum = source.bearishMomentumBars[i];
|
|
|
|
//
|
|
XOHCL iBar;
|
|
bool isFilled = iMomentum.FillBar(iBar);
|
|
if (!isFilled)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//
|
|
bool isInside = iBar.high <= pivot.upper &&
|
|
iBar.high >= pivot.lower;
|
|
if (isInside)
|
|
{
|
|
//
|
|
iMomentum.To(pivot.to);
|
|
|
|
//
|
|
Add(
|
|
iMomentum,
|
|
state.bearishMomentumBars //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Detect Price Inside Zones ...
|
|
*
|
|
* @param state: XPOIState instance Reference ...
|
|
* @param bar: XOHCL instance Reference ...
|
|
* @param hasSupport: Boolean ...
|
|
* @param hasResistanceZone: Boolean ...
|
|
* @param hasSupplyZone: Boolean ...
|
|
* @param hasDemandZone: Boolean ...
|
|
* @param hasOrderBlock: Boolean ...
|
|
* @param hasFairValueGap: Boolean ...
|
|
* @return ( bool )
|
|
*/
|
|
bool DetectPriceInsideZones(
|
|
XPOIState &state,
|
|
XOHCL &bar,
|
|
int &zonesCount,
|
|
bool &hasSupportZone,
|
|
XCSupportZone *&supportZone,
|
|
bool &hasResistanceZone,
|
|
XCResistanceZone *&resistanceZone,
|
|
bool &hasSupplyZone,
|
|
XCSupplyZone *&supplyZone,
|
|
bool &hasDemandZone,
|
|
XCDemandZone *&demandZone,
|
|
bool &hasOrderBlock,
|
|
XCOrderBlock *&orderBlock,
|
|
bool &hasFairValueGap,
|
|
XCFVG *&fairValueGap //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zonesCount = 0;
|
|
|
|
//
|
|
hasSupportZone = false;
|
|
hasResistanceZone = false;
|
|
hasSupplyZone = false;
|
|
hasDemandZone = false;
|
|
hasOrderBlock = false;
|
|
hasFairValueGap = false;
|
|
|
|
//
|
|
supportZone = NULL;
|
|
resistanceZone = NULL;
|
|
supplyZone = NULL;
|
|
demandZone = NULL;
|
|
orderBlock = NULL;
|
|
fairValueGap = NULL;
|
|
|
|
//
|
|
datetime cTime = TimeCurrent();
|
|
|
|
//
|
|
result = bar.IsValid() &&
|
|
state.IsValid() &&
|
|
state.HasChild();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = 0;
|
|
|
|
//
|
|
// Support Zone ...
|
|
count = state.CountSupportZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCSupportZone *iZone = state.supportZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(bar, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
supportZone = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasSupportZone = supportZone != NULL &&
|
|
supportZone.IsValid();
|
|
if (hasSupportZone)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
supportZone.To(cTime);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Resistance Zone ...
|
|
count = state.CountResistanceZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCResistanceZone *iZone = state.resistanceZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(bar, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
resistanceZone = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasResistanceZone = resistanceZone != NULL &&
|
|
resistanceZone.IsValid();
|
|
if (hasResistanceZone)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
resistanceZone.To(cTime);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Supply Zone ...
|
|
count = state.CountSupplyZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCSupplyZone *iZone = state.supplyZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(bar, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
supplyZone = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasSupplyZone = supplyZone != NULL &&
|
|
supplyZone.IsValid();
|
|
if (hasSupplyZone)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
supplyZone.To(cTime);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Demand Zone ...
|
|
count = state.CountDemandZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCDemandZone *iZone = state.demandZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(bar, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
demandZone = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasDemandZone = demandZone != NULL &&
|
|
demandZone.IsValid();
|
|
if (hasDemandZone)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
demandZone.To(cTime);
|
|
}
|
|
}
|
|
|
|
//
|
|
// OrderBlock ...
|
|
count = state.CountBullishOrderBlocks();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCOrderBlock *iZone = state.bullishOrderBlocks[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(bar, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
orderBlock = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasOrderBlock = orderBlock != NULL &&
|
|
orderBlock.IsValid();
|
|
if (hasOrderBlock)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
orderBlock.To(cTime);
|
|
}
|
|
}
|
|
if (!hasOrderBlock)
|
|
{
|
|
//
|
|
count = state.CountBearishOrderBlocks();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCOrderBlock *iZone = state.bearishOrderBlocks[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(bar, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
orderBlock = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasOrderBlock = orderBlock != NULL &&
|
|
orderBlock.IsValid();
|
|
if (hasOrderBlock)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
orderBlock.To(cTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fair Value Gap ...
|
|
count = state.CountBullishFairValueGaps();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCFVG *iZone = state.bullishFairValueGaps[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(bar, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
fairValueGap = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasFairValueGap = fairValueGap != NULL &&
|
|
fairValueGap.IsValid();
|
|
if (hasFairValueGap)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
fairValueGap.To(cTime);
|
|
}
|
|
}
|
|
if (!hasFairValueGap)
|
|
{
|
|
//
|
|
count = state.CountBearishFairValueGaps();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCFVG *iZone = state.bearishFairValueGaps[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(bar, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
fairValueGap = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasFairValueGap = fairValueGap != NULL &&
|
|
fairValueGap.IsValid();
|
|
if (hasFairValueGap)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
fairValueGap.To(cTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
hasSupportZone ||
|
|
hasResistanceZone ||
|
|
hasSupplyZone ||
|
|
hasDemandZone ||
|
|
hasOrderBlock ||
|
|
hasFairValueGap
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Detect Price Inside Zones ...
|
|
*
|
|
* @param state: XPOIState instance Reference ...
|
|
* @param price: Double ...
|
|
* @param hasSupport: Boolean ...
|
|
* @param hasResistanceZone: Boolean ...
|
|
* @param hasSupplyZone: Boolean ...
|
|
* @param hasDemandZone: Boolean ...
|
|
* @param hasOrderBlock: Boolean ...
|
|
* @param hasFairValueGap: Boolean ...
|
|
* @return ( bool )
|
|
*/
|
|
bool DetectPriceInsideZones(
|
|
XPOIState &state,
|
|
double price,
|
|
int &zonesCount,
|
|
bool &hasSupportZone,
|
|
XCSupportZone *&supportZone,
|
|
bool &hasResistanceZone,
|
|
XCResistanceZone *&resistanceZone,
|
|
bool &hasSupplyZone,
|
|
XCSupplyZone *&supplyZone,
|
|
bool &hasDemandZone,
|
|
XCDemandZone *&demandZone,
|
|
bool &hasOrderBlock,
|
|
XCOrderBlock *&orderBlock,
|
|
bool &hasFairValueGap,
|
|
XCFVG *&fairValueGap //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zonesCount = 0;
|
|
|
|
//
|
|
hasSupportZone = false;
|
|
hasResistanceZone = false;
|
|
hasSupplyZone = false;
|
|
hasDemandZone = false;
|
|
hasOrderBlock = false;
|
|
hasFairValueGap = false;
|
|
|
|
//
|
|
supportZone = NULL;
|
|
resistanceZone = NULL;
|
|
supplyZone = NULL;
|
|
demandZone = NULL;
|
|
orderBlock = NULL;
|
|
fairValueGap = NULL;
|
|
|
|
//
|
|
datetime cTime = TimeCurrent();
|
|
|
|
//
|
|
result = price > 0 &&
|
|
state.IsValid() &&
|
|
state.HasChild();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = 0;
|
|
|
|
//
|
|
// Support Zone ...
|
|
count = state.CountSupportZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCSupportZone *iZone = state.supportZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(price, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
supportZone = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasSupportZone = supportZone != NULL &&
|
|
supportZone.IsValid();
|
|
if (hasSupportZone)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
supportZone.To(cTime);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Resistance Zone ...
|
|
count = state.CountResistanceZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCResistanceZone *iZone = state.resistanceZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(price, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
resistanceZone = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasResistanceZone = resistanceZone != NULL &&
|
|
resistanceZone.IsValid();
|
|
if (hasResistanceZone)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
resistanceZone.To(cTime);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Supply Zone ...
|
|
count = state.CountSupplyZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCSupplyZone *iZone = state.supplyZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(price, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
supplyZone = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasSupplyZone = supplyZone != NULL &&
|
|
supplyZone.IsValid();
|
|
if (hasSupplyZone)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
supplyZone.To(cTime);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Demand Zone ...
|
|
count = state.CountDemandZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCDemandZone *iZone = state.demandZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(price, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
demandZone = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasDemandZone = demandZone != NULL &&
|
|
demandZone.IsValid();
|
|
if (hasDemandZone)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
demandZone.To(cTime);
|
|
}
|
|
}
|
|
|
|
//
|
|
// OrderBlock ...
|
|
count = state.CountBullishOrderBlocks();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCOrderBlock *iZone = state.bullishOrderBlocks[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(price, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
orderBlock = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasOrderBlock = orderBlock != NULL &&
|
|
orderBlock.IsValid();
|
|
if (hasOrderBlock)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
orderBlock.To(cTime);
|
|
}
|
|
}
|
|
if (!hasOrderBlock)
|
|
{
|
|
//
|
|
count = state.CountBearishOrderBlocks();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCOrderBlock *iZone = state.bearishOrderBlocks[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(price, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
orderBlock = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasOrderBlock = orderBlock != NULL &&
|
|
orderBlock.IsValid();
|
|
if (hasOrderBlock)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
orderBlock.To(cTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fair Value Gap ...
|
|
count = state.CountBullishFairValueGaps();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCFVG *iZone = state.bullishFairValueGaps[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(price, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
fairValueGap = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasFairValueGap = fairValueGap != NULL &&
|
|
fairValueGap.IsValid();
|
|
if (hasFairValueGap)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
fairValueGap.To(cTime);
|
|
}
|
|
}
|
|
if (!hasFairValueGap)
|
|
{
|
|
//
|
|
count = state.CountBearishFairValueGaps();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCFVG *iZone = state.bearishFairValueGaps[i];
|
|
|
|
//
|
|
bool isValid = IsPriceInsideZone(price, iZone);
|
|
if (isValid)
|
|
{
|
|
//
|
|
fairValueGap = iZone;
|
|
}
|
|
}
|
|
|
|
//
|
|
hasFairValueGap = fairValueGap != NULL &&
|
|
fairValueGap.IsValid();
|
|
if (hasFairValueGap)
|
|
{
|
|
//
|
|
zonesCount++;
|
|
fairValueGap.To(cTime);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
hasSupportZone ||
|
|
hasResistanceZone ||
|
|
hasSupplyZone ||
|
|
hasDemandZone ||
|
|
hasOrderBlock ||
|
|
hasFairValueGap
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool CalculatePriceInsideZones(
|
|
XPriceZones &zone,
|
|
XPOIState &state,
|
|
double price //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zone.Clean();
|
|
|
|
//
|
|
int zonesCount = 0;
|
|
bool hasSupplyZone = false;
|
|
bool hasDemandZone = false;
|
|
bool hasOrderBlock = false;
|
|
bool hasSupportZone = false;
|
|
bool hasFairValueGap = false;
|
|
bool hasResistanceZone = false;
|
|
|
|
//
|
|
result = DetectPriceInsideZones(
|
|
state,
|
|
price,
|
|
zone.count,
|
|
hasSupportZone,
|
|
zone.supportZone,
|
|
hasResistanceZone,
|
|
zone.resistanceZone,
|
|
hasSupplyZone,
|
|
zone.supplyZone,
|
|
hasDemandZone,
|
|
zone.demandZone,
|
|
hasOrderBlock,
|
|
zone.orderBlock,
|
|
hasFairValueGap,
|
|
zone.fairValueGap //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
zone.price = price;
|
|
|
|
//
|
|
result = zone.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool CalculatePriceInsideZones(
|
|
XPriceZones &zone,
|
|
XPOIState &state,
|
|
XOHCL &bar //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zone.Clean();
|
|
|
|
//
|
|
int zonesCount = 0;
|
|
bool hasSupplyZone = false;
|
|
bool hasDemandZone = false;
|
|
bool hasOrderBlock = false;
|
|
bool hasSupportZone = false;
|
|
bool hasFairValueGap = false;
|
|
bool hasResistanceZone = false;
|
|
|
|
//
|
|
result = DetectPriceInsideZones(
|
|
state,
|
|
bar,
|
|
zone.count,
|
|
hasSupportZone,
|
|
zone.supportZone,
|
|
hasResistanceZone,
|
|
zone.resistanceZone,
|
|
hasSupplyZone,
|
|
zone.supplyZone,
|
|
hasDemandZone,
|
|
zone.demandZone,
|
|
hasOrderBlock,
|
|
zone.orderBlock,
|
|
hasFairValueGap,
|
|
zone.fairValueGap //
|
|
);
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
zone.bar = bar;
|
|
|
|
//
|
|
result = zone.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
bool CalculateStateZones(
|
|
XStateZones &zones,
|
|
XPOIState &source,
|
|
double upper,
|
|
double lower,
|
|
datetime from //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
zones.Clean();
|
|
|
|
//
|
|
datetime cTime = TimeCurrent();
|
|
|
|
//
|
|
result =
|
|
//
|
|
upper > 0 &&
|
|
lower > 0 &&
|
|
upper > lower &&
|
|
IsValid(from) &&
|
|
source.IsValid() &&
|
|
source.HasChild()
|
|
//
|
|
;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
int count = 0;
|
|
|
|
//
|
|
// Support ...
|
|
count = source.CountSupportZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCSupportZone *iZone = source.supportZones[i];
|
|
|
|
//
|
|
double iUpper = iZone.Upper();
|
|
double iLower = iZone.Lower();
|
|
datetime iFrom = iZone.From();
|
|
|
|
//
|
|
bool isAbove = iUpper > upper &&
|
|
iLower <= upper;
|
|
|
|
//
|
|
bool isInside = iUpper <= upper &&
|
|
iLower >= lower;
|
|
|
|
//
|
|
bool isBelow = iUpper >= lower &&
|
|
iLower < lower;
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
iFrom > from &&
|
|
(isAbove ||
|
|
isBelow ||
|
|
isInside)
|
|
//
|
|
;
|
|
if (isValid)
|
|
{
|
|
//
|
|
iZone.To(cTime);
|
|
Add(
|
|
iZone,
|
|
zones.supportZones //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Resistance ...
|
|
count = source.CountResistanceZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCResistanceZone *iZone = source.resistanceZones[i];
|
|
|
|
//
|
|
double iUpper = iZone.Upper();
|
|
double iLower = iZone.Lower();
|
|
datetime iFrom = iZone.From();
|
|
|
|
//
|
|
bool isAbove = iUpper > upper &&
|
|
iLower <= upper;
|
|
|
|
//
|
|
bool isInside = iUpper <= upper &&
|
|
iLower >= lower;
|
|
|
|
//
|
|
bool isBelow = iUpper >= lower &&
|
|
iLower < lower;
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
iFrom > from &&
|
|
(isAbove ||
|
|
isBelow ||
|
|
isInside)
|
|
//
|
|
;
|
|
if (isValid)
|
|
{
|
|
//
|
|
iZone.To(cTime);
|
|
Add(
|
|
iZone,
|
|
zones.resistanceZones //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Supply ...
|
|
count = source.CountSupplyZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCSupplyZone *iZone = source.supplyZones[i];
|
|
|
|
//
|
|
double iUpper = iZone.Upper();
|
|
double iLower = iZone.Lower();
|
|
datetime iFrom = iZone.From();
|
|
|
|
//
|
|
bool isAbove = iUpper > upper &&
|
|
iLower <= upper;
|
|
|
|
//
|
|
bool isInside = iUpper <= upper &&
|
|
iLower >= lower;
|
|
|
|
//
|
|
bool isBelow = iUpper >= lower &&
|
|
iLower < lower;
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
iFrom > from &&
|
|
(isAbove ||
|
|
isBelow ||
|
|
isInside)
|
|
//
|
|
;
|
|
if (isValid)
|
|
{
|
|
//
|
|
iZone.To(cTime);
|
|
Add(
|
|
iZone,
|
|
zones.supplyZones //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Demand ...
|
|
count = source.CountDemandZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCDemandZone *iZone = source.demandZones[i];
|
|
|
|
//
|
|
double iUpper = iZone.Upper();
|
|
double iLower = iZone.Lower();
|
|
datetime iFrom = iZone.From();
|
|
|
|
//
|
|
bool isAbove = iUpper > upper &&
|
|
iLower <= upper;
|
|
|
|
//
|
|
bool isInside = iUpper <= upper &&
|
|
iLower >= lower;
|
|
|
|
//
|
|
bool isBelow = iUpper >= lower &&
|
|
iLower < lower;
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
iFrom > from &&
|
|
(isAbove ||
|
|
isBelow ||
|
|
isInside)
|
|
//
|
|
;
|
|
if (isValid)
|
|
{
|
|
//
|
|
iZone.To(cTime);
|
|
Add(
|
|
iZone,
|
|
zones.demandZones //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bullish OrderBlocks ...
|
|
count = source.CountBullishOrderBlocks();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCOrderBlock *iZone = source.bullishOrderBlocks[i];
|
|
|
|
//
|
|
double iUpper = iZone.Upper();
|
|
double iLower = iZone.Lower();
|
|
datetime iFrom = iZone.From();
|
|
|
|
//
|
|
bool isAbove = iUpper > upper &&
|
|
iLower <= upper;
|
|
|
|
//
|
|
bool isInside = iUpper <= upper &&
|
|
iLower >= lower;
|
|
|
|
//
|
|
bool isBelow = iUpper >= lower &&
|
|
iLower < lower;
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
iFrom > from &&
|
|
(isAbove ||
|
|
isBelow ||
|
|
isInside)
|
|
//
|
|
;
|
|
if (isValid)
|
|
{
|
|
//
|
|
iZone.To(cTime);
|
|
Add(
|
|
iZone,
|
|
zones.bullishOrderBlocks //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bearish OrderBlocks ...
|
|
count = source.CountBearishOrderBlocks();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCOrderBlock *iZone = source.bearishOrderBlocks[i];
|
|
|
|
//
|
|
double iUpper = iZone.Upper();
|
|
double iLower = iZone.Lower();
|
|
datetime iFrom = iZone.From();
|
|
|
|
//
|
|
bool isAbove = iUpper > upper &&
|
|
iLower <= upper;
|
|
|
|
//
|
|
bool isInside = iUpper <= upper &&
|
|
iLower >= lower;
|
|
|
|
//
|
|
bool isBelow = iUpper >= lower &&
|
|
iLower < lower;
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
iFrom > from &&
|
|
(isAbove ||
|
|
isBelow ||
|
|
isInside)
|
|
//
|
|
;
|
|
if (isValid)
|
|
{
|
|
//
|
|
iZone.To(cTime);
|
|
Add(
|
|
iZone,
|
|
zones.bearishOrderBlocks //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bullish FairValueGaps ...
|
|
count = source.CountBullishFairValueGaps();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCFVG *iZone = source.bullishFairValueGaps[i];
|
|
|
|
//
|
|
double iUpper = iZone.Upper();
|
|
double iLower = iZone.Lower();
|
|
datetime iFrom = iZone.From();
|
|
|
|
//
|
|
bool isAbove = iUpper > upper &&
|
|
iLower <= upper;
|
|
|
|
//
|
|
bool isInside = iUpper <= upper &&
|
|
iLower >= lower;
|
|
|
|
//
|
|
bool isBelow = iUpper >= lower &&
|
|
iLower < lower;
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
iFrom > from &&
|
|
(isAbove ||
|
|
isBelow ||
|
|
isInside)
|
|
//
|
|
;
|
|
if (isValid)
|
|
{
|
|
//
|
|
iZone.To(cTime);
|
|
Add(
|
|
iZone,
|
|
zones.bullishFairValueGaps //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bearish FairValueGaps ...
|
|
count = source.CountBearishFairValueGaps();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XCFVG *iZone = source.bearishFairValueGaps[i];
|
|
|
|
//
|
|
double iUpper = iZone.Upper();
|
|
double iLower = iZone.Lower();
|
|
datetime iFrom = iZone.From();
|
|
|
|
//
|
|
bool isAbove = iUpper > upper &&
|
|
iLower <= upper;
|
|
|
|
//
|
|
bool isInside = iUpper <= upper &&
|
|
iLower >= lower;
|
|
|
|
//
|
|
bool isBelow = iUpper >= lower &&
|
|
iLower < lower;
|
|
|
|
//
|
|
bool isValid =
|
|
//
|
|
iFrom > from &&
|
|
(isAbove ||
|
|
isBelow ||
|
|
isInside)
|
|
//
|
|
;
|
|
if (isValid)
|
|
{
|
|
//
|
|
iZone.To(cTime);
|
|
Add(
|
|
iZone,
|
|
zones.bearishFairValueGaps //
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
result = zones.IsValid();
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Add Value Change instance to Exists Collection if it's not Exists ...
|
|
*
|
|
* @param item: XValueChange instance Reference ...
|
|
* @param items: XValueChange instance Array Reference ...
|
|
*
|
|
* @return ( int )
|
|
*/
|
|
int AddIfNotExists(
|
|
XValueChange &item,
|
|
XValueChange &items[] //
|
|
)
|
|
{
|
|
//
|
|
int result = 0;
|
|
|
|
//
|
|
result = item.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
bool canAdd = false;
|
|
int count = ArraySize(items);
|
|
if (!IsValidSize(count))
|
|
{
|
|
canAdd = true;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
XValueChange last;
|
|
bool hasItem = GetLastItem(
|
|
last,
|
|
items //
|
|
);
|
|
if (!hasItem)
|
|
{
|
|
canAdd = true;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Compare Last Item with Current ...
|
|
canAdd = item.time > last.time;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add Item if Allowed ...
|
|
if (canAdd)
|
|
{
|
|
//
|
|
AddRef(
|
|
item,
|
|
items //
|
|
);
|
|
}
|
|
|
|
//
|
|
result = ArraySize(items);
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Combine a Collection of States into dest ...
|
|
*
|
|
* @param dest: XPOIState instance ...
|
|
* @param source: XPOIState Collection ...
|
|
*/
|
|
void CombineStates(
|
|
XPOIState &dest,
|
|
XPOIState &source[] //
|
|
)
|
|
{
|
|
//
|
|
dest.Clean();
|
|
|
|
//
|
|
int count = ArraySize(source);
|
|
if (!IsValidSize(count))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
//
|
|
XPOIState iState = source[i];
|
|
|
|
//
|
|
if (dest.ticksZone == NULL)
|
|
{
|
|
dest.ticksZone = iState.ticksZone;
|
|
}
|
|
|
|
//
|
|
Copy(
|
|
iState.swingHighs,
|
|
dest.swingHighs,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.swingLows,
|
|
dest.swingLows,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.bullishMomentumBars,
|
|
dest.bullishMomentumBars,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.bearishMomentumBars,
|
|
dest.bearishMomentumBars,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.bullishRejectionBars,
|
|
dest.bullishRejectionBars,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.bearishRejectionBars,
|
|
dest.bearishRejectionBars,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.supportZones,
|
|
dest.supportZones,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.resistanceZones,
|
|
dest.resistanceZones,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.supplyZones,
|
|
dest.supplyZones,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.demandZones,
|
|
dest.demandZones,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.bullishOrderBlocks,
|
|
dest.bullishOrderBlocks,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.bearishOrderBlocks,
|
|
dest.bearishOrderBlocks,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.bullishFairValueGaps,
|
|
dest.bullishFairValueGaps,
|
|
false //
|
|
);
|
|
|
|
//
|
|
Copy(
|
|
iState.bearishFairValueGaps,
|
|
dest.bearishFairValueGaps,
|
|
false //
|
|
);
|
|
|
|
//
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check Price Above Specified Zone ...
|
|
*
|
|
* @param bar: XOHCL instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPriceAboveZone(
|
|
XOHCL &bar,
|
|
XCZone *zone //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
zone != NULL &&
|
|
bar.IsValid() &&
|
|
zone.IsValidBoundary();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
bar.low > zone.Upper()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Price Above Specified Zone ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPriceAboveZone(
|
|
double price,
|
|
XCZone *zone //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
price > 0 &&
|
|
zone != NULL &&
|
|
zone.IsValidBoundary();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
price > zone.Upper()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Price Below Specified Zone ...
|
|
*
|
|
* @param bar: XOHCL instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPriceBelowZone(
|
|
XOHCL &bar,
|
|
XCZone *zone //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
zone != NULL &&
|
|
bar.IsValid() &&
|
|
zone.IsValidBoundary();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
bar.high < zone.Lower()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Price Below Specified Zone ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPriceBelowZone(
|
|
double price,
|
|
XCZone *zone //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
price > 0 &&
|
|
zone != NULL &&
|
|
zone.IsValidBoundary();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
price < zone.Lower()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Price Inside Specified Zone ...
|
|
*
|
|
* @param bar: XOHCL instance Reference ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPriceInsideZone(
|
|
XOHCL &bar,
|
|
XCZone *zone //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
zone != NULL &&
|
|
bar.IsValid() &&
|
|
zone.IsValidBoundary();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
bar.low <= zone.Upper()
|
|
//
|
|
&&
|
|
//
|
|
bar.low >= zone.Lower()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsPriceInsideZone(
|
|
XOHCL &bar,
|
|
double upper,
|
|
double lower //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
upper > 0 &&
|
|
lower > 0 &&
|
|
upper > lower &&
|
|
bar.IsValid();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
bar.low <= upper
|
|
//
|
|
&&
|
|
//
|
|
bar.low >= lower
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check Price Inside Specified Zone ...
|
|
*
|
|
* @return ( bool )
|
|
*/
|
|
bool IsPriceInsideZone(
|
|
double price,
|
|
XCZone *zone //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
price > 0 &&
|
|
zone != NULL &&
|
|
zone.IsValidBoundary();
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
price <= zone.Upper()
|
|
//
|
|
&&
|
|
//
|
|
price >= zone.Lower()
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
bool IsPriceInsideZone(
|
|
double price,
|
|
double upper,
|
|
double lower //
|
|
)
|
|
{
|
|
//
|
|
bool result = false;
|
|
|
|
//
|
|
result =
|
|
price > 0 &&
|
|
upper > 0 &&
|
|
lower > 0 &&
|
|
upper > lower;
|
|
if (!result)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
result =
|
|
//
|
|
price <= upper
|
|
//
|
|
&&
|
|
//
|
|
price >= lower
|
|
//
|
|
;
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Calculate Target for Specified Direction ...
|
|
*
|
|
* @param bar: XOHCL instance Reference ...
|
|
* @param state: XPOIState instance Reference ...
|
|
* @param forDir: ENUM_S_DIRECTION member ...
|
|
*
|
|
* @return ( double )
|
|
*/
|
|
double CalculateTarget(
|
|
XOHCL &bar,
|
|
XPOIState &state,
|
|
ENUM_X_DIRECTION forDir //
|
|
)
|
|
{
|
|
//
|
|
double result = 0;
|
|
|
|
//
|
|
if (!state.IsValid() ||
|
|
!state.HasChild() ||
|
|
!HasDirection(forDir))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
//
|
|
XCFVG *iFVG = NULL;
|
|
XCOrderBlock *iOB = NULL;
|
|
XCSupplyZone *iSupply = NULL;
|
|
XCDemandZone *iDemand = NULL;
|
|
XCSupportZone *iSupport = NULL;
|
|
XCResistanceZone *iResistance = NULL;
|
|
|
|
//
|
|
bool hasOB = false;
|
|
bool hasFVG = false;
|
|
bool hasSupply = false;
|
|
bool hasDemand = false;
|
|
bool hasSupport = false;
|
|
bool hasResistance = false;
|
|
|
|
//
|
|
int count = 0;
|
|
|
|
//
|
|
if (IsBearish(forDir))
|
|
{
|
|
//
|
|
// FVG ...
|
|
count = state.CountBullishFairValueGaps();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCFVG *iZone = state.bullishFairValueGaps[i];
|
|
|
|
//
|
|
bool isValid = IsPriceAboveZone(
|
|
bar,
|
|
iZone //
|
|
);
|
|
if (isValid)
|
|
{
|
|
//
|
|
iFVG = iZone;
|
|
hasFVG = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// OB ...
|
|
count = state.CountBullishOrderBlocks();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCOrderBlock *iZone = state.bullishOrderBlocks[i];
|
|
|
|
//
|
|
bool isValid = IsPriceAboveZone(
|
|
bar,
|
|
iZone //
|
|
);
|
|
if (isValid)
|
|
{
|
|
//
|
|
iOB = iZone;
|
|
hasOB = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// SUPPORT ...
|
|
count = state.CountSupportZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCSupportZone *iZone = state.supportZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceAboveZone(
|
|
bar,
|
|
iZone //
|
|
);
|
|
if (isValid)
|
|
{
|
|
//
|
|
iSupport = iZone;
|
|
hasSupport = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// DEMAND ...
|
|
count = state.CountDemandZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCDemandZone *iZone = state.demandZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceAboveZone(
|
|
bar,
|
|
iZone //
|
|
);
|
|
if (isValid)
|
|
{
|
|
//
|
|
iDemand = iZone;
|
|
hasDemand = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Summary ...
|
|
result =
|
|
hasFVG
|
|
? iFVG.Upper()
|
|
: hasOB
|
|
? iOB.Upper()
|
|
: hasSupport
|
|
? iSupport.Upper()
|
|
: hasDemand
|
|
? iDemand.Upper()
|
|
: 0;
|
|
if (hasFVG)
|
|
{
|
|
result = MathMax(result, iFVG.Upper());
|
|
}
|
|
if (hasOB)
|
|
{
|
|
result = MathMax(result, iOB.Upper());
|
|
}
|
|
if (hasSupport)
|
|
{
|
|
result = MathMax(result, iSupport.Upper());
|
|
}
|
|
if (hasDemand)
|
|
{
|
|
result = MathMax(result, iDemand.Upper());
|
|
}
|
|
}
|
|
|
|
//
|
|
if (IsBullish(forDir))
|
|
{
|
|
//
|
|
// FVG ...
|
|
count = state.CountBearishFairValueGaps();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCFVG *iZone = state.bearishFairValueGaps[i];
|
|
|
|
//
|
|
bool isValid = IsPriceBelowZone(
|
|
bar,
|
|
iZone //
|
|
);
|
|
if (isValid)
|
|
{
|
|
//
|
|
iFVG = iZone;
|
|
hasFVG = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// OB ...
|
|
count = state.CountBearishOrderBlocks();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCOrderBlock *iZone = state.bearishOrderBlocks[i];
|
|
|
|
//
|
|
bool isValid = IsPriceBelowZone(
|
|
bar,
|
|
iZone //
|
|
);
|
|
if (isValid)
|
|
{
|
|
//
|
|
iOB = iZone;
|
|
hasOB = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// RESISTANCE ...
|
|
count = state.CountResistanceZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCResistanceZone *iZone = state.resistanceZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceBelowZone(
|
|
bar,
|
|
iZone //
|
|
);
|
|
if (isValid)
|
|
{
|
|
//
|
|
iResistance = iZone;
|
|
hasResistance = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// SUPPLY ...
|
|
count = state.CountSupplyZones();
|
|
if (IsValidSize(count))
|
|
{
|
|
//
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
//
|
|
XCSupplyZone *iZone = state.supplyZones[i];
|
|
|
|
//
|
|
bool isValid = IsPriceBelowZone(
|
|
bar,
|
|
iZone //
|
|
);
|
|
if (isValid)
|
|
{
|
|
//
|
|
iSupply = iZone;
|
|
hasSupply = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Summary ...
|
|
result =
|
|
hasFVG
|
|
? iFVG.Lower()
|
|
: hasOB
|
|
? iOB.Lower()
|
|
: hasSupport
|
|
? iSupport.Lower()
|
|
: hasDemand
|
|
? iDemand.Lower()
|
|
: 0;
|
|
if (hasFVG)
|
|
{
|
|
result = MathMin(result, iFVG.Lower());
|
|
}
|
|
if (hasOB)
|
|
{
|
|
result = MathMin(result, iOB.Lower());
|
|
}
|
|
if (hasSupport)
|
|
{
|
|
result = MathMin(result, iSupport.Lower());
|
|
}
|
|
if (hasDemand)
|
|
{
|
|
result = MathMin(result, iDemand.Lower());
|
|
}
|
|
}
|
|
|
|
//
|
|
return result;
|
|
}
|
|
|
|
//
|
|
typedef void (*TOnPOIEvent)(ENUM_XPOI_EVENTS event,
|
|
XCBasePOI *param //
|
|
);
|
|
|
|
// |