在外汇数据分析中使用关联规则·综合运用
📘

在外汇数据分析中使用关联规则·综合运用

第 3/3 篇

◍ 用提升度与杠杆率筛掉伪关联

在关联规则挖掘里,光看置信度不够。一段典型的筛选逻辑是:当置信度超过设定阈值后,先算后件的支持度,再用 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 调用做回测。

MQL5 / C++
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 规则是否和你的盘感吻合。

MQL5 / C++
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 验证样本外表现。

MQL5 / C++
    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 会全盘拒收。

MQL5 / C++
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,看信号频次和胜率怎么变,比空谈有用。

MQL5 / C++
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 试起,观察不同阈值下信号翻转频率再调。

MQL5 / C++
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 的时点重跑一遍验证。

MQL5 / C++
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,样本量有限,直接实盘前先在策略测试器用历史数据跑三个月以上再谈信心。

常见问题

算提升度和杠杆率:提升度接近1多为巧合,杠杆率接近0说明共现纯属随机,两者结合可筛掉伪关联。
按支持度、置信度和提升度排座次,先砍掉支持度过低或提升度不超阈值的弱规则,只留排前面的少数。
可以。小布盯盘的AIGC会直接输出关联规则并摊在对应品种页,省去你手跑算法和落盘的步骤。
看规则触发时的价格反应区和失效边界,把共现区间和后续波动叠一起,才能分辨噪音和可用规律。
代表两品种倾向互斥同现概率低于随机,可用来避开同时持仓的坑,但贵金属高风险仍需结合盘面验证。