【箭头指标】有源码,本人原创

| 发表于 1 小时前 | 显示全部楼层 |复制链接
最后由 ea38849 于 2026-5-27 16:54 编辑

image.png image.png image.png image.png

#property strict
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 Lime
#property indicator_color2 Red
#property indicator_color3 DeepSkyBlue
#property indicator_width1 2
#property indicator_width2 2
#property indicator_width3 2

//+------------------------------------------------------------------+
//|                  结构波段拐点指标                                |
//|                  局部高低点 + ATR过滤 + 最小波段幅度确认          |
//+------------------------------------------------------------------+

//======================== 核心参数 ========================//
extern int    左右确认K线数          = 3;        // 越小越灵敏,越大越稳
extern int    最小波段点数           = 300;      // 小于该幅度的波动不提示
extern bool   使用ATR动态过滤         = true;     // 是否使用ATR动态过滤
extern int    ATR周期                = 14;       // ATR周期
extern double ATR倍数                = 0.80;     // 最小波段 = max(固定点数, ATR*倍数)

extern int    箭头显示位置           = 1;        // 0=确认K线位置,1=拐点K线位置
extern int    箭头距离点数           = 120;      // 箭头距离K线高低点距离

//======================== 过滤参数 ========================//
extern bool   使用RSI过滤            = false;    // 是否启用RSI过滤
extern int    RSI周期                = 6;        // RSI周期
extern double RSI买入上限            = 45.0;     // 买入信号要求RSI低于该值
extern double RSI卖出下限            = 55.0;     // 卖出信号要求RSI高于该值

extern bool   使用确认K线方向         = false;    // 买入要求确认K线为阳线,卖出要求阴线

//======================== 显示与提醒 ========================//
extern bool   显示波段连线           = true;     // 是否显示波段连接线
extern bool   开启弹窗提醒           = true;     // 是否弹窗提醒
extern bool   开启声音提醒           = true;     // 是否声音提醒
extern string 声音文件               = "alert.wav";

//======================== 指标缓存 ========================//
double 买入箭头Buffer[];
double 卖出箭头Buffer[];
double 波段连线Buffer[];

//======================== 防重复提醒 ========================//
datetime 上次提醒时间 = 0;


//+------------------------------------------------------------------+
//| 初始化                                                           |
//+------------------------------------------------------------------+
int OnInit()
{
   IndicatorShortName("结构波段拐点指标");

   SetIndexBuffer(0, 买入箭头Buffer);
   SetIndexStyle(0, DRAW_ARROW);
   SetIndexArrow(0, 233);
   SetIndexLabel(0, "波段买入");

   SetIndexBuffer(1, 卖出箭头Buffer);
   SetIndexStyle(1, DRAW_ARROW);
   SetIndexArrow(1, 234);
   SetIndexLabel(1, "波段卖出");

   SetIndexBuffer(2, 波段连线Buffer);

   if(显示波段连线)
      SetIndexStyle(2, DRAW_SECTION);
   else
      SetIndexStyle(2, DRAW_NONE);

   SetIndexLabel(2, "波段连线");

   ArraySetAsSeries(买入箭头Buffer, true);
   ArraySetAsSeries(卖出箭头Buffer, true);
   ArraySetAsSeries(波段连线Buffer, true);

   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[]
)
{
   if(rates_total <= 左右确认K线数 * 2 + ATR周期 + 10)
      return(0);

   for(int k = 0; k < rates_total; k++)
   {
      买入箭头Buffer[k] = EMPTY_VALUE;
      卖出箭头Buffer[k] = EMPTY_VALUE;
      波段连线Buffer[k] = EMPTY_VALUE;
   }

   int oldest = rates_total - 左右确认K线数 - 2;

   int lastDirection = 0;        // 1=上一个是低点买入,-1=上一个是高点卖出
   int lastPivotIndex = -1;
   int lastBufferIndex = -1;
   double lastPivotPrice = 0.0;

   for(int i = oldest; i >= 左右确认K线数; i--)
   {
      bool swingHigh = IsSwingHigh(i, high, rates_total);
      bool swingLow  = IsSwingLow(i, low, rates_total);

      if(!swingHigh && !swingLow)
         continue;

      //======================== 初始信号 ========================//
      if(lastDirection == 0)
      {
         if(swingLow && BuyFilterOK(i, open, close))
         {
            lastDirection = 1;
            lastPivotIndex = i;
            lastPivotPrice = low;
            lastBufferIndex = DrawBuySignal(i, low, rates_total);
            continue;
         }

         if(swingHigh && SellFilterOK(i, open, close))
         {
            lastDirection = -1;
            lastPivotIndex = i;
            lastPivotPrice = high;
            lastBufferIndex = DrawSellSignal(i, high, rates_total);
            continue;
         }
      }

      //======================== 上一个是买点,等待高点卖出 ========================//
      if(lastDirection == 1)
      {
         // 如果还没出现卖点,又出现更低的低点,则替换买点
         if(swingLow && low < lastPivotPrice && BuyFilterOK(i, open, close))
         {
            ClearSignal(lastBufferIndex);

            lastPivotIndex = i;
            lastPivotPrice = low;
            lastBufferIndex = DrawBuySignal(i, low, rates_total);
            continue;
         }

         // 出现有效高点,且涨幅达到最小波段要求,给出卖点
         if(swingHigh && SellFilterOK(i, open, close))
         {
            double needMove = GetMinWaveDistance(i);

            if(high - lastPivotPrice >= needMove)
            {
               DrawSwingLine(lastPivotIndex, lastPivotPrice);
               DrawSwingLine(i, high);

               lastDirection = -1;
               lastPivotIndex = i;
               lastPivotPrice = high;
               lastBufferIndex = DrawSellSignal(i, high, rates_total);
            }
         }
      }

      //======================== 上一个是卖点,等待低点买入 ========================//
      else if(lastDirection == -1)
      {
         // 如果还没出现买点,又出现更高的高点,则替换卖点
         if(swingHigh && high > lastPivotPrice && SellFilterOK(i, open, close))
         {
            ClearSignal(lastBufferIndex);

            lastPivotIndex = i;
            lastPivotPrice = high;
            lastBufferIndex = DrawSellSignal(i, high, rates_total);
            continue;
         }

         // 出现有效低点,且跌幅达到最小波段要求,给出买点
         if(swingLow && BuyFilterOK(i, open, close))
         {
            double needMove2 = GetMinWaveDistance(i);

            if(lastPivotPrice - low >= needMove2)
            {
               DrawSwingLine(lastPivotIndex, lastPivotPrice);
               DrawSwingLine(i, low);

               lastDirection = 1;
               lastPivotIndex = i;
               lastPivotPrice = low;
               lastBufferIndex = DrawBuySignal(i, low, rates_total);
            }
         }
      }
   }

   CheckAlert(time);

   return(rates_total);
}


//+------------------------------------------------------------------+
//| 判断摆动高点                                                     |
//+------------------------------------------------------------------+
bool IsSwingHigh(int shift, const double &high[], int rates_total)
{
   if(shift - 左右确认K线数 < 0)
      return(false);

   if(shift + 左右确认K线数 >= rates_total)
      return(false);

   double h = high[shift];

   for(int j = 1; j <= 左右确认K线数; j++)
   {
      if(h <= high[shift - j])
         return(false);

      if(h < high[shift + j])
         return(false);
   }

   return(true);
}


//+------------------------------------------------------------------+
//| 判断摆动低点                                                     |
//+------------------------------------------------------------------+
bool IsSwingLow(int shift, const double &low[], int rates_total)
{
   if(shift - 左右确认K线数 < 0)
      return(false);

   if(shift + 左右确认K线数 >= rates_total)
      return(false);

   double l = low[shift];

   for(int j = 1; j <= 左右确认K线数; j++)
   {
      if(l >= low[shift - j])
         return(false);

      if(l > low[shift + j])
         return(false);
   }

   return(true);
}


//+------------------------------------------------------------------+
//| 获取最小波段距离                                                 |
//+------------------------------------------------------------------+
double GetMinWaveDistance(int shift)
{
   double fixedDistance = 最小波段点数 * Point;
   double result = fixedDistance;

   if(使用ATR动态过滤)
   {
      double atr = iATR(NULL, 0, ATR周期, shift);
      double atrDistance = atr * ATR倍数;

      if(atrDistance > result)
         result = atrDistance;
   }

   return(result);
}


//+------------------------------------------------------------------+
//| 买入过滤                                                         |
//+------------------------------------------------------------------+
bool BuyFilterOK(int shift, const double &open[], const double &close[])
{
   if(使用RSI过滤)
   {
      double rsi = iRSI(NULL, 0, RSI周期, PRICE_CLOSE, shift);

      if(rsi > RSI买入上限)
         return(false);
   }

   if(使用确认K线方向)
   {
      int confirmShift = shift - 左右确认K线数;

      if(confirmShift < 0)
         return(false);

      if(close[confirmShift] <= open[confirmShift])
         return(false);
   }

   return(true);
}


//+------------------------------------------------------------------+
//| 卖出过滤                                                         |
//+------------------------------------------------------------------+
bool SellFilterOK(int shift, const double &open[], const double &close[])
{
   if(使用RSI过滤)
   {
      double rsi = iRSI(NULL, 0, RSI周期, PRICE_CLOSE, shift);

      if(rsi < RSI卖出下限)
         return(false);
   }

   if(使用确认K线方向)
   {
      int confirmShift = shift - 左右确认K线数;

      if(confirmShift < 0)
         return(false);

      if(close[confirmShift] >= open[confirmShift])
         return(false);
   }

   return(true);
}


//+------------------------------------------------------------------+
//| 画买入信号                                                       |
//+------------------------------------------------------------------+
int DrawBuySignal(int pivotShift, const double &low[], int rates_total)
{
   int drawShift = pivotShift;

   if(箭头显示位置 == 0)
      drawShift = pivotShift - 左右确认K线数;

   if(drawShift < 0 || drawShift >= rates_total)
      return(-1);

   买入箭头Buffer[drawShift] = low[drawShift] - 箭头距离点数 * Point;

   return(drawShift);
}


//+------------------------------------------------------------------+
//| 画卖出信号                                                       |
//+------------------------------------------------------------------+
int DrawSellSignal(int pivotShift, const double &high[], int rates_total)
{
   int drawShift = pivotShift;

   if(箭头显示位置 == 0)
      drawShift = pivotShift - 左右确认K线数;

   if(drawShift < 0 || drawShift >= rates_total)
      return(-1);

   卖出箭头Buffer[drawShift] = high[drawShift] + 箭头距离点数 * Point;

   return(drawShift);
}


//+------------------------------------------------------------------+
//| 清除旧信号                                                       |
//+------------------------------------------------------------------+
void ClearSignal(int bufferIndex)
{
   if(bufferIndex < 0)
      return;

   买入箭头Buffer[bufferIndex] = EMPTY_VALUE;
   卖出箭头Buffer[bufferIndex] = EMPTY_VALUE;
}


//+------------------------------------------------------------------+
//| 画波段连线                                                       |
//+------------------------------------------------------------------+
void DrawSwingLine(int shift, double price)
{
   if(!显示波段连线)
      return;

   if(shift < 0)
      return;

   波段连线Buffer[shift] = price;
}


//+------------------------------------------------------------------+
//| 信号提醒                                                         |
//+------------------------------------------------------------------+
void CheckAlert(const datetime &time[])
{
   int maxCheck = 左右确认K线数 + 5;

   for(int shift = 1; shift <= maxCheck; shift++)
   {
      if(买入箭头Buffer[shift] != EMPTY_VALUE)
      {
         if(time[shift] == 上次提醒时间)
            return;

         string buyMsg = Symbol() + " 出现结构波段买入信号";

         if(开启弹窗提醒)
            Alert(buyMsg);

         if(开启声音提醒)
            PlaySound(声音文件);

         上次提醒时间 = time[shift];
         return;
      }

      if(卖出箭头Buffer[shift] != EMPTY_VALUE)
      {
         if(time[shift] == 上次提醒时间)
            return;

         string sellMsg = Symbol() + " 出现结构波段卖出信号";

         if(开启弹窗提醒)
            Alert(sellMsg);

         if(开启声音提醒)
            PlaySound(声音文件);

         上次提醒时间 = time[shift];
         return;
      }
   }
}


filetype

自写均线交叉.mq4

24.78 KB, 下载次数: 0, 下载积分: 活跃度 -5  [下载]

评分
  • 1
  • 2
  • 3
  • 4
  • 5
平均分:NAN    参与人数:0    我的评分:未评 下载时遇到问题?
如果有帮助,就支持一下我呗
举报

评论 使用道具

精彩评论2

爱交易
D
| 发表于 1 小时前 | 显示全部楼层
感谢。。。
举报

点赞 评论 使用道具

jrjyzs
DDD
| 发表于 半小时前 | 显示全部楼层
楼主大爱啊......
举报

点赞 评论 使用道具

发新帖
EA交易
您需要登录后才可以评论 登录 | 立即注册