在外汇数据分析中使用关联规则·综合运用
◍ 用提升度与杠杆率筛掉伪关联
在关联规则挖掘里,光看置信度不够。一段典型的筛选逻辑是:当置信度超过设定阈值后,先算后件的支持度,再用 confidence / cons_support 得到 lift(提升度);若 cons_support 为 0 则 lift 记 0,避免除零。 同时补两个指标:leverage = 前件后件联合支持度 - (前件支持度 × 后件支持度),衡量偏离独立的绝对量;conviction = (1 - cons_support) / (1 - confidence),当 confidence 趋近 1 时趋向无穷,反映规则「不可逆误」的强度。 这些指标打包进 rule 字典后,再由 _is_meaningful_rule 做二次过滤,只把通过复杂度判定的塞进 complex_rules。实盘跑这套时,外汇与贵金属波动受事件驱动强,lift>1 仅代表历史共生概率偏高,不等于未来倾向重复,属高风险验证。 下面这段 Python 风格伪代码就是上述计算的骨架,可对照改写成 MT5 的 Python API 或 DLL 调用做回测。
if confidence >= self.min_confidence: # Count the lift cons_support = self._calculate_support(pattern_df, consequent) lift = confidence / cons_support if cons_support > class="num">0 else class="num">0 # Adding additional metrics to evaluate rules leverage = row[&class="macro">#x27;support&class="macro">#x27;] - (ant_support * cons_support) conviction = (class="num">1 - cons_support) / (class="num">1 - confidence) if confidence < class="num">1 else class="type">float(&class="macro">#x27;inf&class="macro">#x27;) rule = { &class="macro">#x27;antecedent&class="macro">#x27;: antecedent, &class="macro">#x27;consequent&class="macro">#x27;: consequent, &class="macro">#x27;support&class="macro">#x27;: row[&class="macro">#x27;support&class="macro">#x27;], &class="macro">#x27;confidence&class="macro">#x27;: confidence, &class="macro">#x27;lift&class="macro">#x27;: lift, &class="macro">#x27;leverage&class="macro">#x27;: leverage, &class="macro">#x27;conviction&class="macro">#x27;: conviction } # Sort the rules by additional criteria if self._is_meaningful_rule(rule): complex_rules.append(rule) # Sort the rules by complex metric
用提升度与杠杆率筛掉噪音规则
这段 Python 片段承接前面的关联规则挖掘,核心是把跑出来的候选规则再做一层交易相关性过滤与排序。_is_meaningful_rule 要求 lift 不低于 1.5、leverage 不低于 0.01,且前件或后件里必须出现 Trend 或 RSI 字样,否则直接丢弃——外汇与贵金属市场噪声极多,这种硬阈值能砍掉大部分无边际收益的组合。 _rule_score 给每条规则算综合分:lift 占 0.4、confidence 占 0.3、support 占 0.2、leverage 占 0.1,随后 complex_rules.sort 按分数倒序排。实际回测里,lift<1.5 的规则在 EURUSD 15M 上后续触发胜率往往贴近随机,杠杆率低于 0.01 意味着该组合相对基准几乎没增量信息。 数据加载部分读的是 forex_data_combined_20241116_074242.csv,utf-16 编码、制表符分隔、以 DateTime 为索引;实例化时 min_support=0.01、min_confidence=0.7、max_length=3,跑完日志会打出耗时和命中条数。开 MT5 导一份自己的 tick 或分钟数据,换掉这个 csv 路径,就能复跑看 Top 10 规则是否和你的盘感吻合。
complex_rules.sort(key=self._rule_score, reverse=True) end_time = time.time() logging.info(f"Pattern search completed in {end_time - start_time:.2f} seconds") logging.info(f"Found {len(complex_rules)} meaningful rules") class="kw">return complex_rules def _calculate_support(self, df, items): """Calculate support for a set of elements""" mask = pd.Series(True, index=df.index) for item in items: col, val = item.split(&class="macro">#x27;=&class="macro">#x27;) mask &= (df[col] == val) class="kw">return mask.mean() def _is_meaningful_rule(self, rule): """Check the rule for its relevance to trading""" # The rule should have the high lift and &class="macro">#x27;leverage&class="macro">#x27; if rule[&class="macro">#x27;lift&class="macro">#x27;] < class="num">1.5 or rule[&class="macro">#x27;leverage&class="macro">#x27;] < class="num">0.01: class="kw">return False # At least one element should be related to a trend or RSI has_trend_or_rsi = any(&class="macro">#x27;Trend&class="macro">#x27; in item or &class="macro">#x27;RSI&class="macro">#x27; in item for item in rule[&class="macro">#x27;antecedent&class="macro">#x27;] + rule[&class="macro">#x27;consequent&class="macro">#x27;]) if not has_trend_or_rsi: class="kw">return False class="kw">return True def _rule_score(self, rule): """Calculate the rule complex evaluation""" class="kw">return (rule[&class="macro">#x27;lift&class="macro">#x27;] * class="num">0.4 + rule[&class="macro">#x27;confidence&class="macro">#x27;] * class="num">0.3 + rule[&class="macro">#x27;support&class="macro">#x27;] * class="num">0.2 + rule[&class="macro">#x27;leverage&class="macro">#x27;] * class="num">0.1) # Load data logging.info("Loading data...") data = pd.read_csv(&class="macro">#x27;forex_data_combined_20241116_074242.csv&class="macro">#x27;, sep=&class="macro">#x27;\t&class="macro">#x27;, encoding=&class="macro">#x27;utf-class="num">16&class="macro">#x27;, index_col=&class="macro">#x27;DateTime&class="macro">#x27;) logging.info(f"Data loaded, shape: {data.shape}") # Apply the algorithm apriori = AdvancedForexApriori(min_support=class="num">0.01, min_confidence=class="num">0.7, max_length=class="num">3) rules = apriori.find_patterns(data) # Display results logging.info("\nTop class="num">10 trading rules:") for i, rule in enumerate(rules[:class="num">10], class="num">1): logging.info(f"\nRule {i}:")
「关联规则的输出与落盘」
把挖掘出的每条外汇价格行为关联规则打印出来,重点看四个指标:支持度(Support)反映该组合在历史样本中出现的概率,置信度(Confidence)是前提成立时结论成立的条件概率,提升度(Lift)大于 1 才说明两者非独立正相关,杠杆率(Leverage)与确信度(Conviction)则进一步量化偏离独立性的强度。 下面这段 Python 片段直接把规则字典里的 antecedent、consequent 及六项统计量格式化输出,并把全部规则存成 UTF-16 制表符分隔的 CSV,方便后续在 MT5 里做信号回测。外汇与贵金属波动剧烈,高 Lift 只代表历史样本中的偏向,实盘仍属高风险。 打印时支持度、置信度等都保留三位小数,例如某条规则输出 Support: 0.142、Confidence: 0.631、Lift: 1.274,意味着该形态组合在约 14.2% 的窗口出现,且后续方向成立概率 63.1%,相对随机基线提升 27.4%。这种数值可直接作为小布盯盘里权重设定的参考,但需自行在 MT5 验证样本外表现。
logging.info(f"IF {&class="macro">#x27; AND &class="macro">#x27;.join(rule[&class="macro">#x27;antecedent&class="macro">#x27;])}") logging.info(f"THEN {&class="macro">#x27; AND &class="macro">#x27;.join(rule[&class="macro">#x27;consequent&class="macro">#x27;])}") logging.info(f"Support: {rule[&class="macro">#x27;support&class="macro">#x27;]:.3f}") logging.info(f"Confidence: {rule[&class="macro">#x27;confidence&class="macro">#x27;]:.3f}") logging.info(f"Lift: {rule[&class="macro">#x27;lift&class="macro">#x27;]:.3f}") logging.info(f"Leverage: {rule[&class="macro">#x27;leverage&class="macro">#x27;]:.3f}") logging.info(f"Conviction: {rule[&class="macro">#x27;conviction&class="macro">#x27;]:.3f}") # Save results results_df = pd.DataFrame(rules) results_df.to_csv(&class="macro">#x27;forex_rules_advanced.csv&class="macro">#x27;, index=False, sep=&class="macro">#x27;\t&class="macro">#x27;, encoding=&class="macro">#x27;utf-class="num">16&class="macro">#x27;) logging.info("Results saved to forex_rules_advanced.csv")
◍ 把购物篮算法塞进外汇盘面的五个旋钮
把 Apriori 从超市收据搬进 MT5,第一道坎是对象本质不同:商店卖的是离散商品,外汇跑的是连续报价和指标流。我花了数月搭出一套由五个指标构成的筛选系统,每个都单独跑过回测才敢用。 支持度(Support)最坑。曾有一条历史表现极漂亮的关联规则,支持度只有 0.02——按频率算约一百年才触发一次,塞进实盘等于摆设。置信度(Confidence)反而直白:在外汇这种高噪市场,70% 已算强信号,剩下 30% 靠仓位和止损兜住,否则再好的规律也扛不住连亏。 提升度(Lift)是我留信号的主刀。数百小时测试后划了条线:Lift > 1.5 的规则在真实 tick 上才大概率有效,低于这值的多数只是样本巧合。杠杆(Leverage)指标一度想删,结果在某段波动率飙升期反而滤掉了大部分假突破。确信度(Conviction)是后来补的,用来判规则是不是“真有用”而非表面显著。 最意外的产出是跨货币对暗链:EURUSD 的某类形态竟能领先预判 USDJPY 走向,这是我盯盘 9 年没肉眼抓到的。外汇和贵金属杠杆高、跳空频发,这类关联只作辅助过滤,不能直接当入场令。
过滤弱信号与给规则排座次
把特征列按语义分组,是降复杂度的第一步。趋势、RSI、成交量、价格区、形态各自成堆,后面做关联规则时只在组内或跨组挑组合,能少算一大半无用配对。 规则不是越多越好。代码里只保留提升度大于 1.5 且杠杆率不低于 0.01 的条目,同时强制要求前件或后件里出现 Trend 或 RSI 字样——纯成交量或形态孤证直接扔掉,避免在外汇和贵金属这种高波动市场里被噪声带偏。 排分用加权而非单指标。lift 占 0.4、confidence 0.3、support 0.2、leverage 0.1,前两项主导,意味着统计显著且命中率稳的规则会更靠上。MT5 里接这套逻辑时,先把你自己的列名对齐到这几类前缀,否则 _is_meaningful_rule 会全盘拒收。
column_groups = {
&class="macro">#x27;trend&class="macro">#x27;: [col for col in df.columns if &class="macro">#x27;Trend&class="macro">#x27; in col],
&class="macro">#x27;rsi&class="macro">#x27;: [col for col in df.columns if &class="macro">#x27;RSI_Zone&class="macro">#x27; in col],
&class="macro">#x27;volume&class="macro">#x27;: [col for col in df.columns if &class="macro">#x27;Volume_Zone&class="macro">#x27; in col],
&class="macro">#x27;price&class="macro">#x27;: [col for col in df.columns if &class="macro">#x27;Price_Zone&class="macro">#x27; in col],
&class="macro">#x27;pattern&class="macro">#x27;: [col for col in df.columns if &class="macro">#x27;Pattern&class="macro">#x27; in col]
}
def _is_meaningful_rule(self, rule):
if rule[&class="macro">#x27;lift&class="macro">#x27;] < class="num">1.5 or rule[&class="macro">#x27;leverage&class="macro">#x27;] < class="num">0.01:
class="kw">return False
has_trend_or_rsi = any(&class="macro">#x27;Trend&class="macro">#x27; in item or &class="macro">#x27;RSI&class="macro">#x27; in item
for item in rule[&class="macro">#x27;antecedent&class="macro">#x27;] + rule[&class="macro">#x27;consequent&class="macro">#x27;])
if not has_trend_or_rsi:
class="kw">return False
class="kw">return True
def _rule_score(self, rule):
class="kw">return (rule[&class="macro">#x27;lift&class="macro">#x27;] * class="num">0.4 +
rule[&class="macro">#x27;confidence&class="macro">#x27;] * class="num">0.3 +
rule[&class="macro">#x27;support&class="macro">#x27;] * class="num">0.2 +
rule[&class="macro">#x27;leverage&class="macro">#x27;] * class="num">0.1)「把规则摊开在图上才算看清」
找到关联规则只是第一步,真正能用的结论要靠可视化逼出来。我写过一个 ForexRulesVisualizer 类,专门干这件事:把算法吐出来的模式做成能肉眼扫的分布图和关系网。 先盯四个数的分布——支持度、置信度、提升度、杠杆。这四个直方图能直接告诉你这批规则是靠堆量凑出来的,还是真有稀疏但高提升度的硬货;分布塌在低端时,多半要把算法的最小支持度往下调。 比直方图更狠的是交互式网络图:节点是指标状态,比如 EURUSD_Trend=Uptrend 或 USDJPY_RSI_Zone=Overbought,边就是规则,边越粗代表提升度越高。外汇与贵金属波动受多因子纠缠,这类图能让你一眼看出哪两个市场状态被反复绑定,但高杠杆品种跳空风险大,网络里看着稳的链路也可能在数据外样本中断。
◍ 用热力图看货币对联动强度
在 MT5 里做多品种组合前,先得弄清哪些货币对是“同频”的。我习惯拉一张相关性热力图,把 EURUSD、GBPUSD、USDJPY 等品种两两配对,用颜色深浅标出皮尔逊相关系数区间(−1 到 +1)。 红色越深代表正相关越强,比如 EURUSD 与 GBPUSD 在 2023 年多数时段系数落在 0.8 以上,同涨同跌概率高;蓝色越深则是负相关,如 EURUSD 与 USDCHF 常年在 −0.9 附近纠缠。 抓出这些强联动对,就能避开“看起来分散、实则一荣俱荣”的伪组合。真正多样化的仓位,应该挑系数绝对值低于 0.3 的跨板块品种,外汇与贵金属混搭时尤其要手动核对,杠杆叠加下风险会非线性放大。
把关联规则变成可下单的信号
可视化完关联规则只是第一步,真正能用的东西是信号。这里的核心思路是写一个生成器类,吃进规则表和市场实时状态,吐出带货币对标签的买卖倾向。 规则强度不是只看某一个指标。下面这段代码把 lift 给 0.4 权重、confidence 0.3、support 0.2、leverage 0.1 做加权平均;如果前件里带 Trend 字样,再乘 1.2 的加成。也就是说,带趋势类条件的规则更容易过线。 min_rule_strength 默认设 0.5,低于这个数的规则直接不进信号池。analyze_market_state 会先按当前数据拼出市场状态,再找匹配规则,最后按 EURUSD、GBPUSD、USDJPY、USDCHF 四个货币对分组出信号。 外汇和贵金属是高杠杆高风险品种,这套信号只是概率倾向,不是确定性指令。开 MT5 接一版 Python 回测,把 min_rule_strength 从 0.5 调到 0.7,看信号频次和胜率怎么变,比空谈有用。
class="kw">import pandas as pd class="kw">import numpy as np from class="type">class="kw">datetime class="kw">import class="type">class="kw">datetime class="kw">import logging class ForexSignalGenerator: def __init__(self, rules_df, min_rule_strength=class="num">0.5): """ Signal generator initialization Parameters: rules_df: DataFrame with association rules min_rule_strength: minimum rule strength to generate a signal """ self.rules_df = rules_df self.min_rule_strength = min_rule_strength self.active_signals = {} def calculate_rule_strength(self, rule): """ Comprehensive assessment of the rule strength Takes into account all metrics with different weights """ strength = ( rule[&class="macro">#x27;lift&class="macro">#x27;] * class="num">0.4 + # Main weight on &class="macro">#x27;lift&class="macro">#x27; rule[&class="macro">#x27;confidence&class="macro">#x27;] * class="num">0.3 + # Rule confidence rule[&class="macro">#x27;support&class="macro">#x27;] * class="num">0.2 + # Occurrence frequency rule[&class="macro">#x27;leverage&class="macro">#x27;] * class="num">0.1 # Improvement over randomness ) # Additional bonus for having trend indicators if any(&class="macro">#x27;Trend&class="macro">#x27; in item for item in rule[&class="macro">#x27;antecedent&class="macro">#x27;]): strength *= class="num">1.2 class="kw">return strength def analyze_market_state(self, current_data): """ Current market state analysis Parameters: current_data: DataFrame with current indicator values """ signals = [] state = self._create_market_state(current_data) # Find all the matching rules matching_rules = self._find_matching_rules(state) # Grouping rules by currency pairs for pair in [&class="macro">#x27;EURUSD&class="macro">#x27;, &class="macro">#x27;GBPUSD&class="macro">#x27;, &class="macro">#x27;USDJPY&class="macro">#x27;, &class="macro">#x27;USDCHF&class="macro">#x27;]: pair_rules = [r for r in matching_rules if any(pair in c for c in r[&class="macro">#x27;consequent&class="macro">#x27;])] if pair_rules: signal = self._generate_pair_signal(pair, pair_rules) signals.append(signal) class="kw">return signals
「把市场状态塞进规则引擎去捞信号」
这段 Python 逻辑干的事很直接:先把最新一根 K 线里的 Zone、Pattern、Trend 类特征拼成字符串集合,作为「当前市场状态」。例如 EURUSD_H1_Trend=up 这种键值对,只取末尾值(iloc[-1]),所以状态永远是对应当前Bar的快照。 _create_market_state 用集合去重,避免同一特征重复计入;_find_matching_rules 则拿这个集合去遍历规则表,要求规则的 antecedent(前提条件)全部命中才留下来,且算出的强度要 ≥ 设定的 min_rule_strength 阈值,否则直接丢弃。 _generate_pair_signal 是针对单个货币对聚合趋势类结论的:把命中规则里带『Trend』且含该 pair 的后续结论拆出方向,按强度累加。最后取累加值最大的方向作为该 pair 的最终信号,并带上 datetime.now() 时间戳。外汇与贵金属波动受杠杆与消息面影响大,这类信号仅反映历史模式匹配概率,实战中需自设阈值验证。 想接进自己的 MT5 辅助面板,可以把 rules_df 换成从 CSV 读的关联规则,min_rule_strength 建议先从 0.6 试起,观察不同阈值下信号翻转频率再调。
def _create_market_state(self, data): """Forming the current market state""" state = [] for col in data.columns: if any(x in col for x in [&class="macro">#x27;_Zone&class="macro">#x27;, &class="macro">#x27;_Pattern&class="macro">#x27;, &class="macro">#x27;Trend&class="macro">#x27;]): state.append(f"{col}={data[col].iloc[-class="num">1]}") class="kw">return set(state) def _find_matching_rules(self, state): """Searching for rules that match the current state""" matching_rules = [] for _, rule in self.rules_df.iterrows(): # Check if all the rule conditions are met if all(cond in state for cond in rule[&class="macro">#x27;antecedent&class="macro">#x27;]): strength = self.calculate_rule_strength(rule) if strength >= self.min_rule_strength: rule[&class="macro">#x27;calculated_strength&class="macro">#x27;] = strength matching_rules.append(rule) class="kw">return matching_rules def _generate_pair_signal(self, pair, rules): """Generating a signal for a specific currency pair""" # Divide the rules by signal type trend_signals = defaultdict(class="type">float) for rule in rules: # Looking for trend-related consequents trend_cons = [c for c in rule[&class="macro">#x27;consequent&class="macro">#x27;] if pair in c and &class="macro">#x27;Trend&class="macro">#x27; in c] if trend_cons: for cons in trend_cons: trend = cons.split(&class="macro">#x27;=&class="macro">#x27;)[class="num">1] trend_signals[trend] += rule[&class="macro">#x27;calculated_strength&class="macro">#x27;] # Determine the final signal if trend_signals: strongest_trend = max(trend_signals.items(), key=lambda x: x[class="num">1]) class="kw">return { &class="macro">#x27;pair&class="macro">#x27;: pair, &class="macro">#x27;signal&class="macro">#x27;: strongest_trend[class="num">0], &class="macro">#x27;strength&class="macro">#x27;: strongest_trend[class="num">1], &class="macro">#x27;timestamp&class="macro">#x27;: class="type">class="kw">datetime.now()
◍ 用历史切片跑一遍关联规则信号
这段 Python 代码把已挖掘的关联规则直接套到历史行情上做信号回放,核心是一个按行滑动的模拟循环。 函数 run_trading_system 接收两个 DataFrame:一个是带历史 K 线的 data,一个是存关联规则的 rules_df。它先实例化信号生成器,再对 data 做 len(data)-1 次遍历,每次只取当前 1 行切片送给 analyze_market_state,把返回的信号塞进 signals_history 列表。 数据加载部分点出了实盘容易踩的坑:forex_data_combined_20241116_090857.csv 用制表符分隔、utf-16 编码、DateTime 列作索引;rules_df 里的 antecedent / consequent 是字符串化的元组,必须用 eval 还原成可迭代对象才能喂给生成器。 跑完得到 signals_df,最后按货币对统计信号分布。外汇与贵金属杠杆高、滑点跳空频繁,这类回测信号只代表历史样本下的概率倾向,开 MT5 前务必用你自己 broker 的时点重跑一遍验证。
def run_trading_system(data, rules_df): """ Trading system launch Parameters: data: DataFrame with historical data rules_df: DataFrame with association rules """ signal_generator = ForexSignalGenerator(rules_df) # Simulate a pass along historical data signals_history = [] for i in range(len(data) - class="num">1): current_slice = data.iloc[i:i+class="num">1] signals = signal_generator.analyze_market_state(current_slice) for signal in signals: if signal: signals_history.append({ &class="macro">#x27;class="type">class="kw">datetime&class="macro">#x27;: current_slice.index[class="num">0], &class="macro">#x27;pair&class="macro">#x27;: signal[&class="macro">#x27;pair&class="macro">#x27;], &class="macro">#x27;signal&class="macro">#x27;: signal[&class="macro">#x27;signal&class="macro">#x27;], &class="macro">#x27;strength&class="macro">#x27;: signal[&class="macro">#x27;strength&class="macro">#x27;] }) class="kw">return pd.DataFrame(signals_history) # Loading historical data and rules data = pd.read_csv(&class="macro">#x27;forex_data_combined_20241116_090857.csv&class="macro">#x27;, sep=&class="macro">#x27;\t&class="macro">#x27;, encoding=&class="macro">#x27;utf-class="num">16&class="macro">#x27;, index_col=&class="macro">#x27;DateTime&class="macro">#x27;, parse_dates=True) rules_df = pd.read_csv(&class="macro">#x27;forex_rules_advanced.csv&class="macro">#x27;, sep=&class="macro">#x27;\t&class="macro">#x27;, encoding=&class="macro">#x27;utf-class="num">16&class="macro">#x27;) rules_df[&class="macro">#x27;antecedent&class="macro">#x27;] = rules_df[&class="macro">#x27;antecedent&class="macro">#x27;].apply(eval) rules_df[&class="macro">#x27;consequent&class="macro">#x27;] = rules_df[&class="macro">#x27;consequent&class="macro">#x27;].apply(eval) # Launch the test signals_df = run_trading_system(data, rules_df) # Analyze the results print("Generated signals statistics:") print(signals_df.groupby(&class="macro">#x27;pair&class="macro">#x27;)[&class="macro">#x27;signal&class="macro">#x27;].value_counts())
给规则打分而不是迷信图形
把图表上看着顺眼的形态变成真正能下单的信号,中间差着一个评估层。作者在 ForexSignalGenerator 模块里踩过坑:昨天高胜率的规则,换周就可能哑火,所以单纯「匹配条件」远远不够。 他最后落地的评分权重是:提升度 40%、置信度 30%、支持度 20%、杠杆率 10%。提升度被单列为核心,因为它衡量的是「这条规则相对随机基线到底强多少」,比单纯命中次数更抗过拟合。 一个实测倾向:带趋势成分的规则信号更强,所以这类规则额外加了 20% 权重奖励,回测中确实更经得起横切。 系统现在对每对货币分析约 20 个参数,除当前指标值外,还扩到近几根 K 线的趋势背景、波动状态、甚至时段。外汇与贵金属属高风险品种,这套权重只是作者单版实验,开 MT5 把比例调成 40/30/20/10 跑一遍自有品种,才知道在你常做的周期上是否同样成立。
「给信号排个序再下手」
做这套规则系统没多久就发现,光把形态找出来没用,信号质量才是命门。前几笔亏钱的单子让我认清一件事:排序比识别模式本身更关键。 最开始只设了一道最低有效性阈值 0.5,结果误报多得没法看。实盘测了两周把阈值拉到 0.7,信号量掉了约三分之一,但干净了很多。 第二道关是一致性。有回某条历史表现很好的规则让我直接开仓,价格却反着走;查完才发现同一时刻别的规则在唱反调。后来定死一条:必须多条规则指同一个方向才进场。 波动一上来系统就容易抽风。我接了个基于 ATR 的动态过滤器——若过去 20 日波动率突破第 75 百分位,就把规则强度要求再抬高 20%。 碰到多空信号互掐且参数都不差的情况,试了一圈最后用最笨的办法:明显矛盾就跳过。少赚几笔,但外汇和贵金属这种高风险盘口里,回撤可控比什么都强。 下个月准备塞进时间筛选,有些流动性差、撞重要新闻的时段规则准头明显垮掉,切掉它们可能还能再抬一点胜率。
◍ 回测里冒出来的真实权重与阈值
系统开发几个月后,最棘手的不是找规则,而是判断哪条规则真有用。真实报价一进来,初期那套朴素评估法立刻露怯,于是我改成一整套带权重的打分:提升度占 40%,置信度 30%,支持度和杠杆率只给少量权重做过滤。 信号不能按找到的顺序无脑跟。先砍掉低于强度阈值的弱信号,再看是否多规则共振——单规则在汇市里可靠性偏低,这点在贵金属和外汇上都一样,属于高杠杆品种的通病。 波动性是隐藏杀手。低波动时系统漂亮,一遇急涨急跌误报就飙升,所以动态过滤器必须随波动率放大而收紧,否则样本外很容易翻车。 实跑近三个月,对四对主要货币做两年回测:USDJPY 胜率 65%、风险回报 1.6;GBPUSD 只有 58%、风险回报 1.4,差距明显。提升度 >2.0 且置信度 >0.8 的规则在全部货币对上结果都偏稳,这两个数倾向是汇市里自然显著的临界线,但外汇高风险,参数换周期可能漂移。
系统下一步的可进化点
当前这套规则最明显的短板是参数静态化:市场状态切换时,写死的阈值容易在震荡与趋势衔接处连续止损。把参数改成随波动率或成交密度自适应,是优先级最高的一件事。 另一个被忽略的维度是宏观与新闻背景。纯价格行为系统在重大数据发布前后会失效,加入事件过滤器必然增加复杂度,但能砍掉一批低质量信号。 自适应过滤器已经有个粗糙版,不同市场阶段对应不同设置的方向是对的。我下周会跑一版带动态仓位优化的测试,历史回测初步结果偏正面,不过真实盘口永远会再教一次做人。外汇与贵金属杠杆高,这类未实盘验证的改动别直接上实金。
「别急着下结论」
把关联规则搬进算法交易,真正值钱的是那些肉眼难辨的隐性组合,但前提是数据清洗到位、规则筛选严格,信号系统本身也得经得起回测。原文作者提到提升率高于 1.5 的规则在实盘过滤中更具参考价值,这一阈值来自数百小时测试,不是拍脑袋定的,复制去 MT5 验证时建议先从 1.2~1.8 区间扫一遍。 任何靠关联规则跑起来的 EA 都绕不开一个事实:市场状态一变,旧规则就可能失效。外汇与贵金属杠杆高、跳空频繁,这类策略必须叠加技术面与基本面监控,且持续跟踪规则命中率衰减。 末了说一句实在的——本文附的 Dataset.mq5 仅 4.29 KB,样本量有限,直接实盘前先在策略测试器用历史数据跑三个月以上再谈信心。