NUNA/Logs/Indicators/Downloads/Autoscaling Zigzag.mq5
2026-01-06 05:44:21 +00:00

342 行
21 KiB
MQL5

#property copyright "Evgeniy Chumakov | © Copyright 2024"
#property description "ZigZag with automatic step size detection for changing wave direction."
#property version "1.0"
#property link "https://www.mql5.com/en/users/jack857752"
#property strict
#property indicator_chart_window
#property indicator_buffers 8
#property indicator_plots 1
#property indicator_label1 "ZigZag"
#property indicator_type1 DRAW_COLOR_ZIGZAG
#property indicator_style1 STYLE_SOLID
#property indicator_color1 clrGray, clrViolet
input double ZZScale = 1.0; // Scale
input int ZZLineWidth = 2; // Line Width
double ArrayHighZZ[]; // High point ZZ
double ArrayLowZZ[]; // Low point ZZ
double ArrayTypeZZ[]; // ZigZag direction buffer
double ArrayHighBarZZ[]; // ZigZag maximum bar location
double ArrayLowBarZZ[]; // ZigZag minimum bar location
double ArrayHighLast[]; // Last maximum value
double ArrayLowLast[]; // Last minimum value
double ArrayLegCol[]; // Leg color
double SpecDivSymb = 1.0; // Special Divider / Symbol Correction
int OnInit()
{
SetIndexBuffer(0,ArrayHighZZ,INDICATOR_DATA);
SetIndexBuffer(1,ArrayLowZZ,INDICATOR_DATA);
SetIndexBuffer(2,ArrayLegCol,INDICATOR_COLOR_INDEX);
SetIndexBuffer(3,ArrayTypeZZ,INDICATOR_CALCULATIONS);
SetIndexBuffer(4,ArrayHighBarZZ,INDICATOR_CALCULATIONS);
SetIndexBuffer(5,ArrayLowBarZZ,INDICATOR_CALCULATIONS);
SetIndexBuffer(6,ArrayHighLast,INDICATOR_CALCULATIONS);
SetIndexBuffer(7,ArrayLowLast,INDICATOR_CALCULATIONS);
ArraySetAsSeries(ArrayHighZZ, true);
ArraySetAsSeries(ArrayLowZZ, true);
ArraySetAsSeries(ArrayTypeZZ, true);
ArraySetAsSeries(ArrayHighBarZZ, true);
ArraySetAsSeries(ArrayLowBarZZ, true);
ArraySetAsSeries(ArrayHighLast, true);
ArraySetAsSeries(ArrayLowLast, true);
ArraySetAsSeries(ArrayLegCol, true);
PlotIndexSetString(0,PLOT_LABEL,"High Point ZZ;Low Point ZZ");
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, ZZLineWidth);
IndicatorSetInteger(INDICATOR_DIGITS,Digits());
IndicatorSetString(INDICATOR_SHORTNAME,"AutoScaleZigZag");
int Find = StringFind(Symbol(),"JPY",0); //
if(Find != -1) {
SpecDivSymb = 100.0;
} else {
SpecDivSymb = 1.0;
}
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
// Checking for the minimum number of bars to calculate
if(rates_total < 3) {
return(0);
}
ArraySetAsSeries(open, true);
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);
// Checking and calculating the number of calculated bars
int total = rates_total - 2;
int limit = (prev_calculated == 0) ? rates_total : rates_total - prev_calculated + 1;
if(limit > 1) {
limit = total;
ArrayInitialize(ArrayHighZZ,EMPTY_VALUE);
ArrayInitialize(ArrayLowZZ,EMPTY_VALUE);
ArrayInitialize(ArrayTypeZZ,EMPTY_VALUE);
ArrayInitialize(ArrayHighBarZZ,EMPTY_VALUE);
ArrayInitialize(ArrayLowBarZZ,EMPTY_VALUE);
ArrayInitialize(ArrayHighLast,EMPTY_VALUE);
ArrayInitialize(ArrayLowLast,EMPTY_VALUE);
CalcStartingExtremes(rates_total,high,low); // Let's get the starting point for ZigZag
}
// Calculating the indicator
//for(int i = 0; i <limit; i++) { // will plot nothing with an incremental loop
for(int i = limit-1; i >=0; i--) {
ArrayHighZZ[i] = EMPTY_VALUE;
ArrayLowZZ[i] = EMPTY_VALUE;
if(ArrayTypeZZ[i + 1] != EMPTY_VALUE && ArrayTypeZZ[i + 1] > 0) {
HighZZPoint(i,high,low);
}
if(ArrayTypeZZ[i + 1] != EMPTY_VALUE && ArrayTypeZZ[i + 1] < 0) {
LowZZPoint(i,high,low);
}
}
return(rates_total);
}
//+------------------------------------------------------------------+
//| Calculation High ZZ Point |
//+------------------------------------------------------------------+
void HighZZPoint(const int index, const double &high[], const double &low[])
{
double PriceHigh = high[index]; // Current maximum price value
double PriceLow = low[index]; // Current minimum price value
bool EventHigh = false; // High point ZZ update event
bool EventLow = false; // Low point ZZ update event
double R_Step = MathAbs((ArrayHighLast[index+1] - PriceLow)/PriceLow) * 100.0; // Price range in percent
double StepDownLevel = PriceLow/SpecDivSymb/ZZScale; // Step to form a segment down
// Updating and redrawing the maximum extremum
if(PriceHigh > ArrayHighLast[index+1]) {
EventHigh = true;
ArrayTypeZZ[index] = 1;
int prev_high_index = (int)ArrayHighBarZZ[index+1];
if(prev_high_index >= 0) ArrayHighZZ[prev_high_index] = EMPTY_VALUE;
ArrayHighZZ[index] = PriceHigh;
ArrayHighBarZZ[index] = index;
ArrayLowBarZZ[index] = ArrayLowBarZZ[index+1];
ArrayHighLast[index] = PriceHigh;
ArrayLowLast[index] = ArrayLowLast[index+1];
ArrayLegCol[index] = 1;
}
//--------------------------------------------------------//
// Creating and drawing the minimum extremum
if(R_Step >= StepDownLevel && !EventHigh) {
EventLow = true;
ArrayTypeZZ[index] = -1;
ArrayLowZZ[index] = PriceLow;
ArrayLowLast[index] = PriceLow;
ArrayHighLast[index] = ArrayHighLast[index+1];
ArrayHighBarZZ[index] = ArrayHighBarZZ[index+1];
ArrayLowBarZZ[index] = index;
ArrayLegCol[index] = 0;
}
//--------------------------------------------------------//
// No events for forming extremes. Copying past data.
if(!EventHigh && !EventLow) {
ArrayTypeZZ[index] = ArrayTypeZZ[index+1];
ArrayHighBarZZ[index] = ArrayHighBarZZ[index+1];
ArrayLowBarZZ[index] = ArrayLowBarZZ[index+1];
ArrayHighLast[index] = ArrayHighLast[index+1];
ArrayLowLast[index] = ArrayLowLast[index+1];
}
//--------------------------------------------------------//
return;
}
//+------------------------------------------------------------------+
//| Calculation Low ZZ Point |
//+------------------------------------------------------------------+
void LowZZPoint(const int index, const double &high[], const double &low[])
{
double PriceHigh = high[index]; // Current maximum price value
double PriceLow = low[index]; // Current minimum price value
bool EventLow = false; // High point ZZ update event
bool EventHigh = false; // Low point ZZ update event
double R_Step = MathAbs((ArrayLowLast[index+1] - PriceHigh)/PriceHigh) * 100.0; // Price range in percent
double StepUpLevel = PriceHigh/SpecDivSymb/ZZScale; // Step to form a segment up
// Updating and redrawing the minimum extremum
if(PriceLow < ArrayLowLast[index+1]) {
EventLow = true;
ArrayTypeZZ[index] = -1;
int prev_low_index = (int)ArrayLowBarZZ[index+1];
if(prev_low_index >= 0) ArrayLowZZ[prev_low_index] = EMPTY_VALUE;
ArrayLowZZ[index] = PriceLow;
ArrayLowBarZZ[index] = index;
ArrayHighBarZZ[index] = ArrayHighBarZZ[index+1];
ArrayHighLast[index] = ArrayHighLast[index+1];
ArrayLowLast[index] = PriceLow;
ArrayLegCol[index] = 0;
}
//--------------------------------------------------------//
// Creating and drawing the maximum extremum
if(R_Step >= StepUpLevel && !EventLow) {
EventHigh = true;
ArrayTypeZZ[index] = 1;
ArrayHighZZ[index] = PriceHigh;
ArrayHighLast[index] = PriceHigh;
ArrayLowLast[index] = ArrayLowLast[index+1];
ArrayHighBarZZ[index] = index;
ArrayLowBarZZ[index] = ArrayLowBarZZ[index+1];
ArrayLegCol[index] = 1;
}
//--------------------------------------------------------//
// No events for forming extremes. Copying past data.
if(!EventHigh && !EventLow) {
ArrayTypeZZ[index] = ArrayTypeZZ[index+1];
ArrayHighBarZZ[index] = ArrayHighBarZZ[index+1];
ArrayLowBarZZ[index] = ArrayLowBarZZ[index+1];
ArrayHighLast[index] = ArrayHighLast[index+1];
ArrayLowLast[index] = ArrayLowLast[index+1];
}
//--------------------------------------------------------//
return;
}
//+------------------------------------------------------------------+
//| Calculation Of Starting Extremes |
//+------------------------------------------------------------------+
int CalcStartingExtremes(int limit, const double &high[], const double &low[])
{
int init_index = 0;
for(int i = limit-1; i >=0; i--) {
int period_start = i; // Measurement start position
int MaxBar = ArrayMaximum(high,period_start,limit); // Position (bar) for the maximum price on the measurement interval.
int MinBar = ArrayMinimum(low,period_start,limit); // Position (bar) for the minimum price on the measurement interval.
double Max_Price = high[MaxBar]; // The value of the maximum price on the measured interval.
double Min_Price = low[MinBar]; // The value of the minimum price on the measured interval.
double R_Step = MathAbs((Max_Price - Min_Price)/Min_Price) * 100.0; // Price range in percent
double StepUpLevel = Max_Price/SpecDivSymb/ZZScale; // Step to form a segment up
double StepDownLevel = Min_Price/SpecDivSymb/ZZScale; // Step to form a segment down
// Formation of the maximum extremum
if(MaxBar != MinBar && MaxBar < MinBar && R_Step >= StepUpLevel) {
ArrayTypeZZ[period_start] = 1;
ArrayHighZZ[MaxBar] = Max_Price;
ArrayLowZZ[MinBar] = Min_Price;
ArrayHighBarZZ[period_start] = MaxBar;
ArrayLowBarZZ[period_start] = MinBar;
ArrayHighLast[period_start] = Max_Price;
ArrayLowLast[period_start] = Min_Price;
init_index = period_start;
}
if(init_index != 0) {
break;
}
//--------------------------------------------------------//
// Formation of a minimum extremum
if(MaxBar != MinBar && MinBar < MaxBar && R_Step >= StepDownLevel) {
ArrayTypeZZ[period_start] = -1;
ArrayHighZZ[MaxBar] = Max_Price;
ArrayLowZZ[MinBar] = Min_Price;
ArrayHighBarZZ[period_start] = MaxBar;
ArrayLowBarZZ[period_start] = MinBar;
ArrayHighLast[period_start] = Max_Price;
ArrayLowLast[period_start] = Min_Price;
init_index = period_start;
}
if(init_index != 0) {
break;
}
}
return(init_index);
}