Add support for Draw Trend Line for Order Flow ...

This commit is contained in:
2025-02-19 03:17:38 +03:30
parent 5d0b655ad9
commit bf8b74d4e7
4 changed files with 613 additions and 504 deletions
@@ -4332,6 +4332,7 @@ class XCPOIDrawer : public XCBase
//
int DrawOBFVG(
//
XOBFVG &item,
XCBaseObject *&objects[],
//
+208
View File
@@ -6067,6 +6067,51 @@ struct XBoxZone
}
};
//
struct XOBFVGPivot
{
//
// Props ...
double value;
datetime at;
//
// Constructor ...
XOBFVGPivot()
{
Clean();
}
//
// Tools ...
//
void Clean()
{
//
value = 0;
at = NULL;
//
ZeroMemory(this);
}
//
bool IsValid()
{
//
bool result = false;
//
result =
value > 0 &&
IsValid(at);
//
return result;
}
};
//
struct XOBFVG
{
@@ -6105,6 +6150,9 @@ struct XOBFVG
Clean(demandZones);
Clean(supportZones);
Clean(resistanceZones);
//
ZeroMemory(this);
}
//
@@ -6176,6 +6224,166 @@ struct XOBFVG
return ArraySize(resistanceZones);
}
//
ENUM_X_DIRECTION GetDirection()
{
//
ENUM_X_DIRECTION result = X_DIRECTION_NONE;
//
bool isValid = IsValid();
if (!isValid)
{
return result;
}
//
result = ob.GetDirection();
//
return result;
}
//
bool IsBullish()
{
return IsBullish(GetDirection());
}
//
bool IsBearish()
{
return IsBearish(GetDirection());
}
//
int GetSwings(
XOBFVGPivot &pivots[] //
)
{
//
int result = 0;
//
Clean(pivots);
//
if (!IsValid())
{
return result;
}
//
ENUM_X_DIRECTION forDir = GetDirection();
bool isBullish = IsBullish(forDir);
//
XOHCL passedBar;
XOBFVGPivot iPivot;
bool isPassed = false;
double appliedPrice = 0;
bool isBodyState = false;
//
// Start ...
isPassed = ob.IsStarted(
forDir,
passedBar,
isBodyState //
);
if (isPassed)
{
//
appliedPrice =
isBullish
? passedBar.low
: passedBar.high;
//
iPivot.Clean();
iPivot.value = appliedPrice;
iPivot.at = passedBar.time;
//
AddRef(
iPivot,
pivots //
);
//
iPivot.Clean();
}
//
// Activation ...
isPassed = ob.IsActivated(
forDir,
passedBar,
isBodyState //
);
if (isPassed)
{
//
appliedPrice =
isBullish
? passedBar.low
: passedBar.high;
//
iPivot.Clean();
iPivot.value = appliedPrice;
iPivot.at = passedBar.time;
//
AddRef(
iPivot,
pivots //
);
//
iPivot.Clean();
}
//
// Worked ...
isPassed = ob.IsWorked(
forDir,
passedBar,
isBodyState //
);
if (isPassed)
{
//
appliedPrice =
isBullish
? passedBar.low
: passedBar.high;
//
iPivot.Clean();
iPivot.value = appliedPrice;
iPivot.at = passedBar.time;
//
AddRef(
iPivot,
pivots //
);
//
iPivot.Clean();
}
//
passedBar.Clean();
//
result = ArraySize(pivots);
//
return result;
}
//
void UpdateTo(datetime value = NULL)
{
+212 -16
View File
@@ -232,26 +232,47 @@ class XCX121SMCXWZSignalDetector : public XCBase
// Setup Conditions ...
//
int bullishFlowCount = mConditions.DetectOrderFlow(
X_DIRECTION_BULLISH,
consolidationState,
analyseState,
decisionState,
zIndex,
period,
ENUM_X_DIRECTION trend = X_DIRECTION_NONE;
bool hasOrderFlow = mConditions.HasOrderFlow(trend);
if (!hasOrderFlow)
{
//
int orderFlowCount = mConditions.DetectOrderFlow(
trend,
consolidationState,
analyseState,
decisionState //
);
hasOrderFlow = IsValidSize(orderFlowCount);
}
//
result = hasOrderFlow;
if (!result)
{
//
// TODO: Implement Clean ...
//
return result;
}
//
isBullish = IsBullish(trend);
isBearish = IsBearish(trend);
//
// Has Order Flow ...
//
// TODO: Remove this ...
DrawConditions(
mConditions,
visionCycleHelper.mPOIDrawer //
);
//
int bearishFlowCount = mConditions.DetectOrderFlow(
X_DIRECTION_BEARISH,
consolidationState,
analyseState,
decisionState,
zIndex,
period,
visionCycleHelper.mPOIDrawer //
);
//
return false;
@@ -1535,6 +1556,7 @@ class XCX121SMCXWZSignalDetector : public XCBase
void DrawConditions(
X121SMCStrategyXWZSignalConditions &conditions,
XCPOIDrawer *drawer,
bool drawTrendLine = true,
bool forceClean = false //
)
{
@@ -1551,6 +1573,8 @@ class XCX121SMCXWZSignalDetector : public XCBase
}
//
int count = 0;
bool has = false;
bool isCreated = false;
//
@@ -1558,6 +1582,160 @@ class XCX121SMCXWZSignalDetector : public XCBase
int subWindow = drawer.SubWindowIdentification();
color bullishColor = drawer.BarBullishColor();
color bearishColor = drawer.BarBearishColor();
//
ENUM_X_DIRECTION trend;
has = conditions.HasOrderFlow(trend);
if (has)
{
//
bool isBullish = IsBullish(trend);
//
count = conditions.CountOrderFlow();
for (int i = 0; i < count; i++)
{
//
XOBFVG iOBFVG = conditions.orderFlow[i];
//
XCBaseObject *drawnObjects[];
int drawnObjectsCount = drawer
.DrawOBFVG(
//
iOBFVG,
drawnObjects,
//
true, // Draw Order Block ...
true, // Draw Fair Value Gap ...
false, // Draw Supply Zones ...
false, // Draw Demand Zones ...
false, // Draw Support Zones ...
false // Draw Resistance Zones ...
);
if (IsValidSize(drawnObjectsCount))
{
AddDrawnObjects(drawnObjects);
}
}
//
if (drawTrendLine)
{
//
XOBFVGPivot pivots[];
count = conditions.GetSwings(pivots);
has = count >= 2;
if (has)
{
//
// Get Max / Min ...
double max = 0;
double min = 0;
datetime maxAt = NULL;
datetime minAt = NULL;
for (int i = 0; i < count; i++)
{
//
XOBFVGPivot iPivot = pivots[i];
//
if (!iPivot.IsValid())
{
//
iPivot.Clean();
continue;
}
//
// Min ...
bool canSetMin =
min == 0
? true
: min > iPivot.value;
if (canSetMin)
{
//
minAt = iPivot.at;
min = iPivot.value;
}
//
// Max ...
bool canSetMax =
max == 0
? true
: max < iPivot.value;
if (canSetMax)
{
//
maxAt = iPivot.at;
max = iPivot.value;
}
//
iPivot.Clean();
}
//
double price1 =
isBullish
? min
: max;
double price2 =
isBullish
? max
: min;
datetime time1 =
isBullish
? minAt
: maxAt;
datetime time2 =
isBullish
? maxAt
: minAt;
//
color clrTrend =
isBullish
? bullishColor
: bearishColor;
//
string trendName =
ToString(trend) + "_" + "XTRNDL_" +
ToString(conditions.period) + "_" +
ToString(price1) + "_" +
ToString(price2) + "_" +
ToMD5(ToString(time1));
//
CChartObjectTrend *mTrend;
mTrend = new CChartObjectTrend();
isCreated = mTrend.Create(
chartID,
trendName,
subWindow,
time1,
price1,
time2,
price2 //
);
//
if (isCreated)
{
//
mTrend.Width(2);
mTrend.Color(clrTrend);
mTrend.RayRight(true);
//
mObjects.Add(mTrend);
}
}
}
}
}
//
@@ -1663,6 +1841,24 @@ class XCX121SMCXWZSignalDetector : public XCBase
return result;
}
//
void AddDrawnObjects(XCBaseObject *&objects[])
{
//
int count = ArraySize(objects);
bool has = IsValidSize(count);
if (!has)
{
return;
}
//
for (int i = 0; i < count; i++)
{
mObjects.Add(objects[i]);
}
}
//
};
+192 -488
View File
@@ -37,306 +37,6 @@ enum ENUM_X121SMC_XWZ_PRIORITY
X121SMC_XWZ_PRIORITY_STRONG_HIGH,
};
//
struct X121SMCXWZZone
{
//
// Props ...
XCFVG *fvg;
XCOrderBlock *ob;
XCSupplyZone *supply;
XCDemandZone *demand;
XCSupportZone *support;
XCResistanceZone *resistance;
//
// Constructor ...
X121SMCXWZZone()
{
Clean();
}
//
// Tools ...
//
void Clean()
{
//
ZeroMemory(ob);
ZeroMemory(fvg);
ZeroMemory(supply);
ZeroMemory(demand);
ZeroMemory(support);
ZeroMemory(resistance);
}
//
bool IsValid()
{
//
return HasOB() &&
HasFVG() &&
HasDirection();
}
//
bool AsBox(XBoxZone &box)
{
//
bool result = false;
//
box.Clean();
//
result = IsValid() &&
HasDirection();
if (!result)
{
return result;
}
//
XBoxZone obBox;
bool hasOBBox = ToBox(
obBox,
ob //
);
result = hasOBBox;
if (!result)
{
//
box.Clean();
obBox.Clean();
return result;
}
//
box = obBox;
//
obBox.Clean();
//
bool hasOB = HasOB();
bool hasFVG = HasFVG();
bool hasSupply = HasSupply();
bool hasDemand = HasDemand();
bool hasSupport = HasSupport();
bool hasResistance = HasResistance();
//
// OB Compared since box used obBox ...
//
if (hasFVG)
{
//
if (fvg.Upper() > box.upper)
{
box.upper = fvg.Upper();
}
//
if (fvg.Lower() < box.lower)
{
box.lower = fvg.Lower();
}
}
//
result = box.IsValid();
//
return result;
}
//
bool HasOB()
{
return ob != NULL &&
ob.IsValid();
}
//
bool HasFVG()
{
return fvg != NULL &&
fvg.IsValid();
}
//
bool HasSupply()
{
return supply != NULL &&
supply.IsValid();
}
//
bool HasDemand()
{
return demand != NULL &&
demand.IsValid();
}
//
bool HasSupport()
{
return support != NULL &&
support.IsValid();
}
//
bool HasResistance()
{
return resistance != NULL &&
resistance.IsValid();
}
//
bool IsBullish()
{
//
return HasOB() &&
ob.IsBullish() &&
HasFVG() &&
fvg.IsBullish();
}
//
bool IsBearish()
{
//
return HasOB() &&
ob.IsBearish() &&
HasFVG() &&
fvg.IsBearish();
}
//
bool HasDirection()
{
return IsBullish() ||
IsBearish();
}
//
bool ValidateZone(
int barIndex = 0,
ENUM_TIMEFRAMES forPeriod = NULL,
bool forceOB = false,
bool forceFVG = false //
)
{
//
bool result = false;
//
if (barIndex < 0)
{
barIndex = 0;
}
//
result = IsValid() &&
HasDirection();
if (!result)
{
return result;
}
//
string symbol = ob.GetSymbol();
if (forPeriod == NULL)
{
forPeriod = ob.GetPeriod();
}
ENUM_X_DIRECTION forDir = GetDirection();
//
XOHCL cBar;
result = cBar.Init(
symbol,
forPeriod,
barIndex + 1 //
);
if (!result)
{
//
cBar.Clean();
return result;
}
//
bool isObBreaked =
IsBullish(forDir)
? cBar.close < ob.Lower()
: cBar.close > ob.Upper();
//
bool isFVGBreaked =
IsBullish(forDir)
? cBar.close < fvg.Lower()
: cBar.close > fvg.Upper();
//
bool isBreaked = true;
if ((forceOB && forceFVG) ||
(!forceOB && !forceFVG))
{
isBreaked =
isObBreaked ||
isFVGBreaked;
}
else if (forceFVG)
{
isBreaked = isFVGBreaked;
}
else if (forceOB)
{
isBreaked = isObBreaked;
}
//
result = !isBreaked;
//
cBar.Clean();
//
return result;
}
//
ENUM_X_DIRECTION GetDirection()
{
//
ENUM_X_DIRECTION result = X_DIRECTION_NONE;
//
bool hasDirection = HasDirection();
if (!hasDirection)
{
return result;
}
//
bool isBullish = IsBullish();
//
result =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
return result;
}
//
};
//
// Definitions ...
struct X121SMCStrategyXWZSignalConditions
@@ -371,9 +71,7 @@ struct X121SMCStrategyXWZSignalConditions
ENUM_X121SMC_XWZ_PRIORITY priority;
//
// X121SMCXWZZone startZone;
X121SMCXWZZone bullishFlow[];
X121SMCXWZZone bearishFlow[];
XOBFVG orderFlow[];
//
// Constructor ...
@@ -503,8 +201,7 @@ struct X121SMCStrategyXWZSignalConditions
//
// startZone.Clean();
Clean(bullishFlow);
Clean(bearishFlow);
Clean(orderFlow);
}
//
@@ -512,27 +209,93 @@ struct X121SMCStrategyXWZSignalConditions
//
//
bool HasBullishFlow()
bool HasOrderFlow()
{
return HasChild(bullishFlow);
//
bool result = false;
//
result = HasChild(orderFlow);
//
return result;
}
//
int CountBullishFlow()
bool HasOrderFlow(
ENUM_X_DIRECTION &orderFlowDir //
)
{
return ArraySize(bullishFlow);
//
bool result = false;
//
result = HasChild(orderFlow);
if (result)
{
orderFlowDir = orderFlow[0].GetDirection();
}
//
return result;
}
//
bool HasBearishFlow()
int CountOrderFlow()
{
return HasChild(bearishFlow);
return ArraySize(orderFlow);
}
//
int CountBearishFlow()
int GetSwings(
XOBFVGPivot &pivots[] //
)
{
return ArraySize(bearishFlow);
//
int result = 0;
//
Clean(pivots);
//
int count = 0;
bool has = false;
//
has = HasOrderFlow();
if (!has)
{
return result;
}
//
count = CountOrderFlow();
for (int i = 0; i < count; i++)
{
//
XOBFVGPivot iPivots[];
int iPivotsCount = orderFlow[i]
.GetSwings(iPivots);
bool hasPivots = IsValidSize(iPivotsCount);
if (hasPivots)
{
//
Copy(
iPivots,
pivots,
false //
);
}
//
Clean(iPivots);
}
//
result = ArraySize(pivots);
//
return result;
}
//
@@ -542,6 +305,22 @@ struct X121SMCStrategyXWZSignalConditions
value = NormalizeTime(value);
//
int count = 0;
bool has = false;
//
// Order Flow ...
ENUM_X_DIRECTION orderFlowDir;
has = HasOrderFlow(orderFlowDir);
if (has)
{
//
count = CountOrderFlow();
for (int i = 0; i < count; i++)
{
orderFlow[i].UpdateTo(value);
}
}
}
//
@@ -550,18 +329,19 @@ struct X121SMCStrategyXWZSignalConditions
//
int DetectOrderFlow(
ENUM_X_DIRECTION forDir,
ENUM_X_DIRECTION &orderFlowDir,
XPOIState &htfState,
XPOIState &mtfState,
XPOIState &stfState,
int barIndex = 0,
ENUM_TIMEFRAMES forPeriod = NULL,
XCPOIDrawer *drawer = NULL //
XPOIState &stfState //
)
{
//
int result = 0;
//
Clean(orderFlow);
orderFlowDir = X_DIRECTION_NONE;
//
bool isValid =
//
@@ -569,8 +349,7 @@ struct X121SMCStrategyXWZSignalConditions
IsValid(period) &&
htfState.HasChild() &&
mtfState.HasChild() &&
stfState.HasChild() &&
HasDirection(forDir)
stfState.HasChild()
//
;
if (!isValid)
@@ -579,27 +358,14 @@ struct X121SMCStrategyXWZSignalConditions
}
//
if (forPeriod == NULL)
{
forPeriod = period;
}
//
bool isBullish = IsBullish(forDir);
//
int idx = -1;
int count = 0;
bool has = false;
//
XOBFVG tmpOBFVGs[];
count = ExtractOBFVGZones(
// Bullish OBFVGs ...
XOBFVG bullOBFVGs[];
int bullOBFVGsCount = ExtractOBFVGZones(
htfState,
mtfState,
stfState,
tmpOBFVGs,
forDir,
bullOBFVGs,
X_DIRECTION_BULLISH,
NULL, // For Period ...
//
// Start ...
@@ -624,169 +390,107 @@ struct X121SMCStrategyXWZSignalConditions
//
true, // Ignore Inside in Place Filter ...
//
true, // Detect Inside OB POI(s) ...
false, // Detect Inside FVG POI(s) ...
true, // Detect Inside OB POI(s) ...
true, // Detect Inside FVG POI(s) ...
true // Apply From Filter to Selected POI(s) ...
);
has = IsValidSize(count);
if (has)
bool hasBullOBFVGs = IsValidSize(bullOBFVGsCount);
//
// Bearish OBFVGs ...
XOBFVG bearOBFVGs[];
int bearOBFVGsCount = ExtractOBFVGZones(
htfState,
mtfState,
stfState,
bearOBFVGs,
X_DIRECTION_BEARISH,
NULL, // For Period ...
//
// Start ...
XZONE_STATE_PASSED,
true, // Force Body Out ...
//
// Activation ...
XZONE_STATE_PASSED,
true, // Force Body In ...
//
// Breaktion ...
XZONE_STATE_FAILED,
false, // Force Body In ...
//
// Works ...
XZONE_STATE_PASSED,
true, // Force Body Out ...
//
true, // Apply Sort ...
true, // From Filter ...
true, // Place Filter ...
//
true, // Ignore Inside in Place Filter ...
//
true, // Detect Inside OB POI(s) ...
true, // Detect Inside FVG POI(s) ...
true // Apply From Filter to Selected POI(s) ...
);
bool hasBearOBFVGs = IsValidSize(bearOBFVGsCount);
//
bool hasOrderBlow = hasBearOBFVGs ||
hasBullOBFVGs;
if (hasOrderBlow)
{
//
for (int i = 0; i < count; i++)
// Vlidate ...
bool isValid =
//
(hasBullOBFVGs &&
!hasBearOBFVGs &&
bullOBFVGsCount > 1)
//
||
//
(hasBearOBFVGs &&
!hasBullOBFVGs &&
bearOBFVGsCount > 1)
//
;
//
if (isValid)
{
//
XOBFVG iOBFVG = tmpOBFVGs[i];
iOBFVG.UpdateTo(NULL);
// //
// if (iOBFVG.HasOB())
// {
// //
// XCBaseObject *iObj;
// drawer.CreateOrderBlock(
// iOBFVG.ob,
// iObj //
// );
// //
// if (stfState.HasSupplyZones())
// {
// //
// for (int j = 0; j < stfState.CountSupplyZones(); j++)
// {
// //
// XCSupplyZone *jZone = stfState.supplyZones[j];
// //
// bool isInside = IsInsideDiff(
// jZone,
// iOBFVG.ob,
// false //
// );
// //
// if (isInside)
// {
// //
// XCSupplyZoneObject *iObj;
// drawer.CreateSupplyZone(
// jZone,
// iObj //
// );
// }
// }
// }
// //
// if (stfState.HasDemandZones())
// {
// //
// for (int j = 0; j < stfState.CountDemandZones(); j++)
// {
// //
// XCDemandZone *jZone = stfState.demandZones[j];
// //
// bool isInside = IsInsideDiff(
// jZone,
// iOBFVG.ob,
// false //
// );
// //
// if (isInside)
// {
// //
// XCDemandZoneObject *iObj;
// drawer.CreateDemandZone(
// jZone,
// iObj //
// );
// }
// }
// }
// //
// if (stfState.HasSupportZones())
// {
// //
// for (int j = 0; j < stfState.CountSupportZones(); j++)
// {
// //
// XCSupportZone *jZone = stfState.supportZones[j];
// //
// bool isInside = IsInsideDiff(
// jZone,
// iOBFVG.ob,
// false //
// );
// //
// if (isInside)
// {
// //
// XCSupportZoneObject *iObj;
// drawer.CreateSupportZone(
// jZone,
// iObj //
// );
// }
// }
// }
// //
// if (stfState.HasResistanceZones())
// {
// //
// for (int j = 0; j < stfState.CountResistanceZones(); j++)
// {
// //
// XCResistanceZone *jZone = stfState.resistanceZones[j];
// //
// bool isInside = IsInsideDiff(
// jZone,
// iOBFVG.ob,
// false //
// );
// //
// if (isInside)
// {
// //
// XCResistanceZoneObject *iObj;
// drawer.CreateResistanceZone(
// jZone,
// iObj //
// );
// }
// }
// }
// }
//
XCBaseObject *drawnObjects[];
int drawnObjectsCount = drawer.DrawOBFVG(
iOBFVG,
drawnObjects,
if (hasBullOBFVGs)
{
//
true, // Draw Order Block ...
true, // Draw Fair Value Gap ...
false, // Draw Supply Zones ...
false, // Draw Demand Zones ...
false, // Draw Support Zones ...
false // Draw Resistance Zones ...
);
Copy(
bullOBFVGs,
orderFlow //
);
}
else if (hasBearOBFVGs)
{
//
Copy(
bearOBFVGs,
orderFlow //
);
}
//
iOBFVG.Clean();
orderFlowDir =
hasBullOBFVGs
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
result = ArraySize(orderFlow);
}
}
//
has = IsValidSize(count);
result = count;
Clean(bullOBFVGs);
Clean(bearOBFVGs);
//
return result;