交易策略中的模糊逻辑·综合运用
反手与裸开仓的信号分支
这段逻辑处理的是持仓反转与无仓直接开仓两类情形。当检测到一笔卖单且 TradeSignal 降至 MaxNeutralSignal 以下时,先按红价平掉该卖单,随后若信号进一步跌破 MinNeutralSignal,则通过 LotsOptimized() 重算手数并以 OP_BUY 在 Ask 价反向开多。 无持仓时的入口更直白:信号低于 MinNeutralSignal 且 CheckMoneyForTrade 校验通过,就买;高于 MaxNeutralSignal 且资金校验通过,就卖。两个 OrderSend 的滑点、止损、止盈参数都传了 0,说明这套框架默认不挂防护单,外汇与贵金属的高波动下可能迅速放大回撤。 镜像处理卖单的部分,原文注释明确写的是「与多头仓位一样,但所有条件都是镜像的」。你在 MT5 里跑这段代码时,可以把 MinNeutralSignal / MaxNeutralSignal 两个阈值打印到日志,观察实盘信号在中性带里的停留时长。
}
}
}
if(OrderType()==OP_SELL && TradeSignal<=MaxNeutralSignal) class=class="str">"cmt">// 选择一笔卖单....///.... 与多头仓位一样, 但所有条件都是镜像的
{
if(OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),class="num">0,Red))
{
if(TradeSignal<MinNeutralSignal)
{
lots = LotsOptimized();
if(OrderSend(Symbol(),OP_BUY,lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK),class="num">0,class="num">0,class="num">0,NULL,OrderMagic,Green)){
};
}
}
}
}
}
class="kw">return;
class=class="str">"cmt">// 如果没有持仓, 根据信号开仓
lots = LotsOptimized();
if(TradeSignal<MinNeutralSignal && CheckMoneyForTrade(_Symbol,lots,ORDER_TYPE_BUY))
{
if(OrderSend(Symbol(),OP_BUY,lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK),class="num">0,class="num">0,class="num">0,NULL,OrderMagic,Green)){
};
}
else if(TradeSignal>MaxNeutralSignal && CheckMoneyForTrade(_Symbol,lots,ORDER_TYPE_SELL))
{
if(OrderSend(Symbol(),OP_SELL,lots,SymbolInfoDouble(_Symbol,SYMBOL_BID),class="num">0,class="num">0,class="num">0,NULL,OrderMagic,Red)){
};
}
class="kw">return;
「M15与M5双周期下的高斯优化实测」
系统先用 M15 周期、跨度 8 个月的历史数据跑优化,价格取开盘价,遗传算法选快速模式,优化准则设为余额加最大利润。从遗传输出里挑出最佳参数组,再丢进严格模型回测做对照,观察成员函数输出在优化前后的偏移。 同样设置换到 M5 重跑一遍,只是周期缩到五分钟,其余不变。两轮结果都出现一个现象:高斯中性区明显偏向买入侧,多头持仓数压过空头,说明这段历史里买卖信号本身不对称,不跑这组实验根本看不出来。 由三个 RSI 拼成的系统,超卖区(区域1)的出现频次可能高于超买区(区域0),而高斯优化能把这种倾斜抹平。即便只动了 4 个参数,8 个月内 equity 曲线也还算稳,其中 Gsigma 和 Gposition 是核心,另两个总在 0.5 附近晃,基本可砍掉只留两个。 对比严格规则系统动辄要建一堆优化标准、参数越加越多,模糊逻辑这条路反而能把待调维度压下来。当然这只是一个粗样:底层是裸 RSI 策略、没接止损,外汇和贵金属这种高波动品种直接照搬风险很大,但用来摸清模糊模块怎么嵌进 EA 足够了。
◍ 把模糊系统从单输出扩成三路委员会
原文收尾处提到一个可自学的改进方向:用多个模糊模型组成委员会,分别负责交易系统的不同层面。给出的代码片段正是一个把 RSI、CCI、随机指标各拆成独立模糊系统的雏形——九个输入术语分三组塞进 Inputs 列表,但 Output 仍只取 FuzzResult 的第 0 个节点,注释里明写「需要更新,以考虑三个而不是一个输出」。 这段实现暴露了单输出架构的硬限制:当您想并行跑三套模糊逻辑(例如 RSI 管超买超卖、CCI 管趋势强度、Stochastic 管反转概率),去模糊化后必须自己加权汇总,而不是直接拿一个清晰值下单。外汇与贵金属市场的高波动下,这种多模型投票比单模型更抗过拟合,但权重分配本身又引入新参数维度。 实操上,您可以把三路输出各自归一到 0–10,再按历史样本回测分配权重(比如 RSI 路 0.4、CCI 路 0.35、Stochastic 路 0.25),总分明低于 3 倾向观望、高于 7 才触发。注意 MT5 编译前需自备 MT4Orders 与 Fuzzy 函数库,否则 hnd1–hnd9 的句柄会全部失效。 别把正态当圣经 原文用「在家看电影/聚会/打怪」比喻模糊推论,本质是说人类决策本就是概率化的。直接搬进 EA 时,记得把「绝对不」这类清晰边界改成隶属度截断,否则小样本里容易误杀有效信号。
class="type">class="kw">double CalculateMamdani() { class=class="str">"cmt">// 缓冲区和数组正常化 class="type">class="kw">double CalculateMamdani() { class=class="str">"cmt">// 缓冲区和数组正常化 CopyBuffer(hnd1,class="num">0,class="num">0,class="num">1,arr1); NormalizeArrays(arr1); CopyBuffer(hnd2,class="num">0,class="num">0,class="num">1,arr2); NormalizeArrays(arr2); CopyBuffer(hnd3,class="num">0,class="num">0,class="num">1,arr3); NormalizeArrays(arr3); CopyBuffer(hnd4,class="num">0,class="num">0,class="num">1,arr4); NormalizeArrays(arr4); CopyBuffer(hnd5,class="num">0,class="num">0,class="num">1,arr5); NormalizeArrays(arr5); CopyBuffer(hnd6,class="num">0,class="num">0,class="num">1,arr6); NormalizeArrays(arr6); CopyBuffer(hnd7,class="num">0,class="num">0,class="num">1,arr7); NormalizeArrays(arr7); CopyBuffer(hnd8,class="num">0,class="num">0,class="num">1,arr8); NormalizeArrays(arr8); CopyBuffer(hnd9,class="num">0,class="num">0,class="num">1,arr9); NormalizeArrays(arr9); class=class="str">"cmt">// 输入 - 第一个模糊系统 [RSI] firstTerm.SetAll(firstInput,arr1[class="num">0]); secondTerm.SetAll(secondInput,arr2[class="num">0]); thirdTerm.SetAll(thirdInput,arr2[class="num">0]); class=class="str">"cmt">// 输入 - 第二模糊系统 [CCI]] fourthTerm.SetAll(fourthInput,arr4[class="num">0]); fifthTerm.SetAll(fifthInput,arr5[class="num">0]); sixthTerm.SetAll(sixthInput,arr6[class="num">0]); class=class="str">"cmt">// 输入 - 第三模糊系统 [随机]] seventhTerm.SetAll(seventhInput,arr7[class="num">0]); eighthTerm.SetAll(eighthInput,arr8[class="num">0]); ninthTerm.SetAll(ninthInput,arr9[class="num">0]); Inputs.Clear(); class=class="str">"cmt">// 添加术语 - 第一个模糊系统 [RSI]] Inputs.Add(firstTerm); Inputs.Add(secondTerm); Inputs.Add(thirdTerm); class=class="str">"cmt">// 增加术语 - 第二模糊系统 [CCI} Inputs.Add(fourthTerm); Inputs.Add(fifthTerm); Inputs.Add(sixthTerm); class=class="str">"cmt">// 增加术语 - 第三模糊系统 [Stockastic] Inputs.Add(seventhTerm); Inputs.Add(eighthTerm); Inputs.Add(ninthTerm); CList *FuzzResult=OurFuzzy.Calculate(Inputs); Output=FuzzResult.GetNodeAtIndex(class="num">0); class=class="str">"cmt">// 需要更新,以考虑三个而不是一个输出 !!!!!!!! }
最后一句大实话
把三个模糊输出的加权汇总塞进 Output.Value(),再 delete 掉 FuzzResult 释放内存,这个 return 就是整个推理链的出口。你在 MT5 里改权重或换隶属度函数,res 的曲线会直接变样,贵金属和外汇这类高波动品种尤其敏感,回测里常见的过拟合就藏在这几行。 跑通之后别急着上实盘,先用历史 tick 把 res 和价格拐点对齐看胜率,概率上能过滤掉一半假信号就已经值回票价。
class="type">class="kw">double res = Output.Value(); class=class="str">"cmt">// 使用权重为三个输出的汇总方法添加代码 class="kw">delete FuzzResult; class="kw">return(res); }