This commit is contained in:
2025-10-15 13:24:34 +03:30
parent cfe8734715
commit d24610c47b
4 changed files with 1981 additions and 346 deletions
@@ -3519,6 +3519,345 @@ class XCMarketPatternDetector : public XCBase
return result;
}
int CollectOBs(
XOHCL &bar,
XBoxZone &dest[],
int zonesLoopback = 5,
int maxRequiredZone = 0,
int loopback = 100 //
)
{
//
int result = 0;
//
// Prepare ...
XClean(dest);
//
// Normalize ...
loopback = NormalizeInt(loopback, 10);
zonesLoopback = NormalizeInt(zonesLoopback, 3);
maxRequiredZone = NormalizeInt(maxRequiredZone, 0);
//
// Validate ...
bool has = bar.IsValid();
if (!has)
{
return result;
}
//
XOHCL iBar;
XBoxZone iBox;
ENUM_X_DIRECTION iDir;
int start = bar.Index();
int end = start + loopback;
for (int i = start; i < end; i++)
{
//
iBar.Clean();
iBox.Clean();
iDir = X_DIRECTION_NONE;
//
has = bar.BarAt(i, iBar);
has = has &&
HasOB(iBar, iDir, iBox, zonesLoopback);
if (has)
{
//
AddIfNotExists(
iBox,
dest //
);
}
//
has = maxRequiredZone <= 0 ||
(maxRequiredZone > 0 && ArraySize(dest) < maxRequiredZone);
if (!has)
{
break;
}
}
//
result = ArraySize(dest);
//
// Cleanup ...
iBar.Clean();
iBox.Clean();
iDir = X_DIRECTION_NONE;
//
return result;
}
int CollectFVGs(
XOHCL &bar,
XBoxZone &dest[],
int zonesLoopback = 5,
int maxRequiredZone = 0,
int loopback = 100 //
)
{
//
int result = 0;
//
// Prepare ...
XClean(dest);
//
// Normalize ...
loopback = NormalizeInt(loopback, 10);
zonesLoopback = NormalizeInt(zonesLoopback, 3);
maxRequiredZone = NormalizeInt(maxRequiredZone, 0);
//
// Validate ...
bool has = bar.IsValid();
if (!has)
{
return result;
}
//
XOHCL iBar;
XBoxZone iBox;
ENUM_X_DIRECTION iDir;
int start = bar.Index();
int end = start + loopback;
for (int i = start; i < end; i++)
{
//
iBar.Clean();
iBox.Clean();
iDir = X_DIRECTION_NONE;
//
has = bar.BarAt(i, iBar);
has = has &&
HasFVG(iBar, iDir, iBox, zonesLoopback);
if (has)
{
//
AddIfNotExists(
iBox,
dest //
);
}
//
has = maxRequiredZone <= 0 ||
(maxRequiredZone > 0 && ArraySize(dest) < maxRequiredZone);
if (!has)
{
break;
}
}
//
result = ArraySize(dest);
//
// Cleanup ...
iBar.Clean();
iBox.Clean();
iDir = X_DIRECTION_NONE;
//
return result;
}
int CollectZones(
XOHCL &bar,
XBoxZone &dest[],
int zonesLoopback = 5,
int zonesValidationLength = 21,
int maxRequiredZone = 0,
int loopback = 100 //
)
{
//
int result = 0;
//
// Prepare ...
XClean(dest);
//
// Normalize ...
loopback = NormalizeInt(loopback, 10);
zonesLoopback = NormalizeInt(zonesLoopback, 3);
maxRequiredZone = NormalizeInt(maxRequiredZone, 0);
zonesValidationLength = NormalizeInt(zonesValidationLength, 3);
//
// Validate ...
bool has = bar.IsValid();
if (!has)
{
return result;
}
//
XOHCL iBar;
XBoxZone iBox;
XOHCL iZoneBar;
int start = bar.Index();
int end = start + loopback;
for (int i = start; i < end; i++)
{
//
iBar.Clean();
iBox.Clean();
iZoneBar.Clean();
//
has = bar.BarAt(i, iBar);
if (!has)
{
continue;
}
//
// Support ...
has = HasSupport(iBar, iZoneBar, zonesValidationLength, zonesLoopback);
if (has)
{
//
has = ToSupportBox(iZoneBar, iBox, bar.time, zonesValidationLength);
if (has)
{
//
AddIfNotExists(
iBox,
dest //
);
}
}
//
// Resistance ...
has = HasResistance(iBar, iZoneBar, zonesValidationLength, zonesLoopback);
if (has)
{
//
has = ToResistanceBox(iZoneBar, iBox, bar.time, zonesValidationLength);
if (has)
{
//
AddIfNotExists(
iBox,
dest //
);
}
}
//
has = maxRequiredZone <= 0 ||
(maxRequiredZone > 0 && ArraySize(dest) < maxRequiredZone);
if (!has)
{
break;
}
}
//
result = ArraySize(dest);
//
// Cleanup ...
iBar.Clean();
iBox.Clean();
iZoneBar.Clean();
//
return result;
}
int FilterZones(
XOHCL &bar,
XBoxZone &source[],
ENUM_X_DIRECTION filterDir,
ENUM_X_PRICE priceType = X_PRICE_CLOSE,
ENUM_X_DIRECTION forDir = X_DIRECTION_NONE //
)
{
//
int result = 0;
//
// Prepare ...
XBoxZone tmp[];
Copy(
source,
tmp //
);
XClean(source);
//
// Validate ...
bool has = bar.IsValid() &&
HasChild(tmp) &&
IsXValid(priceType) &&
HasDirection(filterDir);
if (!has)
{
//
XClean(tmp);
return result;
}
//
XBoxZone iBox;
double price = bar.GetPrice(priceType);
bool isBullish = IsXBullish(filterDir);
while (HasChild(tmp))
{
//
iBox = tmp[0];
ArrayRemove(tmp, 0, 1);
//
has =
//
// Direction Pass ...
(!HasDirection(forDir)
? true
: forDir == iBox.dir)
//
&&
//
// Price Pass ...
(isBullish
? price > iBox.lower
: price < iBox.upper);
if (has)
{
AddIfNotExists(iBox, source);
}
//
iBox.Clean();
}
//
result = ArraySize(source);
//
// Cleanup ...
XClean(tmp);
iBox.Clean();
//
return result;
}
//
// Protected ...
protected:
File diff suppressed because it is too large Load Diff
@@ -7095,6 +7095,163 @@ bool SetChartVolumesColor(
// END Chart Info ...
//
//
// START ATR ...
//
/**
* Calculate True Range of Specified Bar ...
*
* @param _symbol: string, Symbol ...
* @param _period: ENUM_TIMEFRAMES, period ...
* @param _barIndex: int, Specified Bar Index ...
* @param ignorePC: bool, Ignore Previous Bar ...
*
* @return ( double )
*/
double GetTrueRange(
string _symbol = NULL,
ENUM_TIMEFRAMES _period = NULL,
int _barIndex = 0,
bool ignorePC = false // Ignore Previous Close ...
)
{
//
double result = EMPTY_VALUE;
//
// Normalize ...
_symbol = NormalizeSymbol(_symbol);
_period = NormalizePeriod(_period);
_barIndex = NormalizeInt(_barIndex, 0);
//
XOHCL bar;
XOHCL pBar;
//
bool has =
bar.Init(
_symbol,
_period,
_barIndex //
);
if (!ignorePC)
{
//
has = has &&
bar.GetPreviousBar(pBar);
}
if (!has)
{
return result;
}
//
double hlDiff = bar.high - bar.low;
//
if (!ignorePC)
{
//
double hpcDiff = MathAbs(bar.high - pBar.close);
double lpcDiff = MathAbs(bar.high - pBar.close);
//
result = MathMax(hlDiff, hpcDiff);
result = MathMax(result, lpcDiff);
}
else
{
result = hlDiff;
}
//
// Cleanup ...
bar.Clean();
pBar.Clean();
//
return result;
}
/**
* Calculate ATR ...
*
* @param _symbol: string, Symbol ...
* @param _period: ENUM_TIMEFRAMES, period ...
* @param _barIndex: int, Specified Bar Index ...
* @param _length: int ATR Period ...
*
* @return ( double )
*/
double GetAverageTrueRange(
string _symbol = NULL,
ENUM_TIMEFRAMES _period = NULL,
int _barIndex = 0,
int _length = 14 //
)
{
//
double result = EMPTY_VALUE;
//
// Normalize ...
_symbol = NormalizeSymbol(_symbol);
_period = NormalizePeriod(_period);
_length = NormalizeInt(_length, 2);
_barIndex = NormalizeInt(_barIndex, 0);
//
// Collect True Ranges ...
double itr;
double _trs[];
bool has = false;
int start = _barIndex;
int end = start + _length;
for (int i = start; i < end; i++)
{
//
itr = GetTrueRange(
_symbol,
_period,
_barIndex,
i == end - 1 // Ignore PC ...
);
has = NotEmptyZero(itr);
if (has)
{
//
Add(
itr,
_trs //
);
}
}
//
int count = ArraySize(_trs);
has = HasChild(_trs);
if (!has)
{
return result;
}
//
result = GetAverage(_trs);
//
// Cleanup ...
XClean(_trs);
//
return result;
}
//
// END َATR ...
//
//
// START Linear Regression ...
//
@@ -372,11 +372,11 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
structureConfig,
barIndex //
);
poiDrawer.drawnObjects.Clear();
poiDrawer.DrawMarketStructure(
structure,
structureDrawConfig //
);
// poiDrawer.drawnObjects.Clear();
// poiDrawer.DrawMarketStructure(
// structure,
// structureDrawConfig //
// );
//
// Strategy 1 ...
@@ -391,10 +391,9 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
//
// Strategy 2 ...
has = false;
if (!has)
{
//
// //
// has = Strategy2HasSignal(
// iBar,
// iZone,
@@ -407,6 +406,7 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
//
// Strategy 3 ...
has = false;
if (!has)
{
//
@@ -423,13 +423,13 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
//
has = HasDirection(iDir) &&
iZone.IsValid();
if (has)
{
//
has = false;
iZone.Clean();
iDir = X_DIRECTION_NONE;
}
// if (has)
// {
// //
// has = false;
// iZone.Clean();
// iDir = X_DIRECTION_NONE;
// }
//
if (has)
@@ -442,6 +442,11 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
// TODO: Provided SL ...
double _point = GetPoints(iBar.symbol);
double slAddition = 5 * _point;
double atrAddition = GetAverageTrueRange(
iZone.symbol,
iZone.period,
0 //
);
double slPrice =
isBullish
? iZone.lower - slAddition
@@ -1232,27 +1237,182 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
// Define Requirements ...
bool isBullish = false;
bool isBearish = false;
//
XOHCL pBar;
int barIndex = bar.Index();
int pBarIndex = barIndex + 1;
result = bar.GetPreviousBar(pBar);
if (!result)
{
return result;
}
//
// Do Conditions Checking ...
//
result = fimaHelper.HasMACross(
dir,
barIndex,
structureConfig.maCrossValidationDiffMultiplier //
);
isBullish =
result &&
IsXBullish(dir);
isBearish =
result &&
IsXBearish(dir);
XBoxZone zones[];
int zonesCount = 0;
ENUM_X_PRICE bullishPriceType = X_PRICE_LOW;
ENUM_X_PRICE bearishPriceType = X_PRICE_HIGH;
//
result = isBullish ||
isBearish;
isBullish = fimaHelper.IsSwitchedUnderHKBondLower(bullishPriceType, pBarIndex);
//
isBearish = fimaHelper.IsSwitchedOverHKBondUpper(bearishPriceType, pBarIndex);
//
result =
isBullish ||
isBearish;
//
// Do Validations ...
if (result)
{
//
// Direction Assignment ...
dir =
isBullish
? X_DIRECTION_BULLISH
: X_DIRECTION_BEARISH;
//
int lastIDX;
XBoxZone tmpZones[];
int tmpZonesCount = 0;
int validationCount = 0;
ENUM_X_PRICE priceType =
isBullish
? bullishPriceType
: bearishPriceType;
//
// Detect Last Direction Change ...
if (isBullish)
{
result = fimaHelper.FindLastUnderHKBondLower(lastIDX, bullishPriceType, pBarIndex);
}
else
{
result = fimaHelper.FindLastOverHKBondUpper(lastIDX, bearishPriceType, pBarIndex);
}
//
// Validate Direction Changed ...
if (result)
{
//
validationCount = lastIDX - pBarIndex;
result = validationCount >= 10;
}
//
// Collect Zones ...
if (result)
{
//
// Support and Resistances ...
tmpZonesCount = poiDetector.CollectZones(
pBar,
tmpZones,
5,
14, // Zones Validation Length ...
0, // Required Count ...
validationCount // Loopback ...
);
if (IsValidSize(tmpZonesCount))
{
//
Copy(
tmpZones,
zones,
false // ignore Clean ...
);
}
//
// OB ...
tmpZonesCount = poiDetector.CollectOBs(
pBar,
tmpZones,
5, // Zones Loopback ...
0, // Required Count ...
validationCount // Loopback ...
);
if (IsValidSize(tmpZonesCount))
{
//
Copy(
tmpZones,
zones,
false // ignore Clean ...
);
}
//
// FVG ...
tmpZonesCount = poiDetector.CollectFVGs(
pBar,
tmpZones,
5, // Zones Loopback ...
0, // Required Count ...
validationCount // Loopback ...
);
if (IsValidSize(tmpZonesCount))
{
//
Copy(
tmpZones,
zones,
false // ignore Clean ...
);
}
//
// Filter Zones Based on pBar ...
zonesCount = poiDetector.FilterZones(
pBar,
zones,
dir,
priceType,
dir //
);
//
// Extract Affected Zones ...
XClean(tmpZones);
tmpZonesCount = ExtractAffectedZones(
pBar,
zones,
tmpZones,
dir //
);
Copy(tmpZones, zones);
zonesCount = ArraySize(zones);
//
// Update Zones Time ...
UpdateToTime(zones);
}
//
// Draw Zones ...
result = IsValidSize(zonesCount);
if (result)
{
//
for (int i = 0; i < zonesCount; i++)
{
poiDrawer.DrawZone(zones[i], structureDrawConfig.drawConfig);
}
}
//
XClean(tmpZones);
}
//
// Prepare Zone ...
@@ -1260,6 +1420,35 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
{
//
// Zone Detection ...
zone.Clean();
if (isBullish)
{
//
int idx = GetLowest(zones);
if (IsValidIndex(idx))
{
zone = zones[idx];
}
}
else
{
//
int idx = GetHighest(zones);
if (IsValidIndex(idx))
{
zone = zones[idx];
}
}
// zone.dir = dir;
// zone.type = name;
// zone.to = bar.time;
// zone.at = pBar.time;
// zone.from = pBar.time;
// zone.symbol = bar.symbol;
// zone.period = bar.period;
// zone.lower = MathMin(pBar.low, bar.low);
// zone.upper = MathMax(pBar.high, bar.high);
//
result = zone.IsValid();
@@ -1274,6 +1463,7 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
}
//
// Cleanup ...
if (!result)
{
//
@@ -1281,6 +1471,8 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller
XClean(targets);
dir = X_DIRECTION_NONE;
}
pBar.Clean();
XClean(zones);
//
return result;