使用Python和MQL5进行多交易品种分析(第一部分):纳斯达克集成电路制造商·综合运用
「多标的组合管理的资源与校验骨架」
在 MT5 里做跨品种组合,第一步不是算权重,而是确保行情窗口里有你要的标的。下面这段逻辑用 SymbolSelect 把 5 个符号强行加入 Market Watch,只要有一个加不进就直接返回 false 并 Comment 报错,避免后续空跑。 void release_resources(void) 里只做了一件事:调用 ExpertRemove() 释放 EA。实盘里若发现必要符号不可用,与其卡死不如主动退场,这是比硬扛更稳的工程习惯。 check_trade_symbols 遍历 5 个符号,当 PositionsTotal()==0 且该标的 optimal_weights 不为 0 时,才进入 optimize_portfolio。也就是说,无持仓且有权重配置才开仓,能避免重复优化。 optimize_portfolio 中若 weight<0 则走 check_sell,卖出时用 Trade.Sell(trade_size,symbol,bid,0,0,"NASDAQ IC AI")。外汇与贵金属属高杠杆品种,这类组合逻辑若套用至 XAUUSD 等标的,需自行重测滑点与点值,回测不代表实盘概率。
ask = SymbolInfoDouble(Symbol(),SYMBOL_ASK); bid = SymbolInfoDouble(Symbol(),SYMBOL_BID); } class=class="str">"cmt">//+-------------------------------------------------------------------+ class=class="str">"cmt">//| Release the resources we no longer need | class=class="str">"cmt">//+-------------------------------------------------------------------+ class="type">void release_resources(class="type">void) { ExpertRemove(); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Validate that all the symbols we need are available | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool validate_symbol(class="type">void) { for(class="type">int i=class="num">0; i < class="num">5; i++) { class=class="str">"cmt">//--- We failed to add one of the necessary symbols to the Market Watch window! if(!SymbolSelect(stocks[i],true)) { Comment("Failed to add ",stocks[i]," to the market watch. Ensure the symbol is available."); class="kw">return(class="kw">false); } } class=class="str">"cmt">//--- Everything went fine class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check if we have any trade opportunities | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void check_trade_symbols(class="type">void) { class=class="str">"cmt">//--- Loop through all the symbols we have for(class="type">int i=class="num">0;i < class="num">5;i++) { class=class="str">"cmt">//--- Select that symbol and check how many positons we have open if(SymbolSelect(stocks[i],true)) { class=class="str">"cmt">//--- If we have no positions in that symbol, optimize the portfolio if((PositionsTotal() == class="num">0) && (optimal_weights[i] != class="num">0)) { optimize_portfolio(stocks[i],optimal_weights[i]); } } } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Optimize our portfolio | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void optimize_portfolio(class="type">class="kw">string symbol,class="type">int weight) { class=class="str">"cmt">//--- If the weight is less than class="num">0, check if we have any oppurtunities to sell that stock if(weight < class="num">0) { if(SymbolSelect(symbol,true)) { class=class="str">"cmt">//--- If we have oppurtunities to sell, act on it if(check_sell(symbol, weight)) { Trade.Sell(trade_size,symbol,bid,class="num">0,class="num">0,"NASDAQ IC AI");
◍ 多空触发前的过滤器怎么写
上面那段主循环在 else 分支里走买入逻辑:先 SymbolSelect 把标的拉进市场观察窗,再调 check_buy 判机会,过了才用 Trade.Buy 下市价多单,魔术号写的是 "NASDAQ IC AI"。真正决定能不能开的门槛,全在 check_buy / check_sell 两个函数里。 check_buy 先挂 Bollinger 与 RSI 句柄,iBands 取 PRICE_CLOSE、偏差 1、周期 bb_period;iRSI 周期 rsi_period。任一句柄等于 INVALID_HANDLE 直接 return false,避免指标没加载就瞎读缓冲。 关键的滤条件只有一句:若布林上轨 bb_high_buffer[0] 低于最新收盘价,且 RSI 读数大于 70,则 return false。也就是说价格已经戳破上轨又叠加超买,系统反而放弃追多,倾向把它当反转风险而非突破信号。 持仓数用 PositionsTotal() >= weight 卡上限,weight 即允许的最大同方向敞口。check_sell 里先把 weight 乘 -1,逻辑对称,但原文在此处截断,下半段校验未给出,实盘抄写时需补完。外汇与贵金属波动剧烈,这类过滤只能降频、不能消除滑点与跳空风险,参数 bb_period / rsi_period 建议在 MT5 策略测试器里按品种重估。
class="type">bool check_buy(class="type">class="kw">string symbol, class="type">int weight) { SymbolSelect(symbol,true); bb_handler = iBands(symbol,PERIOD_CURRENT,bb_period,class="num">0,class="num">1,PRICE_CLOSE); rsi_handler = iRSI(symbol,PERIOD_CURRENT,rsi_period,PRICE_CLOSE); if((bb_handler == INVALID_HANDLE) || (rsi_handler == INVALID_HANDLE)) { class="kw">return(class="kw">false); } bb_high_buffer.CopyIndicatorBuffer(bb_handler,class="num">1,class="num">0,class="num">1); rsi_buffer.CopyIndicatorBuffer(rsi_handler,class="num">0,class="num">0,class="num">1); current_close.CopyRates(symbol,PERIOD_CURRENT,COPY_RATES_CLOSE,class="num">0,class="num">1); if((bb_high_buffer[class="num">0] < current_close[class="num">0]) && (rsi_buffer[class="num">0] > class="num">70)) { class="kw">return(class="kw">false); } if(PositionsTotal() >= weight) { class="kw">return(class="kw">false); } class="kw">return(true); } class="type">bool check_sell(class="type">class="kw">string symbol, class="type">int weight) { SymbolSelect(symbol,true); weight = weight * -class="num">1; bb_handler = iBands(symbol,PERIOD_CURRENT,bb_period,class="num">0,class="num">1,PRICE_CLOSE); rsi_handler = iRSI(symbol,PERIOD_CURRENT,rsi_period,PRICE_CLOSE); if((bb_handler == INVALID_HANDLE) || (rsi_handler == INVALID_HANDLE)) {
空单触发前的三道闸门
这段逻辑卡的是布林下轨、RSI 与持仓数的组合条件,全过才放单。外汇与贵金属杠杆高,信号失效会迅速扩大浮亏,任何条件都要在 MT5 里实测而非盲信。 先把指标缓冲拉进内存:布林下轨缓冲索引 2、RSI 主缓冲索引 0,各取最新 1 根;收盘价用 CopyRates 抓当前周期最新 1 根。这三行若任一返回 false,函数直接退出,不交易。 真正过滤空单的是这句:下轨值大于收盘价,且 RSI 小于 30,才认为有超卖反弹式的做空机会。若不满足,return(false) 拦掉。 最后一道是仓位闸:PositionsTotal() 大于等于 weight 参数就放弃开仓,避免同一权重下过度堆叠。三关全过返回 true,交给上层去发单。
class=class="str">"cmt">//--- Something went wrong class="kw">return(class="kw">false); } class=class="str">"cmt">//--- Load indicator readings into the buffers bb_low_buffer.CopyIndicatorBuffer(bb_handler,class="num">2,class="num">0,class="num">1); rsi_buffer.CopyIndicatorBuffer(rsi_handler,class="num">0,class="num">0,class="num">1); current_close.CopyRates(symbol,PERIOD_CURRENT,COPY_RATES_CLOSE,class="num">0,class="num">1); class=class="str">"cmt">//--- Validate that we have a valid sell oppurtunity if(!((bb_low_buffer[class="num">0] > current_close[class="num">0]) && (rsi_buffer[class="num">0] < class="num">30))) { class="kw">return(class="kw">false); } class=class="str">"cmt">//--- Do we have enough trades allready open? if(PositionsTotal() >= weight) { class=class="str">"cmt">//--- We have a valid sell setup class="kw">return(class="kw">false); } class=class="str">"cmt">//--- We can go ahead and open a position class="kw">return(true); }
「把工具请下神坛」
前面几节把 AI 定仓位、算分配的逻辑拆开了:实例只用最大化回报这一条目标,模型刻意保持简单,没去碰方差、贝塔或夏普这类指标。 真正进到多品种算法化交易时,你会很快撞上风险敞口和相关性——这系列后续会补,但核心思路不变:优化的是约束下的目标函数,不是求神谕。 附的 NASDAQ_IC_AI.mq5 只有 9.45 KB,Maximizing_Returns.ipynb 是 359.38 KB,先跑通这两个文件比读十篇综述有用。外汇和贵金属杠杆高、回撤可能超预期,任何算法都只是概率优势,别当成保本契约。