作为创建自动化交易系统新方法的自动机编程(基础篇)
📘

作为创建自动化交易系统新方法的自动机编程(基础篇)

第 1/3 篇

自动机编程:EA 开发的新路径

MetaTrader 5 在 2014 年 1 月 9 日上线了一种被称为「自动机编程」的自动化交易系统构建思路,它把策略逻辑抽象成可自描述的状态机,而不是传统的线性下单脚本。 这套方法发布后,原帖在站内获得 4684 次浏览与 61 条互动,说明老交易员对「少写样板代码、多描状态」的诉求一直存在。 苏格拉底那句「我知道自己一无所知」放在这儿挺合适:任何声称已穷尽市场规律的 EA,都该先怀疑自己漏了哪类行情。外汇与贵金属杠杆高、跳空频繁,用状态机也得留好异常退出通道。

「为什么老手也该看自动机编程」

用 MQL4/5 写 EA 的人,在 MetaQuotes 站内能搜到的自动机编程资料基本是空白。我实际去搜过,相关主题几乎查不到成体系的内容。 每位交易者写的 EA 逻辑都不同,但都要面对程序结构混乱、状态跳转难维护的问题。理想状态是 EA 像发条装置,在标准与极端行情下自行运转,不用人盯。

  • 年俄罗斯学者 A.A. Shalyto 提出了“自动机编程”(SWITCH 技术)。这套方法能把 MTS 开发复杂度降得很低,也方便嵌进复杂决策体系,用 MQL5 实现并不难。

外汇和贵金属杠杆高、滑点跳空频繁,EA 状态机若没理清,实盘可能在不该下单的时机触发。建议开 MT5 新建一个用 switch 控制状态的脚本先跑通逻辑。

◍ 算法与代码为什么总会跑偏

写算法的人和写代码的人经常不是同一套逻辑。书面算法通常只记录“做出了什么设计成果”,并不交代“怎么一步步拿到这个结果”;而开发者脑子里另有一套文本化的实现算法。程序定型后再补文档,大量细节又被忽略,于是程序逻辑和算法逻辑出现不一致的概率很高——之所以说“很可能”,是因为没人会去逐行核对别人的程序文本。 项目一大,纯靠读文本判断代码是否忠实于算法就变得不可能。此时只能靠 testing 流程反推:开发者先把算法写下来,在脑中转换成另一套算法,再输出成程序。这个链条里,开发者是唯一掌握原始逻辑与实施差异信息的人。 更麻烦的是,大多数开发者懒得在编码前落笔画流程图,直接开写,最后文档里补一个“大概相似”的通用算法。每个人按自己的智力与语言熟练度引入大量中间变量,程序越大越复杂,就越需要资深专家从文本本身去挖逻辑缺陷——不是系统 bug,而是逻辑被错误地实施了。 截止日期逼近时,有人会在餐巾纸上草拟方案然后急着实现,测试期忽视的同类型错误会越堆越多。从标准算法迁移到代码的过程,确实容易丢掉关键东西。外汇与贵金属交易系统的高风险在于:这种逻辑漂移不会提示报错,却可能在极端行情下触发错误下单。

用状态切换搭出EA控制骨架

把交易逻辑写成自动机,核心就是拿一个整型全局变量当状态机的总开关,所有分支判断都挂在它身上。上面这段结构展示了最朴素的落地方式:STATUS 从 0 到 N 每个值代表一个状态,进 case 后先按优先级查弧线和自环条件,再决定是否改写 STATUS 并跑对应的输出动作。 实际在 MT5 里跑,你可以把 0 设成“空闲等信号”,1 设成“已开仓盯浮盈”,N 设成“强制清仓退出”。每个 case 末尾 break 不能省,否则状态会穿透到下一个分支,造成重复下单或重复平仓。 嵌套自动机也在 case 内调用,意味着小状态机可以挂在主状态机下面,比如“已开仓”状态里再嵌一个“加仓决策”子机。外汇和贵金属波动大、滑点随机,这种结构能让你把高风险时段的切换条件单独隔离,逻辑改起来比一整片 if-else 平整很多。

MQL5 / C++
class="kw">switch(class="type">int STATUS ) class=class="str">"cmt">// Мulti-valued global state variable of the automaton.
{
  case class="num">0:  class=class="str">"cmt">// start
  class=class="str">"cmt">// Checking arc and loop conditions(in order of priority),
  class=class="str">"cmt">// transition(change of the value of the variable STATUS)
  class=class="str">"cmt">// and execution of arc and loop actions(output function execution);
  class=class="str">"cmt">// logging transitions and actions if the condition is met. class="num">0
  class=class="str">"cmt">// Calling nested automata.
  class=class="str">"cmt">// Execution of output functions in the state.
  class="kw">break ;
  
  case class="num">1:
  class=class="str">"cmt">// Checking arc and loop conditions(in order of priority),
  class=class="str">"cmt">// transition(change of the value of the variable STATUS)
  class=class="str">"cmt">// and execution of arc and loop actions(output function execution);
  class=class="str">"cmt">// logging transitions and actions if the condition is met. 
  class=class="str">"cmt">// Calling nested automata.
  class=class="str">"cmt">// Execution of output functions in the state.
  class="kw">break ;
  
*********
*********
*********
  case N-class="num">1:
  class=class="str">"cmt">// Checking arc and loop conditions(in order of priority),
  class=class="str">"cmt">// transition(change of the value of the variable STATUS)
  class=class="str">"cmt">// and execution of arc and loop actions(output function execution);
  class=class="str">"cmt">// logging transitions and actions if the condition is met. 
  class=class="str">"cmt">// Calling nested automata.
  class=class="str">"cmt">// Execution of output functions in the state.
  class="kw">break ;
  case N:
  class=class="str">"cmt">// Checking arc and loop conditions(in order of priority),
  class=class="str">"cmt">// transition(change of the value of the variable STATUS)
  class=class="str">"cmt">// and execution of arc and loop actions(output function execution);
  class=class="str">"cmt">// logging transitions and actions if the condition is met.
  class=class="str">"cmt">// Calling nested automata.
  class=class="str">"cmt">// Execution of output functions in the state.
  class="kw">break ;
}

「用自动机掐掉 EA 的未指定状态」

任何程序在某一时刻的状态,都由当时所有数据值确定。EA 里若有 n 个二进制标志变量,状态数理论在 n 到 2^n 之间,但开发者通常只显式处理了部分组合,最多会有 2^n - n 种组合根本没写进逻辑。 一旦行情出现意料外的输入动作组合——比如跳空、预付款亏损、负余额需追保、持仓红到趋零、买卖仓错误开平——EA 就可能掉进所谓“非可视化”的未指定状态,表现跟交易者离线一样死寂,这是实盘里很隐蔽的安全陷阱。 根治办法是在设计期就用单一多值控制变量显式枚举所有状态,并标明状态间所有可能的迁移,让程序“无路可走”到未定义分支。有限自动机适合当这个数学模型:用迁移图表示状态,选多值状态分配(multi-valued state assignment)后,仅靠一个变量就能区分全部状态,这提升了 program observability(程序可观测性)。 落到 MT5 上,从迁移图转代码用 switch 结构最顺手,这也正是自动机编程常被称为 SWITCH-technology 的原因。你开 MT5 把 EA 的标志群重构成单个 enum 状态机,就能在回测里逼出那些原本未指定的分支。外汇与贵金属杠杆高,未指定状态引发的异常平仓风险很大,重构后务必用极端行情样本验证。

◍ 把状态机写成看得见的实体

事件驱动系统里,显式状态编程把输出动作挂到迁移图的弧、循环或节点上,混合 Moore 与 Mealy 自动机,用一份紧凑的迁移描述覆盖一连串输入响应。EA 的事件处理函数不再塞满逻辑,改为调用一组互相嵌套、互相交换状态的互联自动机,系统相关部分只留输入/输出动作和处理程序。 这套自动机在程序里是独立模块,开发时以三种身份同时存在:写规格、落代码、记日志。日志由程序自动产出,复杂逻辑下每个日志等价于一段可重放的脚本,能直接回看某次运行里状态怎么跳。 日志的价值不只是排错。它证明自动机不是画给人看的图,而是实打实在跑的对象。外汇与贵金属 EA 逻辑一复杂,状态错乱很难肉眼抓,开 MT5 把自动机日志打开,比对每次状态迁移和实际成交,往往比单步调试更快定位。此类策略受滑点、流动性断裂影响,回测与实盘表现可能出现明显偏离,属高风险范畴。

常见问题

它把交易流程拆成明确状态,你只管画状态切换,不用在if嵌套里找漏,控制骨架一次搭对。
多半是漏了未指定状态,自动机要求每个事件都有去处,补齐状态切换就能掐掉这类卡顿。
可以,小布能读你的状态定义并标出未覆盖事件,直接告诉你哪个状态少了切换出口。
把止损单独做成一个状态,只在触发事件进入,退出即回空闲态,主循环只做路由。
先画状态图,列清事件和去向,再照图填代码,能少改三遍以上。