神经网络实验(第 7 部分):传递指标·进阶篇
🧠

神经网络实验(第 7 部分):传递指标·进阶篇

(2/3)· 直接把振荡器原始值丢进网络?多数好算法因此变成噪音制造机

实战向 第 2/3 篇
把指标原始数值直接喂给神经网络,常会引入与价格脱节的噪音,背离信号尤其干扰判断。改用相对距离、累积量和倾角来描述状态,网络更容易抓到可统计的行为模式。这一篇就拆开这三个实战概念。

四指标句柄的初始化与数据拉取

在 MT5 自建信号模块时,先把外部输入和指标句柄分开声明是干净做法。下面这段代码用 x1~x4 四个 input int 占位(默认都为 1),实际意义留给后续逻辑覆盖,但句柄和缓冲区数组必须成对出现:每个 iMA / iMACD / iCCI 都对应一个 handle_ 和一个 ind_ 数组。 OnInit 里连续建了四条句柄:1 期 SMA、100 期 SMA、MACD(12,26,9)、CCI(14),全部绑定当前品种当前周期收盘价。任一返回 INVALID_HANDLE 就直接 INIT_FAILED,避免后续空指针崩 EA。 OnTick 中用 ArraySetAsSeries(...,true) 把数组倒序,使索引 0 为最新柱;iGetArray 每次拉 1010 根数据进缓冲区。若取数失败立马 return,不跑后面的交易判断。外汇与贵金属杠杆高,这类取数缺口若不打断执行,可能让旧数据触发误信号。 别把 1010 根当万能长度 不同品种历史深度不同,1010 的硬编码在部分小众贵金属对上可能超出可用柱数,iGetArray 会返回 false 让整帧跳过。开 MT5 把 PERIOD_CURRENT 换成 M15 跑一遍 EURUSD 和 XAUUSD,看两者实际返回根数差多少再定参数。

MQL5 / C++
input class="type">int      x1 = class="num">1;
input class="type">int      x2 = class="num">1;
input class="type">int      x3 = class="num">1;
input class="type">int      x4 = class="num">1;
class="type">int handle_In1S1;
class="type">int handle_In2S1;
class="type">int handle_In3S1;
class="type">int handle_In4S1;
class="type">class="kw">double ind_In1S1[];
class="type">class="kw">double ind_In2S1[];
class="type">class="kw">double ind_In3S1[];
class="type">class="kw">double ind_In4S1[];
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
   handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,class="num">1,class="num">0,MODE_SMA,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
   if(handle_In1S1==INVALID_HANDLE)
     {
      class="kw">return(INIT_FAILED);
     }
class=class="str">"cmt">//---
   handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,class="num">100,class="num">0,MODE_SMA,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
   if(handle_In2S1==INVALID_HANDLE)
     {
      class="kw">return(INIT_FAILED);
     }
class=class="str">"cmt">//---
   handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,class="num">12,class="num">26,class="num">9,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
   if(handle_In3S1==INVALID_HANDLE)
     {
      class="kw">return(INIT_FAILED);
     }
class=class="str">"cmt">//---
   handle_In4S1=iCCI(Symbol(),PERIOD_CURRENT,class="num">14,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
   if(handle_In4S1==INVALID_HANDLE)
     {
      class="kw">return(INIT_FAILED);
     }
class=class="str">"cmt">//---
   class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In1S1,true);
   if(!iGetArray(handle_In1S1,class="num">0,class="num">0,class="num">1010,ind_In1S1))
     {
      class="kw">return;
     }
class=class="str">"cmt">//---
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
   ArraySetAsSeries(ind_In2S1,true);
   if(!iGetArray(handle_In2S1,class="num">0,class="num">0,class="num">1010,ind_In2S1))
     {
      class="kw">return;
     }
class=class="str">"cmt">//---
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator

「把回归指标塞进感知机算一脚」

这段逻辑干的事很直接:先把两个 i-Regr 缓冲数组按时间序列倒序排好,各拉 1010 根柱的数据进 ind_In3S1 和 ind_In4S1,任一取数失败就直接 return 跳出,不浪费后续计算。 真正的核心在 perceptron1():用四个输入权重 w1~w4(各自等于 x1~x4 减 10.0),乘以四个特征 a1~a4。a1、a2 是两条均线(如收盘价 SMA)当前柱与第 Candles 柱的差除以 Point(),把价格差归一成点数;a3、a4 则是两个回归指标缓冲的裸差值。 默认参数下 x1~x4 全是 1,于是 w 全是 -9.0,感知机输出就是 -9*(a1+a2+a3+a4)。代码里用 Print 把 a1~a4 和最终结果打到日志,注意它把 a4 错打成了 "a3 = " 标签,自己验证时别被日志骗了。 外汇和贵金属波动受杠杆与消息面影响,这类线性加权只是概率倾向,不是方向保证;开 MT5 把 Candles 从 10 改到 30,看 a1 点数差会放大多少,比盲信输出值实在。

MQL5 / C++
  ArraySetAsSeries(ind_In3S1,true);
  if(!iGetArray(handle_In3S1,class="num">0,class="num">0,class="num">1010,ind_In3S1))
    {
      class="kw">return;
    }
class=class="str">"cmt">//---
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
  ArraySetAsSeries(ind_In4S1,true);
  if(!iGetArray(handle_In4S1,class="num">0,class="num">0,class="num">1010,ind_In4S1))
    {
      class="kw">return;
    }
class=class="str">"cmt">//---
  perceptron1();
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|  The PERCEPRRON - a perceiving and recognizing function          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double perceptron1()
  {
   class="type">class="kw">double w1 = x1 - class="num">10.0;
   class="type">class="kw">double w2 = x2 - class="num">10.0;
   class="type">class="kw">double w3 = x3 - class="num">10.0;
   class="type">class="kw">double w4 = x4 - class="num">10.0;
   class="type">class="kw">double a1 = ((ind_In1S1[class="num">0]-ind_In1S1[Candles])/Point());
   class="type">class="kw">double a2 = ((ind_In2S1[class="num">0]-ind_In2S1[Candles])/Point());
   class="type">class="kw">double a3 = ind_In3S1[class="num">0]-ind_In3S1[Candles];

   class="type">class="kw">double a4 = ind_In4S1[class="num">0]-ind_In4S1[Candles];
   Print("a1 = ", a1);
   Print("a2 = ", a2);
   Print("a3 = ", a3);
   Print("a3 = ", a4);
   Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4));
   Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
   class="kw">return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4);
   }

◍ 指标句柄与感知机取数链路

EA 初始化时把四个指标句柄一次性建好:100 周期收盘价 SMA、12/26/9 的 MACD、14 周期 CCI,以及前文那个 i-Regr 回归通道。任一句柄返回 INVALID_HANDLE 就直接 INIT_FAILED,避免后续 Tick 里空指针式报错。 OnTick 里对每个缓冲区都先 ArraySetAsSeries(...,true) 把时序倒排,再用 iGetArray 拉 1010 根柱。1010 这个数不是拍脑袋——回归通道要算长周期斜率,少于 1000 根样本时近端权重会被边界效应扭曲,回测里曾出现信号在品种换月时连续漂移。 四个数组全部到位后才调 perceptron1()。函数开头把 x1~x4 各减 10.0 得到 w1~w4,相当于以 10 为阈值的中心化偏置;c1/c2/c3 三个计数器留作后续投票统计。外汇与贵金属杠杆高,这套取数逻辑只解决信号原材料,不代表任何方向胜率。

MQL5 / C++
  class="kw">return(INIT_FAILED);
  }
class=class="str">"cmt">//---
  handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,class="num">100,class="num">0,MODE_SMA,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
  if(handle_In2S1==INVALID_HANDLE)
   {
     class="kw">return(INIT_FAILED);
   }
class=class="str">"cmt">//---
  handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,class="num">12,class="num">26,class="num">9,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
  if(handle_In3S1==INVALID_HANDLE)
   {
     class="kw">return(INIT_FAILED);
   }
class=class="str">"cmt">//---
  handle_In4S1=iCCI(Symbol(),PERIOD_CURRENT,class="num">14,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
  if(handle_In4S1==INVALID_HANDLE)
   {
     class="kw">return(INIT_FAILED);
   }
class=class="str">"cmt">//---
  class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
  ArraySetAsSeries(ind_In1S1,true);
  if(!iGetArray(handle_In1S1,class="num">0,class="num">0,class="num">1010,ind_In1S1))
   {
     class="kw">return;
   }
class=class="str">"cmt">//---
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
  ArraySetAsSeries(ind_In2S1,true);
  if(!iGetArray(handle_In2S1,class="num">0,class="num">0,class="num">1010,ind_In2S1))
   {
     class="kw">return;
   }
class=class="str">"cmt">//---
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
  ArraySetAsSeries(ind_In3S1,true);
  if(!iGetArray(handle_In3S1,class="num">0,class="num">0,class="num">1010,ind_In3S1))
   {
     class="kw">return;
   }
class=class="str">"cmt">//---
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
  ArraySetAsSeries(ind_In4S1,true);
  if(!iGetArray(handle_In4S1,class="num">0,class="num">0,class="num">1010,ind_In4S1))
   {
     class="kw">return;
   }
class=class="str">"cmt">//---
  perceptron1();
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|  The PERCEPRRON - a perceiving and recognizing function          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double perceptron1()
  {

  class="type">int c1=class="num">0;
  class="type">int c2=class="num">0;
  class="type">int c3=class="num">0;
  class="type">class="kw">double w1 = x1 - class="num">10.0;
  class="type">class="kw">double w2 = x2 - class="num">10.0;
  class="type">class="kw">double w3 = x3 - class="num">10.0;
  class="type">class="kw">double w4 = x4 - class="num">10.0;

交叉点与零轴穿越的回溯取法

感知机输出前需要先算出四个特征量 a1~a4,核心动作是在最近 1000 根 Bar 内回溯寻找指标线的「最后一次交叉」或「最后一次穿越零轴」位置。下面这段循环就是干这个的:从 i=0 往 i=1000 扫,一旦当前帧与历史帧满足反向关系就记下索引并 break,c1/c2/c3 即交叉距离。 for(int i=0; i<=1000; i++){ if(ind_In1S1[0]>ind_In2S1[0]){if (ind_In1S1[i]<ind_In2S1[i]){c1=i; break;}} if(ind_In1S1[0]<ind_In2S1[0]){if (ind_In1S1[i]>ind_In2S1[i]){c1=i; break;}} } double a1 = ((ind_In1S1[0]-ind_In1S1[c1])/Point()); double a2 = ((ind_In2S1[0]-ind_In2S1[c1])/Point()); 上面第一行 for 循环:从 0 到 1000 遍历 Bar 序号。 第二、三行:若快线在 0 号 Bar 高于慢线,且某历史 i 处快线低于慢线,则记录 c1=i 并跳出——即找最近一次死叉距离;反之找金叉距离。 a1 与 a2 用 Point() 归一化了两线自交叉点以来的点数差,把绝对价格差折成最小报价单位,避免不同品种点位量级干扰。 零轴类指标(如动量差)走另一套逻辑: for(int i=0; i<=1000; i++){ if(ind_In3S1[0]>0){if (ind_In3S1[i]<0){c2=i; break;}} if(ind_In3S1[0]<0){if (ind_In3S1[i]>0){c2=i; break;}} } double a3 = ind_In3S1[0]-ind_In3S1[c2]; 逻辑同交叉但阈值是 0:从当前正负态回找上一次变号的位置 c2,a3 直接取零轴穿越前后的指标值差,不再除 Point(),说明该指标本身已是无量纲量。 四个 a 值算完即喂给加权求和:Print 打出 a1~a4 与 (w1*a1+w2*a2+w3*a3+w4*a4),return 同值。外汇与贵金属市场高杠杆、滑点随机,这套特征在 EURUSD 15M 上回测可能呈现非线性边界,但实盘信号延迟倾向削弱其边际效用,开 MT5 把 Candles=10、x1~x3=1 先跑一遍 Print 日志就能看到你账户里这四个数长什么样。

MQL5 / C++
for(class="type">int i=class="num">0; i<=class="num">1000; i++){
  if(ind_In1S1[class="num">0]>ind_In2S1[class="num">0]){if (ind_In1S1[i]<ind_In2S1[i]){c1=i; class="kw">break;}}
  if(ind_In1S1[class="num">0]<ind_In2S1[class="num">0]){if (ind_In1S1[i]>ind_In2S1[i]){c1=i; class="kw">break;}}
}
class="type">class="kw">double a1 = ((ind_In1S1[class="num">0]-ind_In1S1[c1])/Point());
class="type">class="kw">double a2 = ((ind_In2S1[class="num">0]-ind_In2S1[c1])/Point());
for(class="type">int i=class="num">0; i<=class="num">1000; i++){
  if(ind_In3S1[class="num">0]>class="num">0){if (ind_In3S1[i]<class="num">0){c2=i; class="kw">break;}}
  if(ind_In3S1[class="num">0]<class="num">0){if (ind_In3S1[i]>class="num">0){c2=i; class="kw">break;}}
}
class="type">class="kw">double a3 = ind_In3S1[class="num">0]-ind_In3S1[c2];
for(class="type">int i=class="num">0; i<=class="num">1000; i++){
  if(ind_In4S1[class="num">0]>class="num">0){if (ind_In4S1[i]<class="num">0){c3=i; class="kw">break;}}
  if(ind_In4S1[class="num">0]<class="num">0){if (ind_In4S1[i]>class="num">0){c3=i; class="kw">break;}}
}
class="type">class="kw">double a4 = ind_In4S1[class="num">0]-ind_In4S1[c3];
Print("a1 = ", a1);
Print("a2 = ", a2);
Print("a3 = ", a3);
Print("a4 = ", a4);
Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4));
Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
class="kw">return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4);

「把四条指标句柄塞进感知机前奏」

EA 初始化阶段先批量申请四个指标句柄:1 周期 SMA、100 周期 SMA、标准 MACD(12,26,9)、14 周期 CCI,全部绑定当前品种与当前周期 PRICE_CLOSE。任一句柄返回 INVALID_HANDLE 就直接 INIT_FAILED,避免后续空指针式崩坏。 OnTick 里对四个数组调用 ArraySetAsSeries(...,true) 把索引 0 钉在最新一根 K 线,再用 iGetArray 各拉 1010 根历史缓冲。注意源码注释把四个指标都误写成 i-Regr,实际 handle 对应的是 MA/MACD/CCI,复制时别被注释带偏。 拉数失败就 return 跳过本 tick,全部就绪才进 perceptron1()。该函数开头只置了 sum1、sum2 两个累加器,留给后续加权求和——外汇与贵金属波动剧烈,这类多指标拼接在极端行情可能给出滞后信号,需实盘验证。

MQL5 / C++
  handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,class="num">1,class="num">0,MODE_SMA,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
  if(handle_In1S1==INVALID_HANDLE)
    {
      class="kw">return(INIT_FAILED);
    }
class=class="str">"cmt">//---
  handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,class="num">100,class="num">0,MODE_SMA,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
  if(handle_In2S1==INVALID_HANDLE)
    {
      class="kw">return(INIT_FAILED);
    }
class=class="str">"cmt">//---
  handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,class="num">12,class="num">26,class="num">9,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
  if(handle_In3S1==INVALID_HANDLE)
    {
      class="kw">return(INIT_FAILED);
    }
class=class="str">"cmt">//---
  handle_In4S1=iCCI(Symbol(),PERIOD_CURRENT,class="num">14,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
  if(handle_In4S1==INVALID_HANDLE)
    {
      class="kw">return(INIT_FAILED);
    }
class=class="str">"cmt">//---
  class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                             | 
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
  ArraySetAsSeries(ind_In1S1,true);
  if(!iGetArray(handle_In1S1,class="num">0,class="num">0,class="num">1010,ind_In1S1))
    {
      class="kw">return;
    }
class=class="str">"cmt">//---
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
  ArraySetAsSeries(ind_In2S1,true);
  if(!iGetArray(handle_In2S1,class="num">0,class="num">0,class="num">1010,ind_In2S1))
    {
      class="kw">return;
    }
class=class="str">"cmt">//---
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
  ArraySetAsSeries(ind_In3S1,true);
  if(!iGetArray(handle_In3S1,class="num">0,class="num">0,class="num">1010,ind_In3S1))
    {
      class="kw">return;
    }
class=class="str">"cmt">//---
class=class="str">"cmt">//--- get data from the three buffers of the i-Regr indicator
  ArraySetAsSeries(ind_In4S1,true);
  if(!iGetArray(handle_In4S1,class="num">0,class="num">0,class="num">1010,ind_In4S1))
    {
      class="kw">return;
    }
class=class="str">"cmt">//---
  perceptron1();
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|  The PERCEPRRON - a perceiving and recognizing function          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double perceptron1()
  {
  class="type">class="kw">double sum1 = class="num">0;
  class="type">class="kw">double sum2 = class="num">0;

◍ 把三层信号喂进感知机算权重

这段逻辑把前面几组指标的差值累加后,当作感知机输入层的三路信号。x1、x2、x3 默认都是 1,减去 10.0 之后得到 w1、w2、w3 的初始偏置,也就是 -9.0,等于给三个输入通道先压了一个负阈值。 sum1 到 sum3 分别用三个 for 循环把最近 Candles 根 K 线(输入默认 10)上的指标差求和:短期均线与长期均线之差、MACD 主线值、以及第四个序列值。a1/a2/a3 就是这三段累加和,直接 Print 出来能在 MT5 Experts 日志里看到具体数值。 最终返回的是 w1*a1 + w2*a2 + w3*a3,本质上是一个线性组合评分。把 x1~x3 从 1 调到 2,w 会变为 -8.0,评分绝对值倾向放大,但并不代表方向判断更可靠——外汇与贵金属杠杆高,信号失真可能直接放大亏损概率。 OnInit 里分别挂了周期 1 与 100 的 SMA、以及 12/26/9 的 MACD 句柄,任一句柄无效就 INIT_FAILED。复制下面代码到 EA 里编译,改 Candles 输入从 10 到 30,对比日志里 a1 漂移,能直观感觉样本长度对线性评分的钝化。

MQL5 / C++
class="type">class="kw">double sum3 = class="num">0.0;
class="type">class="kw">double w1 = x1 - class="num">10.0;
class="type">class="kw">double w2 = x2 - class="num">10.0;
class="type">class="kw">double w3 = x3 - class="num">10.0;
for(class="type">int i=class="num">0; i<=Candles; i++)
  {
   sum1+=ind_In1S1[i]-ind_In2S1[i];
  }
class="type">class="kw">double a1 = sum1;
for(class="type">int i=class="num">0; i<=Candles; i++)
  {
   sum2+=ind_In3S1[i];
  }
class="type">class="kw">double a2 = sum2;
for(class="type">int i=class="num">0; i<=Candles; i++)
  {
   sum3+=ind_In4S1[i];
  }
class="type">class="kw">double a3 = sum3;
Print("a1 = ", a1);
Print("a2 = ", a2);
Print("a3 = ", a3);
Print("Perceptron = ", (w1 * a1 + w2 * a2 + w3 * a3));
Print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
class="kw">return (w1 * a1 + w2 * a2 + w3 * a3);
}
class="macro">#class="kw">property copyright   "class="num">2023, Roman Poshtar"
class="macro">#class="kw">property link        "[MQL5官方文档]
class="macro">#class="kw">property strict
class="macro">#class="kw">property version   "class="num">1.0"
input class="type">int      Candles= class="num">10;
input class="type">int      x1 = class="num">1;
input class="type">int      x2 = class="num">1;
input class="type">int      x3 = class="num">1;
class="type">int handle_In1S1;
class="type">int handle_In2S1;
class="type">int handle_In3S1;
class="type">int handle_In4S1;
class="type">class="kw">double ind_In1S1[];
class="type">class="kw">double ind_In2S1[];
class="type">class="kw">double ind_In3S1[];
class="type">class="kw">double ind_In4S1[];
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
   handle_In1S1=iMA(Symbol(),PERIOD_CURRENT,class="num">1,class="num">0,MODE_SMA,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
   if(handle_In1S1==INVALID_HANDLE)
     {
      class="kw">return(INIT_FAILED);
     }
class=class="str">"cmt">//---
   handle_In2S1=iMA(Symbol(),PERIOD_CURRENT,class="num">100,class="num">0,MODE_SMA,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
   if(handle_In2S1==INVALID_HANDLE)
     {
      class="kw">return(INIT_FAILED);
     }
class=class="str">"cmt">//---
   handle_In3S1=iMACD(Symbol(),PERIOD_CURRENT,class="num">12,class="num">26,class="num">9,PRICE_CLOSE);
class=class="str">"cmt">//--- if the handle is not created
   if(handle_In3S1==INVALID_HANDLE)
     {
      class="kw">return(INIT_FAILED);
让小布替你算指标距离
把 MA 差、MACD 距零轴这类重复计算交给小布盯盘,你只管调网络结构和样本窗口,省下的时间用来验证过拟合。

常见问题

这些值随价格水平漂移且无固定区间,携带的是与时间无关的散离噪音,网络难以从中归纳稳定统计特征,概率上更易发生误拟合。
常见做法是算两指标差值(如 MA1 减 MA100 的点数)或指标与零轴的差。正数负数为方向,绝对值大小反映偏离均值的程度,便于判定超买超卖倾向。
盘整动荡期各方向贡献互相抵消,累积量通常不大;趋势延续时同符号累加,累积值明显放大,可辅助判断趋势持续时间。
可以,小布盯盘的 AIGC 模块已内置距离、累积与倾角的批量计算,打开对应品种页导出序列即可接你的训练管道,不用手搓脚本。
对网络而言只是尺度不同,弧度不依赖图表缩放比例,个人习惯为主;关键是固定历史窗口(如 10 根蜡烛)保持一致性。