インジケータ
//https://forex-station.com/viewtopic.php?f=579496&p=1295483261#p1295483261//https://www.mql5.com/en/forum/175037/page868#comment_4591975//https://www.mql5.com/en/forum/175037/page867#comment_4591966//https://www.mql5.com/en/forum/175037/page867 extreme_spike_mtf BT_.mq4//+-------------------------------------------------------------------+//| Extreme_Spike.mq4//| Based on Symphonie_Extreme_Cycle_Indikator//| !!! this file is created with Tab size 4 and no space indentation//+-------------------------------------------------------------------+#property copyright ""#property link ""#property indicator_separate_window//#property indicator_height 99#property indicator_minimum -1.2#property indicator_maximum +1.2#property indicator_buffers 5#property indicator_color1 clrRed#property indicator_width1 3#property indicator_style1 STYLE_SOLID#property indicator_color2 clrDodgerBlue#property indicator_width2 3#property indicator_style2 STYLE_SOLID#property indicator_color3 clrDimGray#property indicator_width3 0#property indicator_color4 clrWhite#property indicator_width4 1#property indicator_style4 STYLE_SOLID#property indicator_color5 clrWhite#property indicator_width5 2#property indicator_style5 STYLE_SOLID#define ALERT_TOP 1#define ALERT_BOTTOM 2#define ALERT_STABLE 3#define LINE_MINOR 1#define LINE_MAJOR 2#define LINE_SHADOW 3#define LINE_STABLE 4#define LINE_VALUE_UP 1.0#define LINE_VALUE_FLAT 0.0#define LINE_VALUE_DOWN -1.0#define MODE_LOOKING_FOR_BOTTOM 1#define MODE_LOOKING_FOR_TOP -1#define MODE_UNDETERMINED 0//---- input parametersextern int timeFrame = 30;extern bool NoRepaint = true;extern double MinorMinExtremeHeightATRs = 2.5;extern double MajorToMinorHeightRatio = 2.5;extern int MinorMinExtremeWidth = 2;extern int MajorMinExtremeWidth = 2;extern bool AlertMajorBottomEnabled = false;extern bool AlertMajorTopEnabled = false;extern bool AlertMinorTopEnabled = false;extern bool AlertMinorBottomEnabled = false;extern bool AlertStableEnabled = false;extern int btn_Subwindow = 3;extern ENUM_BASE_CORNER btn_corner = CORNER_RIGHT_UPPER;extern string btn_text = "exspike";extern string btn_Font = "Arial";extern int btn_FontSize = 8;extern color btn_text_ON_color = clrWhite;extern color btn_text_OFF_color = clrRed;extern string btn_pressed = "exspike off";extern string btn_unpressed = "exspike on";extern color btn_background_color = clrDimGray;extern color btn_border_color = clrDarkGray;extern int button_x = 140;extern int button_y = 0;extern int btn_Width = 65;extern int btn_Height = 20;extern string soundBT = "tick.wav";bool show_data = true;string IndicatorName, IndicatorObjPrefix,buttonId ;//---- buffersdouble line1[]; // lineMajorUpdouble line2[]; // lineMajorDowndouble line3[]; // lineShadowUp, lineShadowDowndouble line4[]; // lineStableUp, lineStableDowndouble line5[]; // lineMinorUp, lineMinorDownint MinorLowExtremeIdx = 1;bool MinorFirstLow = TRUE;int MinorHiExtremeIdx = 1;bool MinorFirstHigh = TRUE;int MinorExtremeMode = 0;double MinorLowExtremePrice;double MinorHiExtremePrice;int MajorLowExtremeIdx = 1;bool MajorFirstLow = TRUE;int MajorHiExtremeIdx = 1;bool MajorFirstHigh = TRUE;int MajorExtremeMode = 0;double MajorLowExtremePrice;double MajorHiExtremePrice;double MinorMinExtremeHeight;double MajorMinExtremeHeight;datetime AlertMinorTopIdx;datetime AlertMinorBottomIdx;datetime AlertMajorTopIdx;datetime AlertMajorBottomIdx;datetime AlertStableIdx;string periodName,indicatorFileName;int BarNumber;#define RANGE_AVERAGING_PERIOD 250string GenerateIndicatorName(const string target) { string name = target; int try = 2; while(WindowFind(name) != -1) { name = target + " #" + IntegerToString(try ++); } return name; }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+int init() { indicatorFileName = WindowExpertName(); timeFrame = MathMax(timeFrame,Period()); int line = 0;// order of these calls is important - for example the 'spike' line is last - it will be drawn last and therefore will be on top of all other lines SetIndexStyle(line, DRAW_HISTOGRAM); SetIndexBuffer(line, line1); line++; SetIndexStyle(line, DRAW_HISTOGRAM); SetIndexBuffer(line, line2); line++; SetIndexStyle(line, DRAW_ARROW); SetIndexArrow(line, 108); SetIndexBuffer(line, line3); line++; SetIndexStyle(line, DRAW_HISTOGRAM); SetIndexBuffer(line, line4); line++; SetIndexStyle(line, DRAW_LINE); SetIndexBuffer(line, line5); line++; IndicatorName = GenerateIndicatorName(btn_text); IndicatorObjPrefix = "__" + IndicatorName + "__"; IndicatorShortName(WindowExpertName()); IndicatorDigits(Digits); double val; if(GlobalVariableGet(IndicatorName + "_visibility", val)) show_data = val != 0; ChartSetInteger(ChartID(), CHART_EVENT_MOUSE_MOVE, 1); buttonId = IndicatorObjPrefix+btn_text; createButton(buttonId, btn_text, btn_Width, btn_Height, btn_Font, btn_FontSize, btn_background_color, btn_border_color, btn_text_ON_color); ObjectSetInteger(ChartID(), buttonId, OBJPROP_YDISTANCE, button_y); ObjectSetInteger(ChartID(), buttonId, OBJPROP_XDISTANCE, button_x); return (0); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void createButton(string buttonID,string buttonText,int width,int height,string font,int fontSize,color bgColor,color borderColor,color txtColor) { ObjectDelete(ChartID(),buttonID); ObjectCreate(ChartID(),buttonID,OBJ_BUTTON,btn_Subwindow,0,0); ObjectSetInteger(ChartID(),buttonID,OBJPROP_COLOR,txtColor); ObjectSetInteger(ChartID(),buttonID,OBJPROP_BGCOLOR,bgColor); ObjectSetInteger(ChartID(),buttonID,OBJPROP_BORDER_COLOR,borderColor); ObjectSetInteger(ChartID(),buttonID,OBJPROP_XSIZE,width); ObjectSetInteger(ChartID(),buttonID,OBJPROP_YSIZE,height); ObjectSetString(ChartID(),buttonID,OBJPROP_FONT,font); ObjectSetString(ChartID(),buttonID,OBJPROP_TEXT,buttonText); ObjectSetInteger(ChartID(),buttonID,OBJPROP_FONTSIZE,fontSize); ObjectSetInteger(ChartID(),buttonID,OBJPROP_SELECTABLE,0); ObjectSetInteger(ChartID(),buttonID,OBJPROP_CORNER,btn_corner); ObjectSetInteger(ChartID(),buttonID,OBJPROP_HIDDEN,1); ObjectSetInteger(ChartID(),buttonID,OBJPROP_XDISTANCE,9999); ObjectSetInteger(ChartID(),buttonID,OBJPROP_YDISTANCE,9999); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+int deinit() { ObjectsDeleteAll(0,"exspike"); ObjectsDeleteAll(ChartID(), IndicatorObjPrefix); return(0); }bool recalc = true;//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void handleButtonClicks() { if(ObjectGetInteger(ChartID(), buttonId, OBJPROP_STATE)) { ObjectSetInteger(ChartID(), buttonId, OBJPROP_STATE, false); show_data = !show_data; GlobalVariableSet(IndicatorName + "_visibility", show_data ? 1.0 : 0.0); recalc = true; start(); } }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { handleButtonClicks(); if(id==CHARTEVENT_OBJECT_CLICK && ObjectGet(sparam,OBJPROP_TYPE)==OBJ_BUTTON) { if(soundBT!="") PlaySound(soundBT); } }//template code//------------------------------------------------------------------////------------------------------------------------------------------//////////+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+int start() {//template code handleButtonClicks(); recalc = false; start2(); SetIndexStyle(0,DRAW_HISTOGRAM); SetIndexStyle(1,DRAW_HISTOGRAM); SetIndexStyle(2,DRAW_ARROW); SetIndexStyle(3,DRAW_HISTOGRAM); SetIndexStyle(4,DRAW_LINE); if(show_data) { ObjectSetInteger(ChartID(),buttonId,OBJPROP_COLOR,btn_text_ON_color); ObjectSetString(ChartID(),buttonId,OBJPROP_TEXT,btn_unpressed); } else { ObjectSetInteger(ChartID(),buttonId,OBJPROP_COLOR,btn_text_OFF_color); ObjectSetString(ChartID(),buttonId,OBJPROP_TEXT,btn_pressed); SetIndexStyle(0,DRAW_NONE); SetIndexStyle(1,DRAW_NONE); SetIndexStyle(2,DRAW_NONE); SetIndexStyle(3,DRAW_NONE); SetIndexStyle(4,DRAW_NONE); SetIndexStyle(5,DRAW_NONE); //template code } return(0); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+int start2() { BarNumber = IndicatorCounted();// 'BarNumber' changes from 1 to 'Bars', so the array index is [Bars-1 .. 0] if(timeFrame != Period()) { for(int i=Bars-1; i>= 0; i--) { int y = iBarShift(NULL,timeFrame,Time[i]); line1[i] = iCustom(NULL,timeFrame,indicatorFileName,0,NoRepaint,MinorMinExtremeHeightATRs,MajorToMinorHeightRatio,MinorMinExtremeWidth,MajorMinExtremeWidth,AlertMajorBottomEnabled,AlertMajorTopEnabled,AlertMinorTopEnabled,AlertMinorBottomEnabled,AlertStableEnabled,0,y); line2[i] = iCustom(NULL,timeFrame,indicatorFileName,0,NoRepaint,MinorMinExtremeHeightATRs,MajorToMinorHeightRatio,MinorMinExtremeWidth,MajorMinExtremeWidth,AlertMajorBottomEnabled,AlertMajorTopEnabled,AlertMinorTopEnabled,AlertMinorBottomEnabled,AlertStableEnabled,1,y); line3[i] = iCustom(NULL,timeFrame,indicatorFileName,0,NoRepaint,MinorMinExtremeHeightATRs,MajorToMinorHeightRatio,MinorMinExtremeWidth,MajorMinExtremeWidth,AlertMajorBottomEnabled,AlertMajorTopEnabled,AlertMinorTopEnabled,AlertMinorBottomEnabled,AlertStableEnabled,2,y); line4[i] = iCustom(NULL,timeFrame,indicatorFileName,0,NoRepaint,MinorMinExtremeHeightATRs,MajorToMinorHeightRatio,MinorMinExtremeWidth,MajorMinExtremeWidth,AlertMajorBottomEnabled,AlertMajorTopEnabled,AlertMinorTopEnabled,AlertMinorBottomEnabled,AlertStableEnabled,3,y); line5[i] = iCustom(NULL,timeFrame,indicatorFileName,0,NoRepaint,MinorMinExtremeHeightATRs,MajorToMinorHeightRatio,MinorMinExtremeWidth,MajorMinExtremeWidth,AlertMajorBottomEnabled,AlertMajorTopEnabled,AlertMinorTopEnabled,AlertMinorBottomEnabled,AlertStableEnabled,4,y); } return(0); } for(; BarNumber < Bars;) { BarNumber++; processBar(); } return (0); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void processBar() { switch(BarNumber) { case 0: break; case 1: periodName = getPeriodName(); AlertMinorTopIdx = Time[Bars-1]; AlertMinorBottomIdx = Time[Bars-1]; AlertMajorTopIdx = Time[Bars-1]; AlertMajorBottomIdx = Time[Bars-1]; MinorLowExtremePrice = getLow(); MinorHiExtremePrice = getHigh(); MajorLowExtremePrice = getLow(); MajorHiExtremePrice = getHigh(); break; default: MinorMinExtremeHeight = average() * MinorMinExtremeHeightATRs; MajorMinExtremeHeight = MinorMinExtremeHeight * MajorToMinorHeightRatio; checkForExtremes(MinorLowExtremeIdx, MinorLowExtremePrice, MinorFirstLow, MinorHiExtremeIdx, MinorHiExtremePrice, MinorFirstHigh, MinorExtremeMode, MinorMinExtremeHeight, MinorMinExtremeWidth, LINE_MINOR); checkForExtremes(MajorLowExtremeIdx, MajorLowExtremePrice, MajorFirstLow, MajorHiExtremeIdx, MajorHiExtremePrice, MajorFirstHigh, MajorExtremeMode, MajorMinExtremeHeight, MajorMinExtremeWidth, LINE_MAJOR); break; } return; }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void checkForExtremes(int& lowExtremeIdx, double& lowExtremePrice, bool& firstLow, int& hiExtremeIdx, double& hiExtremePrice, bool& firstHigh, int& extremeMode, double MinExtremeHeight, int MinExtremeWidth, int lineType) {// ----------- check for Bottom ---------------- if(extremeMode > -1) { if(getLow() < lowExtremePrice) { if(!firstLow) eraseExtreme(lineType, lowExtremeIdx, LINE_VALUE_DOWN); // to repaint (erase) the spike lowExtremePrice = getLow(); // set LowestLow to this low (getLow) lowExtremeIdx = BarNumber; // remember the LL bar number firstLow = FALSE; // the was a Bottom } else if(getLow() > lowExtremePrice) // higher low (getLow) - not necesserally higher than the last bar - could be lower than the last bar, but still higher than the bottom { // there was bottom (lower low then higher low) - final or intermediate drawExtreme(lineType, lowExtremeIdx, LINE_VALUE_DOWN); // update LowestLow bar with the spike DOWN and mark it as unstable alert(ALERT_BOTTOM, lineType, lowExtremeIdx); firstLow = FALSE; if(((getLow() - lowExtremePrice) >= MinExtremeHeight) // the bottom was distinct enough (difference between it and price is big enough) && ((BarNumber - lowExtremeIdx) >= MinExtremeWidth)) // and the bottom was long enough ago in the past (there was no another bottom since) { extremeMode = -1; // set flags to start looking for top hiExtremePrice = getHigh(); hiExtremeIdx = BarNumber; firstHigh = TRUE; firstLow = TRUE; if(NoRepaint) // only draw extreme when it is not going to be repainted (WILL in troduce a lag) draw(lineType, lowExtremeIdx, LINE_VALUE_DOWN); if(drawStableLine(lineType, lowExtremeIdx, LINE_VALUE_FLAT)) // this spike will not repaint alert(ALERT_STABLE, lineType, lowExtremeIdx); } } }// ----------- check for Top ---------------- if(extremeMode < 1) // extremeMode could have been MinExtremeHeighted in the code above so can't really put "Else" here; initial goes here as well (0) { if(getHigh() > hiExtremePrice) { if(!firstHigh) eraseExtreme(lineType, hiExtremeIdx, LINE_VALUE_UP); // to repaint (erase) the spike hiExtremePrice = getHigh(); hiExtremeIdx = BarNumber; firstHigh = FALSE; } else if(getHigh() < hiExtremePrice) { drawExtreme(lineType, hiExtremeIdx, LINE_VALUE_UP); alert(ALERT_TOP, lineType, hiExtremeIdx); firstHigh = FALSE; if(((hiExtremePrice - getHigh()) >= MinExtremeHeight) && ((BarNumber - hiExtremeIdx) >= MinExtremeWidth)) { extremeMode = 1; lowExtremePrice = getLow(); lowExtremeIdx = BarNumber; firstHigh = TRUE; firstLow = TRUE; if(NoRepaint) // only draw extreme when it is not going to be repainted (WILL in troduce a lag) draw(lineType, hiExtremeIdx, LINE_VALUE_UP); if(drawStableLine(lineType, hiExtremeIdx, LINE_VALUE_FLAT)) // this spike will not repaint alert(ALERT_STABLE, lineType, hiExtremeIdx); } } } draw(lineType, BarNumber, LINE_VALUE_FLAT); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void eraseExtreme(int lineType, int barIdx, double value) { bool drawShadow = (lineType == LINE_MAJOR) && ( NoRepaint // in non-repainting mode always alert of the possible extreme || ((value == LINE_VALUE_UP) && (line1[Bars-barIdx] != 0)) || ((value == LINE_VALUE_DOWN) && (line2[Bars-barIdx] != 0)) ); drawExtreme(lineType, barIdx, LINE_VALUE_FLAT); if(drawShadow) draw(LINE_SHADOW, barIdx, value); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void drawExtreme(int lineType, int barIdx, double value) { if(!NoRepaint) // only draw extreme when it is not going to be repainted (WILL in troduce a lag) { draw(lineType, barIdx, value); drawStableLine(lineType, barIdx, value); } }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+bool drawStableLine(int lineType, int barIdx, double value) { if(lineType == LINE_MAJOR) return (false); draw(LINE_STABLE, barIdx, value); return (true); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void draw(int lineType, int barIdx, double value) { switch(lineType) { case LINE_MAJOR: updateLine(line1, line2, barIdx, value); break; case LINE_MINOR: updateLine(line5, line5, barIdx, value); break; case LINE_SHADOW: updateLine(line3, line3, barIdx, value); break; case LINE_STABLE: updateLine(line4, line4, barIdx, value); break; } }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void updateLine(double& lineUp[], double& lineDown[], int barIdx, double value) { if((value == LINE_VALUE_FLAT) || (value == LINE_VALUE_UP)) lineUp[ Bars-barIdx ] = value; if((value == LINE_VALUE_FLAT) || (value == LINE_VALUE_DOWN)) lineDown[ Bars-barIdx ] = value; }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+double average() {// original code uses 250-bar SMA of the simple range (high-low) return (iATR(NULL, 0, RANGE_AVERAGING_PERIOD, 0)); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+double getLow() { return (Close[ Bars-BarNumber ]); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+double getHigh() { return (Close[ Bars-BarNumber ]); }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+void alert(int alertType, int lineType, int barIdx) { datetime barTime = Time[Bars-barIdx]; switch(alertType) { case ALERT_TOP: switch(lineType) { case LINE_MAJOR: if(AlertMajorTopEnabled && (barTime != AlertMajorTopIdx)) { Alert(Symbol(), " ", periodName, ": Major Top Detected"); AlertMajorTopIdx = barTime; } break; case LINE_MINOR: if(AlertMinorTopEnabled && (barTime != AlertMinorTopIdx)) { Alert(Symbol(), " ", periodName, ": Minor Top Detected"); AlertMinorTopIdx = barTime; } break; } break; case ALERT_BOTTOM: switch(lineType) { case LINE_MAJOR: if(AlertMajorBottomEnabled && (barTime != AlertMajorBottomIdx)) { Alert(Symbol(), " ", periodName, ": Major Bottom Detected"); AlertMajorBottomIdx = barTime; } break; case LINE_MINOR: if(AlertMinorBottomEnabled && (barTime != AlertMinorBottomIdx)) { Alert(Symbol(), " ", periodName, ": Minor Bottom Detected"); AlertMinorBottomIdx = barTime; } break; } break; case ALERT_STABLE: if(AlertStableEnabled && (barTime != AlertStableIdx)) { Alert(Symbol(), " ", periodName, ": Latest extreme will not repaint anymore"); AlertStableIdx = barTime; } break; } }//+------------------------------------------------------------------+//| |//+------------------------------------------------------------------+string getPeriodName() { switch(Period()) { case PERIOD_M1: return ("M1"); case PERIOD_M5: return ("M5"); case PERIOD_M15: return ("M15"); case PERIOD_M30: return ("M30"); case PERIOD_H1: return ("H1"); case PERIOD_H4: return ("H4"); case PERIOD_D1: return ("D1"); case PERIOD_W1: return ("W1"); case PERIOD_MN1: return ("MN1"); } return(""); }//+------------------------------------------------------------------+