乐于分享
好东西不私藏

缠论源码-笔

缠论源码-笔
✅ 正统缠论指标
✅ 原生图表适配,纯精准算法实现
✅ 零偏差精准识别顶 / 底分型
    一、  分型以上因人而异,这次分享一个新笔(MT4版)源码,以此支持更多缠迷朋友创作
#property strict #property indicator_chart_window #property indicator_buffers 2 #property indicator_color1 clrRed #property indicator_color2 clrLime #property indicator_width1 2 #property indicator_width2 2 #property indicator_style1 STYLE_SOLID #property indicator_style2 STYLE_SOLID  enum MERGE_DIRECTION { MERGE_NONE, MERGE_HIGH_HIGH, MERGE_LOW_LOW }; enum STROKE_MODE { MODE_X };  double upStrokeBuffer[]; double downStrokeBuffer[];  struct FractalPoint {     datetime time;     double price;     bool isTop;     int barIndex;     int mergedIndex;     double fractalHigh;     double fractalLow; };  struct MergedCandle {    double high;    double low;    datetime time;    bool isMerged;    datetime highTime;    datetime lowTime;    int highBarIndex;    int lowBarIndex; };  MergedCandle mergedCandles[]; FractalPoint fractalPoints[]; FractalPoint validFractals[]; FractalPoint finalFractals[]; int strokeStartIndex = -1;  int OnInit() {    IndicatorShortName("MT4缠论新笔");    SetIndexBuffer(0, upStrokeBuffer);    SetIndexBuffer(1, downStrokeBuffer);        SetIndexStyle(0, DRAW_LINE);    SetIndexStyle(1, DRAW_LINE);        SetIndexLabel(0, "上升笔");    SetIndexLabel(1, "下降笔");    return(INIT_SUCCEEDED); }  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[]) {    ArrayInitialize(upStrokeBuffer, EMPTY_VALUE);    ArrayInitialize(downStrokeBuffer, EMPTY_VALUE);        int mergedCount = ProcessMergedCandles(rates_total, high, low, time);    IdentifyFractals(mergedCount);    FilterFractals();    ProcessStrokesFractals(high, low);    IdentifyAndDrawStrokes(rates_total, time);    return(rates_total); }  int ProcessMergedCandles(int rates_total, const double& high[], const double& low[], const datetime& time[]) {    int allocSize = MathMin(rates_total, 256);    ArrayResize(mergedCandles, allocSize);    int mergedIndex = 0;    for(int i = rates_total - 1; i >= 0; i--)    {       if(mergedIndex >= allocSize)       {          allocSize *= 2;          ArrayResize(mergedCandles, allocSize);       }       if(mergedIndex == 0)       {          mergedCandles[mergedIndex].high = high[i];          mergedCandles[mergedIndex].low = low[i];          mergedCandles[mergedIndex].time = time[i];          mergedCandles[mergedIndex].highTime = time[i];          mergedCandles[mergedIndex].lowTime = time[i];          mergedCandles[mergedIndex].highBarIndex = i;          mergedCandles[mergedIndex].lowBarIndex = i;          mergedCandles[mergedIndex].isMerged = false;          mergedIndex++;          continue;       }       int lastIndex = mergedIndex - 1;       double lastHigh = mergedCandles[lastIndex].high;       double lastLow = mergedCandles[lastIndex].low;       if((high[i] <= lastHigh && low[i] >= lastLow) ||           (high[i] >= lastHigh && low[i] <= lastLow))       {          MERGE_DIRECTION direction = MERGE_NONE;          if(mergedIndex >= 2)          {             double prevHigh = mergedCandles[lastIndex-1].high;             double prevLow = mergedCandles[lastIndex-1].low;             if(lastHigh >= prevHigh && lastLow >= prevLow) {                direction = MERGE_HIGH_HIGH;             }             else if(lastHigh <= prevHigh && lastLow <= prevLow) {                direction = MERGE_LOW_LOW;             }          }          if(direction == MERGE_NONE) {             direction = (high[i] > lastHigh) ? MERGE_HIGH_HIGH : MERGE_LOW_LOW;          }          if(direction == MERGE_HIGH_HIGH)          {             if(high[i] > lastHigh) {                mergedCandles[lastIndex].highTime = time[i];                mergedCandles[lastIndex].highBarIndex = i;             }             if(low[i] > lastLow) {                mergedCandles[lastIndex].lowTime = time[i];                mergedCandles[lastIndex].lowBarIndex = i;             }             mergedCandles[lastIndex].high = MathMax(lastHigh, high[i]);             mergedCandles[lastIndex].low = MathMax(lastLow, low[i]);             mergedCandles[lastIndex].isMerged = true;          }          else          {             if(high[i] < lastHigh) {                mergedCandles[lastIndex].highTime = time[i];                mergedCandles[lastIndex].highBarIndex = i;             }             if(low[i] < lastLow) {                mergedCandles[lastIndex].lowTime = time[i];                mergedCandles[lastIndex].lowBarIndex = i;             }             mergedCandles[lastIndex].high = MathMin(lastHigh, high[i]);             mergedCandles[lastIndex].low = MathMin(lastLow, low[i]);             mergedCandles[lastIndex].isMerged = true;          }       }       else       {          mergedCandles[mergedIndex].high = high[i];          mergedCandles[mergedIndex].low = low[i];          mergedCandles[mergedIndex].time = time[i];          mergedCandles[mergedIndex].highTime = time[i];          mergedCandles[mergedIndex].lowTime = time[i];          mergedCandles[mergedIndex].highBarIndex = i;          mergedCandles[mergedIndex].lowBarIndex = i;          mergedCandles[mergedIndex].isMerged = false;          mergedIndex++;       }    }    return mergedIndex; }  void IdentifyFractals(int mergedCount) {    if(mergedCount < 3) { ArrayResize(fractalPoints, 0); return; }    int maxFractals = mergedCount - 2;    ArrayResize(fractalPoints, maxFractals);    int fIdx = 0;    for(int i = 0; i < mergedCount - 2; i++)    {       int left = i+2;       int middle = i+1;       int right = i;       double leftHigh = mergedCandles[left].high;       double leftLow = mergedCandles[left].low;       double midHigh = mergedCandles[middle].high;       double midLow = mergedCandles[middle].low;       double rightHigh = mergedCandles[right].high;       double rightLow = mergedCandles[right].low;       if(midHigh > leftHigh && midHigh > rightHigh &&           midLow > leftLow && midLow > rightLow)       {          fractalPoints[fIdx].time = mergedCandles[middle].highTime;          fractalPoints[fIdx].price = midHigh;          fractalPoints[fIdx].isTop = true;          fractalPoints[fIdx].barIndex = mergedCandles[middle].highBarIndex;          fractalPoints[fIdx].mergedIndex = middle;          fractalPoints[fIdx].fractalHigh = MathMax(MathMax(leftHigh, midHigh), rightHigh);          fractalPoints[fIdx].fractalLow = MathMin(MathMin(leftLow, midLow), rightLow);          fIdx++;       }       else if(midLow < leftLow && midLow < rightLow &&                midHigh < leftHigh && midHigh < rightHigh)       {          fractalPoints[fIdx].time = mergedCandles[middle].lowTime;          fractalPoints[fIdx].price = midLow;          fractalPoints[fIdx].isTop = false;          fractalPoints[fIdx].barIndex = mergedCandles[middle].lowBarIndex;          fractalPoints[fIdx].mergedIndex = middle;          fractalPoints[fIdx].fractalHigh = MathMax(MathMax(leftHigh, midHigh), rightHigh);          fractalPoints[fIdx].fractalLow = MathMin(MathMin(leftLow, midLow), rightLow);          fIdx++;       }    }    ArrayResize(fractalPoints, fIdx); }  void FilterFractals() {    ArrayResize(validFractals, 0);    int total = ArraySize(fractalPoints);    if(total < 1) return;        int sorted[];    ArrayResize(sorted, total);    for(int i = 0; i < total; i++) sorted[i] = i;    for(int i = 1; i < total; i++)    {       int key = sorted[i];       datetime keyTime = fractalPoints[key].time;       int j = i - 1;       while(j >= 0 && fractalPoints[sorted[j]].time > keyTime)       {          sorted[j + 1] = sorted[j];          j--;       }       sorted[j + 1] = key;    }        ArrayResize(validFractals, total);    int vIdx = 0;    for(int si = 0; si < total; si++)    {       int fi = sorted[si];       if(vIdx == 0) { validFractals[vIdx++] = fractalPoints[fi]; continue; }       FractalPoint last = validFractals[vIdx - 1];       if(last.isTop == fractalPoints[fi].isTop)       {          if(last.isTop) { if(fractalPoints[fi].price > last.price) validFractals[vIdx - 1] = fractalPoints[fi]; }          else { if(fractalPoints[fi].price < last.price) validFractals[vIdx - 1] = fractalPoints[fi]; }       }       else       {          validFractals[vIdx++] = fractalPoints[fi];       }    }    ArrayResize(validFractals, vIdx); }  void ProcessStrokesFractals(const double& high[], const double& low[]) {    ArrayResize(finalFractals, 0);    int total = ArraySize(validFractals);    if(total < 1) return;    ArrayResize(finalFractals, 1);    finalFractals[0] = validFractals[0];    for(int i = 1; i < total; i++)    {       int lastIdx = ArraySize(finalFractals) - 1;       FractalPoint last = finalFractals[lastIdx];       FractalPoint current = validFractals[i];       if(last.isTop == current.isTop)       {          if(last.isTop)          {             if(current.price >= last.price)             {                finalFractals[lastIdx] = current;             }          }          else          {             if(current.price <= last.price)             {                finalFractals[lastIdx] = current;             }          }       }       else       {          int barDiff = MathAbs(last.barIndex - current.barIndex);          bool validStroke = false;          bool case2Stroke = false;                    if(barDiff >= 4)          {             int mergedIndexDiff = MathAbs(last.mergedIndex - current.mergedIndex);             if(mergedIndexDiff > 1)             {                bool originalValid = true;                for(int j = i-1; j > 0; j--)                {                   if(validFractals[j].time < last.time) break;                   if(last.isTop && !current.isTop)                   {                      if(!validFractals[j].isTop && validFractals[j].price < current.price && validFractals[j].price != current.price)                      {                         originalValid = false;                         break;                      }                      if(validFractals[j].isTop && validFractals[j].price > last.price && validFractals[j].price != last.price)                      {                         originalValid = false;                         break;                      }                   }                   else if(!last.isTop && current.isTop)                   {                      if(validFractals[j].isTop && validFractals[j].price > current.price && validFractals[j].price != current.price)                      {                         originalValid = false;                         break;                      }                      if(!validFractals[j].isTop && validFractals[j].price < last.price && validFractals[j].price != last.price)                      {                         originalValid = false;                         break;                      }                   }                }                if(originalValid) validStroke = true;             }                          if(!validStroke)                {                int case2End;                if(!last.isTop && current.isTop)                {                   case2Stroke = CheckUpStrokeCase2(validFractals, total, i, last.price, current.price, case2End);                   if(case2Stroke) { current = validFractals[case2End]; i = case2End; }                }                else if(last.isTop && !current.isTop)                {                   case2Stroke = CheckDownStrokeCase2(validFractals, total, i, last.price, current.price, case2End);                   if(case2Stroke) { current = validFractals[case2End]; i = case2End; }                }                if(case2Stroke) validStroke = true;             }          }                    if(validStroke)          {             ArrayResize(finalFractals, lastIdx + 2);             finalFractals[lastIdx + 1] = current;          }       }    }     }  bool CheckUpStrokeCase2(FractalPoint &fractalArr[], int count, int startIdx, double firstLow, double prevHigh, int &endIdx) {    endIdx = startIdx;    if(startIdx + 1 >= count) return false;     for(int i = startIdx + 1; i < count; i++)    {       if(!fractalArr[i-1].isTop && fractalArr[i].isTop)       {          double currentLow = fractalArr[i-1].price;          double currentHigh = fractalArr[i].price;          if(currentLow <= firstLow) return false;          if(currentHigh > prevHigh)          {             endIdx = i;             return true;          }          prevHigh = currentHigh;       }    }    return false; }  bool CheckDownStrokeCase2(FractalPoint &fractalArr[], int count, int startIdx, double firstHigh, double prevLow, int &endIdx) {    endIdx = startIdx;    if(startIdx + 1 >= count) return false;     for(int i = startIdx + 1; i < count; i++)    {       if(fractalArr[i-1].isTop && !fractalArr[i].isTop)       {          double currentHigh = fractalArr[i-1].price;          double currentLow = fractalArr[i].price;          if(currentHigh >= firstHigh) return false;          if(currentLow < prevLow)          {             endIdx = i;             return true;          }          prevLow = currentLow;       }    }    return false; }  void IdentifyAndDrawStrokes(int rates_total, const datetime &time[]) {    int total = ArraySize(finalFractals);    if(total < 2) return;    for(int i = 1; i < total; i++)    {       FractalPoint prev = finalFractals[i-1];       FractalPoint curr = finalFractals[i];       int startBar = prev.barIndex;       int endBar = curr.barIndex;       double startPrice = prev.price;       double endPrice = curr.price;              if(startBar > endBar)       {          int tempBar = startBar;          startBar = endBar;          endBar = tempBar;                    double tempPrice = startPrice;          startPrice = endPrice;          endPrice = tempPrice;       }              if(!prev.isTop && curr.isTop)       {          for(int j = startBar; j <= endBar; j++)          {             if(j >= 0 && j < rates_total)             {                double ratio = (double)(j - startBar) / (endBar - startBar);                upStrokeBuffer[j] = startPrice + ratio * (endPrice - startPrice);             }          }       }       else if(prev.isTop && !curr.isTop)       {          for(int j = startBar; j <= endBar; j++)          {             if(j >= 0 && j < rates_total)             {                double ratio = (double)(j - startBar) / (endBar - startBar);                downStrokeBuffer[j] = startPrice - ratio * (startPrice - endPrice);             }          }       }    }        for(int j = 0; j < rates_total; j++)    {       if(upStrokeBuffer[j] == 0) upStrokeBuffer[j] = EMPTY_VALUE;       if(downStrokeBuffer[j] == 0) downStrokeBuffer[j] = EMPTY_VALUE;    } }

二、实时监控三级共振策略,能及时弹窗和预警,还能把共振信号推送到微信。

注意,目前只有MT4/MT5。
有需要的朋友请留言或私信(扫码加好友)