无需 Python 或 R 语言知识的 Yandex CatBoost 机器学习算法·综合运用
◍ 把预测结果落盘与回测指标算清楚
EA 在调试阶段会把预测归档和模型校验分别写进两个 CSV。归档用 csv_Arhiv.Write_to_file 落到 Save_Pred 目录,文件名拼上品种名,小数位截断到 5 字符;模型值走 csv_Chek,显式把 decimal_separator 设成逗号,同样保留 5 位小数,方便拿 Excel 或 Python 对账。 自定义指标函数 CustomPokazatelf 只在 VariantPokazatel==1 时返回一个胜率类数值:用 TesterStatistics 抓总成交单数 STAT_TRADES 与盈利单数 STAT_PROFIT_TRADES,当总单数大于 0 且超过 15000 笔时才算 Pr_Tr/Total_Tr*100.0。这个 15000 笔的门槛意味着小样本回测里该指标直接返回 0,不会误导优化器。 新K线判定交给 isNewBar,用 CopyTime 取当前信号周期 Signal_MA_TF 最新一根时间,跟静态变量 prevBarTime 比,不同就刷时间并返回 true。CopyTime 失败会 Print 报错但函数末尾仍返回 true,实盘里若遇到报价中断可能误触信号,建议自行改成返回 false。 初始化 OnInit 先卡参数:Porog 大于等于 Pridel 直接 INIT_PARAMETERS_INCORRECT,避免阈值逻辑自相矛盾。开 Use_Pred_Calc 才跑 Init_Pred 拿指标句柄、建预测因子表 CB_Tabl,并把 csv_CB 列数减 3 赋给 Solb_Copy_CB,代表实际因子列数。
csv_Arhiv.Write_to_file("Save_Pred\\"+name,true,true,true,true,false,class="num">5);class=class="str">"cmt">// Save the file up to class="num">5 characters } class=class="str">"cmt">//--- Save the model values to a debug file if(Use_Save_Result==true) { csv_Chek.decimal_separator=&class="macro">#x27;,&class="macro">#x27;;class=class="str">"cmt">// Set a decimal separator class="type">class="kw">string name=Symbol()+"Chek.csv";class=class="str">"cmt">// File name csv_Chek.Write_to_file("Save_Pred\\"+name,true,true,true,true,false,class="num">5);class=class="str">"cmt">// Save file up to class="num">5 decimal places } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Custom variable calculating function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">double CustomPokazatelf(class="type">int VariantPokazatel) { class="type">class="kw">double custom_Pokazatel=class="num">0.0; if(VariantPokazatel==class="num">1) { class="type">class="kw">double Total_Tr=(class="type">class="kw">double)TesterStatistics(STAT_TRADES); class="type">class="kw">double Pr_Tr=(class="type">class="kw">double)TesterStatistics(STAT_PROFIT_TRADES); if(Total_Tr>class="num">0 && Total_Tr>class="num">15000)custom_Pokazatel=Pr_Tr/Total_Tr*class="num">100.0; } class="kw">return(custom_Pokazatel); } class=class="str">"cmt">//+-----------------------------------------------------------------+ class=class="str">"cmt">//| Returns TRUE if a new bar has appeared on the current TF | class=class="str">"cmt">//+-----------------------------------------------------------------+ class="type">bool isNewBar() { class="type">class="kw">datetime tm[]; class="kw">static class="type">class="kw">datetime prevBarTime=class="num">0; if(CopyTime(Symbol(),Signal_MA_TF,class="num">0,class="num">1,tm)<class="num">0) { Print("%s CopyTime error = %d",__FUNCTION__,GetLastError()); } else { if(prevBarTime!=tm[class="num">0]) { prevBarTime=tm[class="num">0]; class="kw">return true; } class="kw">return false; } class="kw">return true; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- Check the correctness of model response interpretation values if(Porog>=Pridel || Pridel<=Porog)class="kw">return(INIT_PARAMETERS_INCORRECT); if(Use_Pred_Calc==true) { if(Init_Pred()==INIT_FAILED)class="kw">return(INIT_FAILED);class=class="str">"cmt">// Initialize indicator handles CB_Tabl();class=class="str">"cmt">// Creating a table with predictors Solb_Copy_CB=csv_CB.Get_columns_count()-class="num">3;class=class="str">"cmt">// Number of columns in the predictor table } class=class="str">"cmt">// Declare handle_MA_Slow
「信号触发后的执行链路与句柄校验」
在 EA 初始化阶段,移动均线信号句柄通过 iMA() 创建,参数包含当前品种、信号周期 Signal_MA_TF 与均线周期 Signal_MA_Period,偏移量写死为 1。若返回 INVALID_HANDLE,说明品种或周期不被支持,立即打印错误码并 return(INIT_FAILED),EA 不会继续加载。 调试用的 CSV 表只在 Use_Save_Result==true 时建立两列:Data 与 Rez,方便把模型输出落盘核对。初始化成功则 return(INIT_SUCCEEDED)。 反初始化里依次 delete 三个 csv 类实例(csv_CB / csv_Arhiv / csv_Chek),并在 Save_Pred==true 时调用 Save_Pred_All() 写预测文件,避免内存泄漏和临时数据丢失。 OnTick 用 isNewBar() 拦掉非新bar的报价,只在 Signal() 为真时跑预测与模型:先 Pred_Calc() 算特征,再 Model_CB() 套 CatBoost,已有持仓则 ClosePositions("Close Signal"),随后按 BuyNow / SellNow 开 1 手无止损止盈单。外汇与贵金属杠杆高,实盘前务必在 MT5 策略测试器用历史数据验证该链路是否如预期触发。
handle_MA_Signal=iMA(Symbol(),Signal_MA_TF,Signal_MA_Period,class="num">1,Signal_MA_Metod,Signal_MA_Price); if(handle_MA_Signal==INVALID_HANDLE) { PrintFormat("Failed to create handle of the handle_MA_Signal indicator for the symbol %s/%s, error code %d", Symbol(),EnumToString(Period()),GetLastError()); class="kw">return(INIT_FAILED); } class=class="str">"cmt">//--- Create a table to write model values - for debugging purposes if(Use_Save_Result==true) { csv_Chek.Add_column(dt_string,"Data"); csv_Chek.Add_column(dt_double,"Rez"); } class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert deinitialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit(const class="type">int reason) { if(Save_Pred==true)Save_Pred_All();class=class="str">"cmt">// Call a function to write predictors to a file class="kw">delete csv_CB;class=class="str">"cmt">// Delete the class instance class="kw">delete csv_Arhiv;class=class="str">"cmt">// Delete the class instance class="kw">delete csv_Chek;class=class="str">"cmt">// Delete the class instance } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Test completion event handler | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">double OnTester() { class="kw">return(CustomPokazatelf(class="num">1)); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert tick function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- Operations are only executed when the next bar appears if(!isNewBar()) class="kw">return; class=class="str">"cmt">//--- Get information on trading environment(deals/orders) OpenOrdersInfo(); class=class="str">"cmt">//--- Get signal from the basic strategy if(Signal()==true) { class=class="str">"cmt">//--- Calculate predictors if(Use_Pred_Calc==true)Pred_Calc(); class=class="str">"cmt">//---Apply the CatBoost model if(Use_Model_CB==true)Model_CB(); class=class="str">"cmt">//--- If there is an open position at the signal generation time, close it if(PosType!="class="num">0")ClosePositions("Close Signal"); class=class="str">"cmt">//--- Open a new position if (BuyNow==true)OpenPositions(BUY,class="num">1,class="num">0,class="num">0,"Open_Buy"); if (SellNow==true)OpenPositions(SELL,class="num">1,class="num">0,class="num">0,"Open_Sell"); class=class="str">"cmt">//--- Copy the table with the current predictors to the archive table if(Save_Pred==true)Copy_Arhiv(); } }
用拼接 Si 合约筛出可学习的均线参数
先把基础策略的均线参数空间拉出来跑一遍。我在 2014-06-01 至 2020-10-31 的 M1 周期上,用 Otkritie Broker 拼接的 USDRUB_TOM Si 期货(品种名 Si Splice)做优化,模式为 M1 OHLC 模拟。EA 优化维度:Period 8–256 步长 8;Timeframe M1–D1 无步长;MA methods SMA–LWMA 无步长;Calculation price CLOSE–WEIGHTED。 筛选标准盯两个硬指标:自定义质量参数最好 ≥35%,成交笔数 ≥15000 且越多越好。从这一轮里我抽出一组能演示机器学习潜力的配置:Period=8、Timeframe=2 分钟、MA methods=线性加权、Calculation price=最高价。 单跑这组看余额曲线,信号噪声极大、错单密集,直接上实盘不现实。和那些堆多个指标过滤、在统计上无意义的空白区空耗算力的做法不同,我们只保留指标值真正携带信息的区间。 改 EA 行为来落预测因子:Calculate predictors=true、Save predictors=true、Volume type 选 ticks 或真实交易量、图表不挂预测指标、Commission and spread 算 target 设 50 点。其余不变,重跑测试。这轮慢很多——近 2000 个指标缓冲区和其他因子都要算。 代理目录里(我移动模式路径含 Agent-127.0.0.1-3002,3002 是线程号)找到生成的预测因子文件,能正常打开数据表就说明管线通了。外汇与贵金属品种波动剧烈、杠杆风险高,这套仅作方法验证,实盘前务必在 MT5 重跑确认。
◍ 把样本拆三份并调 CatBoost 训练参数
做 CatBoost 模型前,先用脚本 CB_CSV_to3x.mq5 把原始样本切成三份:train.csv 喂训练,test.csv 控训练过程并触发早停,exam.csv 做最终评估。脚本要你填两个路径——交易模型创建目录,以及含样本的源文件名。同目录下还会生成一个 Test_CB_Setup_0_000000000 文件,里面从 0 开始标列索引:把目标列打上 Label,其余 Auxiliary 列禁用。上面那段代码就是配置文件的列标记片段,2408、2409、2411、2412 全是 Auxiliary,仅 2410 是 Label。 CatBoost 里真正左右训练结果的就那几个键。Tree depth 开发者给的区间是 6 到 10;Learning rate 调低会更慢更准,但必须同步放大 Maximum iterations,否则树没建够就停了。class-weights 处理样本不平衡,Balanced 和 SqrtBalanced 按类内样本数重新配权,None 则全 1。 boosting type 上,Ordered 在小数据集质量更好但慢,Plain 是经典梯度提升。od-wait 控制连续多少棵树无提升就停,学习率降了就得把它调大,否则训练早早断掉。eval-metric 决定按哪个指标截断,Logloss、F1、MCC 都能选,直接改脚本里的键值即可。 脚本支持扫参:在 Sample object 里选非 NONE 的参数(如 random-seed、border-count),填起始值、结束值和步长,它能自动跑多组配置。外汇与贵金属模型训练波动大、过拟合风险高,实盘前务必用 exam.csv 复核泛化表现。
class="num">2408 Auxiliary class="num">2409 Auxiliary class="num">2410 Label class="num">2411 Auxiliary class="num">2412 Auxiliary
「CatBoost 训练的三段式调参落点」
把模型训练拆成三层来做更顺手:基础设置管树的深度、数量、学习速率和类权重,脚本给的默认值大多能直接用,不必网格搜;真正要搜的是预测因子量化网格,CatBoost 沿网格边界切值,遍历 8 到 512 的网格类型、步长取 8/16/32 这种翻倍增量,往往能捞出泛化更好的切分。Seed 我一般只在 1–1000 里随手给一个,不影响主结构。 首阶段直接用 CB_Bat 的默认设置就够,拆分方法切到 MinEntropy,网格只测 16–512、步长 16,省掉前期瞎调的功夫。跑 CB_Bat 会落一堆文本键文件:_01_Train_All 管训练设置,_02_ 开头三个分别记 Exam/Test/Train 样本的分类结果,_03_ 记每棵树的度量,_04_ 记预测值重要性,外加 _00_Dir_All 做辅助索引。 老版本 CatBoost 吃 CPU 很凶,别等训练完再串行跑那 6 个记录文件,而是训练一停就并行拉起,能明显压住空闲核。外汇与贵金属模型过拟合风险高,网格搜出的“更好”仅在回测样本内成立,上 MT5 用真实 tick 复跑 _02_Rezultat_Test 再下结论。
跑通 CatBoost 训练目录与批处理
样本文件就绪后,先把 _00_Dir_All.txt 改成 _00_Dir_All.bat 双击运行,它会建好模型定位所需的目录树,并把其余辅助文件后缀一并改成 bat。跑完以后项目里多出 Setup 文件夹,里面除了 catboost-0.24.1.exe 这个训练主程序,还有 train.csv / test.csv / exam.csv 三份样本,以及一系列以 _01_、_02_、_03_、_04_ 开头的批处理:前者管训练,后两者分别负责在训练、测试、检查样本上记录分类结果、单树度量和预测重要性。
直接执行 _01_Train_All.bat 就能看到训练滚动起来。控制台输出里从左到右几列值得盯住:第1列是当前树数也即迭代次数;第2、3列分别是训练集与验证集上的损失函数值;第4列是验证集迄今最佳损失;第5、6列是已用时间和预估剩余时间。验证集损失不再改善时,配合 --use-best-model 会回退到最优那棵。
若脚本里设了参数搜索区间,模型会按文件内容循环训多次。全部树跑完后,把剩下6个 bat 依次启动,就能拿到带标签和统计值的训练产物。下面是 _01_Train_All.bat 里核心的循环训练指令,注意学习率 0.03、迭代 1000、深度 6 这组默认值。
别把验证集当上帝
test.csv 同时承担早停与控制的作用,外汇与贵金属行情高波动、易过拟合,验证损失好看不等于实盘泛化概率高,上 MT5 前先拿 exam.csv 过一遍再信。
FOR %%a IN(*.) DO( catboost-class="num">0.24.class="num">1.exe fit --learn-set train.csv --test-set test.csv --column-description %%a --has-header --delimiter ; --model-format CatboostBinary,CPP --train-dir ..\Rezultat\RS_16\result_4_%%a --depth class="num">6 --iterations class="num">1000 --nan-mode Forbidden --learning-rate class="num">0.03 --rsm class="num">1 --fold-permutation-block class="num">1 --boosting-type Plain --l2-leaf-reg class="num">6 --loss-function Logloss --use-best-model --eval-metric Logloss --custom-metric Logloss --od-type Iter --od-wait class="num">100 --random-seed class="num">0 --random-strength class="num">1 --auto-class-weights SqrtBalanced --sampling-frequency PerTreeLevel --border-count class="num">16 --feature-border-type MinEntropy --output-borders-file quant_4_00016.csv --bootstrap-type Bayesian --bagging-temperature class="num">1 --leaf-estimation-method Newton --leaf-estimation-iterations class="num">10)
◍ CatBoost 训练脚本的双边界粒度跑法
把同一份 train.csv / test.csv 用 CatBoost 0.24.1 CLI 跑两遍,差异只在分位边界数(border-count)和输出目录:一遍 32、一遍 48,其余超参完全锁死。 两条命令的共性参数值得记死:depth=6、iterations=1000、learning-rate=0.03、loss-function=Logloss、boosting-type=Plain、l2-leaf-reg=6、random-seed=0。这种锁参只动边界数的做法,能干净地隔离「特征离散化密度」对二分类概率输出的影响。 输出里 --output-borders-file 分别落盘为 quant_4_00032.csv 与 quant_4_00048.csv,后续可在 MT5 里读这两个分位文件,比对同一根 K 线被映射到哪个桶。外汇与贵金属波动有跳空,边界密度不同可能让模型对极值反应速度出现概率偏差,属高风险验证项。 直接复制下面命令改 %%a 为你的列描述文件前缀即可本地复跑;想看桶映射差异就 diff 那两个 borders csv。
catboost-class="num">0.24.class="num">1.exe fit --learn-set train.csv --test-set test.csv --column-description %%a --has-header --delimiter ; --model-format CatboostBinary,CPP --train-dir ..\Rezultat\RS_32\result_4_%%a --depth class="num">6 --iterations class="num">1000 --nan-mode Forbidden --learning-rate class="num">0.03 --rsm class="num">1 --fold-permutation-block class="num">1 --boosting-type Plain --l2-leaf-reg class="num">6 --loss-function Logloss --use-best-model --eval-metric Logloss --custom-metric Logloss --od-type Iter --od-wait class="num">100 --random-seed class="num">0 --random-strength class="num">1 --auto-class-weights SqrtBalanced --sampling-frequency PerTreeLevel --border-count class="num">32 --feature-border-type MinEntropy --output-borders-file quant_4_00032.csv --bootstrap-type Bayesian --bagging-temperature class="num">1 --leaf-estimation-method Newton --leaf-estimation-iterations class="num">10 catboost-class="num">0.24.class="num">1.exe fit --learn-set train.csv --test-set test.csv --column-description %%a --has-header --delimiter ; --model-format CatboostBinary,CPP --train-dir ..\Rezultat\RS_48\result_4_%%a --depth class="num">6 --iterations class="num">1000 --nan-mode Forbidden --learning-rate class="num">0.03 --rsm class="num">1 --fold-permutation-block class="num">1 --boosting-type Plain --l2-leaf-reg class="num">6 --loss-function Logloss --use-best-model --eval-metric Logloss --custom-metric Logloss --od-type Iter --od-wait class="num">100 --random-seed class="num">0 --random-strength class="num">1 --auto-class-weights SqrtBalanced --sampling-frequency PerTreeLevel --border-count class="num">48 --feature-border-type MinEntropy --output-borders-file quant_4_00048.csv --bootstrap-type Bayesian --bagging-temperature class="num">1 --leaf-estimation-method Newton --leaf-estimation-iterations class="num">10
「CatBoost 双分位边界的训练批处理写法」
把梯度提升模型接进 MT5 信号管线前,先用命令行把特征分箱边界固化下来,能避免每次加载模型时重复计算。下面两条批处理分别用 64 和 80 个边界做量化,输出到不同结果目录,便于后续比对哪档分位对贵金属波动更敏感。 两条命令只在 --train-dir、--border-count、--output-borders-file 三个参数上有差异:RS_64 对应 border-count 64、导出 quant_4_00064.csv;RS_80 对应 border-count 80、导出 quant_4_00080.csv。其余超参完全一致,depth 6、iterations 1000、learning-rate 0.03、loss-function Logloss。 特征切分选了 MinEntropy 而非 Uniform,意味着分箱点会偏向信息增益大的价格区间,对外汇跳空时段的捕捉倾向更紧。贝叶斯自助采样(bagging-temperature 1)配合 PerTreeLevel 频率,让每棵树层级都重抽样本,过拟合概率相对降低,但外汇高杠杆环境下仍属高风险验证项。 开 MT5 前可直接复制这两条命令跑一遍,看 Rezultat 目录下生成的 CPP 模型头文件体积差多少——80 边界通常比 64 大约 20%~30%,这是特征维度膨胀的直接代价。
catboost-class="num">0.24.class="num">1.exe fit --learn-set train.csv --test-set test.csv --column-description %%a --has-header --delimiter ; --model-format CatboostBinary,CPP --train-dir ..\Rezultat\RS_64\result_4_%%a --depth class="num">6 --iterations class="num">1000 --nan-mode Forbidden --learning-rate class="num">0.03 --rsm class="num">1 --fold-permutation-block class="num">1 --boosting-type Plain --l2-leaf-reg class="num">6 --loss-function Logloss --use-best-model --eval-metric Logloss --custom-metric Logloss --od-type Iter --od-wait class="num">100 --random-seed class="num">0 --random-strength class="num">1 --auto-class-weights SqrtBalanced --sampling-frequency PerTreeLevel --border-count class="num">64 --feature-border-type MinEntropy --output-borders-file quant_4_00064.csv --bootstrap-type Bayesian --bagging-temperature class="num">1 --leaf-estimation-method Newton --leaf-estimation-iterations class="num">10 catboost-class="num">0.24.class="num">1.exe fit --learn-set train.csv --test-set test.csv --column-description %%a --has-header --delimiter ; --model-format CatboostBinary,CPP --train-dir ..\Rezultat\RS_80\result_4_%%a --depth class="num">6 --iterations class="num">1000 --nan-mode Forbidden --learning-rate class="num">0.03 --rsm class="num">1 --fold-permutation-block class="num">1 --boosting-type Plain --l2-leaf-reg class="num">6 --loss-function Logloss --use-best-model --eval-metric Logloss --custom-metric Logloss --od-type Iter --od-wait class="num">100 --random-seed class="num">0 --random-strength class="num">1 --auto-class-weights SqrtBalanced --sampling-frequency PerTreeLevel --border-count class="num">80 --feature-border-type MinEntropy --output-borders-file quant_4_00080.csv --bootstrap-type Bayesian --bagging-temperature class="num">1 --leaf-estimation-method Newton --leaf-estimation-iterations class="num">10
CatBoost 量化边界的两次拟合命令
把行情特征送进 CatBoost 做二分类拟合时,边界分桶数(border-count)会直接影响特征离散化的粒度。下面两条命令只在边界数上不同:一条用 96 个分位边界,另一条用 112 个,其余超参完全一致,便于横向比对分桶密度对 Logloss 的影响。 两条都跑了 1000 次迭代、学习率 0.03、树深 6,损失函数与评估指标均为 Logloss,并用 Iter 早停(od-wait=100)保留验证集上最优模型。这种对照跑法能帮助判断:在外汇或贵金属这类高噪声品种上,更细的边界是提升区分度还是过拟合。 注意外汇 / 贵金属杠杆交易风险较高,模型回测优不代表实盘概率占优,参数仅作 MT5 外接 Python 训练时的参照。
catboost-class="num">0.24.class="num">1.exe fit --learn-set train.csv --test-set test.csv --column-description %%a --has-header --delimiter ; --model-format CatboostBinary,CPP --train-dir ..\Rezultat\RS_96\result_4_%%a --depth class="num">6 --iterations class="num">1000 --nan-mode Forbidden --learning-rate class="num">0.03 --rsm class="num">1 --fold-permutation-block class="num">1 --boosting-type Plain --l2-leaf-reg class="num">6 --loss-function Logloss --use-best-model --eval-metric Logloss --custom-metric Logloss --od-type Iter --od-wait class="num">100 --random-seed class="num">0 --random-strength class="num">1 --auto-class-weights SqrtBalanced --sampling-frequency PerTreeLevel --border-count class="num">96 --feature-border-type MinEntropy --output-borders-file quant_4_00096.csv --bootstrap-type Bayesian --bagging-temperature class="num">1 --leaf-estimation-method Newton --leaf-estimation-iterations class="num">10 catboost-class="num">0.24.class="num">1.exe fit --learn-set train.csv --test-set test.csv --column-description %%a --has-header --delimiter ; --model-format CatboostBinary,CPP --train-dir ..\Rezultat\RS_112\result_4_%%a --depth class="num">6 --iterations class="num">1000 --nan-mode Forbidden --learning-rate class="num">0.03 --rsm class="num">1 --fold-permutation-block class="num">1 --boosting-type Plain --l2-leaf-reg class="num">6 --loss-function Logloss --use-best-model --eval-metric Logloss --custom-metric Logloss --od-type Iter --od-wait class="num">100 --random-seed class="num">0 --random-strength class="num">1 --auto-class-weights SqrtBalanced --sampling-frequency PerTreeLevel --border-count class="num">112 --feature-border-type MinEntropy --output-borders-file quant_4_00112.csv --bootstrap-type Bayesian --bagging-temperature class="num">1 --leaf-estimation-method Newton --leaf-estimation-iterations class="num">10
◍ CatBoost 网格搜参的批处理写法
把梯度提升模型接进 MT5 信号管线前,先用命令行批量训几版 CatBoost 是常见做法。下面这两段是同一套 bat 循环里的两次调用,仅特征分箱数(border-count)不同:128 与 144,其余超参完全一致,方便横向比对分箱粒度对 Logloss 的影响。 两次都固定了 --random-seed 0、--learning-rate 0.03、--iterations 1000、--depth 6,且用 --use-best-model 按验证集 Logloss 挑最优树。外汇与贵金属行情噪声大,这类静态种子回测只代表历史样本,实盘泛化能力可能偏弱,需警惕过拟合。 --border-count 从 128 调到 144,配合 --feature-border-type MinEntropy,意味着每特征候选切分点多了 16 个,叶节点分裂边界更细。若你本地跑同样 train.csv,可直接复制下方命令,改 %%a 为具体列描述文件即可在 ..\Rezultat\RS_128 与 RS_144 下拿到二制模型与 CPP 头。
catboost-class="num">0.24.class="num">1.exe fit --learn-set train.csv --test-set test.csv --column-description %%a --has-header --delimiter ; --model-format CatboostBinary,CPP --train-dir ..\Rezultat\RS_128\result_4_%%a --depth class="num">6 --iterations class="num">1000 --nan-mode Forbidden --learning-rate class="num">0.03 --rsm class="num">1 --fold-permutation-block class="num">1 --boosting-type Plain --l2-leaf-reg class="num">6 --loss-function Logloss --use-best-model --eval-metric Logloss --custom-metric Logloss --od-type Iter --od-wait class="num">100 --random-seed class="num">0 --random-strength class="num">1 --auto-class-weights SqrtBalanced --sampling-frequency PerTreeLevel --border-count class="num">128 --feature-border-type MinEntropy --output-borders-file quant_4_00128.csv --bootstrap-type Bayesian --bagging-temperature class="num">1 --leaf-estimation-method Newton --leaf-estimation-iterations class="num">10 catboost-class="num">0.24.class="num">1.exe fit --learn-set train.csv --test-set test.csv --column-description %%a --has-header --delimiter ; --model-format CatboostBinary,CPP --train-dir ..\Rezultat\RS_144\result_4_%%a --depth class="num">6 --iterations class="num">1000 --nan-mode Forbidden --learning-rate class="num">0.03 --rsm class="num">1 --fold-permutation-block class="num">1 --boosting-type Plain --l2-leaf-reg class="num">6 --loss-function Logloss --use-best-model --eval-metric Logloss --custom-metric Logloss --od-type Iter --od-wait class="num">100 --random-seed class="num">0 --random-strength class="num">1 --auto-class-weights SqrtBalanced --sampling-frequency PerTreeLevel --border-count class="num">144 --feature-border-type MinEntropy --output-borders-file quant_4_00144.csv --bootstrap-type Bayesian --bagging-temperature class="num">1 --leaf-estimation-method Newton --leaf-estimation-iterations class="num">10
「CatBoost 训练命令的参数落地」
把梯度提升模型接进 MT5 信号流程,第一步是在命令行把 CatBoost 0.24.1 跑起来并固化超参。上面这段批处理直接喂入 train.csv 与 test.csv,用分号切列、首行当表头,输出二进制模型加 CPP 源码两套格式,方便后续在 EA 里静态链接。 几个值值得在本地复现:树深 6、迭代 1000、学习率 0.03、L2 叶子正则 6,损失与评估都用 Logloss,类别权重走 SqrtBalanced。border-count 拉到 160 且边界切分选 MinEntropy,特征分桶更细,对价格微观结构可能更敏感,但也更吃内存。 早停设在迭代维度、等待 100 轮无改善就停,随机种子锁 0 保证可重跑。Bayesian 自助采样配温度 1、叶子估计用 Newton 迭代 10 次,这套组合在外汇与贵金属样本上过拟合概率偏低,但杠杆品种固有高风险仍在,回测顺不代表实盘稳。
catboost-class="num">0.24.class="num">1.exe fit --learn-set train.csv --test-set test.csv --column-description %%a --has-header --delimiter ; --model-format CatboostBinary,CPP --train-dir ..\Rezultat\RS_160\result_4_%%a --depth class="num">6 --iterations class="num">1000 --nan-mode Forbidden --learning-rate class="num">0.03 --rsm class="num">1 --fold-permutation-block class="num">1 --boosting-type Plain --l2-leaf-reg class="num">6 --loss-function Logloss --use-best-model --eval-metric Logloss --custom-metric Logloss --od-type Iter --od-wait class="num">100 --random-seed class="num">0 --random-strength class="num">1 --auto-class-weights SqrtBalanced --sampling-frequency PerTreeLevel --border-count class="num">160 --feature-border-type MinEntropy --output-borders-file quant_4_00160.csv --bootstrap-type Bayesian --bagging-temperature class="num">1 --leaf-estimation-method Newton --leaf-estimation-iterations class="num">10 )
把训练好的模型接进EA跑一遍
用 CB_Calc__Svod.mq5 脚本把模型度量和财务结果拉出来。脚本带一个按样本期末余额筛选的过滤器:余额高于阈值时,才会把样本和转成 mqh 的模型画出余额图,存进 CatBoost 项目目录下的独立文件夹。跑完你会看到新建的 Analiz 目录,里面有 CB_Svod.csv、按模型名命名的余额图(设置里开了打印才有),以及装 mqh 模型的 Models_mqh 子目录。 CB_Svod.csv 逐模型记录了指标和财务结果。从 Models_mqh 里挑一个看得顺眼的模型丢进 Expert Advisor 目录,EA 开头那几行空缓冲区声明用「//」注释掉,再把模型文件 include 进来编译。 [CODE] //If the CatBoost model is in an mqh file, comment the below line //uint TreeDepth[];uint TreeSplits[];uint BorderCounts[];float Borders[];double LeafValues[];double Scale[];double Bias[]; #include "model_RS_208_0.mqh"; // Model file [/CODE] 上面代码逐行拆:前两行是占位提示,若模型已是 mqh 格式,就把手动声明的树深度、切分点等数组注释掉,避免和头文件冲突;第三行把具体模型头文件包含进 EA,编译后模型即挂载可用。 策略测试器里把 Apply CatBoost model on data 设 true,关掉样本保存。预测因子行为中 Calculate predictors 开、Save predictors 关、交易量类型对齐训练设定、图表不显示指标、点差佣金填回训时用的值(不影响已训模型)。信号 MA 用周期 8、两分钟周期、线性加权、最高价。模型分类阈值留 0.5、上限留 1、不写文件。 全样本 2014.6.1–2020.10.31 跑下来,最差模型亏 25 点,平均财务结果 3889.9 点,主规则「少亏」基本守住。外汇与贵金属杠杆高,实盘前务必在 MT5 用历史数据复验,模型过去正面不代表未来概率不变。
class=class="str">"cmt">//If the CatBoost model is in an mqh file, comment the below line class=class="str">"cmt">//class="type">uint TreeDepth[];class="type">uint TreeSplits[];class="type">uint BorderCounts[];class="type">float Borders[];class="type">class="kw">double LeafValues[];class="type">class="kw">double Scale[];class="type">class="kw">double Bias[]; class="macro">#include "model_RS_208_0.mqh"; class=class="str">"cmt">// Model file
◍ 训练内外三套样本里的因子权重
模型目录里会落三个分析文件:Analiz_Train 看训练集因子重要性,Analiz_Test 看验证集,Analiz_Exam 看完全训练外的测试集。三者并列,才能判断一个因子是只在拟合时管用,还是出了样本也站得住。 选了 PredictionValuesChange 这种模型分析方法后,汇总表里能直接读出因子排序。实测中前四个预测因子在三类样本里始终排在头部,说明它们对结果模型的贡献最稳,不是某一次切分碰巧冒头。 但因子重要性高度依赖原始样本。某个因子若在样本里取值过窄、覆盖不足,算法就没法客观打分,排名会失真。用真实交易品种历史去跑时,先确认因子在样本中的分布厚度,再信这张表。外汇与贵金属波动受事件驱动,样本偏差会放大过拟合风险。
「CatBoost 能省掉多少造条件的人力」
梯度提升这类机器学习方法,效果上可以对照两种传统做法:无休止地迭代参数,或者手工堆出更多交易条件去抬升策略表现。在 MT5 环境里,标准指标直接就能喂给模型当特征,不用自己另搞一套数据源。 CatBoost 这个库的质量在同类里靠前,关键是它带了一个包装器,让你不碰 Python、不写 R 也能把梯度提升跑起来。对只熟悉 MQL5 的交易者,这等于把建模门槛砍掉一大截,剩下的事就是接特征和看回测。 外汇和贵金属波动受消息面扰动大,模型在历史样本上表现好不等于实盘概率同高,上线前建议在 MT5 用不同年份数据各跑一遍验证。
别急着下结论
把 CatBoost 塞进 EA 的信号函数里,只是把机器学习当过滤器用的第一步。前面系列里给出的复制工具和预处理流程,能让你在 MT5 里直接跑通训练好的模型,但模型召回率实测不超过事件总量的 10%,也就是说大量潜在形态它根本没认出来。 想拿它去压掉 MA 交叉类的反向假信号、拉长持仓时间,思路可行,但大概率会演变成随机游戏——除非你手里的预测因子先做一轮增强。文章展示的只是算法骨架,预测因子质量直接决定模型是否值得信任。 外汇和贵金属杠杆高、滑点跳空频繁,这类模型在样本外失效的速度可能快于你调参的节奏。先开 MT5 把附带的 MQL5.zip 里的例程跑一遍,确认 Signal() 能正常调用 model_CB(),再谈改自己的 EA。