Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // expr_trendlines_sample.mq5 (トレンドラインを引くだけのEA実験サンプル)
- // by 2026, (c)hyrolean
- //---------------------------------------------------------------------------
- #property copyright "2026, (c)hyrolean"
- #property link "https://pastebin.com/18RWHQe2"
- #property strict
- #property version "3.01"
- #include <User/hyrDefs.mqh> // https://pastebin.com/iHZKAWqC
- #include <User/hyrTmpl.mqh> // https://pastebin.com/LG1vurny
- #include <User/hyrGlobal.mqh> // https://pastebin.com/2PdBW6NQ
- #include <User/hyrIQueue.mqh> // https://pastebin.com/3pRKTce4
- // NOTE: トレンドの転換点は、レジサポの転換点ではなく、ダウ理論の転換点で
- // 捉えている為、あまり正確ではありません.
- #define ENTRY_NAME "ExprTrendlines"
- #define QI_ARRAYSIZE 100
- #define SWING_LIMIT 1000
- #define ARROW_BULL 233 // ↑
- #define ARROW_BEAR 234 // ↓
- //--- 入力パラメータ
- input group "ZIGZAG"
- input int ZigZagDepth = 12; // ZigZag Depth
- input int ZigZagDeviation = 5; // ZigZag Deviation
- input int ZigZagBackstep = 3; // ZigZag Backstep
- input group "APPEARANCE"
- input color ClrUpperTrend = clrCoral; // Upper Trend line color
- input color ClrLowerTrend = clrAqua; // Lower Trend line color
- input color ClrBullDvgn = clrBlue; // Bullish Divergence arrow color
- input color ClrBearDvgn = clrRed; // Bearish Divergnece arrow color
- input group "DEBUGGING"
- input bool DBGMODE = true; // DEBUG MODE
- //===========================================================================
- // クラス
- //---------------------------------------------------------------------------
- // CHyrIQueueZigZag
- class CHyrIQueueZigZag : public CHyrIQueue
- {
- public:
- bool Init(string symbol, ENUM_TIMEFRAMES tf,
- int depth, int deviation, int backstep, int queueSize) {
- int handle = iCustom(_Symbol, tf, "Examples\\ZigZag",
- depth, deviation, backstep);
- if(handle == INVALID_HANDLE) {
- Print("CHyrIQueueZigZag::Init() - iCustom handle 作成失敗: "
- + IntegerToString(GetLastError()));
- return false;
- }
- return CHyrIQueue::Init(handle, symbol, tf, queueSize);
- }
- };
- //===========================================================================
- // 型
- //---------------------------------------------------------------------------
- // TIMESHIFT
- struct TIMESHIFT {
- datetime Time;
- int Shift;
- TIMESHIFT(): Time(0), Shift(0) {}
- TIMESHIFT(const TIMESHIFT &src)
- : Time(src.Time), Shift(src.Shift) {}
- TIMESHIFT(datetime Time_, int Shift_=0)
- : Time(Time_), Shift(Shift_) {}
- };
- //---------------------------------------------------------------------------
- // COORD
- struct COORD : public TIMESHIFT {
- double Price;
- COORD(): TIMESHIFT(), Price(0) {}
- COORD(const COORD &src)
- : TIMESHIFT(src), Price(src.Price) {}
- COORD(double Price_, datetime Time_, int Shift_=0)
- : TIMESHIFT(Time_, Shift_), Price(Price_) {}
- };
- //---------------------------------------------------------------------------
- // ZIGZAG_STATUS
- struct ZIGZAG_STATUS: public COORD {
- ZIGZAG_STATUS(): COORD() {}
- ZIGZAG_STATUS(const ZIGZAG_STATUS &src)
- : COORD(src) {}
- ZIGZAG_STATUS(double Price_, datetime Time_, int Shift_, double VWAP_=0)
- : COORD(Price_, Time_, Shift_) {}
- bool operator <(const ZIGZAG_STATUS &rhs) const {
- return Time < rhs.Time ;
- }
- };
- //---------------------------------------------------------------------------
- // SWING_STATUS
- struct SWING_STATUS {
- ENUM_TIMEFRAMES TimeFrame;
- ZIGZAG_STATUS High;
- ZIGZAG_STATUS Low;
- ZIGZAG_STATUS DvgnHigh;
- ZIGZAG_STATUS DvgnLow;
- fixed_queue<COORD> QExtr;
- SWING_STATUS(ENUM_TIMEFRAMES TimeFrame_=0,int NumQExtr_=2):
- TimeFrame(TimeFrame_), QExtr(NumQExtr_), High(), Low(), DvgnHigh(), DvgnLow() {}
- SWING_STATUS(const SWING_STATUS &src):
- TimeFrame(src.TimeFrame),
- QExtr(src.QExtr),
- High(src.High), Low(src.Low),
- DvgnHigh(src.DvgnHigh), DvgnLow(src.DvgnLow) {}
- void Init() {ZIGZAG_STATUS emp();High=emp;Low=emp;DvgnHigh=emp;DvgnLow=emp;}
- bool Valid() { return High.Time!=0 && Low.Time!=0 && DvgnHigh.Time!=0 && DvgnLow.Time!=0 ; }
- double Distance() const { return High.Price-Low.Price ; }
- datetime Duration() const { return MathAbs(High.Time-Low.Time) ; }
- FLAG Flag() const { return High.Time>Low.Time ? FLAG_BUY : FLAG_SELL ; }
- OP Type() const { return High.Time>Low.Time ? OP_BUY : OP_SELL ; }
- bool Bullish() const { return High.Time>Low.Time ; }
- bool Bearish() const { return Low.Time>High.Time ; }
- ZIGZAG_STATUS DvgnPos() const {
- if(DvgnHigh.Time>DvgnLow.Time)
- return DvgnHigh ;
- return DvgnLow ;
- }
- void RecordDvgn() {
- DvgnHigh = High;
- DvgnLow = Low;
- }
- void PushExtr(const COORD &Extr) {
- if(QExtr.full()) QExtr.pop_back();
- QExtr.push_front(Extr);
- }
- void ClearExtr() { QExtr.clear(); }
- };
- //---------------------------------------------------------------------------
- // TRENDLINE
- struct TRENDLINE {
- COORD P, Q; // P -> Q
- TIMESHIFT M, N; // duration
- TRENDLINE(): P(), Q() {}
- TRENDLINE(const COORD &P_, const COORD &Q_) : P(P_), Q(Q_) {}
- TRENDLINE(double PriceP_, datetime TimeP_, double PriceQ_, datetime TimeQ_)
- : P(PriceP_, TimeP_), Q(PriceQ_, TimeQ_) {}
- TRENDLINE(double PriceP_, datetime TimeP_, int ShiftP_,
- double PriceQ_, datetime TimeQ_, int ShiftQ_)
- : P(PriceP_, TimeP_, ShiftP_), Q(PriceQ_, TimeQ_, ShiftQ_) {}
- TRENDLINE(const TRENDLINE &src): P(src.P), Q(src.Q), M(src.M), N(src.N) {}
- double IncliByTime() const {
- double dPrice = Q.Price - P.Price ;
- datetime dTime = Q.Time - P.Time ;
- if(!dTime) return 0;
- return dPrice/double(dTime) ;
- }
- double IncliByShift() const {
- double dPrice = Q.Price - P.Price ;
- int dShift = P.Shift - Q.Shift ;
- if(!dShift) return 0;
- return dPrice/double(dShift) ;
- }
- double PriceByTime(datetime Time_) const {
- return P.Price + IncliByTime() * ( Time_ - P.Time ) ;
- }
- double PriceByShift(int Shift_) const {
- return P.Price + IncliByShift() * ( P.Shift - Shift_ ) ;
- }
- };
- //---------------------------------------------------------------------------
- // TRENDLINES
- struct TRENDLINES {
- string Name;
- ENUM_TIMEFRAMES TimeFrame;
- TRENDLINE Upper, Lower;
- TRENDLINES(ENUM_TIMEFRAMES TimeFrame_=PERIOD_CURRENT, string Name_="")
- : Name(Name_), TimeFrame(TimeFrame_), Upper(), Lower() {}
- TRENDLINES(const TRENDLINES &Src):
- TimeFrame(Src.TimeFrame), Name(Src.Name), Upper(Src.Upper), Lower(Src.Lower) {}
- };
- //===========================================================================
- // 変数
- //---------------------------------------------------------------------------
- //時間
- datetime CurCurrentTime;
- bool NextCurrentTimed;
- //トレンドライン
- TRENDLINES TrendLines(PERIOD_CURRENT,"Trend");
- //スイングの状態
- SWING_STATUS CurrentSwing(PERIOD_CURRENT,ZigZagBackstep);
- //ライン情報
- #define TRENDINFO_UPPERNAME "TREND UPPER INFO"
- #define TRENDINFO_LOWERNAME "TREND LOWER INFO"
- //転換点矢印
- #define DIVERGENCE_ARROWNAME "DIVERGNECE ARROW"
- //デバッグ情報
- #define DBGINFO_NAME "DEBUG INFO"
- string DBGMSG = "" ;
- //--- IQueue ATR14 (デバッグ用)
- CHyrIQueueATR QiATR14;
- //===========================================================================
- // 関数
- //---------------------------------------------------------------------------
- int OnInit()
- {
- //テスターで表示されるインジケータを非表示にする
- TesterHideIndicators(!DBGMODE);
- //--- IQueue ATR 14 (デバッグ用)
- if(!QiATR14.Init (_Symbol, PERIOD_CURRENT, 14, 2))
- return INIT_FAILED;
- GlobalSettings(ENTRY_NAME);
- //現在時刻を初期化
- CurCurrentTime=CurrentTime();
- //スイング初期化
- CurrentSwing.Init();
- CheckSwingStatus(CurrentSwing,1);
- UpdateDivergenceArrow(CurrentSwing);
- // トレンドライン更新
- UpdateTrendLines(TrendLines,CurrentSwing);
- //トレンド情報
- if(DBGMODE) {
- int trend_y = 40 ;
- ObjectCreate(0, TRENDINFO_UPPERNAME, OBJ_LABEL, 0, 0, 0);
- ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_XDISTANCE, 10);
- ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_YDISTANCE, trend_y);
- ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
- ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
- ObjectSetString (0, TRENDINFO_UPPERNAME, OBJPROP_TEXT, "UPPER TREND INFO");
- ObjectSetString (0, TRENDINFO_UPPERNAME, OBJPROP_FONT, "Verdana");
- ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_FONTSIZE, 8);
- ObjectSetInteger(0, TRENDINFO_UPPERNAME, OBJPROP_COLOR, ClrUpperTrend);
- trend_y+=12;
- ObjectCreate(0, TRENDINFO_LOWERNAME, OBJ_LABEL, 0, 0, 0);
- ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_XDISTANCE, 10);
- ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_YDISTANCE, trend_y);
- ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
- ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER);
- ObjectSetString (0, TRENDINFO_LOWERNAME, OBJPROP_TEXT, "LOWER TREND INFO");
- ObjectSetString (0, TRENDINFO_LOWERNAME, OBJPROP_FONT, "Verdana");
- ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_FONTSIZE, 8);
- ObjectSetInteger(0, TRENDINFO_LOWERNAME, OBJPROP_COLOR, ClrLowerTrend);
- // トレンド情報更新
- UpdateTrendInfo(TRENDINFO_UPPERNAME,TrendLines.Upper);
- UpdateTrendInfo(TRENDINFO_LOWERNAME,TrendLines.Lower);
- //DEBUG INFO
- ObjectCreate(0, DBGINFO_NAME, OBJ_LABEL, 0, 0, 0);
- ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_XDISTANCE, 10);
- ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_YDISTANCE, 15);
- ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
- ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
- ObjectSetString (0, DBGINFO_NAME, OBJPROP_TEXT, "DEBUG INFO");
- ObjectSetString (0, DBGINFO_NAME, OBJPROP_FONT, "Verdana");
- ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_FONTSIZE, 8);
- ObjectSetInteger(0, DBGINFO_NAME, OBJPROP_COLOR, clrAquamarine);
- }
- return(INIT_SUCCEEDED);
- }
- //---------------------------------------------------------------------------
- void OnDeinit(const int reason)
- {
- if(DBGMODE) {
- ObjectDelete(0, DBGINFO_NAME) ;
- ObjectDelete(0, TRENDINFO_LOWERNAME) ;
- ObjectDelete(0, TRENDINFO_UPPERNAME) ;
- }
- ObjectDelete(0, DIVERGENCE_ARROWNAME);
- DestroyTrendLines(TrendLines);
- }
- //---------------------------------------------------------------------------
- void OnTick()
- {
- datetime nextCurrentTime = CurrentTime();
- NextCurrentTimed = nextCurrentTime != CurCurrentTime ;
- CurCurrentTime = nextCurrentTime;
- QiATR14.Update();
- if(NextCurrentTimed) {
- // スイング遷移更新
- CheckSwingStatus(CurrentSwing,1);
- UpdateDivergenceArrow(CurrentSwing);
- // トレンドライン更新
- UpdateTrendLines(TrendLines,CurrentSwing);
- if(DBGMODE) {
- // トレンド情報更新
- UpdateTrendInfo(TRENDINFO_UPPERNAME,TrendLines.Upper);
- UpdateTrendInfo(TRENDINFO_LOWERNAME,TrendLines.Lower);
- }
- }
- // デバッグ情報
- string msg = DBGMSG ;
- if(msg!="") msg += " | ";
- msg += StringFormat("ATR(14): %g | ",QiATR14[0]);
- msg += "DVGN: "+DoubleToString(CurrentSwing.DvgnPos().Price,_Digits);
- DBGOUT(msg);
- }
- //---------------------------------------------------------------------------
- //DBGOUT
- void DBGOUT(string text)
- {
- if(DBGMODE) {
- ObjectSetString(0, DBGINFO_NAME, OBJPROP_TEXT, text);
- }
- }
- //---------------------------------------------------------------------------
- //現在基軸タイムを返す
- datetime CurrentTime(int shift=0)
- {
- return iTime(Symbol(), PERIOD_CURRENT, shift);
- }
- //---------------------------------------------------------------------------
- // ZigZag のポジションを列挙する
- bool EnumZigZagStatus(int num, ZIGZAG_STATUS &arrayZZ[], ENUM_TIMEFRAMES timeFrame, int si=0, int ei=INT_MAX)
- {
- int limit = ei==INT_MAX ? ei : (si<ei?ei+1:ei-1) ;
- int bars = iBars(NULL,timeFrame) ;
- limit = MathMin(limit,bars);
- limit = MathMax(limit,-1);
- ArraySetAsSeries(arrayZZ,true);
- ArrayResize(arrayZZ,num);
- CHyrIQueueZigZag qiZigZag;
- qiZigZag.UpdateShift(si);
- qiZigZag.Init(_Symbol, timeFrame, ZigZagDepth, ZigZagDeviation, ZigZagBackstep, QI_ARRAYSIZE);
- for (int i = si, n=0; i != limit ; si<limit? i++: i--) {
- double zz = qiZigZag.sv(i);
- // iCustom(NULL, timeFrame, "ZigZag", ZigZagDepth, ZigZagDeviation, ZigZagBackstep, 0, i);
- if(zz!=0) {
- arrayZZ[n] = ZIGZAG_STATUS(zz, iTime(_Symbol, timeFrame, i), i);
- n++;
- if(n>=num) return true;
- }
- }
- return false;
- }
- //---------------------------------------------------------------------------
- // ZigZag のスイングを調べる
- int CheckSwingStatus(SWING_STATUS &Swing, int si=0)
- {
- ENUM_TIMEFRAMES timeFrame = Swing.TimeFrame ;
- double margin = 0 ; //ZigZagSwingMargin * _Point ;
- FLAG flag = (Swing.High.Time>Swing.Low.Time)? FLAG_BUY: FLAG_SELL;
- int limit = //iBars(NULL,timeFrame)-ZigZagDepth;
- MathMin(iBars(NULL,timeFrame)-ZigZagDepth,SWING_LIMIT);
- int start=0, initial=2;
- datetime lastTime = MathMax(Swing.High.Time, Swing.Low.Time);
- bool first=true ;
- ZIGZAG_STATUS prev_zzs ;
- CHyrIQueueZigZag qiZigZag;
- qiZigZag.UpdateShift(si);
- qiZigZag.Init(_Symbol, timeFrame, ZigZagDepth, ZigZagDeviation, ZigZagBackstep, QI_ARRAYSIZE);
- //起点調査
- if(lastTime!=0) {
- for(int i = si; i<limit ; i++) {
- double zz = qiZigZag.sv(i);
- // iCustom(NULL, timeFrame, "ZigZag", ZigZagDepth, ZigZagDeviation, ZigZagBackstep, 0, i);
- if(zz!=0) {
- ZIGZAG_STATUS zzs(zz, iTime(_Symbol, timeFrame, i), i);
- if(zzs.Time<=lastTime) {
- start = zzs.Shift -1 ;
- prev_zzs = zzs ;
- first = false ;
- break;
- }
- }
- }
- if(!MathMin(Swing.High.Time, Swing.Low.Time))
- initial = 1 ;
- }else {
- start = limit;
- initial = 0 ;
- }
- //スイング検証
- for(int i=start ; i>=si ; i--) {
- double zz = qiZigZag.sv(i);
- // iCustom(NULL, timeFrame, "ZigZag", ZigZagDepth, ZigZagDeviation, ZigZagBackstep, 0, i);
- if(zz!=0) {
- ZIGZAG_STATUS zzs(zz, iTime(_Symbol, timeFrame, i), i);
- if(initial<2) {
- if(!initial)
- Swing.High = zzs ;
- else
- Swing.Low = zzs ;
- initial++ ;
- if(initial>=2) {
- if(Swing.Low.Price>Swing.High.Price) {
- ZIGZAG_STATUS tmps(Swing.Low) ;
- Swing.Low = Swing.High ;
- Swing.High = tmps ;
- flag = FLAG_BUY ;
- Swing.DvgnHigh = Swing.Low ;
- Swing.DvgnLow = Swing.Low ;
- }else {
- flag = FLAG_SELL ;
- Swing.DvgnLow = Swing.High ;
- Swing.DvgnHigh = Swing.High ;
- }
- first = false ;
- }
- }else {
- if(flag==FLAG_BUY?zzs.Price>Swing.High.Price:zzs.Price<Swing.Low.Price) { // 最大値更新
- if(first) {
- ZIGZAG_STATUS bef_zzs[1];
- if(EnumZigZagStatus(1, bef_zzs, timeFrame, i+1)) {
- prev_zzs = bef_zzs[0] ;
- }
- first=false ;
- }
- if(flag==FLAG_BUY?zzs.Price>prev_zzs.Price:zzs.Price<prev_zzs.Price) {
- // 価格更新
- switch(flag) {
- case FLAG_BUY:
- Swing.High = zzs ;
- Swing.PushExtr(zzs);
- if(zzs.Price-prev_zzs.Price>=margin)
- Swing.Low = prev_zzs ;
- break;
- case FLAG_SELL:
- Swing.Low = zzs ;
- Swing.PushExtr(zzs);
- if(prev_zzs.Price-zzs.Price>=margin)
- Swing.High = prev_zzs ;
- break;
- }
- }
- }else {
- if(flag==FLAG_BUY?zzs.Price<Swing.Low.Price:zzs.Price>Swing.High.Price) { // ダイバージェンス
- double cls = iClose(NULL, timeFrame, i);
- if(flag==FLAG_BUY?cls<Swing.Low.Price:cls>Swing.High.Price) {
- // トレンド逆転
- Swing.RecordDvgn();
- Swing.ClearExtr();
- switch(flag) {
- case FLAG_BUY:
- if(first)
- Swing.High = Swing.Low ;
- else if(prev_zzs.Price-zzs.Price>=margin)
- Swing.High = prev_zzs ;
- Swing.Low = zzs ;
- Swing.PushExtr(zzs);
- flag = FLAG_SELL ;
- break;
- case FLAG_SELL:
- if(first)
- Swing.Low = Swing.High ;
- else if(zzs.Price-prev_zzs.Price>=margin)
- Swing.Low = prev_zzs ;
- Swing.High = zzs ;
- Swing.PushExtr(zzs);
- flag = FLAG_BUY ;
- break;
- }
- }
- }
- }
- }
- if(!first) prev_zzs = zzs ;
- }
- }
- return flag;
- }
- //---------------------------------------------------------------------------
- // 転換位置ポジションに矢印を描画する関数
- void UpdateDivergenceArrow(const SWING_STATUS &Swing)
- {
- string name = DIVERGENCE_ARROWNAME ;
- uchar code = Swing.Bullish() ? ARROW_BULL : ARROW_BEAR ;
- color clr = Swing.Bullish() ? ClrBullDvgn : ClrBearDvgn ;
- datetime time = Swing.DvgnPos().Time ;
- double price = Swing.DvgnPos().Price ;
- if(ObjectFind(0, name) < 0) {
- ObjectCreate(0, name, OBJ_ARROW, 0, time, price);
- ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
- ObjectSetInteger(0, name, OBJPROP_BACK, false); // 最前面に表示
- }else {
- ObjectMove(0, name, 0, time, price);
- }
- ObjectSetInteger(0, name, OBJPROP_ANCHOR, Swing.Bullish() ? ANCHOR_TOP: ANCHOR_BOTTOM);
- ObjectSetInteger(0, name, OBJPROP_ARROWCODE, code);
- ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
- }
- //---------------------------------------------------------------------------
- // MARK: トレンドライン @ 2026/05/04
- #define TREND_UPPER_PREFIX ENTRY_NAME"_UPPER_"
- #define TREND_LOWER_PREFIX ENTRY_NAME"_LOWER_"
- //-----
- void DestroyTrendLines(const TRENDLINES &Lines)
- {
- ObjectDelete(0,TREND_UPPER_PREFIX+Lines.Name);
- ObjectDelete(0,TREND_LOWER_PREFIX+Lines.Name);
- }
- //-----
- void UpdateTrendLines(TRENDLINES &Lines, const SWING_STATUS &Swing)
- {
- datetime lastTime = iTime(_Symbol, Lines.TimeFrame, 0);
- int MinimumShift = 0; // ZigZagBackstep;
- //--- 1. 直近 ZigZag の最終頂点を2つ求める
- ZIGZAG_STATUS zz[];
- const int zzNum = 2 ;
- bool valid = EnumZigZagStatus(zzNum,zz,Lines.TimeFrame,1);
- bool carry = false ;
- if(valid&&zz[0].Shift<MinimumShift) {
- carry = true ;
- valid = EnumZigZagStatus(zzNum,zz,Lines.TimeFrame,zz[0].Shift+1);
- }
- //--- 2. Dvgnの転換の直近位置を求める
- int M2=-1, M4=-1; {
- ZIGZAG_STATUS zzDvgnNext[];
- if(EnumZigZagStatus(1,zzDvgnNext,Lines.TimeFrame,
- Bars(_Symbol, Lines.TimeFrame, Swing.DvgnPos().Time, lastTime)-2,0)) {
- int shift2 = Bars(_Symbol, Lines.TimeFrame, zzDvgnNext[0].Time, lastTime)-1 ;
- if(shift2>=MinimumShift) { // MinimumShift以上シフト位置が離れていることが条件
- M2 = shift2 ;
- if(M2>2&&EnumZigZagStatus(2,zzDvgnNext,Lines.TimeFrame,M2-1,0)) {
- int shift4 = Bars(_Symbol, Lines.TimeFrame, zzDvgnNext[1].Time, lastTime)-1 ;
- if(shift4>=MinimumShift) // MinimumShift以上シフト位置が離れていることが条件
- M4 = shift4 ;
- }
- }
- }
- }
- //--- 3. 直近のZigZagの頂点更新位置を探す
- COORD E;
- for(int i=0;i<Swing.QExtr.size();i++) {
- int shift = Bars(_Symbol, Lines.TimeFrame, Swing.QExtr[i].Time, lastTime)-1 ;
- if(shift>=MinimumShift) { // MinimumShift以上シフト位置が離れていることが条件
- E = Swing.QExtr[i] ;
- E.Shift = shift ;
- break;
- }
- }
- if(!E.Shift) {
- // みつからない場合は、最上位位置を検出する
- if(valid) {
- int si = zz[0].Shift ;
- int count = (si-MinimumShift)+1 ;
- int shift = Swing.Bullish()?
- iHighest(_Symbol, Lines.TimeFrame, MODE_HIGH, count, si):
- iLowest(_Symbol, Lines.TimeFrame, MODE_LOW, count, si);
- if(shift>=MinimumShift) {
- E.Shift = shift ;
- E.Time = iTime(_Symbol, Lines.TimeFrame, shift) ;
- E.Price = Swing.Bullish()?
- iHigh(_Symbol, Lines.TimeFrame, shift):
- iLow(_Symbol, Lines.TimeFrame, shift);
- }
- }
- }
- //--- 4. ぶつからないトレンドラインの端点を計算 ---
- int M1 = Bars(_Symbol, Lines.TimeFrame, Swing.DvgnPos().Time , lastTime)-1; //CurrentSwing.DvgnPos().Shift ;
- int M0 = Bars(_Symbol, Lines.TimeFrame, MathMin(Swing.DvgnHigh.Time,Swing.DvgnLow.Time) , lastTime)-1;
- int MHi, MLo;
- int Mextr = M2 ;
- if(M2==-1||M4==-1) {
- Mextr = M0 ;
- }
- if(Swing.DvgnHigh.Time>Swing.DvgnLow.Time) {
- MHi = M1 ; MLo = Mextr ;
- }else {
- MLo = M1 ; MHi = Mextr ;
- }
- int NHi = MinimumShift , NLo = MinimumShift ;
- if(valid) {
- if(carry) {
- NHi = NLo = zz[0].Shift ;
- }else {
- if(zz[0].Price>zz[1].Price) {
- NHi = zz[0].Shift ; NLo = zz[1].Shift ;
- }else {
- NHi = zz[1].Shift ; NLo = zz[0].Shift ;
- }
- }
- }
- if(E.Shift>0) {
- if(Swing.Bullish()) {
- if(E.Shift<NHi) {
- NHi = E.Shift ;
- }
- }
- if(Swing.Bearish()) {
- if(E.Shift<NLo) {
- NLo = E.Shift ;
- }
- }
- }
- DetectTrendLine(Lines, MHi, MLo, NHi, NLo);
- DrawTrendLine(TREND_UPPER_PREFIX+Lines.Name, Lines.Upper, ClrUpperTrend);
- DrawTrendLine(TREND_LOWER_PREFIX+Lines.Name, Lines.Lower, ClrLowerTrend);
- }
- //-----
- //トレンドラインを描画・更新する補助関数(視覚確認用)
- void DrawTrendLine(string name, const TRENDLINE &line, color clr)
- {
- datetime qTime = line.P.Price==line.Q.Price && line.P.Time==line.Q.Time
- ? line.P.Time + PeriodSeconds(_Period) : line.Q.Time ;
- if(ObjectFind(0, name) < 0)
- {
- ObjectCreate(0, name, OBJ_TREND, 0,
- line.P.Time, line.P.Price, qTime, line.Q.Price );
- ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true); // 右側に延長
- ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT); // 点線
- ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); // 選択不可
- }
- else
- {
- ObjectMove(0, name, 0, line.P.Time, line.P.Price);
- ObjectMove(0, name, 1, qTime, line.Q.Price);
- }
- ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
- }
- //-----
- // M~N区間の上下トレンドラインを検出する
- void DetectTrendLine(TRENDLINES &Lines, int MHi, int MLo, int NHi, int NLo)
- {
- int AHi=MHi, BHi=NHi, ALo=MLo, BLo=NLo ;
- DetectNonCollisionSection(true, Lines.TimeFrame, MHi, NHi, AHi, BHi) ;
- Lines.Upper = TRENDLINE(
- iHigh(_Symbol, Lines.TimeFrame, AHi), iTime(_Symbol, Lines.TimeFrame, AHi), AHi,
- iHigh(_Symbol, Lines.TimeFrame, BHi), iTime(_Symbol, Lines.TimeFrame, BHi), BHi );
- Lines.Upper.M = TIMESHIFT( iTime(_Symbol, Lines.TimeFrame, MHi), MHi );
- Lines.Upper.N = TIMESHIFT( iTime(_Symbol, Lines.TimeFrame, NHi), NHi );
- DetectNonCollisionSection(false, Lines.TimeFrame, MLo, NLo, ALo, BLo) ;
- Lines.Lower = TRENDLINE(
- iLow(_Symbol, Lines.TimeFrame, ALo), iTime(_Symbol, Lines.TimeFrame, ALo), ALo,
- iLow(_Symbol, Lines.TimeFrame, BLo), iTime(_Symbol, Lines.TimeFrame, BLo), BLo );
- Lines.Lower.M = TIMESHIFT( iTime(_Symbol, Lines.TimeFrame, MLo), MLo );
- Lines.Lower.N = TIMESHIFT( iTime(_Symbol, Lines.TimeFrame, NLo), NLo );
- }
- //-----
- // ぶつからないラインの区間を検出する関数(区間A~Bは、M~N区間内とする、かつM>N&&A>B)
- double DetectNonCollisionSection(
- bool isUpper, ENUM_TIMEFRAMES tf, int M, int N, int &A, int &B, bool skip=false)
- {
- // 同じ位置
- if(A==B) return 0;
- // 始点
- double pA = (isUpper) ? iHigh(_Symbol, tf, A) : iLow(_Symbol, tf, A);
- // 終点
- double pB = (isUpper) ? iHigh(_Symbol, tf, B) : iLow(_Symbol, tf, B);
- // 傾き
- double inclination = (pB-pA)/double(A-B) ;
- // 初期プライス
- double price = pA - ( inclination * double(M-A) ) ;
- // 高値安値チェック
- bool collision = false ;
- double score = 0 ;
- for(int i=M ; i>=N ; i--) {
- if(i!=A&&i!=B) { // A B 地点は飛ばす
- if(isUpper) { // 高値ラインの場合
- double checkHigh = iHigh(_Symbol, tf, i);
- if(!(skip&&A>=i&&i>=B)&&checkHigh>price&&!InnerPoint(checkHigh,price)) collision = true ;
- else score += price - checkHigh ;
- }else { // 安値ラインの場合
- double checkLow = iLow(_Symbol, tf, i);
- if(!(skip&&A>=i&&i>=B)&&checkLow<price&&!InnerPoint(checkLow,price)) collision = true ;
- else score += checkLow - price ;
- }
- if(collision) { // 新しい起点を検出
- if(A>i) {
- int newA1=A, newB1 = i ;
- double score1 = DetectNonCollisionSection(isUpper,tf,M,N,newA1,newB1,true);
- if(!skip) {
- int newA2=newB1, newB2 = N ;
- double score2 = (newA2<=newB2) ? score1 :
- DetectNonCollisionSection(isUpper,tf,M,N,newA2,newB2);
- if(score2<score1) { // スコアが小さい方を優先する
- A=newA2; B=newB2 ;
- return score2 ;
- }
- }
- A=newA1; B=newB1 ;
- return score1 ;
- }else {
- //PrintMessage("間違った起点");
- return DBL_MAX ; // 間違った起点
- }
- }
- }
- price += inclination ;
- }
- return score ; // 一度もぶつからなかったので、A~B間は正しい区間である
- }
- //---------------------------------------------------------------------------
- // トレンド情報の更新
- void UpdateTrendInfo(string ObjName,const TRENDLINE &TrendLine)
- {
- double a = TrendLine.IncliByShift() ;
- string text = StringFormat("INC: %g | INC/ATR(14): %g", a, a/QiATR14[0]);
- ObjectSetString (0, ObjName, OBJPROP_TEXT, text);
- }
- //---------------------------------------------------------------------------
- // ぶつからないラインの端点を計算する関数 ( by Gemini ) ※未使用
- //-----
- // isUpper: true=高値ライン, false=安値ライン
- void CalculateNonCollisionLine(bool isUpper, int M, int N,
- datetime &t1, double &p1, datetime &t2, double &p2)
- {
- // 始点(t1, p1)をM本前の足に固定
- t1 = iTime(_Symbol, _Period, M);
- p1 = (isUpper) ? iHigh(_Symbol, _Period, M) : iLow(_Symbol, _Period, M);
- // 暫定の終点(t2, p2)をN本前の足に設定
- t2 = iTime(_Symbol, _Period, N);
- p2 = (isUpper) ? iHigh(_Symbol, _Period, N) : iLow(_Symbol, _Period, N);
- // M-1本前からN本前までループして、ラインの外側にある足を探す
- for(int i = M - 1; i >= N; i--)
- {
- datetime checkTime = iTime(_Symbol, _Period, i);
- double checkHigh = iHigh(_Symbol, _Period, i);
- double checkLow = iLow(_Symbol, _Period, i);
- // その時の暫定ラインの価格を計算
- double linePrice = CalculatePriceAtTime(t1, p1, t2, p2, checkTime);
- if(isUpper) // 高値ラインの場合
- {
- // もし足の高値がラインより上にあれば、その足を新たな終点にする
- if(checkHigh > linePrice)
- {
- t2 = checkTime;
- p2 = checkHigh;
- // 終点が変わったので、M-1からループをやり直す(簡略化のためこのまま続行)
- }
- }
- else // 安値ラインの場合
- {
- // もし足の安値がラインより下にあれば、その足を新たな終点にする
- if(checkLow < linePrice)
- {
- t2 = checkTime;
- p2 = checkLow;
- }
- }
- }
- }
- //---------------------------------------------------------------------------
- // 2点を通る直線の、指定した時間における価格を計算する関数 ( by Gemini ) ※未使用
- double CalculatePriceAtTime(datetime t1, double p1, datetime t2, double p2, datetime targetT)
- {
- if(t1 == t2) return 0; // 垂直な線は計算不可
- // 直線の式: y = p1 + (p2 - p1) * (targetT - t1) / (t2 - t1)
- double price = p1 + (p2 - p1) * (double)(targetT - t1) / (double)(t2 - t1);
- return price;
- }
- //---------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment