MQL5 中的范畴论 (第 17 部分):函子与幺半群(基础篇)
「用函子把 MT5 指标映射成幺半群」
在 MQL5 里谈范畴论不是炫学,核心是把一组同构对象之间的映射用代码固化下来。函子负责把指标缓冲区这张图里的对象送到另一张图,保持复合结构不变;幺半群则给这种映射一个可叠加的单位元与结合律。 以均线数组为例,把不同周期 SMA 的输出视作范畴里的对象,周期切换看作态射,用函子封装后就能在 EA 里统一处理。下面这段给出一个最简幺半群结构的 MQL5 骨架,单位元是空数组,二元运算是拼接。 外汇与贵金属市场高杠杆、滑点随机,这类抽象仅用于理清信号组合逻辑,不预示任何方向。实盘前请在 MT5 策略测试器用 2023 年 XAUUSD 的 M1 数据跑一遍,观察拼接后信号延迟是否超过 3 根 K 线。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| 最简幺半群:数组拼接 | class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">struct MonoidArray { class="type">class="kw">double arr[]; class=class="str">"cmt">// 单位元:空数组 class="type">void Empty(class="type">void) { ArrayResize(arr,class="num">0); } class=class="str">"cmt">// 二元运算:拼接 class="type">void Append(class="type">class="kw">double &b[]) { class="type">int n=ArraySize(arr); ArrayResize(arr,n+ArraySize(b)); for(class="type">int i=class="num">0;i<ArraySize(b);i++) arr[n+i]=b[i]; } };
◍ 用函子把资金类接进向导拼装
范畴论这一脉继续往下走,本文焦点从尾随类、信号类转到智能资金类。这几类都出自 Meta Editor IDE,配合 MQL5 向导能以极少代码拼出 EA,资金类自定义实例的介入点就在这里。 持仓规模是系统初步测试里最敏感的参数之一,固定保证金或固定手数常被视为排除干扰的首选;若必须动态 sizing,惯例是等入场信号确定后再挂上,和退出方法对齐。本文反其道试一次:用资金类实例预测的止损倒推理想持仓。 函子作为范畴间桥梁,不只抓对象差异也抓态射差异。第14、15篇用简单线性方程实现函子,映射只需斜率系数加 y 截距就能判定协域对象与态射;第16篇起把它视作多层感知器——源于 Sturgis、McCulloch 与 Pitts 的工作,已证可在 -1 到 +1 间近似任意连续函数,多层结构也能复刻任意 XOR 函数。 本文汇总视角落在幺半群与证券价格预序的配对上:当两者结合,可针对 BTCUSD 这类标的制定持仓规模系统。幺半群由集合、二元运算、衡点元素构成,此前主要用于交易步骤分类,本文沿用该结构覆盖开仓决策中的每个名义步骤。外汇与贵金属杠杆高、回撤快,动态 sizing 仅作概率层面的参考,实盘前请在 MT5 策略测试器用历史数据校验。
用幺半群把交易决策拆成可计算步骤
在范畴论视角下,函子负责把两个范畴连起来,协域若是一个时间序列,就能直接服务于行情预测。前一篇里我们靠函子把图形范畴映射到线性序,给标普500的多空判断提供了输入;这一篇把域范畴换成幺半群,思路更贴近实盘决策流。 所谓幺半群,在这里就是每一步交易决策对应的代数结构:选时间帧、选回溯区间、选应用价格、选能跟前三项协同出读数的指标,最后是跟趋势还是逆价位的交易动作。每一步都编了号,各自带一个二元运算,作用是在遍历完该步所有候选集合值之后,挑出唯一确定的那个数。 对交易者来说,这意味着你盘前那套'先定周期再定回看根数'的模糊流程,可以被显式写成一组有序的幺半群。打开MT5,把你的时间帧和回溯长度列成枚举,就能看清哪一步的集合定义和其他步不兼容,从而漏掉信号或重复计算。 外汇与贵金属杠杆高、滑点跳空频繁,这套结构只解决'决策怎么收敛到一个数',不解决方向对错,实盘仍以小仓位验证为宜。
「用 MLP 预测止损间隙反推手数」
把四个幺半群步骤的输出喂给 MLP,训练目标设成持仓的理想止损间隙,而不是去猜价格方向。间隙越大,单手承受的回撤越重,手数就得反向收缩——这是把模型输出直接绑死到仓位管理的链条上。 具体落地时,先拿间隙除以 TickSize 再乘 TickValue,得到一手亏穿预测间隙的货币损失。假设账户允许用 m_percent% 的空闲保证金去顶最大回撤,手数就等于 (m_percent/100)×FreeMargin 再除以这个单手损失。外汇与贵金属杠杆高,间隙估计偏一点,手数就会劈叉,实盘前务必在 MT5 策略测试器跑一遍。 下面这段是核心计算逻辑,逐行拆一下:_y_output[0] 是 MLP 给出的止损间隙;sl 用 Ask 加间隙绝对值定卖出止损位;_ct_1_lot_loss 算一手亏损金额;lot 按保证金占比反推;FreeMarginCheck 为负就退回平台允许的最大手数;最后 Optimize 做取整返回。
class=class="str">"cmt">//output from MLP forecast class="type">class="kw">double _stoploss_gap=_y_output[class="num">0]; class=class="str">"cmt">//printf(__FUNCSIG__+" ct call: "+DoubleToString(_stoploss_gap)); sl=m_symbol.Ask()+fabs(_stoploss_gap); class=class="str">"cmt">//--- select lot size class="type">class="kw">double _ct_1_lot_loss=(_stoploss_gap/m_symbol.TickSize())*m_symbol.TickValue(); class="type">class="kw">double lot=((m_percent/class="num">100.0)*m_account.FreeMargin())/_ct_1_lot_loss; class=class="str">"cmt">//--- calculate margin requirements for class="num">1 lot if(m_account.FreeMarginCheck(m_symbol.Name(),ORDER_TYPE_SELL,lot,m_symbol.Bid())<class="num">0.0) { printf(__FUNCSIG__" insufficient margin for sl lot! "); lot=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,m_symbol.Bid(),m_percent); } class=class="str">"cmt">//--- class="kw">return trading volume class="kw">return(Optimize(lot));