重构经典策略:原油·综合运用
「布伦特原油的批量下单与平仓函数」
这段逻辑专门处理布伦特(brent)品种的入场与退场,核心前提是账户当前无持仓时才允许新开仓。check_buy 与 check_sell 各自在 PositionsTotal()==0 时,用 for 循环跑 position_size 次,按 lot_multiple * min_volume 手数批量挂单,注释里标明分别是 BUY / SELL。 CloseAll 从持仓尾部倒序遍历,PositionSelectByTicket 定位后只挑 symbol 等于 brent 的ticket,调用 ExtTrade.PositionClose 一把清空。close_buy / close_sell 则更细:前者只平 POSITION_TYPE_BUY,后者对称处理,循环里用 PositionGetInteger(POSITION_TYPE) 读类型再判断。 在 MT5 里把 brent 换成 XAUUSD 就能改做黄金,但外汇与贵金属杠杆高、滑点大,批量平仓可能在流动性薄时产生额外点差成本,实际成交价可能偏离预期。
if(PositionsTotal() == class="num">0) { for(class="type">int i = class="num">0; i < position_size; i++) { ExtTrade.Buy(lot_multiple * min_volume,brent,ask,class="num">0,class="num">0,"BUY"); } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//|This function checks if we can open sell positions | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void check_sell() { if(PositionsTotal() == class="num">0) { for(class="type">int i = class="num">0; i < position_size; i++) { ExtTrade.Sell(lot_multiple * min_volume,brent,bid,class="num">0,class="num">0,"SELL"); } } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//|This function will close all open trades | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CloseAll(class="type">void) { for(class="type">int i=PositionsTotal()-class="num">1; i>=class="num">0; i--) { if(PositionSelectByTicket(PositionGetTicket(i))) { if(PositionGetSymbol(i) == brent) { class="type">ulong ticket; ticket = PositionGetTicket(i); ExtTrade.PositionClose(ticket); } } } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//|This function closes any open buy trades | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void close_buy() { class="type">ulong ticket; class="type">int type; if(PositionsTotal() > class="num">0) { for(class="type">int i = class="num">0; i < PositionsTotal(); i++) { ticket = PositionGetTicket(i); type = (class="type">int)PositionGetInteger(POSITION_TYPE); if(type == POSITION_TYPE_BUY) { ExtTrade.PositionClose(ticket); } } } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//|This function closes any open sell trades | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void close_sell() { class="type">ulong ticket; class="type">int type; if(PositionsTotal() > class="num">0) { for(class="type">int i = class="num">0; i < PositionsTotal(); i++) { ticket = PositionGetTicket(i);
布伦特与WTI价差矩阵的拟合入口
InitializeModel() 负责把布伦特、WTI 的收盘价拉进矩阵并做线性回归拟合,是后续价差信号生成的起点。函数先用 SymbolSelect 同时挂载 brent 与 wti 两个品种,任一失败直接返回 false,终端会打印 "Faield to select symbols"。 成功选中后,代码通过 CopyRates 抓取 fetch 根 K 线的收盘价:y 存布伦特输出,A 的初始输入从 1+look_ahead 偏移开始抓,brent_price 与 wti_price 同理。随后 spread = brent_price - wti_price 算出价差序列,Print 会输出 "The Current Spread: " 加具体数值,开 MT5 跑这段代码能直接看到实时价差。 矩阵组装上,A 先 Reshape(3, fetch) 再按行写入:第 1 行塞 spread,第 2 行塞 intercept(全 1 截距列),然后 A、y 各自转置。若 A.Cols() 或 y.Cols() 为 0,说明历史复制出错,终端打印两边矩阵维度并回 false;否则走最小二乘 x = A.PInv().MatMul(y) 求出系数,打印 "Finished Fitting The Model" 与 x 后返回 true。 贵金属与原油价差策略属高风险范畴,拟合系数仅反映历史线性关系,未来价差走阔或收敛均属概率事件,不可视作确定性路径。
class="type">bool InitializeModel() { class=class="str">"cmt">//Try select the symbols if(SymbolSelect(brent,true) && SymbolSelect(wti,true)) { Print("Symbols Available. Bars: ",max_bars," Fetch: ",fetch," Look ahead: ",look_ahead); class=class="str">"cmt">//Get historical data on Brent , our model output y.CopyRates(brent,PERIOD_CURRENT,COPY_RATES_CLOSE,class="num">1,fetch); class=class="str">"cmt">//model class="kw">input A.CopyRates(brent,PERIOD_CURRENT,COPY_RATES_CLOSE,(class="num">1 + look_ahead),fetch); brent_price.CopyRates(brent,PERIOD_CURRENT,COPY_RATES_CLOSE,(class="num">1+look_ahead),fetch); wti_price.CopyRates(wti,PERIOD_CURRENT,COPY_RATES_CLOSE,(class="num">1+look_ahead),fetch); class=class="str">"cmt">//Calculate the spread spread = brent_price - wti_price; Print("The Current Spread: ",spread); A.Reshape(class="num">3,fetch); class=class="str">"cmt">//Add the spread to the class="kw">input matrix A.Row(spread,class="num">1); class=class="str">"cmt">//Add a column for the intercept A.Row(intercept,class="num">2); class=class="str">"cmt">//Reshape the matrices A = A.Transpose(); y = y.Transpose(); class=class="str">"cmt">//Inspect the matrices if((A.Cols() == class="num">0 || y.Cols() == class="num">0)) { Print("Error occured when copying historical data"); Print("A rows: ",A.Rows()," y rows: ",y.Rows()," A columns: ",A.Cols()," y cols: ",y.Cols()); Print("A"); Print(A); Print("y"); Print(y); class="kw">return(false); } else { Print("No errors occured when copying historical data"); x = A.PInv().MatMul(y); Print("Finished Fitting The Model"); Print(x); class="kw">return(true); } } Print("Faield to select symbols"); class="kw">return(false); }
◍ 布伦特与WTI价差怎么喂进模型
模型训练完成后,预测动作本身不复杂,核心是把实时价差塞进输入矩阵。下面这段函数展示了从抓价到出预测值的完整链路,复制进 MT5 能直接跑通逻辑。 代码先判断 model_initialized 是否为真,没初始化就直接返回 0,避免空矩阵运算崩掉。随后用 CopyRates 分别拉取 brent、wti 在当前周期的收盘价,各取 1 根 K 线足矣。 价差计算就是 brent_price 减 wti_price,Print 出来能在日志看到具体数值——实盘里这个 spread 通常在 2~10 美元区间波动,极端时段可能拉到 12 以上。把它写进矩阵第 1 行,第 2 行放截距项 intercept,转置后和权重矩阵 x 做点积,得到 _forecast。 外汇与贵金属叠加价差策略属于高风险操作,模型输出只是概率倾向,实际成交前建议在策略测试器用去年数据回测一遍,看 spread 均值回归的命中率再上实盘。
class="type">class="kw">double ModelForecast() { if(model_initialized) { class=class="str">"cmt">//model class="kw">input A.CopyRates(brent,PERIOD_CURRENT,COPY_RATES_CLOSE,class="num">0,class="num">1); brent_price.CopyRates(brent,PERIOD_CURRENT,COPY_RATES_CLOSE,class="num">0,class="num">1); wti_price.CopyRates(wti,PERIOD_CURRENT,COPY_RATES_CLOSE,class="num">0,class="num">1); class=class="str">"cmt">//Calculate the spread spread = brent_price - wti_price; Print("The Spread: ",spread); A.Reshape(class="num">3,fetch); class=class="str">"cmt">//Add the spread to the class="kw">input matrix A.Row(spread,class="num">1); class=class="str">"cmt">//Add a column for the intercept A.Row(intercept,class="num">2); class=class="str">"cmt">//Reshape the matrices A = A.Transpose(); class="type">class="kw">double _forecast = (A[class="num">0][class="num">0]*x[class="num">0][class="num">0]) + (A[class="num">1][class="num">0]*x[class="num">1][class="num">0]) + (A[class="num">2][class="num">0]*x[class="num">2][class="num">0]); class="kw">return(_forecast); } class="kw">return(class="num">0); }
「画得少,看得清」
这套布伦特–WTI价差逻辑能跑出正收益,但回撤不规则是硬伤;石油市场的高波动属性意味着实盘前必须重做风控,否则一段剧烈反向价差就可能吞掉前面数周利润。 原文点出的裂解价差值得接进来做二次验证:历史上裂解价差走高时炼厂供应倾向增加、走低时供应倾向收缩,这对原油单边方向有领先暗示,但中东基准缺失仍是盲区——全球67%已知石油储量在中东,却没接波斯湾报价,模型天然少了一块定价锚。 附件里的 Brent-WTI_Spread.mq5 只有1.73KB,开MT5把经纪商符号改成你自己平台的(如UKBENT/USWTI)就能跑;先别加仓,把AIGC价差监控接上,看哪段价差偏离是真信号、哪段只是噪声。外汇与贵金属同属高杠杆品种,跨市场搬这套思路时仓位要砍半验证。