使用Python和MQL5进行多交易品种分析(第一部分):纳斯达克集成电路制造商·综合运用
📘

使用Python和MQL5进行多交易品种分析(第一部分):纳斯达克集成电路制造商·综合运用

第 3/3 篇

「多标的组合管理的资源与校验骨架」

在 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 等标的,需自行重测滑点与点值,回测不代表实盘概率。

MQL5 / C++
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 策略测试器里按品种重估。

MQL5 / C++
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,交给上层去发单。

MQL5 / C++
   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,先跑通这两个文件比读十篇综述有用。外汇和贵金属杠杆高、回撤可能超预期,任何算法都只是概率优势,别当成保本契约。

常见问题

给每个品种设独立刷新间隔,非活跃时段拉长期限;主循环用事件触发代替死循环轮询,能压到 30% 以内。
在信号函数外再包一层:成交量低于 20 日均量 60% 直接弃单,叠加波动率百分位 < 40 才放行。
小布已内置多标的触发前过滤器与资源占用诊断,打开对应品种页即可看到闸口状态,不用自己写轮询。
至少加价差偏离阈值、相关品种联动背离、以及盘口大单净流出三道;三者共振才提高胜率。
写个轻量校验骨架:比对实时价与本地缓存差值超 0.5% 就标红告警,每日开盘重拉一次基准。