MQL5 中的范畴论 (第 10 部分):幺半群组·进阶篇
🧮

MQL5 中的范畴论 (第 10 部分):幺半群组·进阶篇

(2/3)· 从衡点元素到逆反属性,看幺半群如何升级为组并落地关键买卖判定

新手友好 第 2/3 篇
很多交易者把幺半群当成静态工具集,忽略了给每个决策选项配一个逆反项就能把集合升级成组。理解这点,你在关键拐点就不容易被单边信号锁死。

◍ 把域和幺半群塞进模板里

做价格行为统计时,常需要对一组元素(比如最近 N 根 K 线的极值或成交量)做聚合。MQL5 里用模板类把「域」和「运算」分开封装,可以避免每换一种品种或时间框架就重写一遍逻辑。 下面这段定义了 CDomain 作为基类,管元素集合和基数(cardinality)。它内部用 CElement<T> elements[] 存数据,cardinal 记录当前有效元素个数;构造函数直接把基数置 0,析构为空实现。 随后用 enum EOperations 把六种聚合方式编码成整数:OP_ADD=0 到 OP_FURTHEST=5。注意这里 OP_CLOSEST=4 与 OP_FURTHEST=5 是对称的距离类运算,回测里若取最近 20 根 H1 蜡烛做聚类,这两种模式给出的参考边界往往差出 1~2 个波动单位。 CMonoid 继承 CDomain,额外持有 identity(单位元)和 operation(当前运算类型),并暴露 weights[] 数组与 Operation() 设值接口。你开 MT5 把这段贴进 MQEditor,改 T 为 double,就能直接挂到 EA 里做多因子加权。外汇与贵金属杠杆高,这类聚合仅作概率参考,实盘须控仓。

MQL5 / C++
class="type">int cardinal;
CElement<T> elements[];

class="kw">public:

class="type">bool Cardinality(class="type">int Value) { ... }
class="type">int Cardinality() { class="kw">return(cardinal); }

...

CDomain(class="type">void)
{
 Cardinality(class="num">0);
};
~CDomain(class="type">void) {};
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Enumeration for Monoid Operations                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum EOperations
{
 OP_FURTHEST=class="num">5,
 OP_CLOSEST=class="num">4,
 OP_MOST=class="num">3,
 OP_LEAST=class="num">2,
 OP_MULTIPLY=class="num">1,
 OP_ADD=class="num">0
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Monoid Class                                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">template <class="kw">typename T>
class CMonoid : class="kw">public CDomain<T>
{
 class="kw">protected:
 class=class="str">"cmt">//class="type">class="kw">double weights[];

 class="type">int identity;
 EOperations operation;

 class="kw">public:

 class="type">class="kw">double weights[];

 ...

 class="type">void Operation(EOperations Value) { operation=Value; }

群结构里逆元存在的暴力校验

在单子(Monoid)基础上,若每个元素都能找到另一个元素与之运算后得到单位元,就构成了群(Group)。CMonoidGroup 继承 CMonoid,用 HasInversion() 做这件事:对基数 Cardinality() 范围内的每个 i,再遍历所有 ii,看 Operate(i,ii) 是否等于 Identity()。 只要有一轮内层循环没碰到逆元,_has_inversion 就保持 false,整个群结构判定失败。这种 O(n²) 的双重遍历在元素少时可直接跑,元素一多就会拖慢 MT5 策略初始化。 把单位元写死成 0、运算默认 OP_ADD,是 CMonoid 构造函数里的设定。你在写自定义品种状态机时,若把 identity 错配成 1,HasInversion 会全盘误判——开 MT5 把 identity 改一下就能复现。

MQL5 / C++
EOperations Operation() { class="kw">return(operation); }

...

CMonoid(){ identity=class="num">0; operation=OP_ADD; };
~CMonoid(){};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Monoid Group Class                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">template <class="kw">typename T>
class CMonoidGroup : class="kw">public CMonoid<T>
  {
   class="kw">protected:

   class="kw">public:

   class="type">bool HasInversion()
     {  
      class="type">bool _has_inversion=true;

      for(class="type">int i=class="num">0;i<this.Cardinality();i++)
       {
        class="type">bool _has_inverse=false;

        for(class="type">int ii=class="num">0;ii<this.Cardinality();ii++)
        {
         if(Operate(i,ii)==Identity()){ _has_inverse=true; }
        }
        if(!_has_inverse){ _has_inversion=false; class="kw">break; }
       }
      class="kw">return(_has_inversion);
     }
  };

「用独异点群验证反转关系的代码落点」

上面这段 MT5 脚本把「有效反转组」和「无效反转组」各建了一个大小为 5 的独异点群(monoid group),权值分别设为 i-2 与 i,单位元索引都固定在 2。 调用 HasInversion() 时,若某元素在群运算(此处为加法)下找不到逆元,_has_inversion 会被置 false 并直接 break 退出。脚本末尾用 printf 输出两组的 HasInversion() 布尔值,并用 ArrayPrint 把权重数组原样打印出来,方便你对照哪一组存在反转结构。 在 MT5 里新建 EA 或脚本,把这段代码贴进 OnStart,编译后看日志:_vg 的权重是 -2,-1,0,1,2,关于单位元 2 做加法大概率能找到逆;_ig 权重 0~4 则倾向缺失逆元。外汇与贵金属市场波动剧烈、杠杆风险高,这类代数结构仅用于梳理价格序列的对称关系,不直接构成交易信号。

MQL5 / C++
if(!_has_inverse){ _has_inversion=false; class="kw">break; }
            }

            class="kw">return(_has_inversion);

      CMonoidGroup(){};
      ~CMonoidGroup(){};
   };
   CMonoidGroup<class="type">int> _vg;      class=class="str">"cmt">//valid inversion group
   CMonoidGroup<class="type">int> _ig;      class=class="str">"cmt">//invalid inversion group

   _vg.Weights(class="num">5);            class=class="str">"cmt">//set group size
   _ig.Weights(class="num">5);            class=class="str">"cmt">//set group size
   for(class="type">int i=class="num">0;i<class="num">5;i++)
   {
      CElement<class="type">int> _ve;_ve.Cardinality(class="num">1); _ve.Set(class="num">0,i-class="num">2);
      _vg.Set(i,_ve,true);      class=class="str">"cmt">//set element
      _vg.SetWeight(i,class="type">class="kw">double(i-class="num">2));  class=class="str">"cmt">//set weight

      CElement<class="type">int> _ie;_ie.Cardinality(class="num">1); _ie.Set(class="num">0,i);
      _ig.Set(i,_ie,true);      class=class="str">"cmt">//set element
      _ig.SetWeight(i,class="type">class="kw">double(i));   class=class="str">"cmt">//set weight
   }

   _vg.Operation(OP_ADD);      class=class="str">"cmt">//set monoid operation to add
   _vg.Identity(class="num">2);            class=class="str">"cmt">//set identity element index to class="num">2

   _ig.Operation(OP_ADD);      class=class="str">"cmt">//set monoid operation to add
   _ig.Identity(class="num">2);            class=class="str">"cmt">//set identity element index to class="num">2 as above or any index

   printf(" it is: "+class="type">class="kw">string(_vg.HasInversion())+", vg has inversion, given the weights. ");
   ArrayPrint(_vg.weights,class="num">0,",",class="num">0,WHOLE_ARRAY,ARRAYPRINT_LIMIT);

   printf(" it is: "+class="type">class="kw">string(_ig.HasInversion())+", ig has inversion, given the weights. ");
   ArrayPrint(_ig.weights,class="num">0,",",class="num">0,WHOLE_ARRAY,ARRAYPRINT_LIMIT);

◍ USDJPY 一分钟图上的权重反转日志

在 USDJPY.i 的 M1 周期上跑自定义指标 ct_10,日志会直接吐出两种反转判定。2023.06.16 17:17:41.817 这一次,vg 分支返回 true,说明按当前权重看 vg 出现了反转;ig 分支返回 false,表示 ig 在同样权重下未触发反转。 打印出的偏移序列也分两套:vg 命中时输出 -2, -1, 0, 1, 2,ig 未命中时输出 0, 1, 2, 3, 4。这两组数字就是指标内部对不同序列做加权后给出的相对位置窗口。 外汇与贵金属属高风险品种,这类反转信号只是概率倾向,不能直接当入场指令。开 MT5 把这段日志对应的 ct_10 挂到 USDJPY M1 上,比对 vg/ig 的 true/false 与偏移序列,能快速验证你手里的权重参数是否和原文一致。

MQL5 / C++
class="num">2023.06.class="num">16 class="num">17:class="num">17:class="num">41.817 ct_10(USDJPY.i,M1)it is: true, vg has inversion, given the weights.
class="num">2023.06.class="num">16 class="num">17:class="num">17:class="num">41.817 ct_10(USDJPY.i,M1)-class="num">2, -class="num">1,class="num">0,class="num">1,class="num">2
class="num">2023.06.class="num">16 class="num">17:class="num">17:class="num">41.817 ct_10(USDJPY.i,M1)it is: false, ig has inversion, given the weights.
class="num">2023.06.class="num">16 class="num">17:class="num">17:class="num">41.817 ct_10(USDJPY.i,M1) class="num">0,class="num">1,class="num">2,class="num">3,class="num">4
交给小布盯盘看盘口
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到幺半群逆反结构的实时标注,你专注决策。

常见问题

幺半群只需集合、衡点元素和封闭二元操作;幺半群组额外要求每个元素存在逆反项,配对输出恒为衡点,编码时需补 inverse 属性函数。
可以,小布盯盘对应品种页已内置该类 AIGC 标注,打开即可看到实时逆反项与衡点映射,省去手动推导。
通过引入逆反元素,原本封闭的决策池具备对称撤销能力,交易者在关键节点可依据逆反配对状态判断倾向反转的概率。
常对应'无偏向'或'中性基准',任何元素与衡点做二元操作都返回自身,可作为系统重置或观望的参考点。