时间序列挖掘的数据标签(第1部分):通过EA操作图制作具有趋势标记的数据集·综合运用
📊

时间序列挖掘的数据标签(第1部分):通过EA操作图制作具有趋势标记的数据集·综合运用

(3/3)·手工切分K线标注趋势既慢又易错,这套EA操作图流程让标注变成可视化拖拽

偏理论 第 3/3 篇
很多人直接按固定窗口把K线硬切成上升段和下降段,结果把跨段的延续趋势切断,模型学到的是噪声。手工在Excel里标趋势,几百根柱子就眼花,标签一致性根本保不住。外汇贵金属杠杆高、波动突变多,错标一段就可能让后续训练偏到离谱。

◍ 用键盘在图上打标记并落盘

这段初始化与图表事件逻辑,解决的是「手动在 MT5 图表上按快捷键标注入场/出场点,并自动存成 CSV」的需求。EA 启动时若找不到历史文件,会用 FileOpen 以写入+CSV+读取模式新建一个形如 EURUSD5-1700000000.csv 的文件,并用 iBarShift 反推起点 bar 偏移,把图表滚到末端、画一条叫 Start 的竖线。 初始化尾部连开两个图表事件开关:ChartSetInteger(ChartID(), CHART_EVENT_OBJECT_CREATE, true) 与 CHART_EVENT_OBJECT_DELETE 同理置真,意思是对象被创建或删除时 OnChartEvent 都能吃到回调;最后 ChartRedraw(0) 强制重绘一次,返回 INIT_SUCCEEDED。 真正的交互在 OnChartEvent 的 CHARTEVENT_KEYDOWN 分支。按 B 键时,若 first 为真,记蓝色箭头 OBJ_ARROW_BUY、typ=0、tp="start"、Num 自增 1;否则记红色箭头、typ=1、tp="end"。每次打完 first 取反,对象名拼成 0-1-start 这种格式,方便后续回放。外汇与贵金属波动剧烈,这类手动标注仅作复盘素材,不代表任何方向判定。

MQL5 / C++
ChartNavigate(class="num">0,CHART_END,shift);
  }
  else
  {
   file_handle = FileOpen(StringFormat("%s%d-%d.csv",Symbol(),Period(),start_t),FILE_WRITE|FILE_CSV|FILE_READ);
   Print(FileTell(file_handle));
   Print("No history file,create file:",StringFormat("%s%d-%d",Symbol(),Period(),start_t));
   shift = -iBarShift(Symbol(),PERIOD_CURRENT,(class="type">class="kw">datetime)start_t);
   ChartNavigate(class="num">0,CHART_END,shift);
   ObjectCreate(class="num">0,"Start",OBJ_VLINE,class="num">0,(class="type">class="kw">datetime)start_t,class="num">0);
  }
class=class="str">"cmt">//---
  Print("EA:",MQL5InfoString(MQL5_PROGRAM_NAME),"Working!");
class=class="str">"cmt">//---
  ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_CREATE,true);
class=class="str">"cmt">//---
  ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_DELETE,true);
class=class="str">"cmt">//---
  ChartRedraw(class="num">0);
class=class="str">"cmt">//---
  class="kw">return(INIT_SUCCEEDED);
  }
class="type">void OnChartEvent(class="kw">const class="type">int id,
                class="kw">const class="type">long &lparam,
                class="kw">const class="type">class="kw">double &dparam,
                class="kw">const class="type">class="kw">string &sparam)
  {
class=class="str">"cmt">//Comment(__FUNCTION__,": id=",id," lparam=",lparam," dparam=",dparam," sparam=",sparam);
  if(id==CHARTEVENT_KEYDOWN)
   {
    class="kw">switch(lparam)
      {
       case KEY_B:
         if(first)
          {
           col=clrBlue ;
           typ =class="num">0;
           Num+=class="num">1;
           tp = "start";
          }
         else
          {
           col=clrRed ;
           typ = class="num">1;
           tp = "end";
          }
        ob =OBJ_ARROW_BUY;
        first = !first;
        Name = StringFormat("%d-%d-%s",typ,Num,tp);
        class="kw">break;
       case KEY_S:
         if(first)

「图表点击落点与区间标记的落地逻辑」

这段脚本承接键盘事件之后,把鼠标在 MT5 图表上的点击转换成可记录的对象。核心在 CHARTEVENT_CLICK 分支:先用 ChartXYToTimePrice 把像素坐标 x、y 反算成时间 dt 与价格 price,window 固定为 0 表示主图窗口。 若反算成功,ObjectCreate 以之前键盘事件里定好的 Name 和 ob(箭头类型)在主图画出标记,并用 ObjectSetInteger 写入颜色 col。start 类标记会把 dt 存进 Start 变量;end 类则在文件句柄存在时调用 file_write(Start,dt) 写出区间起止时间。 键盘分支里 typ 非 3 时才响应点击,typ 等于 3 即视为已完成一轮标记,不再画新对象。删除或创建对象时仅 Print 出名称做日志,不影响标记流程。 开 MT5 把这段接进 EA 的 OnChartEvent,连按两次键切换红蓝箭头后点图表,就能看到 1/0 型编号对象生成;外汇与贵金属波动剧烈,标记仅作主观区间参考,实际触发概率随品种流动性变化。

MQL5 / C++
  if(id==CHARTEVENT_CLICK&&(typ!=class="num">3))
   {
   class=class="str">"cmt">//--- definition
   class="type">int x=(class="type">int)lparam;
   class="type">int y=(class="type">int)dparam;
   class="type">class="kw">datetime dt   =class="num">0;
   class="type">class="kw">double  price =class="num">0;
   class="type">int     window=class="num">0;
   if(ChartXYToTimePrice(class="num">0,x,y,window,dt,price))
     {
      ObjectCreate(class="num">0,Name,ob,window,dt,price);
      ObjectSetInteger(class="num">0,Name,OBJPROP_COLOR,col);
      class=class="str">"cmt">//Print("time:",dt,"shift:",iBarShift(Symbol(),PERIOD_CURRENT,dt));
      if(tp=="start")
         Start=dt;
      else
       {
       if(file_handle)
          file_write(Start,dt);
       }
      ChartRedraw(class="num">0);
     }
   else
      Print("ChartXYToTimePrice class="kw">return error code: ",GetLastError());
   }
class=class="str">"cmt">//--- object class="kw">delete
  if(id==CHARTEVENT_OBJECT_DELETE)
   {
    Print("The object with name ",sparam," has been deleted");
   }
class=class="str">"cmt">//--- object create
  if(id==CHARTEVENT_OBJECT_CREATE)
   {
    Print("The object with name ",sparam," has been created!");
   }
  }
if (id==CHARTEVENT_CLICK&&(typ!=class="num">3))
typ=class="num">3;
class="type">void file_write(class="type">class="kw">datetime start,

画得少,看得清

上面这段把 K 线抽取和落盘收尾连在一起:CopyRates 拉完当前周期数据后,若文件指针恰在 2 字节位置(即刚写过标记),先补一行表头 time/open/high/low/close/tick_volume/trend_group/trend_index,再逐根写柱;否则直接续写,不重复表头。 读侧用 read_csv 从文件句柄一直读到 FileIsEnding,每读一行 ArrayResize 扩一位再存字符串,回测或离线分析时直接吃这个数组就行。 OnDeinit 里 FileClose 并打「Write data!」,保证 EA 卸载时缓冲区落盘不丢。外汇与贵金属波动剧烈、杠杆风险高,这套导出只解决数据搬运,进出场仍靠你自己的价格行为判断。

MQL5 / C++
class="type">class="kw">datetime end)
  {
  class="type">MqlRates rates[];
  ArraySetAsSeries(rates,false);
  class="type">int n_cp=CopyRates(Symbol(),PERIOD_CURRENT,start,end,rates);
  if(n_cp>class="num">0)
    {
     if(FileTell(file_handle)==class="num">2)
       {
        FileWrite(file_handle,"time","open","high","low","close","tick_volume","trend_group","trend_index");
        for(class="type">int i=class="num">0; i<n_cp; i++)
          {
           FileWrite(file_handle,
                     rates[i].time,
                     rates[i].open,
                     rates[i].high,
                     rates[i].low,
                     rates[i].close,
                     rates[i].tick_volume,
                     typ,
                     i);
          }
       }
     else
       {
        for(class="type">int i=class="num">0; i<n_cp; i++)
          {
           FileWrite(file_handle,
                     rates[i].time,
                     rates[i].open,
                     rates[i].high,
                     rates[i].low,
                     rates[i].close,
                     rates[i].tick_volume,
                     typ,
                     i);
          }
       }
    }
  else
     Print("No data copied!");
  FileFlush(file_handle);
  typ=class="num">3;
  }
class="type">void read_csv(class="type">int hd,
              class="type">class="kw">string &arry[])
  {
  class="type">int i=class="num">0;
  class="kw">while(!FileIsEnding(hd))
    {
     ArrayResize(arry,i+class="num">1);
     arry[i]=FileReadString(hd);
     i++;
    }
  }
class="type">void OnDeinit(class="kw">const class="type">int reason)
  {
  FileClose(file_handle);
  Print("Write data!");
  }
把标注过程交给小布盯盘看盘口
这些诊断小布盯盘的AIGC已内置,打开对应品种页即可看到历史段的趋势着色与成交量异常提示,你只需在EA里确认边界,重复劳动交给小布,你专注决策。

常见问题

纯差分会把小幅回撤也算作反转,产生大量短命标签;图表交互标注允许按结构高低点确认段边界,标签更贴近人工判势逻辑,但需警惕主观过拟合。
目前小布盯盘提供品种页的趋势可视化与异常段提示,导出为EA可用的标记文件仍需本篇的EA流程落地,二者配合可省掉大半肉眼比对时间。
可能。若在M15上标的中段趋势,换到H1看可能只是噪声,建议在EA里多周期回看再落笔,倾向以主交易周期为准、次周期校验。
写文件时把每段的起止Time原样落盘,再用脚本按Time左连接原始行情做行数断言;偏移一行在后续训练里会表现为延迟信号,概率上拉低胜率。