使用Python和MQL5开发机器人(第一部分):数据预处理·综合运用
◍ 用随机算子自动造特征
做特征工程不必全靠人工挑变量。让算法从已有行情数据里自动组合出一批新特征,往往能挖到人工容易忽略的非线性关联,这对后续训练价格行为模型有实际帮助。 下面这段 Python 函数演示了自动生成思路:给定原始数据、要造的特征数和随机种子,它会在加减乘除、位移以及 2~20 窗口的滚动统计等算子间随机抽选,把两个已有列组合成新列。种子固定后,每次跑出来的特征集完全一致,方便你复现实验。 random_seed 不是摆设。原文示例里先用了 1,后来改成 42;种子一变,抽到的列索引和算子就全变,生成结果不可比对。想做交叉验证或给小布这类 AIGC 工具喂稳定样本,种子必须锁死。 代码跑完会打印尾部 100 行新特征。原文提到一次生成 100 个新特征后进入聚类阶段——你也可以把 num_features 调到 200 看维度爆炸后模型拟合时间的变化。外汇与贵金属波动受事件驱动,自动特征仅提高信息覆盖概率,不预示方向,实盘前务必在 MT5 历史数据上回测。
def generate_new_features(data, num_features=class="num">200, random_seed=class="num">1): random.seed(random_seed) new_features = {} for _ in range(num_features): feature_name = f&class="macro">#x27;feature_{len(new_features)}&class="macro">#x27; col1_idx, col2_idx = random.sample(range(len(data.columns)), class="num">2) col1, col2 = data.columns[col1_idx], data.columns[col2_idx] operation = random.choice([&class="macro">#x27;add&class="macro">#x27;, &class="macro">#x27;subtract&class="macro">#x27;, &class="macro">#x27;multiply&class="macro">#x27;, &class="macro">#x27;divide&class="macro">#x27;, &class="macro">#x27;shift&class="macro">#x27;, &class="macro">#x27;rolling_mean&class="macro">#x27;, &class="macro">#x27;rolling_std&class="macro">#x27;, &class="macro">#x27;rolling_max&class="macro">#x27;, &class="macro">#x27;rolling_min&class="macro">#x27;, &class="macro">#x27;rolling_sum&class="macro">#x27;]) if operation == &class="macro">#x27;add&class="macro">#x27;: new_features[feature_name] = data[col1] + data[col2] elif operation == &class="macro">#x27;subtract&class="macro">#x27;: new_features[feature_name] = data[col1] - data[col2] elif operation == &class="macro">#x27;multiply&class="macro">#x27;: new_features[feature_name] = data[col1] * data[col2] elif operation == &class="macro">#x27;divide&class="macro">#x27;: new_features[feature_name] = data[col1] / data[col2] elif operation == &class="macro">#x27;shift&class="macro">#x27;: shift = random.randint(class="num">1, class="num">10) new_features[feature_name] = data[col1].shift(shift) elif operation == &class="macro">#x27;rolling_mean&class="macro">#x27;: window = random.randint(class="num">2, class="num">20) new_features[feature_name] = data[col1].rolling(window).mean() elif operation == &class="macro">#x27;rolling_std&class="macro">#x27;: window = random.randint(class="num">2, class="num">20) new_features[feature_name] = data[col1].rolling(window).std() elif operation == &class="macro">#x27;rolling_max&class="macro">#x27;: window = random.randint(class="num">2, class="num">20) new_features[feature_name] = data[col1].rolling(window).max() elif operation == &class="macro">#x27;rolling_min&class="macro">#x27;: window = random.randint(class="num">2, class="num">20) new_features[feature_name] = data[col1].rolling(window).min() elif operation == &class="macro">#x27;rolling_sum&class="macro">#x27;: window = random.randint(class="num">2, class="num">20) new_features[feature_name] = data[col1].rolling(window).sum() new_data = pd.concat([data, pd.DataFrame(new_features)], axis=class="num">1) print("\nGenerated features:") print(new_data[list(new_features.keys())].tail(class="num">100)) class="kw">return data random_seed=class="num">42
用高斯混合模型给特征做软分组
把高度相关的指标塞进同一个模型,往往只是堆噪声。特征聚类的用意是把相似维度并到一组,压低冗余、缓解多重共线性,让后续训练不容易过拟合。 比起 k-means 强制球形划分,高斯混合模型(GMM)假设数据由若干个正态分布叠加生成,每个分布即一个聚类,能容纳形状歪斜、边界交叠的特征群,这对价格行为里那些纠缠在一起的动量/波动率类因子更友好。 下面这段 Python 实现直接可用于 MT5 导出的特征表(label 列单独剥离): [CODE] from sklearn.mixture import GaussianMixture def cluster_features_by_gmm(data, n_components=4): X = data.drop(['label', 'labels'], axis=1) X = X.replace([np.inf, -np.inf], np.nan) X = X.fillna(X.median()) gmm = GaussianMixture(n_components=n_components, random_state=1) gmm.fit(X) data['cluster'] = gmm.predict(X) print("\nFeature clusters:") print(data[['cluster']].tail(100)) return data [/CODE] 逐行看:第 3 行去掉标签列,避免把分类目标混进无监督聚类;第 4–5 行把无穷和缺失用中位数填掉,MT5 导出的价差类字段常出 inf;第 6 行设 4 个聚类、random_state=1 保证可复现;第 7 行拟合,第 8 行打回聚类编号;第 9–11 行只打印末 100 行便于快速瞄分布。 实跑时把 n_components 从 3 调到 6 对比一次,若某组聚类内特征数低于 2 个,说明该维度在样本里倾向是孤立噪声,可直接弃用。外汇与贵金属杠杆高、跳空频繁,这类特征筛选只降低过拟合概率,不承诺任何方向收益。
from sklearn.mixture class="kw">import GaussianMixture def cluster_features_by_gmm(data, n_components=class="num">4): X = data.drop([&class="macro">#x27;label&class="macro">#x27;, &class="macro">#x27;labels&class="macro">#x27;], axis=class="num">1) X = X.replace([np.inf, -np.inf], np.nan) X = X.fillna(X.median()) gmm = GaussianMixture(n_components=n_components, random_state=class="num">1) gmm.fit(X) data[&class="macro">#x27;cluster&class="macro">#x27;] = gmm.predict(X) print("\nFeature clusters:") print(data[[&class="macro">#x27;cluster&class="macro">#x27;]].tail(class="num">100)) class="kw">return data
「用随机森林筛掉无效特征」
做价格行为模型时,最容易被忽略的一步是特征清洗。把原始聚类的类别标签先摘掉,它们不参与预测变量评估,留着只会干扰选择过程。 核心思路是搬出随机森林:在随机特征子集上建上百棵决策树,训练完后每棵树都会给出特征对分类的贡献度。RFECV 再拿交叉验证(这里 cv=5)反复剔掉最弱变量,直到剩你指定的数量——代码里默认留 10 个。 实测跑下来,用于价格方向预测最顶的特征居然是开盘价本身,移动均线、价格增量、标准差、日/月价差也都排在前排。那些自动生成的花哨特征被证明显得无信息量,直接拖慢训练。 别把正态当圣经 特征重要性高不代表因果,外汇和贵金属波动受事件冲击,随机森林筛出的前十名在另一段行情可能换位,上 MT5 把不同品种的历史都跑一遍再信。 让小布替你跑这套 把下面函数丢进你的 Python 环境,传进打过标签的 DataFrame,终端会打印选中的特征表,复制回 MT5 做指标组合就能少踩很多坑。外汇贵金属杠杆高,模型胜率只是概率倾向,实盘务必轻仓验证。
from sklearn.feature_selection class="kw">import RFECV from sklearn.ensemble class="kw">import RandomForestClassifier class="kw">import pandas as pd def feature_engineering(data, n_features_to_select=class="num">10): # Remove the &class="macro">#x27;label&class="macro">#x27; column as it is not a feature X = data.drop([&class="macro">#x27;label&class="macro">#x27;, &class="macro">#x27;labels&class="macro">#x27;], axis=class="num">1) y = data[&class="macro">#x27;labels&class="macro">#x27;] # Create a RandomForestClassifier model clf = RandomForestClassifier(n_estimators=class="num">100, random_state=class="num">1) # Use RFECV to select n_features_to_select best features rfecv = RFECV(estimator=clf, step=class="num">1, cv=class="num">5, scoring=&class="macro">#x27;accuracy&class="macro">#x27;, n_jobs=-class="num">1, verbose=class="num">1, min_features_to_select=n_features_to_select) rfecv.fit(X, y) # Return a DataFrame with the best features, &class="macro">#x27;label&class="macro">#x27; column, and &class="macro">#x27;labels&class="macro">#x27; column selected_features = X.columns[rfecv.get_support(indices=True)] selected_data = data[selected_features.tolist() + [&class="macro">#x27;label&class="macro">#x27;, &class="macro">#x27;labels&class="macro">#x27;]] # Convert selected_features to a list # Print the table of best features print("\nBest features:") print(pd.DataFrame({&class="macro">#x27;Feature&class="macro">#x27;: selected_features})) class="kw">return selected_data labeled_data_engineered = feature_engineering(labeled_data_clustered, n_features_to_select=class="num">10)
◍ 数据集成型后接 Python 训练的路径
整套流程跑完,EURUSD 原始报价先从 MT5 抽出来,再靠加噪、位移、缩放这类随机扰动把样本量做大,否则后面机器学习很容易过拟合。 价格列被打上‘增长 / 下降’的趋势标签,标签生成时把止损止盈一起算进去;冗余样本直接剔掉,类别才算平衡。 特征工程分三步:从时间序列自动扩出几百个衍生变量,用高斯混合聚类抓冗余,再拿随机森林排重要性、筛出信息量最高的子集。下面这段代码就是聚类前丢掉标签列的动作,X 里只留特征。 [CODE] 里那行 X = data.drop(['label','labels'], axis=1) 说明聚类阶段不把监督标签带进去,避免信息泄露。 最终拿到的是一份特征最优、样本厚实的数据集,下一步进 Python 训分类模型、写策略,再回 MT5 集成。外汇与贵金属杠杆高,这套管线只是研究基础,实盘前必须用历史数据交叉验证。
def cluster_features_by_gmm(data, n_components=class="num">4): X = data.drop([&class="macro">#x27;label&class="macro">#x27;, &class="macro">#x27;labels&class="macro">#x27;], axis=class="num">1)