mql5/Experts/AnotherTriBible/Inducators.mqh
younglubah-gmail 540d58914e
2026-03-15 02:46:38 +02:00

402 lines
14 KiB
MQL5

//+------------------------------------------------------------------+
//| Arjo_Indicators.mqh |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#include <Mql5Book\Timer.mqh>
#include <Mql5Book\Indicators.mqh>
#include "Chapter1_ChartDebug.mqh"
#include "Barsbydate.mqh"
string location = "DexterrFX - SMC Bible/";
//+------------------------------------------------------------------+
//| Swing wrapper for iCustom "External" |
//| NOTE: We keep arrays NON-series: index 0 = oldest |
//+------------------------------------------------------------------+
datetime FirstOfPreviousMonths(datetime currentTime, int monthsBack) {
MqlDateTime dt;
TimeToStruct(currentTime, dt);
dt.mon -= monthsBack;
while(dt.mon <= 0) {
dt.mon += 12;
dt.year--;
}
dt.day = 1;
dt.hour = 0;
dt.min = 0;
dt.sec = 0;
return StructToTime(dt);
}
// Copies buffer values by DATE RANGE (not count)
// Arrays remain NON-series: high[0] oldest within range, high[copied-1] newest
int CopyBufRange(long indicator_handle, int buffer_index, datetime start_time, datetime stop_time, double &dst[]) {
ArrayResize(dst, 0);
if(indicator_handle == INVALID_HANDLE) return 0;
if(start_time <= 0 || stop_time <= 0 || stop_time <= start_time) return 0;
int copied = CopyBuffer(indicator_handle, buffer_index, start_time, stop_time, dst);
if(copied <= 0) {
Print("CopyBufRange failed. buf=", buffer_index,
" err=", GetLastError(),
" from=", TimeToString(start_time),
" to=", TimeToString(stop_time));
return 0;
}
// DO NOT ArraySetAsSeries(dst,true); (your rule)
return copied;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
struct Fvg {
double top, bottom;
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class FairValue: public CIndicator {
private:
double bullTop[], bullBottom[], bearTop[], bearBottom[];
datetime fromTime;
datetime toTime;
public:
FairValue();
int Init(string indName, string pSymbol, ENUM_TIMEFRAMES pTimeframe, int InpLeftRightBars = 3, int InpSwingWindow = 1);
bool IsValidValue(Fvg &fvg) {
return ((fvg.top != 0.0 && fvg.top != EMPTY_VALUE) && (fvg.bottom != 0.0 && fvg.bottom != EMPTY_VALUE));
}
void getBullFvg(Fvg &fvg, int barIndex = 0);
void getBearFvg(Fvg &fvg, int barIndex = 0);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
FairValue::FairValue(void) {
fromTime = 0;
toTime = 0;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int FairValue::Init(string indName, string pSymbol, ENUM_TIMEFRAMES pTimeframe, int InpLeftRightBars = 3, int InpSwingWindow = 1) {
handle = iCustom(pSymbol, pTimeframe, location + indName, InpLeftRightBars, InpSwingWindow);
if(handle == INVALID_HANDLE) {
Print("Error creating Swing Indicator: ", GetLastError());
return -1;
}
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3); // <<--- ONLY 3 MONTHS
return handle;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void FairValue::getBullFvg(Fvg &fvg, int barIndex = 0) {
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
int copied = CopyBufRange(handle, 1, fromTime, toTime, bullTop);
int copied0 = CopyBufRange(handle, 2, fromTime, toTime, bullBottom);
if(copied <= 0 && copied0 <= 0) return ;
if(barIndex < 0 || (barIndex >= copied && barIndex >= copied0)) return ;
fvg.top = bullTop[barIndex];
fvg.bottom = bullBottom[barIndex];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void FairValue::getBearFvg(Fvg &fvg, int barIndex = 0) {
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
int copied = CopyBufRange(handle, 5, fromTime, toTime, bearTop);
int copied0 = CopyBufRange(handle, 6, fromTime, toTime, bearBottom);
if(copied <= 0 && copied0 <= 0) return ;
if(barIndex < 0 || (barIndex >= copied && barIndex >= copied0)) return ;
fvg.top = bearTop[barIndex];
fvg.bottom = bearBottom[barIndex];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class Swing: public CIndicator {
private:
double high[], low[], swings[];
CIntegerArrayList hs;
CIntegerArrayList ls;
CIntegerArrayList zz;
// we only copy last 3 months
datetime fromTime;
datetime toTime;
public:
Swing();
int Init(string indName, string pSymbol, ENUM_TIMEFRAMES pTimeframe, int InpLeftRightBars = 3, int InpSwingWindow = 1);
bool IsValidValue(double v) {
return (v != 0.0 && v != EMPTY_VALUE);
}
// ---------------------------
// SET A: FILTERED (non-empty) — returns the BAR INDEX (within the copied range)
// pShift = 0 -> most recent non-empty swing in range
// ---------------------------
int High(int pShift = 0);
int Low(int pShift = 0);
int ZZ(int pShift = 0);
double HighPrice(int pShift = 0);
double LowPrice(int pShift = 0);
double ZZPrice(int pShift = 0);
// ---------------------------
// SET B: EXACT INDEX — returns raw buffer VALUE at an EXACT bar index (within the copied range)
// barIndex: 0 oldest in range, BarCount-1 newest in range
// ---------------------------
double HighAt(int barIndex);
double LowAt(int barIndex);
double ZZAt(int barIndex);
// Range info (optional but handy)
int BarsCountHigh();
int BarsCountLow();
int BarsCountZZ();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Swing::Swing(void) {
// IMPORTANT: no series
ArrayResize(high, 0);
ArrayResize(low, 0);
ArrayResize(swings, 0);
fromTime = 0;
toTime = 0;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int Swing::Init(string indName, string pSymbol, ENUM_TIMEFRAMES pTimeframe, int InpLeftRightBars, int InpSwingWindow) {
handle = iCustom(pSymbol, pTimeframe, location + indName, InpLeftRightBars, InpSwingWindow);
if(handle == INVALID_HANDLE) {
Print("Error creating Swing Indicator: ", GetLastError());
return -1;
}
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3); // <<--- ONLY 3 MONTHS
return handle;
}
//+------------------------------------------------------------------+
//| Exact value at exact bar index (within range) |
//+------------------------------------------------------------------+
double Swing::HighAt(int barIndex) {
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
int copied = CopyBufRange(handle, 0, fromTime, toTime, high);
if(copied <= 0) return EMPTY_VALUE;
if(barIndex < 0 || barIndex >= copied) return EMPTY_VALUE;
return high[barIndex];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Swing::LowAt(int barIndex) {
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
int copied = CopyBufRange(handle, 1, fromTime, toTime, low);
if(copied <= 0) return EMPTY_VALUE;
if(barIndex < 0 || barIndex >= copied) return EMPTY_VALUE;
return low[barIndex];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Swing::ZZAt(int barIndex) {
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
int copied = CopyBufRange(handle, 4, fromTime, toTime, swings);
if(copied <= 0) return EMPTY_VALUE;
if(barIndex < 0 || barIndex >= copied) return EMPTY_VALUE;
return swings[barIndex];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int Swing::BarsCountHigh() {
return ArraySize(high);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int Swing::BarsCountLow() {
return ArraySize(low);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int Swing::BarsCountZZ() {
return ArraySize(swings);
}
//+------------------------------------------------------------------+
//| FILTERED (non-empty): return BAR INDEX of pShift-th swing HIGH |
//| pShift=0 -> most recent non-empty in the 3-month window |
//+------------------------------------------------------------------+
int Swing::High(int pShift) {
hs.Clear();
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
int copied = CopyBufRange(handle, 0, fromTime, toTime, high);
if(copied <= 0) return -1;
// scan oldest->newest but we want "most recent" first,
// so collect indexes then read from the end.
for(int i = 0; i < copied; i++)
if(IsValidValue(high[i]))
hs.Add(i);
int count = hs.Size();
if(count == 0) return -1;
int idxFromEnd = count - 1 - pShift;
if(idxFromEnd < 0) idxFromEnd = 0; // fallback to oldest swing in range
return hs.Get(idxFromEnd);
}
//+------------------------------------------------------------------+
//| FILTERED (non-empty): return BAR INDEX of pShift-th swing LOW |
//+------------------------------------------------------------------+
int Swing::Low(int pShift) {
ls.Clear();
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
int copied = CopyBufRange(handle, 1, fromTime, toTime, low);
if(copied <= 0) return -1;
for(int i = 0; i < copied; i++)
if(IsValidValue(low[i]))
ls.Add(i);
int count = ls.Size();
if(count == 0) return -1;
int idxFromEnd = count - 1 - pShift;
if(idxFromEnd < 0) idxFromEnd = 0;
return ls.Get(idxFromEnd);
}
//+------------------------------------------------------------------+
//| FILTERED (non-empty): return BAR INDEX of pShift-th ZZ swing |
//+------------------------------------------------------------------+
int Swing::ZZ(int pShift) {
zz.Clear();
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
int copied = CopyBufRange(handle, 4, fromTime, toTime, swings);
if(copied <= 0) return -1;
for(int i = 0; i < copied; i++)
if(IsValidValue(swings[i]))
zz.Add(i);
int count = zz.Size();
if(count == 0) return -1;
int idxFromEnd = count - 1 - pShift;
if(idxFromEnd < 0) idxFromEnd = 0;
return zz.Get(idxFromEnd);
}
//+------------------------------------------------------------------+
//| FILTERED price by swing order |
//+------------------------------------------------------------------+
double Swing::HighPrice(int pShift) {
int barIndex = High(pShift);
if(barIndex < 0) return EMPTY_VALUE;
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
if(barIndex >= ArraySize(high)) CopyBufRange(handle, 0, fromTime, toTime, high);
if(barIndex < 0 || barIndex >= ArraySize(high)) return EMPTY_VALUE;
return high[barIndex];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Swing::LowPrice(int pShift) {
int barIndex = Low(pShift);
if(barIndex < 0) return EMPTY_VALUE;
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
if(barIndex >= ArraySize(low)) CopyBufRange(handle, 1, fromTime, toTime, low);
if(barIndex < 0 || barIndex >= ArraySize(low)) return EMPTY_VALUE;
return low[barIndex];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Swing::ZZPrice(int pShift) {
int barIndex = ZZ(pShift);
if(barIndex < 0) return EMPTY_VALUE;
toTime = TimeCurrent();
fromTime = FirstOfPreviousMonths(toTime, 3);
if(barIndex >= ArraySize(swings)) CopyBufRange(handle, 4, fromTime, toTime, swings);
if(barIndex < 0 || barIndex >= ArraySize(swings)) return EMPTY_VALUE;
return swings[barIndex];
}
//+------------------------------------------------------------------+
//| Base chapter (fixed constructor name + uses CBarsbydate) |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+