MQL5 中的范畴论 (第 2 部分)·综合运用
🧮

MQL5 中的范畴论 (第 2 部分)·综合运用

(3/3)·从乘积余积到通用属性,把抽象公理落成 EURJPY 实测过的向导信号

新手友好 第 3/3 篇
把两个指标数值直接相加做信号,是多数 DIY EA 的常见写法,却悄悄丢掉了各自域的结构信息。范畴论的乘积和余积给出配对与求和的严格定义,避免把相关性误当成因果。外汇贵金属杠杆高,抽象建模只是降低盲区,不消除爆仓风险。

「监管标识分支里的映射计数逻辑」

这段片段在处理不同监管主体的资产属性时,先用 _product_all.universality.Morphisms() 做自增计数,再调用 _mm.Morph() 执行属性到锥体的映射,最后用 Morphisms()-1 回退计数并 Set。 当 _e_property.Get(0) 命中 China Securities Regulatory Commission (CSRC) 时,还会用 StringFind 检查 _e_cone 是否包含 Shanghai Stock Exchange (SSE)Shenzhen Stock Exchange (SZSE),索引 >=0 才进入内层同样的计数与映射流程。 对外汇与贵金属交易者而言,这类结构提醒我们:MT5 里自定义品种或跨市场映射若依赖监管标签分支,计数回退一旦漏写就可能让 universality 栈深度偏差,概率上引发后续信号过滤异常。 下面把第一段 CSRC 之外的通用分支原样拆开看:

MQL5 / C++
if(_product_all.universality.Morphisms(_product_all.universality.Morphisms()+class="num">1))
            {
              if(_mm.Morph(_product_all.class="kw">property,_product_all.cone,_e_property,_e_cone))
              {
                if(!_product_all.universality.Set(_product_all.universality.Morphisms()-class="num">1,_mm))
                {
                }
              }
            }
            }
            }
            else if(_e_property.Get(class="num">0)=="China Securities Regulatory Commission(CSRC)")
            {
              if(StringFind(_e_cone.Get(class="num">0),"Shanghai Stock Exchange(SSE)")>=class="num">0||StringFind(_e_cone.Get(class="num">0),"Shenzhen Stock Exchange(SZSE)")>=class="num">0)
              {
                if(_product_all.universality.Morphisms(_product_all.universality.Morphisms()+class="num">1))
                {
                  if(_mm.Morph(_product_all.class="kw">property,_product_all.cone,_e_property,_e_cone))
                  {
                    if(!_product_all.universality.Set(_product_all.universality.Morphisms()-class="num">1,_mm))
                    {
                    }
                  }
                }
              }
            }
            else if(_e_property.Get(class="num">0)=="Financial Services Agency(FSA)")
            {

◍ 按监管与交易所归属做产品映射

这段逻辑在做一件事:根据标的的监管属性和所在交易所,把外部产品对象塞进内部统一容器里。先判断交易所描述里是否含东京证交所(TSE)或大坂交易所(OSE),命中就走日本市场的分支。 日本分支里,先给 _product_all.universality 的 Morphisms 计数 +1,再调用 _mm.Morph 把属性与交易所上下文做一次变形映射;若 Set 回写失败(返回 false)则静默跳过,不抛异常。 德国分支走 BaFin 监管且交易所含 Eurex Exchange 的路径,结构与日本分支完全一致:Morphisms 自增、Morph 映射、失败静默。可见两套市场只是字符串常量不同,流程是同构的。 英国分支只写了 FCA 监管的入口判断,后续映射代码被截断;实盘接这套框架时,得自己补完 FCA 下的交易所匹配与 Morph 调用,否则 LSE 类标的会漏映射。外汇与贵金属品种若混进该容器,需先确认监管字段不为空,否则可能命中 else 空分支。

MQL5 / C++
if(StringFind(_e_cone.Get(class="num">0),"Tokyo Stock Exchange(TSE)")>=class="num">0||StringFind(_e_cone.Get(class="num">0),"Osaka Exchange(OSE)")>=class="num">0)
      {
         if(_product_all.universality.Morphisms(_product_all.universality.Morphisms()+class="num">1))
         {
            if(_mm.Morph(_product_all.class="kw">property,_product_all.cone,_e_property,_e_cone))
            {
               if(!_product_all.universality.Set(_product_all.universality.Morphisms()-class="num">1,_mm))
               {
               }
            }
         }
      }
      else if(_e_property.Get(class="num">0)=="Federal Financial Supervisory Authority(BaFin)")
      {
         if(StringFind(_e_cone.Get(class="num">0),"Eurex Exchange")>=class="num">0)
         {
            if(_product_all.universality.Morphisms(_product_all.universality.Morphisms()+class="num">1))
            {
               if(_mm.Morph(_product_all.class="kw">property,_product_all.cone,_e_property,_e_cone))
               {
                  if(!_product_all.universality.Set(_product_all.universality.Morphisms()-class="num">1,_mm))
                  {
                  }
               }
            }
         }
      }
      else if(_e_property.Get(class="num">0)=="Financial Conduct Authority(FCA)")
      {

从监管标识里拆出品种映射关系

这段逻辑干的事很直接:先拿字符串匹配抓出『London Stock Exchange (LSE)』,命中后才去动 universality 的计数与映射对象。外层用 StringFind 返回 >=0 判断包含关系,避免误判子串位置。 代码里 _product_all.universality.Morphisms() 先自增 1,再交给 _mm.Morph 去把属性与锥体做一次形变关联;成功后用 Set 把计数减 1 写回。这种加减配对是为了在嵌套遍历中标记『已处理』状态,防止同一条 LSE 记录被重复映射。 下面这段 2023.02.21 09:57:41 在 USDCHF.ln H1 上的日志,能验证上面的结构确实跑通了。universal property 打印出 5 个监管机构:CFTC、CSRC、FSA、BaFin、FCA;其中 CFTC 向下挂了 EURUSD 与 CBOE 的组合,并按 JAJO / FMAN / MJSD 三类交割月给出 1000 或 1250 points 的档位。 你在 MT5 里把这段脚本挂到任意货币对 H1 上,改掉 StringFind 里的交易所名,就能看到不同监管树下的品种—期权所—点位映射。外汇与贵金属杠杆高,这类结构映射只帮你看清合约关系,不预示任何方向。

MQL5 / C++
if(StringFind(_e_cone.Get(class="num">0),"London Stock Exchange(LSE)")>=class="num">0)
      {
         if(_product_all.universality.Morphisms(_product_all.universality.Morphisms()+class="num">1))
         {
            if(_mm.Morph(_product_all.class="kw">property,_product_all.cone,_e_property,_e_cone))
            {
               if(!_product_all.universality.Set(_product_all.universality.Morphisms()-class="num">1,_mm))
               {
               }
            }
         }
      }

「监管标签与合约月份如何被打印出来」

在 USDCHF.ln 的 H1 图表上跑 ct_3_1 这个脚本,会在 2023.02.21 09:57:41 同一毫秒内吐出一大串日志,把不同监管机构和交易所的合约映射关系直接打到专家日志里。 从日志看,CFTC 项下出现了 EURUSD 配 CBOE、USDJPY 配 CBOE 两类;月份代码分 MJSD(3/6/9/12月)、JAJO(1/4/7/10月)、FMAN(2/5/8/11月)三种,每个组合又各挂 1000 点与 1250 点两个档位。 CSRC 项下则把 EURUSD 分别映射到 SSE 与 SZSE,同样覆盖 JAJO、FMAN、MJSD 全部三个月份序列,且每序列都重复 1000 / 1250 点两档。这种成对输出说明脚本内部大概率用嵌套循环遍历「品种×交易所×月份×点数」四层结构。 开 MT5 把这段日志贴进观测窗口,重点看 09:57:41.077 到 .078 之间是否严格按「监管方→品种→交易所→月份→点数」顺序展开;若你本地只打印出部分行,可能是 SymbolSelect 没放行对应品种导致内层循环被跳过。外汇与贵金属杠杆交易高风险,这类映射仅作数据结构验证,不直接构成方向判断。

◍ 日志里炸出的日历价差组合

在 USDCHF.ln 的 H1 图表上跑 ct_3_1 脚本,2023.02.21 09:57:41.078 这一毫秒内连续吐出 15 条打印,全部带 CSRC 前缀和 -----> 箭头结构,说明脚本在单次 tick 里遍历了多组跨市场映射。 每条记录都是三层嵌套:外层是标的与交易所配对(如 EURUSD 配 SZSE、USDJPY 配 SSE/SZSE),中层是合约月份代码,内层是点数阈值。月份代码分三类——JAJO 覆盖 1/4/7/10 月,FMAN 覆盖 2/5/8/11 月,MJSD 覆盖 3/6/9/12 月。 点数阈值只出现 1000 和 1250 两档,且同一配对下两档紧挨着打印,疑似在测两个触发边界。外汇与贵金属本身高杠杆、高风险,这类映射若接实盘需先在策略测试器里核对交易所字段是否只是占位标签。 直接开 MT5 把这段日志贴进专家日志过滤器,搜 ct_3_1CSRC,能确认你的脚本是否也在无声无息中扫了 15 组组合;若只出几条,多半是品种池被券商白名单截断了。

监管映射日志里的跨市场合约信号

在 USDCHF.ln 的 H1 图表上跑 ct_3_1 专家,2023.02.21 09:57:41.078 这一毫秒内吐出了 17 条带监管标签的映射记录,全部由 CSRC 或 FSA 前缀引出,说明脚本把外汇品种和境外交易所合约做了瞬时关联。 日志结构很规律:每条都是「(监管机构)|---->(((外汇对),(交易所)),((合约代码-月份周期),(点数)))」。例如 USDJPY 被绑到 SZSE 的 MJSD 季度合约并标 1250 点,EURUSD 与 TSE/OSE 的 JAJO、FMAN、MJSD 三类月周期合约分别挂了 1000 点和 1250 点两档。 值得注意,同一外汇对+交易所+合约周期组合会出现 1000 与 1250 两个点数阈值,倾向意味着脚本在区分「触发线」和「确认线」两道过滤。外汇与贵金属本身高杠杆、高风险,这类跨市场映射只作关联参考,不预示任何价格方向。 直接在 MT5 终端打开 USDCHF.ln 的 H1 周期,把 ct_3_1 挂上跑一遍,搜 Expert 日志里的 FSA/CSRC 前缀,就能复现这 17 行原始输出,核对自己的环境是否一致。

「监管辖区与合约月份的关联输出」

上面这组日志来自一个在 USDCHF.ln 的 H1 周期上跑的 EA,打印时间是 2023.02.21 09:57:41.078,同一毫秒内连续吐出十几条记录,说明它是初始化阶段批量扫描出来的,不是逐根 K 线触发的。 每条记录的箭头左边是监管机构:日本金融厅(FSA)管到东京证交所(TSE)和大阪证交所(OSE)的日元相关标的,德国联邦金融监管局(BaFin)则指向 Eurex 的欧元、美元品种。箭头右边是「合约代码 + 月份组 + 点数阈值」三元组,比如 JAJO 对应 1/4/7/10 月,FMAN 对应 2/5/8/11 月,MJSD 对应 3/6/9/12 月,阈值只有 1000 和 1250 两档。 从数据能直接读出规律:同一交易所同一月份组,必然成对出现 1000 与 1250 两个阈值——这大概率是测试小参数档和大参数档。外汇与贵金属受多国监管,跨所套利或跨月对冲策略的高风险在于,不同辖区保证金与交割规则可能突变,阈值本身不构成任何方向判断。 开 MT5 把这段日志贴进专家日志比对,重点看自己 EA 是否在 OnInit 里用循环把监管映射表一次性 dump 出来;若你只看到单条记录,说明映射表没建全,可能漏掉 OSE 或 Eurex 的某个月份组。

◍ 监管映射下的跨市场交割阈值

在 USDCHF.ln 的 H1 图表上跑 ct_3_1 脚本,日志会把「监管机构—标的—交易所—季月代码—点数阈值」这条链直接打印出来。2023.02.21 09:57:41 这一秒内,BaFin 名下出现了 USDJPY 对 Eurex 的 5 组映射,FCA 名下则有 EURUSD、USDJPY 对 LSE 的 10 组映射,说明同一脚本能按监管域切分不同的品种权限。 季月代码沿用了期货惯例:JAJO 覆盖 1/4/7/10 月,FMAN 覆盖 2/5/8/11 月,MJSD 覆盖 3/6/9/12 月。每个季月组都挂了 1000 点与 1250 点两档阈值,BaFin 的 JAJO 组只给 1250 点一档,是个例外。 这种打印结构对实盘的意义在于:你可以用它快速核对某监管机构下哪些货币对允许在哪个交易所通道交易,以及该通道的波动容差是多少。外汇与贵金属本身杠杆高、跳空频繁,1250 点阈值在 USDJPY 上可能只是单日常态波动,照搬阈值做止损容易被动挨打。 开 MT5 把这段日志对应的脚本挂到任意 ln 品种 H1 周期,搜自己关心的监管缩写,就能知道当前环境给你开了哪些跨市场交割口子。

用域乘积拼出跨品种对冲结构

日志里那串 2023.02.21 09:57:41.079 的输出,本质是把 USDJPY 与 LSE、MJSD 合约(3/6/9/12 月、1250 点)绑成一条关系链;同帧还展开 EURUSD 在 CBOE 的 JAJO(1/4/7/10 月)与 FMAN(2/5/8/11 月)各 1000、1250 点四组组合。这说明多品种策略在 MT5 里不是拍脑袋写死,而是先定义「域」再算「乘积」。 下面这段 EX no.2 用 CDomain<string> 与 CElement<string> 把对冲、覆盖、仓位三类货币对分别建域:hedge 放 EURUSD、GBPUSD 两个;cover 放 USDCHF、USDJPY 两个;postion 放 EURCHF、EURJPY、GBPCHF、GBPJPY 四个。Cardinality 就是该域元素个数,Set 负责把具体品种塞进下标位置。 [CODE] //////////////////////////// //PRODUCT UNIVERSAL-PROPERTY //////////////////////////// //EX no.2 CDomain<string> _d_hedge,_d_cover,_d_postion,_d_p2_property; // CElement<string> _ep2;_ep2.Cardinality(1); // _d_hedge.Cardinality(2); _ep2.Set(0,"EURUSD");_d_hedge.Set(0,_ep2,true); _ep2.Set(0,"GBPUSD");_d_hedge.Set(1,_ep2,true); // _d_cover.Cardinality(2); _ep2.Set(0,"USDCHF");_d_cover.Set(0,_ep2,true); _ep2.Set(0,"USDJPY");_d_cover.Set(1,_ep2,true); // _d_postion.Cardinality(4); _ep2.Set(0,"EURCHF");_d_postion.Set(0,_ep2,true); _ep2.Set(0,"EURJPY");_d_postion.Set(1,_ep2,true); _ep2.Set(0,"GBPCHF");_d_postion.Set(2,_ep2,true); _ep2.Set(0,"GBPJPY");_d_postion.Set(3,_ep2,true); // printf(__FUNCSIG__+" hedge domain: "+PrintDomain(_d_hedge,0)); printf(__FUNCSIG__+" cover domain: "+PrintDomain(_d_cover,0)); printf(__FUNCSIG__+" postion domain: "+PrintDomain(_d_postion,0)); CProduct _product_hc; GetProduct(_d_hedge,_d_cover,_product_hc,0); printf(__FUNCSIG__+" hedge & cover product: "+PrintDomain(_product_hc.cone,0)); CProduct _product_hcp; GetProduct(_product_hc.cone,_d_postion,_product_hcp,0); printf(__FUNCSIG__+" hedge & cover & postion product: "+PrintDomain(_product_hcp.cone,0)); // [/CODE] 逐行看:前几行注释标明这是「产品通用属性」示例;CElement 设基数 1,即单值元素。_d_hedge 基数 2,先后写入 EURUSD、GBPUSD。_d_cover 同理写 USDCHF、USDJPY。_d_postion 基数 4,把四个交叉盘塞满。三个 printf 把域打印出来,方便在专家日志里肉眼核对。 GetProduct 做笛卡尔积:先 hedge×cover 得 _product_hc,再乘 postion 得 _product_hcp,cone 里就是 2×2×4 = 16 种组合。外汇与贵金属杠杆高、滑点跳空频繁,这种结构只是把组合空间列清楚,实盘触发哪一组仍取决于你的价格行为信号,概率上偏多不代表稳。 开 MT5 把这段代码丢进 EA 的 OnStart,把 PrintDomain 输出贴到表格,就能确认自己策略覆盖的货币对组合是否漏了 GBP 系——漏了就可能在对冲环上断一条边。

MQL5 / C++
class=class="str">"cmt">////////////////////////////
class=class="str">"cmt">//PRODUCT UNIVERSAL-PROPERTY
class=class="str">"cmt">////////////////////////////

class=class="str">"cmt">//EX no.class="num">2

CDomain<class="type">class="kw">string> _d_hedge,_d_cover,_d_postion,_d_p2_property;
class=class="str">"cmt">//
CElement<class="type">class="kw">string> _ep2;_ep2.Cardinality(class="num">1);
class=class="str">"cmt">//
_d_hedge.Cardinality(class="num">2);
_ep2.Set(class="num">0,"EURUSD");_d_hedge.Set(class="num">0,_ep2,true);
_ep2.Set(class="num">0,"GBPUSD");_d_hedge.Set(class="num">1,_ep2,true);
class=class="str">"cmt">//
_d_cover.Cardinality(class="num">2);
_ep2.Set(class="num">0,"USDCHF");_d_cover.Set(class="num">0,_ep2,true);
_ep2.Set(class="num">0,"USDJPY");_d_cover.Set(class="num">1,_ep2,true);
class=class="str">"cmt">//
_d_postion.Cardinality(class="num">4);
_ep2.Set(class="num">0,"EURCHF");_d_postion.Set(class="num">0,_ep2,true);
_ep2.Set(class="num">0,"EURJPY");_d_postion.Set(class="num">1,_ep2,true);
_ep2.Set(class="num">0,"GBPCHF");_d_postion.Set(class="num">2,_ep2,true);
_ep2.Set(class="num">0,"GBPJPY");_d_postion.Set(class="num">3,_ep2,true);
class=class="str">"cmt">//
printf(__FUNCSIG__+" hedge domain: "+PrintDomain(_d_hedge,class="num">0));
printf(__FUNCSIG__+" cover domain: "+PrintDomain(_d_cover,class="num">0));
printf(__FUNCSIG__+" postion domain: "+PrintDomain(_d_postion,class="num">0));

CProduct _product_hc;

GetProduct(_d_hedge,_d_cover,_product_hc,class="num">0);
printf(__FUNCSIG__+" hedge & cover product: "+PrintDomain(_product_hc.cone,class="num">0));

CProduct _product_hcp;

GetProduct(_product_hc.cone,_d_postion,_product_hcp,class="num">0);
printf(__FUNCSIG__+" hedge & cover & postion product: "+PrintDomain(_product_hcp.cone,class="num">0));
class=class="str">"cmt">//

「八组货币对的 ATR 域一次性灌入」

做跨品种波动率扫描时,先把 EURUSD、GBPUSD、USDCHF、USDJPY、EURCHF、EURJPY、GBPCHF、GBPJPY 这 8 个直盘/交叉盘的 ATR 值收进各自的 CDomain<double> 容器,每条记录只留 1 个基数(Cardinality(1)),相当于给后面比对留了单值槽位。 ATR 句柄用 iATR 按当前周期 _Period 和宏 __product_size 去取,8 行连续声明,没有循环封装,属于硬编码但跑起来直观。外汇与贵金属波动受杠杆与消息面影响大,这类多品种同步读取在高波动时段可能触发重算延迟,需自行在 MT5 里观察终端日志。 FillDomain 把最新一根 K 线的 ATR 填进域,8 个调用用 && 串起来,任一失败就整体跳过。成功后从各域 Get(0) 取元素,再拼成 "EURUSD的ATR,EURCHF的ATR,GBPCHF的ATR" 这种定点 3 位小数的字符串塞进属性容器——这套结构让你在 EA 面板里一眼看到欧系三组的实时波动刻度。

MQL5 / C++
CDomain<class="type">class="kw">double> _d_p2_eu,_d_p2_gu,_d_p2_uc,_d_p2_uj,_d_p2_ec,_d_p2_ej,_d_p2_gc,_d_p2_gj;
_d_p2_eu.Cardinality(class="num">1);_d_p2_gu.Cardinality(class="num">1);_d_p2_uc.Cardinality(class="num">1);_d_p2_uj.Cardinality(class="num">1);
_d_p2_ec.Cardinality(class="num">1);_d_p2_ej.Cardinality(class="num">1);_d_p2_gc.Cardinality(class="num">1);_d_p2_gj.Cardinality(class="num">1);

class="type">int _eu_handle=iATR("EURUSD",_Period,__product_size);
class="type">int _gu_handle=iATR("GBPUSD",_Period,__product_size);
class="type">int _uc_handle=iATR("USDCHF",_Period,__product_size);
class="type">int _uj_handle=iATR("USDJPY",_Period,__product_size);
class="type">int _ec_handle=iATR("EURCHF",_Period,__product_size);
class="type">int _ej_handle=iATR("EURJPY",_Period,__product_size);
class="type">int _gc_handle=iATR("GBPCHF",_Period,__product_size);
class="type">int _gj_handle=iATR("GBPJPY",_Period,__product_size);

if
(
FillDomain(_d_p2_eu,class="num">0,class="num">1,_eu_handle)
&&
FillDomain(_d_p2_gu,class="num">0,class="num">1,_gu_handle)
&&
FillDomain(_d_p2_uc,class="num">0,class="num">1,_uc_handle)
&&
FillDomain(_d_p2_uj,class="num">0,class="num">1,_uj_handle)
&&
FillDomain(_d_p2_ec,class="num">0,class="num">1,_ec_handle)
&&
FillDomain(_d_p2_ej,class="num">0,class="num">1,_ej_handle)
&&
FillDomain(_d_p2_gc,class="num">0,class="num">1,_gc_handle)
&&
FillDomain(_d_p2_gj,class="num">0,class="num">1,_gj_handle)
)
{
  CElement<class="type">class="kw">double> _e_eu,_e_gu,_e_uc,_e_uj,_e_ec,_e_ej,_e_gc,_e_gj;
  class=class="str">"cmt">//
  if
  (
  _d_p2_eu.Get(class="num">0,_e_eu) && _d_p2_gu.Get(class="num">0,_e_gu) &&
  _d_p2_uc.Get(class="num">0,_e_uc) && _d_p2_uj.Get(class="num">0,_e_uj) &&
  _d_p2_ec.Get(class="num">0,_e_ec) && _d_p2_ej.Get(class="num">0,_e_ej) &&
  _d_p2_gc.Get(class="num">0,_e_gc) && _d_p2_gj.Get(class="num">0,_e_gj)
  )
  {
    _d_p2_property.Cardinality(class="num">4);
    _ep2.Set(class="num">0,DoubleToString(_e_eu.Get(class="num">0),class="num">3)+","+DoubleToString(_e_uc.Get(class="num">0),class="num">3)+","+DoubleToString(_e_ec.Get(class="num">0),class="num">3));_d_p2_property.Set(class="num">0,_ep2,true);

◍ 把货币对三元组塞进属性表

这段逻辑干的事很直接:把三组交叉汇率的实时值拼成逗号分隔字符串,写进属性对象的对应槽位。第一组是 GBPUSD、EURUSD、EURGBP 各取三位小数,挂到索引 1;第二组 EURUSD、USDJPY、EURJPY 挂索引 2;第三组 GBPUSD、USDJPY、GBPJPY 挂索引 3。 _ep2.Set(0, ...) 每次重用一个临时元素,把 DoubleToString(...,3) 的结果拼起来,再交给 _d_p2_property.Set(槽位,_ep2,true) 落地。注意第三个参数 true 代表触发更新通知,MT5 里若绑了界面控件会立刻重绘。 属性表填完之后,代码把 property 赋给 product_hcp 的 universality.domain,codomain 接上 cone,相当于声明了从属性集到锥集的映射关系。随后建了一个 CMorphism<string,string> 的 _m_p2 做同样的 domain/codomain 绑定,为后面的遍历匹配铺路。 真正跑匹配的是那个双层 for:外层扫 property 的每个元素,内层扫 cone 的每个元素,都跳过空串。当 c==0 时,检查 cone 元素里是否同时含 EURUSD、USDCHF、EURCHF 三个子串——这意味着属性索引 0 对应的三元组,只在锥集出现完整欧元交叉链时才算命中。外汇与贵金属市场波动剧烈,这类字符串匹配仅作结构演示,实盘信号需自行验证。

MQL5 / C++
_ep2.Set(class="num">0,DoubleToString(_e_gu.Get(class="num">0),class="num">3)+","+DoubleToString(_e_uc.Get(class="num">0),class="num">3)+","+DoubleToString(_e_gc.Get(class="num">0),class="num">3));_d_p2_property.Set(class="num">1,_ep2,true);
_ep2.Set(class="num">0,DoubleToString(_e_eu.Get(class="num">0),class="num">3)+","+DoubleToString(_e_uj.Get(class="num">0),class="num">3)+","+DoubleToString(_e_ej.Get(class="num">0),class="num">3));_d_p2_property.Set(class="num">2,_ep2,true);
_ep2.Set(class="num">0,DoubleToString(_e_gu.Get(class="num">0),class="num">3)+","+DoubleToString(_e_uj.Get(class="num">0),class="num">3)+","+DoubleToString(_e_gj.Get(class="num">0),class="num">3));_d_p2_property.Set(class="num">3,_ep2,true);
class=class="str">"cmt">//
_product_hcp.class="kw">property=_d_p2_property;
class=class="str">"cmt">//
_product_hcp.universality.domain=_product_hcp.class="kw">property;
_product_hcp.universality.codomain=_product_hcp.cone;
class=class="str">"cmt">//
CMorphism<class="type">class="kw">string,class="type">class="kw">string> _m_p2;
_m_p2.domain=_product_hcp.class="kw">property;
_m_p2.codomain=_product_hcp.cone;
class=class="str">"cmt">//

for(class="type">int c=class="num">0;c<_product_hcp.class="kw">property.Cardinality();c++)
{
  CElement<class="type">class="kw">string> _e_property;_e_property.Cardinality(class="num">1);
  if(_product_hcp.class="kw">property.Get(c,_e_property) && _e_property.Get(class="num">0)!="")
  {
    for(class="type">int cc=class="num">0;cc<_product_hcp.cone.Cardinality();cc++)
    {
      CElement<class="type">class="kw">string> _e_cone;_e_cone.Cardinality(class="num">1);
      if(_product_hcp.cone.Get(cc,_e_cone) && _e_cone.Get(class="num">0)!="")
      {
        if(c==class="num">0)
        {
          if(StringFind(_e_cone.Get(class="num">0),"EURUSD")>=class="num">0&&StringFind(_e_cone.Get(class="num">0),"USDCHF")>=class="num">0&&StringFind(_e_cone.Get(class="num">0),"EURCHF")>=class="num">0)

三元货币对的态射写入判定

这段逻辑在对象范畴里处理两种分支:默认情形与 c==1 的指定筛选情形。核心动作都是先给 universality 的 Morphisms 计数 +1,再尝试用 _m_p2.Morph 把 product 与传入的 property、cone 做态射绑定。 若 Morph 成功,则把结果通过 universality.Set 写回,且 Morphisms 计数 -1。注意 Set 返回 false 时这里留了空块,意味着写入失败仅跳过、不抛错,实盘跑时可能漏掉一次配对。 c==1 分支额外用 StringFind 对 _e_cone.Get(0) 做字符串包含判断,必须同时命中 GBPUSD、USDCHF、GBPCHF 三个符号才进入态射流程。外汇与贵金属属高风险品种,这类硬编码品种组合在跨周期回测中可能因点差跳变而概率性失效。 把下面代码直接贴进 MT5 的 EA 调试片段,改 _e_cone 的入参即可观察 Morphisms 计数增减是否符合预期。

MQL5 / C++
{
   if(_product_hcp.universality.Morphisms(_product_hcp.universality.Morphisms()+class="num">1))
   {
      if(_m_p2.Morph(_product_hcp.class="kw">property,_product_hcp.cone,_e_property,_e_cone))
      {
         if(!_product_hcp.universality.Set(_product_hcp.universality.Morphisms()-class="num">1,_m_p2))
         {
         }
      }
   }
}
            else if(c==class="num">1)
            {
               if(StringFind(_e_cone.Get(class="num">0),"GBPUSD")>=class="num">0&&StringFind(_e_cone.Get(class="num">0),"USDCHF")>=class="num">0&&StringFind(_e_cone.Get(class="num">0),"GBPCHF")>=class="num">0)
               {
                  if(_product_hcp.universality.Morphisms(_product_hcp.universality.Morphisms()+class="num">1))
                  {
                     if(_m_p2.Morph(_product_hcp.class="kw">property,_product_hcp.cone,_e_property,_e_cone))
                     {
                        if(!_product_hcp.universality.Set(_product_hcp.universality.Morphisms()-class="num">1,_m_p2))
                        {
                        }
                     }
                  }
               }
            }

「三角货币对的态射触发条件」

这段逻辑处理的是跨品种关联下的态射(Morph)写入:当计数器 c 走到 2,先检查事件锥首元素是否同时包含 EURUSD、USDJPY、EURJPY 三个字符串,三者齐全才进入通用性计数加一的分支。 若通用性 Morphisms 自增成功,再调用 _m_p2.Morph 把产品属性与事件锥做一次映射;映射返回真时,又把通用性计数减一并尝试用 _m_p2 写回 Set。外汇与贵金属属高风险品种,这类关联判定在实盘可能受报价延迟干扰,验证时建议先开 MT5 用 EUR 相关符号跑一遍。 c==3 的分支结构完全一致,只是把符号换成 GBPUSD、USDJPY、GBPJPY,说明框架把英镑三角和欧元三角当作同类拓扑来处理,没有额外硬编码差异。

MQL5 / C++
    }
          }
          else if(c==class="num">2)
          {
             if(StringFind(_e_cone.Get(class="num">0),"EURUSD")>=class="num">0&&StringFind(_e_cone.Get(class="num">0),"USDJPY")>=class="num">0&&StringFind(_e_cone.Get(class="num">0),"EURJPY")>=class="num">0)
             {
               if(_product_hcp.universality.Morphisms(_product_hcp.universality.Morphisms()+class="num">1))
               {
                 if(_m_p2.Morph(_product_hcp.class="kw">property,_product_hcp.cone,_e_property,_e_cone))
                 {
                   if(!_product_hcp.universality.Set(_product_hcp.universality.Morphisms()-class="num">1,_m_p2))
                   {
                   }
                 }
               }
             }
          }
          else if(c==class="num">3)
          {
             if(StringFind(_e_cone.Get(class="num">0),"GBPUSD")>=class="num">0&&StringFind(_e_cone.Get(class="num">0),"USDJPY")>=class="num">0&&StringFind(_e_cone.Get(class="num">0),"GBPJPY")>=class="num">0)
             {
               if(_product_hcp.universality.Morphisms(_product_hcp.universality.Morphisms()+class="num">1))
               {

◍ 通用属性打印与叉积映射实证

在范畴化汇率对的处理里,真正落地的是把构造好的通用态射(universality)打印出来核对。下面这段逻辑先尝试对二元积对象做态射变形,成功后才把计数减一的态射写回通用属性数组,空分支意味着写回失败也不阻断后续诊断。 [CODE] if(_m_p2.Morph(_product_hcp.property,_product_hcp.cone,_e_property,_e_cone)) { if(!_product_hcp.universality.Set(_product_hcp.universality.Morphisms()-1,_m_p2)) { } } printf(__FUNCSIG__+" universal property hcp: "+PrintHomomorphism(_product_hcp.universality,0)); [/CODE] 代码逐行拆解:第1行判定 _m_p2 能否把积对象的 property/cone 映射到目标 _e_property/_e_cone;第3行把通用态射集中倒数第1个位置替换为 _m_p2,返回 false 代表替换未生效;第7行用 printf 把整个通用同态结构序列化到日志,便于肉眼比对。 实盘日志(USDCHF.ln H1,2023.02.21 20:21:53.614)显示,通用属性集包含4条映射:前两条权重向量为 (0.002,0.001,0.001) 与 (0.002,0.001,0.002),分别把 ((EURUSD),(USDCHF)) 引向 (EURCHF)、((GBPUSD),(USDCHF)) 引向 (GBPCHF);后两条权重跳到 (0.002,0.145,0.189) 和 (0.002,0.145,0.258),对应 ((EURUSD),(USDJPY))→(EURJPY) 与 ((GBPUSD),(USDJPY))→(GBPJPY)。 权重从 0.001 级跃到 0.145 级,说明 JPY 交叉对的态射成本显著高于 CHF 交叉对,这在做多币种协整组合时可能影响对冲比例。外汇与贵金属属高风险品种,上述权重仅来自单次 H1 快照,换周期或换货币对倾向出现结构漂移,建议自己开 MT5 跑同段代码验证。

MQL5 / C++
if(_m_p2.Morph(_product_hcp.class="kw">property,_product_hcp.cone,_e_property,_e_cone))
{
  if(!_product_hcp.universality.Set(_product_hcp.universality.Morphisms()-class="num">1,_m_p2))
  {
  }
}
printf(__FUNCSIG__+" universal class="kw">property hcp: "+PrintHomomorphism(_product_hcp.universality,class="num">0));

三货币嵌套组合的日志实样

下面这条 MT5 日志来自 USDCHF.ln 的 H1 图表,时间戳为 2023.02.21 20:21:53.614,打印的是 ct_3_1 指标识别出的三货币嵌套组合集合。 从输出看,组合以「两货币对构成基底、再叠一个交叉盘」的嵌套结构出现,例如 (((EURUSD),(USDCHF)),(GBPJPY)) 表示用 EURUSD 与 USDCHF 作底层、再关联 GBPJPY。一共列出了 16 组,覆盖了 EURUSD/USDCHF、EURUSD/USDJPY、GBPUSD/USDCHF、GBPUSD/USDJPY 四类基底,各自挂接 GBPJPY、GBPCHF、EURJPY、EURCHF 四个交叉盘。 这类日志价值在于:你能在 MT5 终端直接翻 Expert/Journal 标签核对同样时间戳下的组合数量,验证自己的指标是否漏算或重复。外汇与贵金属属高风险品种,组合相关性随流动性切换会变形,日志只能反映当时盘面,不能当作恒定规律。

MQL5 / C++
class="num">2023.02.class="num">21 class="num">20:class="num">21:class="num">53.614 ct_3_1(USDCHF.ln,H1)   {(((EURUSD),(USDCHF)),(GBPJPY)),(((EURUSD),(USDCHF)),(GBPCHF)),(((EURUSD),(USDCHF)),(EURJPY)),(((EURUSD),(USDCHF)),(EURCHF)),(((EURUSD),(USDJPY)),(GBPJPY)),(((EURUSD),(USDJPY)),(GBPCHF)),(((EURUSD),(USDJPY)),(EURJPY)),(((EURUSD),(USDJPY)),(EURCHF)),(((GBPUSD),(USDCHF)),(GBPJPY)),(((GBPUSD),(USDCHF)),(GBPCHF)),(((GBPUSD),(USDCHF)),(EURJPY)),(((GBPUSD),(USDCHF)),(EURCHF)),(((GBPUSD),(USDJPY)),(GBPJPY)),(((GBPUSD),(USDJPY)),(GBPCHF)),(((GBPUSD),(USDJPY)),(EURJPY)),(((GBPUSD),(USDJPY)),(EURCHF))}

「用余积给多资产组合估个保守值」

范畴论里的余积,本质是把两个结构 A 和 B 拼成第三个结构 C,使得 C 代表「从 A 或 B 里选一个」的替代行为,而不是像乘积那样代表「A 和 B 同时持有」。它满足结合律、交换律,且 A+0 同构于 A、A+1 同构于 1,数学上是个最小上界式的余限。 放到交易组合里,余积可以当一种低波动估值口径:两个数值的余积直接取最大值,而不是相加。假设股票现值 50 美元、债券现值 100 美元,余积就是 max(50,100)=100 美元,意味着无论行情怎么走,组合底值至少 100 美元。 若股票涨到 60 美元而债券不动,余积值变为 110 美元,比单持任一资产都高,但明显低于总和 160 美元;若债券跌到 90 美元、股票不动,余积仍为 100 美元,高于 50 或 90,也低于 140 的总和。外汇与贵金属组合同理,这类品种杠杆高、跳空频繁,用余积视角可压低对价格极端叠加的误判概率。 这种算法不预言收益,只提供比简单加总更保守的敞口下限。实盘里你可以把持仓标的的实时报价接进 MT5 自定义指标,用 MathMax 取两两余积,观察组合「替代持有」下的缓冲带宽度。

◍ 用余积泛性质锁定组合选择的唯一性

在范畴论里,余积的通用属性(泛性质)说的是:只要示意图在同构意义下可交换,那个从余积到任意对象 Z 的唯一态射就确定下来。放到多资产组合里,这意味着「股票、债券、REIT 三选一」这种结构,在换一种等价表示时本质不变,我们可以用它做更干净的推理。 举个具体例子:股票 50 美元、债券 100 美元、REIT 150 美元,把组合看成这三者的余积。若各自风险独立,股票 10%、债券 5%、REIT 8%,联合风险按余积取最大值处理就是 10%。这是一个可直接在表格里验算的数字。 泛性质真正有用之处在相关性假设切换。若股票与 REIT 风险正相关,泛性质允许我们推断:联合风险会高于个人风险的最大值 10%,因为示意图里的态射不再保持独立叠加。外汇与贵金属组合同理,但杠杆与跳空会让相关性突变,属高风险场景,结论只作概率性参考。 开 MT5 自己搭个三类资产权重表,把相关性矩阵从 0 调到 0.8,看组合回撤是否突破单资产最大风险线,就能验证这套泛性质推演。

把范畴结构接进 EA 才是真落地

乘积和余积在 MQL5 里不是数学摆设。用 CTrade 同时开 EURUSD 和 XAUUSD 的多单,就是在实例层构造一个乘积对象;当两者价差突破 200 点后平仓其一,相当于对余积做模式匹配。外汇和贵金属杠杆高,这类联合持仓在美联储议息夜可能双向扫损,先开模拟账户验证再上真金。 附件里 ct_3_1.mq5 有 96.41 KB,SignalCT3.mqh 是 10.76 KB,直接拖进 MT5 的 MQL5/Include 和 Scripts 就能编译。极限和共限的抽象层帮你把多周期风控写成通用函数,而不是每个品种重写一遍。 写完了,下一步就是改 SignalCT3.mqh 里的权重参数,看回测曲线会不会更平。

交给小布盯盘看盘口
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到 DeMarker 与 WPR 的实时域态射变化,你专注决定是否采信乘积信号。

常见问题

在信号文件里定义两域各自的多空态射,再按 A×B 有序对保留成分信息后相加,净结果映射为典型买入卖出函数。
小布盯盘内置了指标域可视化,可对照文中 EURJPY 的跳价测试思路自行验证,但不代你下单。
乘积保留配对不丢信息,适合并发条件;余积做 tagged union 式合并,适合互斥分支,两者通用属性相反。
说明接一个恒等域不改变系统行为,可安全插入日志或风控态射而不破坏原信号结构。
可看成唯一桥梁条件:所有其他态射都得穿过它,写代码时即最小化冗余映射的约束。