HYROLEAN

expr_trendlines_sample.mq5

May 23rd, 2026 (edited)
164
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 28.64 KB | Money | 0 0
  1. // expr_trendlines_sample.mq5 (トレンドラインを引くだけのEA実験サンプル)
  2. //  by 2026, (c)hyrolean
  3. //---------------------------------------------------------------------------
  4. #property copyright "2026, (c)hyrolean"
  5. #property link      "https://pastebin.com/18RWHQe2"
  6. #property strict
  7. #property version "3.01"
  8.  
  9. #include <User/hyrDefs.mqh>    // https://pastebin.com/iHZKAWqC
  10. #include <User/hyrTmpl.mqh>    // https://pastebin.com/LG1vurny
  11. #include <User/hyrGlobal.mqh>  // https://pastebin.com/2PdBW6NQ
  12. #include <User/hyrIQueue.mqh>  // https://pastebin.com/3pRKTce4
  13.  
  14.   // NOTE: トレンドの転換点は、レジサポの転換点ではなく、ダウ理論の転換点で
  15.   //       捉えている為、あまり正確ではありません.
  16.  
  17. #define ENTRY_NAME "ExprTrendlines"
  18.  
  19. #define QI_ARRAYSIZE 100
  20. #define SWING_LIMIT 1000
  21.  
  22. #define ARROW_BULL 233 // ↑
  23. #define ARROW_BEAR 234 // ↓
  24.  
  25. //--- 入力パラメータ
  26. input group "ZIGZAG"
  27. input int       ZigZagDepth     = 12;       // ZigZag Depth
  28. input int       ZigZagDeviation = 5;        // ZigZag Deviation
  29. input int       ZigZagBackstep  = 3;        // ZigZag Backstep
  30.  
  31. input group "APPEARANCE"
  32. input color   ClrUpperTrend   = clrCoral;  // Upper Trend line color
  33. input color   ClrLowerTrend   = clrAqua;   // Lower Trend line color
  34. input color   ClrBullDvgn = clrBlue;  // Bullish Divergence arrow color
  35. input color   ClrBearDvgn = clrRed;  // Bearish Divergnece arrow color
  36.  
  37. input group "DEBUGGING"
  38. input bool      DBGMODE         = true;     // DEBUG MODE
  39.  
  40. //===========================================================================
  41. // クラス
  42. //---------------------------------------------------------------------------
  43.  
  44.   // CHyrIQueueZigZag
  45. class CHyrIQueueZigZag : public CHyrIQueue
  46. {
  47. public:
  48.   bool Init(string symbol, ENUM_TIMEFRAMES tf,
  49.               int depth, int deviation, int backstep, int queueSize) {
  50.        int handle = iCustom(_Symbol, tf, "Examples\\ZigZag",
  51.                        depth, deviation, backstep);
  52.        if(handle == INVALID_HANDLE) {
  53.          Print("CHyrIQueueZigZag::Init() - iCustom handle 作成失敗: "
  54.            + IntegerToString(GetLastError()));
  55.          return false;
  56.        }
  57.        return CHyrIQueue::Init(handle, symbol, tf, queueSize);
  58.   }
  59. };
  60.  
  61. //===========================================================================
  62. // 型
  63. //---------------------------------------------------------------------------
  64. // TIMESHIFT
  65. struct TIMESHIFT {
  66.   datetime Time;
  67.   int Shift;
  68.   TIMESHIFT(): Time(0), Shift(0) {}
  69.   TIMESHIFT(const TIMESHIFT &src)
  70.    : Time(src.Time), Shift(src.Shift) {}
  71.   TIMESHIFT(datetime Time_, int Shift_=0)
  72.    : Time(Time_), Shift(Shift_) {}
  73. };
  74. //---------------------------------------------------------------------------
  75. // COORD
  76. struct COORD : public TIMESHIFT {
  77.   double Price;
  78.   COORD(): TIMESHIFT(), Price(0) {}
  79.   COORD(const COORD &src)
  80.    : TIMESHIFT(src), Price(src.Price) {}
  81.   COORD(double Price_, datetime Time_, int Shift_=0)
  82.    : TIMESHIFT(Time_, Shift_), Price(Price_) {}
  83. };
  84. //---------------------------------------------------------------------------
  85. // ZIGZAG_STATUS
  86. struct ZIGZAG_STATUS: public COORD {
  87.   ZIGZAG_STATUS(): COORD() {}
  88.   ZIGZAG_STATUS(const ZIGZAG_STATUS &src)
  89.    : COORD(src) {}
  90.   ZIGZAG_STATUS(double Price_, datetime Time_, int Shift_, double VWAP_=0)
  91.    : COORD(Price_, Time_, Shift_) {}
  92.   bool operator <(const ZIGZAG_STATUS &rhs) const {
  93.     return Time < rhs.Time ;
  94.   }
  95. };
  96. //---------------------------------------------------------------------------
  97. // SWING_STATUS
  98. struct SWING_STATUS {
  99.   ENUM_TIMEFRAMES TimeFrame;
  100.   ZIGZAG_STATUS High;
  101.   ZIGZAG_STATUS Low;
  102.   ZIGZAG_STATUS DvgnHigh;
  103.   ZIGZAG_STATUS DvgnLow;
  104.   fixed_queue<COORD> QExtr;
  105.   SWING_STATUS(ENUM_TIMEFRAMES TimeFrame_=0,int NumQExtr_=2):
  106.    TimeFrame(TimeFrame_), QExtr(NumQExtr_), High(), Low(), DvgnHigh(), DvgnLow() {}
  107.   SWING_STATUS(const SWING_STATUS &src):
  108.    TimeFrame(src.TimeFrame),
  109.    QExtr(src.QExtr),
  110.    High(src.High), Low(src.Low),
  111.    DvgnHigh(src.DvgnHigh), DvgnLow(src.DvgnLow) {}
  112.   void Init() {ZIGZAG_STATUS emp();High=emp;Low=emp;DvgnHigh=emp;DvgnLow=emp;}
  113.   bool Valid() { return High.Time!=0 && Low.Time!=0 && DvgnHigh.Time!=0 && DvgnLow.Time!=0 ; }
  114.   double Distance() const { return High.Price-Low.Price ; }
  115.   datetime Duration() const { return MathAbs(High.Time-Low.Time) ; }
  116.   FLAG Flag() const { return High.Time>Low.Time ? FLAG_BUY : FLAG_SELL ; }
  117.   OP Type() const { return High.Time>Low.Time ? OP_BUY : OP_SELL ; }
  118.   bool Bullish() const { return High.Time>Low.Time ; }
  119.   bool Bearish() const { return Low.Time>High.Time ; }
  120.   ZIGZAG_STATUS DvgnPos() const {
  121.     if(DvgnHigh.Time>DvgnLow.Time)
  122.       return DvgnHigh ;
  123.     return DvgnLow ;
  124.   }
  125.   void RecordDvgn() {
  126.     DvgnHigh = High;
  127.     DvgnLow = Low;
  128.   }
  129.   void PushExtr(const COORD &Extr) {
  130.     if(QExtr.full()) QExtr.pop_back();
  131.     QExtr.push_front(Extr);
  132.   }
  133.   void ClearExtr() { QExtr.clear(); }
  134. };
  135. //---------------------------------------------------------------------------
  136. // TRENDLINE
  137. struct TRENDLINE {
  138.   COORD P, Q;  // P -> Q
  139.   TIMESHIFT M, N; // duration
  140.   TRENDLINE(): P(), Q() {}
  141.   TRENDLINE(const COORD &P_, const COORD &Q_) : P(P_), Q(Q_) {}
  142.   TRENDLINE(double PriceP_, datetime TimeP_, double PriceQ_, datetime TimeQ_)
  143.     : P(PriceP_, TimeP_), Q(PriceQ_, TimeQ_) {}
  144.   TRENDLINE(double PriceP_, datetime TimeP_, int ShiftP_,
  145.     double PriceQ_, datetime TimeQ_, int ShiftQ_)
  146.     : P(PriceP_, TimeP_, ShiftP_), Q(PriceQ_, TimeQ_, ShiftQ_) {}
  147.   TRENDLINE(const TRENDLINE &src): P(src.P), Q(src.Q), M(src.M), N(src.N) {}
  148.   double IncliByTime() const {
  149.     double dPrice = Q.Price - P.Price ;
  150.     datetime dTime = Q.Time - P.Time ;
  151.     if(!dTime) return 0;
  152.     return dPrice/double(dTime) ;
  153.   }
  154.   double IncliByShift() const {
  155.     double dPrice = Q.Price - P.Price ;
  156.     int dShift = P.Shift - Q.Shift ;
  157.     if(!dShift) return 0;
  158.     return dPrice/double(dShift) ;
  159.   }
  160.   double PriceByTime(datetime Time_) const {
  161.     return P.Price + IncliByTime() * ( Time_ - P.Time ) ;
  162.   }
  163.   double PriceByShift(int Shift_) const {
  164.     return P.Price + IncliByShift() * ( P.Shift - Shift_ ) ;
  165.   }
  166. };
  167. //---------------------------------------------------------------------------
  168. // TRENDLINES
  169. struct TRENDLINES {
  170.   string Name;
  171.   ENUM_TIMEFRAMES TimeFrame;
  172.   TRENDLINE Upper, Lower;
  173.   TRENDLINES(ENUM_TIMEFRAMES TimeFrame_=PERIOD_CURRENT, string Name_="")
  174.    : Name(Name_), TimeFrame(TimeFrame_), Upper(), Lower() {}
  175.   TRENDLINES(const TRENDLINES &Src):
  176.     TimeFrame(Src.TimeFrame), Name(Src.Name), Upper(Src.Upper), Lower(Src.Lower) {}
  177. };
  178. //===========================================================================
  179. // 変数
  180. //---------------------------------------------------------------------------
  181.  
  182. //時間
  183. datetime CurCurrentTime;
  184. bool NextCurrentTimed;
  185.  
  186. //トレンドライン
  187. TRENDLINES TrendLines(PERIOD_CURRENT,"Trend");
  188.  
  189. //スイングの状態
  190. SWING_STATUS CurrentSwing(PERIOD_CURRENT,ZigZagBackstep);
  191.  
  192. //ライン情報
  193. #define TRENDINFO_UPPERNAME "TREND UPPER INFO"
  194. #define TRENDINFO_LOWERNAME "TREND LOWER INFO"
  195.  
  196. //転換点矢印
  197. #define DIVERGENCE_ARROWNAME "DIVERGNECE ARROW"
  198.  
  199. //デバッグ情報
  200. #define DBGINFO_NAME "DEBUG INFO"
  201. string DBGMSG = "" ;
  202.  
  203. //--- IQueue ATR14 (デバッグ用)
  204. CHyrIQueueATR QiATR14;
  205.  
  206. //===========================================================================
  207. // 関数
  208. //---------------------------------------------------------------------------
  209. int OnInit()
  210. {
  211.   //テスターで表示されるインジケータを非表示にする
  212.   TesterHideIndicators(!DBGMODE);
  213.  
  214.   //--- IQueue ATR 14 (デバッグ用)
  215.   if(!QiATR14.Init     (_Symbol, PERIOD_CURRENT, 14, 2))
  216.     return INIT_FAILED;
  217.  
  218.   GlobalSettings(ENTRY_NAME);
  219.  
  220.   //現在時刻を初期化
  221.   CurCurrentTime=CurrentTime();
  222.  
  223.   //スイング初期化
  224.   CurrentSwing.Init();
  225.   CheckSwingStatus(CurrentSwing,1);
  226.   UpdateDivergenceArrow(CurrentSwing);
  227.  
  228.   // トレンドライン更新
  229.   UpdateTrendLines(TrendLines,CurrentSwing);
  230.  
  231.   //トレンド情報
  232.   if(DBGMODE) {
  233.  
  234.     int trend_y = 40 ;
  235.  
  236.     ObjectCreate(0, TRENDINFO_UPPERNAME, OBJ_LABEL, 0, 0, 0);
  237.     ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_XDISTANCE, 10);
  238.     ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_YDISTANCE, trend_y);
  239.     ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
  240.     ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
  241.     ObjectSetString (0, TRENDINFO_UPPERNAME, OBJPROP_TEXT, "UPPER TREND INFO");
  242.     ObjectSetString (0, TRENDINFO_UPPERNAME, OBJPROP_FONT, "Verdana");
  243.     ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_FONTSIZE, 8);
  244.     ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_COLOR, ClrUpperTrend);
  245.  
  246.     trend_y+=12;
  247.  
  248.     ObjectCreate(0, TRENDINFO_LOWERNAME, OBJ_LABEL, 0, 0, 0);
  249.     ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_XDISTANCE, 10);
  250.     ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_YDISTANCE, trend_y);
  251.     ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
  252.     ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
  253.     ObjectSetString (0, TRENDINFO_LOWERNAME, OBJPROP_TEXT, "LOWER TREND INFO");
  254.     ObjectSetString (0, TRENDINFO_LOWERNAME, OBJPROP_FONT, "Verdana");
  255.     ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_FONTSIZE, 8);
  256.     ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_COLOR, ClrLowerTrend);
  257.  
  258.     // トレンド情報更新
  259.     UpdateTrendInfo(TRENDINFO_UPPERNAME,TrendLines.Upper);
  260.     UpdateTrendInfo(TRENDINFO_LOWERNAME,TrendLines.Lower);
  261.    
  262.     //DEBUG INFO
  263.     ObjectCreate(0, DBGINFO_NAME, OBJ_LABEL, 0, 0, 0);
  264.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_XDISTANCE, 10);
  265.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_YDISTANCE, 15);
  266.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
  267.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
  268.     ObjectSetString (0, DBGINFO_NAME, OBJPROP_TEXT, "DEBUG INFO");
  269.     ObjectSetString (0, DBGINFO_NAME, OBJPROP_FONT, "Verdana");
  270.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_FONTSIZE, 8);
  271.     ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_COLOR, clrAquamarine);
  272.   }
  273.  
  274.   return(INIT_SUCCEEDED);
  275. }
  276. //---------------------------------------------------------------------------
  277. void OnDeinit(const int reason)
  278. {
  279.   if(DBGMODE) {
  280.     ObjectDelete(0, DBGINFO_NAME) ;
  281.     ObjectDelete(0, TRENDINFO_LOWERNAME) ;
  282.     ObjectDelete(0, TRENDINFO_UPPERNAME) ;
  283.   }
  284.   ObjectDelete(0, DIVERGENCE_ARROWNAME);
  285.   DestroyTrendLines(TrendLines);
  286. }
  287. //---------------------------------------------------------------------------
  288. void OnTick()
  289. {
  290.   datetime nextCurrentTime = CurrentTime();
  291.   NextCurrentTimed = nextCurrentTime != CurCurrentTime ;
  292.   CurCurrentTime = nextCurrentTime;
  293.  
  294.   QiATR14.Update();
  295.  
  296.   if(NextCurrentTimed) {
  297.     // スイング遷移更新
  298.     CheckSwingStatus(CurrentSwing,1);
  299.     UpdateDivergenceArrow(CurrentSwing);
  300.     // トレンドライン更新
  301.     UpdateTrendLines(TrendLines,CurrentSwing);
  302.     if(DBGMODE) {
  303.       // トレンド情報更新
  304.       UpdateTrendInfo(TRENDINFO_UPPERNAME,TrendLines.Upper);
  305.       UpdateTrendInfo(TRENDINFO_LOWERNAME,TrendLines.Lower);
  306.     }
  307.   }
  308.  
  309.   // デバッグ情報
  310.   string msg = DBGMSG ;
  311.   if(msg!="") msg += " | ";
  312.   msg += StringFormat("ATR(14): %g | ",QiATR14[0]);
  313.   msg += "DVGN: "+DoubleToString(CurrentSwing.DvgnPos().Price,_Digits);
  314.   DBGOUT(msg);
  315. }
  316. //---------------------------------------------------------------------------
  317. //DBGOUT
  318. void DBGOUT(string text)
  319. {
  320.   if(DBGMODE) {
  321.     ObjectSetString(0, DBGINFO_NAME, OBJPROP_TEXT, text);
  322.   }
  323. }
  324. //---------------------------------------------------------------------------
  325. //現在基軸タイムを返す
  326. datetime CurrentTime(int shift=0)
  327. {
  328.   return iTime(Symbol(), PERIOD_CURRENT, shift);
  329. }
  330. //---------------------------------------------------------------------------
  331. // ZigZag のポジションを列挙する
  332. bool EnumZigZagStatus(int num, ZIGZAG_STATUS &arrayZZ[], ENUM_TIMEFRAMES timeFrame, int si=0, int ei=INT_MAX)
  333. {
  334.   int limit = ei==INT_MAX ? ei : (si<ei?ei+1:ei-1) ;
  335.   int bars = iBars(NULL,timeFrame) ;
  336.   limit = MathMin(limit,bars);
  337.   limit = MathMax(limit,-1);
  338.   ArraySetAsSeries(arrayZZ,true);
  339.   ArrayResize(arrayZZ,num);
  340.   CHyrIQueueZigZag qiZigZag;
  341.   qiZigZag.UpdateShift(si);
  342.   qiZigZag.Init(_Symbol, timeFrame, ZigZagDepth, ZigZagDeviation, ZigZagBackstep, QI_ARRAYSIZE);
  343.   for (int i = si, n=0; i != limit ; si<limit? i++: i--) {
  344.     double zz = qiZigZag.sv(i);
  345.      // iCustom(NULL, timeFrame, "ZigZag", ZigZagDepth, ZigZagDeviation, ZigZagBackstep, 0, i);
  346.     if(zz!=0) {
  347.       arrayZZ[n] = ZIGZAG_STATUS(zz, iTime(_Symbol, timeFrame, i), i);
  348.       n++;
  349.       if(n>=num) return true;
  350.     }
  351.   }
  352.   return false;
  353. }
  354. //---------------------------------------------------------------------------
  355. // ZigZag のスイングを調べる
  356. int CheckSwingStatus(SWING_STATUS &Swing, int si=0)
  357. {
  358.   ENUM_TIMEFRAMES timeFrame = Swing.TimeFrame ;
  359.   double margin = 0 ; //ZigZagSwingMargin * _Point ;
  360.   FLAG flag = (Swing.High.Time>Swing.Low.Time)? FLAG_BUY: FLAG_SELL;
  361.   int limit = //iBars(NULL,timeFrame)-ZigZagDepth;
  362.     MathMin(iBars(NULL,timeFrame)-ZigZagDepth,SWING_LIMIT);
  363.   int start=0, initial=2;
  364.   datetime lastTime = MathMax(Swing.High.Time, Swing.Low.Time);
  365.   bool first=true ;
  366.   ZIGZAG_STATUS prev_zzs ;
  367.   CHyrIQueueZigZag qiZigZag;
  368.   qiZigZag.UpdateShift(si);
  369.   qiZigZag.Init(_Symbol, timeFrame, ZigZagDepth, ZigZagDeviation, ZigZagBackstep, QI_ARRAYSIZE);
  370.   //起点調査
  371.   if(lastTime!=0) {
  372.     for(int i = si; i<limit ; i++) {
  373.       double zz = qiZigZag.sv(i);
  374.         // iCustom(NULL, timeFrame, "ZigZag", ZigZagDepth, ZigZagDeviation, ZigZagBackstep, 0, i);
  375.       if(zz!=0) {
  376.         ZIGZAG_STATUS zzs(zz, iTime(_Symbol, timeFrame, i), i);
  377.         if(zzs.Time<=lastTime) {
  378.           start = zzs.Shift -1 ;
  379.           prev_zzs = zzs ;
  380.           first = false ;
  381.           break;
  382.         }
  383.       }
  384.     }
  385.     if(!MathMin(Swing.High.Time, Swing.Low.Time))
  386.       initial = 1 ;
  387.   }else {
  388.     start = limit;
  389.     initial = 0 ;
  390.   }
  391.   //スイング検証
  392.   for(int i=start ; i>=si ; i--) {
  393.     double zz = qiZigZag.sv(i);
  394.       // iCustom(NULL, timeFrame, "ZigZag", ZigZagDepth, ZigZagDeviation, ZigZagBackstep, 0, i);
  395.     if(zz!=0) {
  396.       ZIGZAG_STATUS zzs(zz, iTime(_Symbol, timeFrame, i), i);
  397.       if(initial<2) {
  398.         if(!initial)
  399.           Swing.High = zzs ;
  400.         else
  401.           Swing.Low = zzs ;
  402.         initial++ ;
  403.         if(initial>=2) {
  404.           if(Swing.Low.Price>Swing.High.Price) {
  405.             ZIGZAG_STATUS tmps(Swing.Low) ;
  406.             Swing.Low = Swing.High ;
  407.             Swing.High = tmps ;
  408.             flag = FLAG_BUY ;
  409.             Swing.DvgnHigh = Swing.Low ;
  410.             Swing.DvgnLow = Swing.Low ;
  411.           }else {
  412.             flag = FLAG_SELL ;
  413.             Swing.DvgnLow = Swing.High ;
  414.             Swing.DvgnHigh = Swing.High ;
  415.           }
  416.           first = false ;
  417.         }
  418.       }else {
  419.         if(flag==FLAG_BUY?zzs.Price>Swing.High.Price:zzs.Price<Swing.Low.Price) { // 最大値更新
  420.           if(first) {
  421.             ZIGZAG_STATUS bef_zzs[1];
  422.             if(EnumZigZagStatus(1, bef_zzs, timeFrame, i+1)) {
  423.               prev_zzs = bef_zzs[0] ;
  424.             }
  425.             first=false ;
  426.           }
  427.           if(flag==FLAG_BUY?zzs.Price>prev_zzs.Price:zzs.Price<prev_zzs.Price) {
  428.             // 価格更新
  429.             switch(flag) {
  430.               case FLAG_BUY:
  431.                 Swing.High = zzs ;
  432.                 Swing.PushExtr(zzs);
  433.                 if(zzs.Price-prev_zzs.Price>=margin)
  434.                   Swing.Low = prev_zzs ;
  435.                 break;
  436.               case FLAG_SELL:
  437.                 Swing.Low = zzs ;
  438.                 Swing.PushExtr(zzs);
  439.                 if(prev_zzs.Price-zzs.Price>=margin)
  440.                   Swing.High = prev_zzs ;
  441.                 break;
  442.             }
  443.           }
  444.         }else {
  445.           if(flag==FLAG_BUY?zzs.Price<Swing.Low.Price:zzs.Price>Swing.High.Price) { // ダイバージェンス
  446.             double cls = iClose(NULL, timeFrame, i);
  447.             if(flag==FLAG_BUY?cls<Swing.Low.Price:cls>Swing.High.Price) {
  448.               // トレンド逆転
  449.               Swing.RecordDvgn();
  450.               Swing.ClearExtr();
  451.               switch(flag) {
  452.                 case FLAG_BUY:
  453.                   if(first)
  454.                     Swing.High = Swing.Low ;
  455.                   else if(prev_zzs.Price-zzs.Price>=margin)
  456.                     Swing.High = prev_zzs ;
  457.                   Swing.Low = zzs ;
  458.                   Swing.PushExtr(zzs);
  459.                   flag = FLAG_SELL ;
  460.                   break;
  461.                 case FLAG_SELL:
  462.                   if(first)
  463.                     Swing.Low = Swing.High ;
  464.                   else if(zzs.Price-prev_zzs.Price>=margin)
  465.                     Swing.Low = prev_zzs ;
  466.                   Swing.High = zzs ;
  467.                   Swing.PushExtr(zzs);
  468.                   flag = FLAG_BUY ;
  469.                   break;
  470.               }
  471.             }
  472.           }
  473.         }
  474.       }
  475.       if(!first) prev_zzs = zzs ;
  476.     }
  477.   }
  478.   return flag;
  479. }
  480. //---------------------------------------------------------------------------
  481. // 転換位置ポジションに矢印を描画する関数                              
  482. void UpdateDivergenceArrow(const SWING_STATUS &Swing)
  483. {
  484.   string name = DIVERGENCE_ARROWNAME ;
  485.   uchar code = Swing.Bullish() ? ARROW_BULL : ARROW_BEAR ;
  486.   color clr = Swing.Bullish() ? ClrBullDvgn : ClrBearDvgn ;
  487.   datetime time = Swing.DvgnPos().Time ;
  488.   double price = Swing.DvgnPos().Price ;
  489.  
  490.   if(ObjectFind(0, name) < 0) {
  491.     ObjectCreate(0, name, OBJ_ARROW, 0, time, price);
  492.     ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
  493.     ObjectSetInteger(0, name, OBJPROP_BACK, false); // 最前面に表示
  494.   }else {
  495.     ObjectMove(0, name, 0, time, price);
  496.   }
  497.   ObjectSetInteger(0, name, OBJPROP_ANCHOR, Swing.Bullish() ? ANCHOR_TOP: ANCHOR_BOTTOM);
  498.   ObjectSetInteger(0, name, OBJPROP_ARROWCODE, code);
  499.   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
  500. }
  501. //---------------------------------------------------------------------------
  502. // MARK: トレンドライン @ 2026/05/04
  503. #define TREND_UPPER_PREFIX ENTRY_NAME"_UPPER_"
  504. #define TREND_LOWER_PREFIX ENTRY_NAME"_LOWER_"
  505. //-----
  506. void DestroyTrendLines(const TRENDLINES &Lines)
  507. {
  508.   ObjectDelete(0,TREND_UPPER_PREFIX+Lines.Name);
  509.   ObjectDelete(0,TREND_LOWER_PREFIX+Lines.Name);
  510. }
  511. //-----
  512. void UpdateTrendLines(TRENDLINES &Lines, const SWING_STATUS &Swing)
  513. {
  514.   datetime lastTime = iTime(_Symbol, Lines.TimeFrame, 0);
  515.   int MinimumShift = 0; // ZigZagBackstep;
  516.  
  517.   //--- 1. 直近 ZigZag の最終頂点を2つ求める
  518.   ZIGZAG_STATUS zz[];
  519.   const int zzNum = 2 ;
  520.   bool valid = EnumZigZagStatus(zzNum,zz,Lines.TimeFrame,1);
  521.   bool carry = false ;
  522.   if(valid&&zz[0].Shift<MinimumShift) {
  523.     carry = true ;
  524.     valid = EnumZigZagStatus(zzNum,zz,Lines.TimeFrame,zz[0].Shift+1);
  525.   }
  526.  
  527.   //--- 2. Dvgnの転換の直近位置を求める
  528.   int M2=-1, M4=-1; {
  529.     ZIGZAG_STATUS zzDvgnNext[];
  530.     if(EnumZigZagStatus(1,zzDvgnNext,Lines.TimeFrame,
  531.      Bars(_Symbol, Lines.TimeFrame, Swing.DvgnPos().Time, lastTime)-2,0)) {
  532.       int shift2 = Bars(_Symbol, Lines.TimeFrame, zzDvgnNext[0].Time, lastTime)-1 ;
  533.       if(shift2>=MinimumShift) { // MinimumShift以上シフト位置が離れていることが条件
  534.         M2 = shift2 ;
  535.         if(M2>2&&EnumZigZagStatus(2,zzDvgnNext,Lines.TimeFrame,M2-1,0)) {
  536.           int shift4 = Bars(_Symbol, Lines.TimeFrame, zzDvgnNext[1].Time, lastTime)-1 ;
  537.           if(shift4>=MinimumShift) // MinimumShift以上シフト位置が離れていることが条件
  538.             M4 = shift4 ;
  539.         }
  540.       }
  541.     }
  542.   }
  543.  
  544.   //--- 3. 直近のZigZagの頂点更新位置を探す
  545.   COORD E;
  546.   for(int i=0;i<Swing.QExtr.size();i++) {
  547.     int shift = Bars(_Symbol, Lines.TimeFrame, Swing.QExtr[i].Time, lastTime)-1 ;
  548.     if(shift>=MinimumShift) { // MinimumShift以上シフト位置が離れていることが条件
  549.       E = Swing.QExtr[i] ;
  550.       E.Shift = shift ;
  551.       break;
  552.     }
  553.   }
  554.   if(!E.Shift) {
  555.     // みつからない場合は、最上位位置を検出する
  556.     if(valid) {
  557.       int si = zz[0].Shift ;
  558.       int count = (si-MinimumShift)+1 ;
  559.       int shift = Swing.Bullish()?
  560.        iHighest(_Symbol, Lines.TimeFrame, MODE_HIGH, count, si):
  561.        iLowest(_Symbol, Lines.TimeFrame, MODE_LOW, count, si);
  562.       if(shift>=MinimumShift) {
  563.         E.Shift = shift ;
  564.         E.Time = iTime(_Symbol, Lines.TimeFrame, shift) ;
  565.         E.Price = Swing.Bullish()?
  566.          iHigh(_Symbol, Lines.TimeFrame, shift):
  567.          iLow(_Symbol, Lines.TimeFrame, shift);
  568.       }
  569.     }
  570.   }
  571.  
  572.   //--- 4. ぶつからないトレンドラインの端点を計算 ---
  573.   int M1 = Bars(_Symbol, Lines.TimeFrame, Swing.DvgnPos().Time , lastTime)-1; //CurrentSwing.DvgnPos().Shift ;
  574.   int M0 = Bars(_Symbol, Lines.TimeFrame, MathMin(Swing.DvgnHigh.Time,Swing.DvgnLow.Time) , lastTime)-1;
  575.   int MHi, MLo;
  576.   int Mextr = M2 ;
  577.   if(M2==-1||M4==-1) {
  578.     Mextr = M0 ;
  579.   }
  580.   if(Swing.DvgnHigh.Time>Swing.DvgnLow.Time) {
  581.     MHi = M1 ; MLo = Mextr ;
  582.   }else {
  583.     MLo = M1 ; MHi = Mextr ;
  584.   }
  585.   int NHi = MinimumShift , NLo = MinimumShift ;
  586.   if(valid) {
  587.     if(carry) {
  588.         NHi = NLo = zz[0].Shift ;
  589.     }else {
  590.       if(zz[0].Price>zz[1].Price) {
  591.         NHi = zz[0].Shift ; NLo = zz[1].Shift ;
  592.       }else {
  593.         NHi = zz[1].Shift ; NLo = zz[0].Shift ;
  594.       }
  595.     }
  596.   }
  597.   if(E.Shift>0) {
  598.     if(Swing.Bullish()) {
  599.       if(E.Shift<NHi) {
  600.         NHi = E.Shift ;
  601.       }
  602.     }
  603.     if(Swing.Bearish()) {
  604.       if(E.Shift<NLo) {
  605.         NLo = E.Shift ;
  606.       }
  607.     }
  608.   }
  609.  
  610.   DetectTrendLine(Lines, MHi, MLo, NHi, NLo);
  611.  
  612.   DrawTrendLine(TREND_UPPER_PREFIX+Lines.Name, Lines.Upper, ClrUpperTrend);
  613.   DrawTrendLine(TREND_LOWER_PREFIX+Lines.Name, Lines.Lower, ClrLowerTrend);
  614. }
  615. //-----
  616. //トレンドラインを描画・更新する補助関数(視覚確認用)
  617. void DrawTrendLine(string name, const TRENDLINE &line, color clr)
  618. {
  619.     datetime qTime = line.P.Price==line.Q.Price && line.P.Time==line.Q.Time
  620.       ? line.P.Time + PeriodSeconds(_Period) : line.Q.Time ;
  621.     if(ObjectFind(0, name) < 0)
  622.     {
  623.         ObjectCreate(0, name, OBJ_TREND, 0,
  624.           line.P.Time, line.P.Price, qTime, line.Q.Price );
  625.         ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true); // 右側に延長
  626.         ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT); // 点線
  627.         ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); // 選択不可
  628.     }
  629.     else
  630.     {
  631.         ObjectMove(0, name, 0, line.P.Time, line.P.Price);
  632.         ObjectMove(0, name, 1, qTime, line.Q.Price);
  633.     }
  634.     ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
  635. }
  636. //-----
  637. // M~N区間の上下トレンドラインを検出する
  638. void DetectTrendLine(TRENDLINES &Lines, int MHi, int MLo, int NHi, int NLo)
  639. {
  640.   int AHi=MHi, BHi=NHi, ALo=MLo, BLo=NLo ;
  641.   DetectNonCollisionSection(true, Lines.TimeFrame, MHi, NHi, AHi, BHi) ;
  642.    Lines.Upper = TRENDLINE(
  643.      iHigh(_Symbol, Lines.TimeFrame, AHi), iTime(_Symbol, Lines.TimeFrame, AHi), AHi,
  644.      iHigh(_Symbol, Lines.TimeFrame, BHi), iTime(_Symbol, Lines.TimeFrame, BHi), BHi );
  645.    Lines.Upper.M = TIMESHIFT( iTime(_Symbol, Lines.TimeFrame, MHi), MHi );
  646.    Lines.Upper.N = TIMESHIFT( iTime(_Symbol, Lines.TimeFrame, NHi), NHi );
  647.   DetectNonCollisionSection(false, Lines.TimeFrame, MLo, NLo, ALo, BLo) ;
  648.    Lines.Lower = TRENDLINE(
  649.      iLow(_Symbol, Lines.TimeFrame, ALo), iTime(_Symbol, Lines.TimeFrame, ALo), ALo,
  650.      iLow(_Symbol, Lines.TimeFrame, BLo), iTime(_Symbol, Lines.TimeFrame, BLo), BLo );
  651.    Lines.Lower.M = TIMESHIFT( iTime(_Symbol, Lines.TimeFrame, MLo), MLo );
  652.    Lines.Lower.N = TIMESHIFT( iTime(_Symbol, Lines.TimeFrame, NLo), NLo );
  653. }
  654. //-----
  655. // ぶつからないラインの区間を検出する関数(区間A~Bは、M~N区間内とする、かつM>N&&A>B)
  656. double DetectNonCollisionSection(
  657.   bool isUpper, ENUM_TIMEFRAMES tf, int M, int N, int &A, int &B, bool skip=false)
  658. {
  659.   // 同じ位置
  660.   if(A==B) return 0;
  661.  
  662.   // 始点
  663.   double pA = (isUpper) ? iHigh(_Symbol, tf, A) : iLow(_Symbol, tf, A);
  664.  
  665.   // 終点
  666.   double pB = (isUpper) ? iHigh(_Symbol, tf, B) : iLow(_Symbol, tf, B);
  667.  
  668.   // 傾き
  669.   double inclination = (pB-pA)/double(A-B) ;
  670.  
  671.   // 初期プライス
  672.   double price = pA - ( inclination * double(M-A) ) ;
  673.  
  674.   // 高値安値チェック
  675.   bool collision = false ;
  676.   double score = 0 ;
  677.   for(int i=M ; i>=N ; i--) {
  678.     if(i!=A&&i!=B) { // A B 地点は飛ばす
  679.       if(isUpper) { // 高値ラインの場合
  680.         double checkHigh = iHigh(_Symbol, tf, i);
  681.         if(!(skip&&A>=i&&i>=B)&&checkHigh>price&&!InnerPoint(checkHigh,price)) collision = true ;
  682.         else score += price - checkHigh ;
  683.       }else { // 安値ラインの場合
  684.         double checkLow  = iLow(_Symbol, tf, i);
  685.         if(!(skip&&A>=i&&i>=B)&&checkLow<price&&!InnerPoint(checkLow,price)) collision = true ;
  686.         else score += checkLow - price ;
  687.       }
  688.       if(collision) { // 新しい起点を検出
  689.         if(A>i) {
  690.           int newA1=A, newB1 = i ;
  691.           double score1 = DetectNonCollisionSection(isUpper,tf,M,N,newA1,newB1,true);
  692.           if(!skip) {
  693.             int newA2=newB1, newB2 = N ;
  694.             double score2 = (newA2<=newB2) ? score1 :
  695.               DetectNonCollisionSection(isUpper,tf,M,N,newA2,newB2);
  696.             if(score2<score1) { // スコアが小さい方を優先する
  697.               A=newA2; B=newB2 ;
  698.               return score2 ;
  699.             }
  700.           }
  701.           A=newA1; B=newB1 ;
  702.           return score1 ;
  703.         }else {
  704.           //PrintMessage("間違った起点");
  705.           return DBL_MAX ; // 間違った起点
  706.         }
  707.       }
  708.     }
  709.     price += inclination ;
  710.   }
  711.   return score ; // 一度もぶつからなかったので、A~B間は正しい区間である
  712. }
  713. //---------------------------------------------------------------------------
  714. // トレンド情報の更新
  715. void UpdateTrendInfo(string ObjName,const TRENDLINE &TrendLine)
  716. {
  717.   double a = TrendLine.IncliByShift() ;
  718.   string text = StringFormat("INC: %g | INC/ATR(14): %g", a, a/QiATR14[0]);
  719.   ObjectSetString (0, ObjName, OBJPROP_TEXT, text);
  720. }
  721. //---------------------------------------------------------------------------
  722. // ぶつからないラインの端点を計算する関数 ( by Gemini ) ※未使用
  723. //-----
  724. // isUpper: true=高値ライン, false=安値ライン
  725. void CalculateNonCollisionLine(bool isUpper, int M, int N,
  726.                                datetime &t1, double &p1, datetime &t2, double &p2)
  727. {
  728.     // 始点(t1, p1)をM本前の足に固定
  729.     t1 = iTime(_Symbol, _Period, M);
  730.     p1 = (isUpper) ? iHigh(_Symbol, _Period, M) : iLow(_Symbol, _Period, M);
  731.  
  732.     // 暫定の終点(t2, p2)をN本前の足に設定
  733.     t2 = iTime(_Symbol, _Period, N);
  734.     p2 = (isUpper) ? iHigh(_Symbol, _Period, N) : iLow(_Symbol, _Period, N);
  735.  
  736.     // M-1本前からN本前までループして、ラインの外側にある足を探す
  737.     for(int i = M - 1; i >= N; i--)
  738.     {
  739.         datetime checkTime = iTime(_Symbol, _Period, i);
  740.         double checkHigh = iHigh(_Symbol, _Period, i);
  741.         double checkLow  = iLow(_Symbol, _Period, i);
  742.  
  743.         // その時の暫定ラインの価格を計算
  744.         double linePrice = CalculatePriceAtTime(t1, p1, t2, p2, checkTime);
  745.  
  746.         if(isUpper) // 高値ラインの場合
  747.         {
  748.             // もし足の高値がラインより上にあれば、その足を新たな終点にする
  749.             if(checkHigh > linePrice)
  750.             {
  751.                 t2 = checkTime;
  752.                 p2 = checkHigh;
  753.                 // 終点が変わったので、M-1からループをやり直す(簡略化のためこのまま続行)
  754.             }
  755.         }
  756.         else // 安値ラインの場合
  757.         {
  758.             // もし足の安値がラインより下にあれば、その足を新たな終点にする
  759.             if(checkLow < linePrice)
  760.             {
  761.                 t2 = checkTime;
  762.                 p2 = checkLow;
  763.             }
  764.         }
  765.     }
  766. }
  767. //---------------------------------------------------------------------------
  768. // 2点を通る直線の、指定した時間における価格を計算する関数 ( by Gemini ) ※未使用
  769. double CalculatePriceAtTime(datetime t1, double p1, datetime t2, double p2, datetime targetT)
  770. {
  771.     if(t1 == t2) return 0; // 垂直な線は計算不可
  772.  
  773.     // 直線の式: y = p1 + (p2 - p1) * (targetT - t1) / (t2 - t1)
  774.     double price = p1 + (p2 - p1) * (double)(targetT - t1) / (double)(t2 - t1);
  775.     return price;
  776. }
  777. //---------------------------------------------------------------------------
  778.  
Tags: Mt5
Advertisement
Add Comment
Please, Sign In to add comment