自适应交易系统以及它们在 MetaTrader 5 客户端中的运用·进阶篇
📘

自适应交易系统以及它们在 MetaTrader 5 客户端中的运用·进阶篇

第 2/3 篇

批量挂策略对象的坑与周期排布

在 MT5 里用 CArrayObj 管理多策略时,常见写法是循环 new 出策略对象再 Add 进数组。下面这段把 MA 策略按 3+10*i 的步长铺了 100 个,周期从 3 一路走到 993,回测时内存里会同时驻留上百个 CStrategyMA 实例,EA 初始化耗时可能明显拉长。 对象创建失败必须立刻 delete 已挂的数组并 return(-1),否则 m_all_strategies 里会留半截脏数据,后续 At(i) 取指针容易踩空。注意原文两处循环都用了同样的判空回收逻辑,但第二处把 Print 换成了 printf,编译都能过,只是日志风格不统一。 Stoch 策略那组只跑了 5 个,K/D 周期用 2+5*i、Slowing 用 3+i,也就是 K/D 从 2 到 22、Slowing 从 3 到 7。外汇与贵金属杠杆高,这类多周期堆叠策略组合在历史回测中表现可能与实盘偏离,参数组合爆炸前先想清楚样本量。 别把正态当圣经:周期线性递增不代表覆盖市场状态,993 期 MA 在 M15 上已经跨到十几天,和短期 Stoch 同框跑,信号频率差可能差出两个数量级,组合权重不调就等于瞎加权。

MQL5 / C++
if(t_StrategyMA==NULL)
  {
   class="kw">delete m_all_strategies;
   Print("创建 CStrategyMA 类型对象错误");
   class="kw">return(-class="num">1);
  }
class=class="str">"cmt">//给每个策略设置周期
class="type">int period=class="num">3+i*class="num">10;
class=class="str">"cmt">// 初始化策略
t_StrategyMA.Initialization(period,true);
class=class="str">"cmt">// 设置策略详细信息
t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period));
class=class="str">"cmt">//t_StrategyMA.Set_Stops(class="num">3500,class="num">1000);
class=class="str">"cmt">//把策略对象添加到 m_all_strategies 数组中
m_all_strategies.Add(t_StrategyMA);
 }
 for(class="type">int i=class="num">0; i<m_all_strategies.Total(); i++)
 {
  CSampleStrategy *t_SampleStrategy;
  t_SampleStrategy=m_all_strategies.At(i);
  Print(i," 策略名称:",t_SampleStrategy.StrategyName(),
        " 策略编号:",t_SampleStrategy.StrategyID(),
        " 虚拟交易:",t_SampleStrategy.IsVirtualTradeAllowed());
 }
class=class="str">"cmt">//---
  class="kw">return(class="num">0);
 }
 for(class="type">int i=class="num">0; i<class="num">100; i++)
  {
   CStrategyMA *t_StrategyMA;
   t_StrategyMA=new CStrategyMA;
   if(t_StrategyMA==NULL)
     {
      class="kw">delete m_all_strategies;
      Print("创建 CStrategyMA 类型对象错误");
      class="kw">return(-class="num">1);
     }
   class=class="str">"cmt">//设置每个策略的周期
   class="type">int period=class="num">3+i*class="num">10;
   class=class="str">"cmt">// 初始化策略
   t_StrategyMA.Initialization(period,true);
   class=class="str">"cmt">// 设置策略详细内容
   t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period));
   class=class="str">"cmt">//把策略对象添加到 m_all_strategies 数组中
   m_all_strategies.Add(t_StrategyMA);
  }
 for(class="type">int i=class="num">0; i<class="num">5; i++)
  {
   CStrategyStoch *t_StrategyStoch;
   t_StrategyStoch=new CStrategyStoch;
   if(t_StrategyStoch==NULL)
     {
      class="kw">delete m_all_strategies;
      printf("创建 CStrategyStoch 类型对象错误");
      class="kw">return(-class="num">1);
     }
   class=class="str">"cmt">//设置每个策略的周期
   class="type">int Kperiod=class="num">2+i*class="num">5;
   class="type">int Dperiod=class="num">2+i*class="num">5;
   class="type">int Slowing=class="num">3+i;
   class=class="str">"cmt">// 初始化策略
   t_StrategyStoch.Initialization(Kperiod,Dperiod,Slowing,true);
   class=class="str">"cmt">// 设置策略详细内容

「自适应EA如何在新柱挑出最优策略」

自适应EA的核心调度逻辑放在 OnTick 里:每跳先让容器内所有策略对象刷新各自持仓数据,再用 IsNewBar() 拦截,只在出新柱时才跑交易条件检查。这样能把非必要计算压到最低,MT5 实盘里 CPU 占用倾向更平稳。 挑最优策略靠的是效率数组。代码里先 ArrayResize 出与策略总数等长的 performance[],逐个调 StrategyPerformance() 填值,再用 ArrayMaximum 拿到最大效率对应的索引。若你挂了 5 套随机参数 Stoch 策略,日志会打印「策略总数=5 最佳索引=3」这类数据,直接可抄去观察哪套参数在当前品种更扛打。 去初始化时别漏了虚拟成交落地。DeInit 里对每个策略先 SaveVirtualDeals 写 txt,再调 Deinitialization,最后 delete 数组对象——外汇与贵金属杠杆高,回测虚拟权益和实盘滑点可能偏差明显,拿这套做仓位切换前务必先跑几天模拟盘验证。

MQL5 / C++
class="type">class="kw">string s=IntegerToString(Kperiod)+"/"+IntegerToString(Dperiod)+"/"+IntegerToString(Slowing);
t_StrategyStoch.SetStrategyInfo(_Symbol,"[Stoch_"+s+"]",class="num">100+i," Stochastic "+s);
class=class="str">"cmt">//把策略对象添加到 m_all_strategies 数组中
m_all_strategies.Add(t_StrategyStoch);
 }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 自适应EA的去初始化函数              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int CAdaptiveStrategy::Expert_OnDeInit(const class="type">int reason)
  {
 class=class="str">"cmt">// 去初始化所有的策略
  for(class="type">int i=class="num">0; i<m_all_strategies.Total(); i++)
   {
    CSampleStrategy *t_Strategy;
    t_Strategy=m_all_strategies.At(i);
    t_Strategy.SaveVirtualDeals(t_Strategy.StrategyName()+"_deals.txt");
    t_Strategy.Deinitialization();
   }
 class=class="str">"cmt">//删除策略对象数组 
  class="kw">delete m_all_strategies;
  class="kw">return(class="num">0);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 自适应策略的订单处理函数                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CAdaptiveStrategy::Expert_OnTick()
  {
  CSampleStrategy *t_Strategy;
  class=class="str">"cmt">// 重新计算策略的仓位信息
  for(class="type">int i=class="num">0; i<m_all_strategies.Total(); i++)
   {
    t_Strategy=m_all_strategies.At(i);
    t_Strategy.UpdatePositionData();
   }
  class=class="str">"cmt">// EA应该只有在新柱出现的时候才检查进行交易操作的条件
  if(IsNewBar()==false) { class="kw">return; }
  class=class="str">"cmt">// 检查所有策略的交易条件 
  for(class="type">int i=class="num">0; i<m_all_strategies.Total(); i++)
   {
    t_Strategy=m_all_strategies.At(i);
    t_Strategy.CheckTradeConditions();
   }
  class=class="str">"cmt">//寻找最佳仓位
  class=class="str">"cmt">//准备 performance[] 数组
  class="type">class="kw">double performance[];
  ArrayResize(performance,m_all_strategies.Total());
    class=class="str">"cmt">//请求每个策略的效率值,
  class=class="str">"cmt">//每个策略在 Strategyperformance() 函数中返回它
  for(class="type">int i=class="num">0; i<m_all_strategies.Total(); i++)
   {
    t_Strategy=m_all_strategies.At(i);
    performance[i]=t_Strategy.StrategyPerformance();
   }
  class=class="str">"cmt">//寻找策略 (或者说寻找它在 m_all_strategies 容器中的索引)
  class=class="str">"cmt">//根据 Strategyperformance() 返回的最大值
  class="type">int best_strategy_index=ArrayMaximum(performance,class="num">0,WHOLE_ARRAY);
  class=class="str">"cmt">//这个策略是 - t_Strategy
  t_Strategy=m_all_strategies.At(best_strategy_index);
  class=class="str">"cmt">//请求仓位方向
  class="type">int best_direction=t_Strategy.PositionDirection();
  class="type">class="kw">string s=s+" "+t_Strategy.StrategyName()+" "+DoubleToString(t_Strategy.GetVirtualEquity())+" "+IntegerToString(best_direction);
  Print(TimeCurrent()," 策略总数=",m_all_strategies.Total(),
                            " 最佳索引=",best_strategy_index,
                            " 最佳策略="," ",t_Strategy.StrategyName(),
                            " 最佳成绩=",performance[best_strategy_index],"  ="

◍ 用虚拟仓位隔离策略与实盘风险

这段逻辑先把最佳策略的方向和成绩打印出来,供调试时肉眼核对。关键一句:若 best_strategy_index 对应的绩效为负,且 RealPositionDirection() 返回 POSITION_NEUTRAL(即 0,无实仓),函数直接 return,不下达任何订单——这是用代码强制空仓的硬开关。 当 best_direction 与当前实盘方向不一致时,才调用 ProceedSignalReal(best_direction, t_Strategy.GetCurrentLotSize()) 去触发真实信号。也就是说,策略层算出的最佳方向不会每次都覆盖实盘,只在方向冲突时动手。 下方头文件里用宏把仓位状态固化成数字:POSITION_NEUTRAL=0、POSITION_LONG=1、POSITION_SHORT=-1;信号侧则用 SIGNAL_OPEN_LONG=10、SIGNAL_OPEN_SHORT=-10 等区分开仓与平仓意图。虚拟仓位结构 virtual_position 单独存 symbol、direction、volume、profit、stop_loss、take_profit 及开平时间价格,实盘与回测可共用同一套字段。 外汇与贵金属杠杆高,虚拟仓位即便算错也只丢点数不丢本金;但把虚拟信号接进实盘前,务必在 MT5 策略测试器跑通 direction 与 performance 的符号校验,避免负收益策略误发单。

MQL5 / C++
              " 最佳方向=",best_direction,
              " 成绩=",t_Strategy.StrategyPerformance());
  class=class="str">"cmt">//如果最佳策略结果为负并且没有开启的仓位,最好不要进行交易
  if((performance[best_strategy_index]<class="num">0) && (RealPositionDirection()==POSITION_NEUTRAL)) {class="kw">return;}
  if(best_direction!=RealPositionDirection())
    {
      ProceedSignalReal(best_direction,t_Strategy.GetCurrentLotSize());
    }
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                     CSampleStrategy.mqh |
class=class="str">"cmt">//|           Copyright class="num">2010, MetaQuotes Software Corp. |
class=class="str">"cmt">//|                     [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2010, MetaQuotes Software Corp."
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#include <Object.mqh>
class="macro">#define POSITION_NEUTRAL    class="num">0     class=class="str">"cmt">// 没有仓位
class="macro">#define POSITION_LONG       class="num">1     class=class="str">"cmt">// 买入仓位
class="macro">#define POSITION_SHORT     -class="num">1     class=class="str">"cmt">// 卖出仓位
class="macro">#define SIGNAL_OPEN_LONG    class="num">10    class=class="str">"cmt">// 开启买入仓位的信号
class="macro">#define SIGNAL_OPEN_SHORT  -class="num">10    class=class="str">"cmt">// 开启卖出仓位的信号
class="macro">#define SIGNAL_CLOSE_LONG   -class="num">1    class=class="str">"cmt">// 关闭买入仓位的信号
class="macro">#define SIGNAL_CLOSE_SHORT   class="num">1    class=class="str">"cmt">// 关闭卖出仓位的信号
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 保存虚拟仓位参数的结构           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">struct virtual_position
  {
   class="type">class="kw">string            symbol;            class=class="str">"cmt">// 交易品种
   class="type">int               direction;         class=class="str">"cmt">// 虚拟仓位方向 (class="num">0-没有仓位,+class="num">1 买入,-class="num">1 卖出)
   class="type">class="kw">double            volume;            class=class="str">"cmt">// 仓位交易量
   class="type">class="kw">double            profit;            class=class="str">"cmt">// 当前虚拟仓位的利润点数
   class="type">class="kw">double            stop_loss;         class=class="str">"cmt">// 虚拟仓位的止损价位
   class="type">class="kw">double            take_profit;       class=class="str">"cmt">// 虚拟仓位的获利价位
   class="type">class="kw">datetime          time_open;         class=class="str">"cmt">// 虚拟仓位的开启时间
   class="type">class="kw">datetime          time_close;        class=class="str">"cmt">// 虚拟仓位的关闭时间
   class="type">class="kw">double            price_open;        class=class="str">"cmt">// 虚拟仓位的建仓价位

策略类的虚拟仓位结构怎么摆

在 MT5 里做无风险预演,核心是把真实下单逻辑换成一套虚拟持仓结构。下面这段类声明把每笔模拟交易的元数据全摊开了:平仓价、生命周期高低点、进出场效率都单独成字段,方便后面回测时直接算滑点损耗。 初始余额在构造函数里默认给 10000,止损止盈以点数(m_sl_points / m_tp_points)形式存,不绑定具体点值,换品种时不用改结构。虚拟余额和净值是分开维护的,这样能看出浮盈回撤和真实权益的偏离。 开 MT5 新建 EA 时,直接照这个 protected 成员清单抄一遍,先把 m_virtual_trade_allowed 置 true,就能在不碰实盘的情况下跑通信号 state 机。外汇和贵金属杠杆高,虚拟测试过的参数上线后仍可能因点差跳变失效,需小仓验证。

MQL5 / C++
  class="type">class="kw">double                price_close;      class=class="str">"cmt">// 虚拟仓位的平仓价位
  class="type">class="kw">double                price_highest;     class=class="str">"cmt">// 虚拟仓位生命周期中的最高价位
  class="type">class="kw">double                price_lowest;      class=class="str">"cmt">// 虚拟仓位生命周期中的最低价位
  class="type">class="kw">double                entry_eff;         class=class="str">"cmt">// 进入效率
  class="type">class="kw">double                exit_eff;          class=class="str">"cmt">// 退出效率
  class="type">class="kw">double                trade_eff;         class=class="str">"cmt">// 交易效率
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| CSampleStrategy 类                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class CSampleStrategy: class="kw">public CObject
  {
class="kw">protected:
   class="type">int                m_strategy_id;          class=class="str">"cmt">// 策略编号
   class="type">class="kw">string             m_strategy_symbol;      class=class="str">"cmt">// 交易品种 
   class="type">class="kw">string             m_strategy_name;        class=class="str">"cmt">// 策略名称
   class="type">class="kw">string             m_strategy_comment;     class=class="str">"cmt">// 注释
   class="type">MqlTick            m_price_last;           class=class="str">"cmt">// 最后价位
   class="type">MqlRates           m_rates[];              class=class="str">"cmt">// 当前报价的数组
   class="type">bool               m_virtual_trade_allowed;class=class="str">"cmt">// 允许虚拟交易的标志 
   class="type">int                m_current_signal_state; class=class="str">"cmt">// 当前策略的状态
   class="type">class="kw">double             m_current_trade_volume; class=class="str">"cmt">// 交易手数
   class="type">class="kw">double             m_initial_balance;      class=class="str">"cmt">// 初始余额 (在构造函数中设定, 默认值为 class="num">10000)
   class="type">int                m_sl_points;            class=class="str">"cmt">// 止损点数
   class="type">int                m_tp_points;            class=class="str">"cmt">// 获利点数
   virtual_position   m_position;             class=class="str">"cmt">// 虚拟仓位
   virtual_position   m_deals_history[];      class=class="str">"cmt">// 交易数组
   class="type">int                m_virtual_deals_total;  class=class="str">"cmt">// 交易总数
   class="type">class="kw">double             m_virtual_balance;      class=class="str">"cmt">// 虚拟余额
   class="type">class="kw">double             m_virtual_equity;       class=class="str">"cmt">// 虚拟净值
   class="type">class="kw">double             m_virtual_cumulative_profit; class=class="str">"cmt">// 累计虚拟利润

「虚拟持仓与风控接口的底层声明」

在 MT5 里做策略回测或影子账户,最怕真实下单把本金打穿。把仓位逻辑抽象成 virtual_position 结构,用一套独立函数管理虚拟开平,就能在不开真实单的前提下观察权益曲线。 double m_virtual_profit; // 当前开启的虚拟仓位的利润 bool CheckVirtual_Stops(virtual_position &position); // 检查并且如有必要根据止损价位关闭虚拟仓位 void RecalcPositionProperties(virtual_position &position); // 重新计算仓位和余额 void Position_RefreshInfo(virtual_position &position); // 重新根据现有价位计算虚拟建仓信息 void Position_OpenShort(virtual_position &position); // 开启虚拟卖出仓位 void Position_CloseShort(virtual_position &position); // 关闭虚拟卖出仓位 void Position_OpenLong(virtual_position &position); // 开启虚拟买入仓位 void Position_CloseLong(virtual_position &position); // 关闭虚拟买入仓位 void Position_CloseOpenedPosition(virtual_position &position); // 关闭开启的虚拟仓位 void AddDealToHistory(virtual_position &position); // 把关闭的仓位添加到 m_deals_history[] 数组中 (交易历史) virtual double MoneyManagement_CalculateLots(double trade_volume); // 计算并且返回将用于交易的推荐的交易量 上面这组声明里,CheckVirtual_Stops 是风控闸门,Position_OpenShort / OpenLong 决定方向,AddDealToHistory 把每笔闭环写入本地历史数组。外汇与贵金属波动剧烈、杠杆高危,实盘前先用这套虚拟接口跑至少 3 个月 tick 数据,才可能看出止损点数是不是设得太紧。 对外暴露的 public 接口更轻量:GetVirtualBalance 返回虚拟余额,Set_Stops(int tp,int sl) 直接写止损止盈点数,SetLots 设定手数。StrategyID 和 StrategyName 用来在多策略并行时区分实例,避免日志串号。

MQL5 / C++
class="type">class="kw">double                m_virtual_profit;                class=class="str">"cmt">// 当前开启的虚拟仓位的利润
class=class="str">"cmt">//检查并且如有必要根据止损价位关闭虚拟仓位
class="type">bool                 CheckVirtual_Stops(virtual_position &position);
class=class="str">"cmt">// 重新计算仓位和余额
class="type">void                 RecalcPositionProperties(virtual_position &position);
class=class="str">"cmt">// 重新根据现有价位计算虚拟建仓信息 
class="type">void                 Position_RefreshInfo(virtual_position &position);
class=class="str">"cmt">// 开启虚拟卖出仓位
class="type">void                 Position_OpenShort(virtual_position &position);
class=class="str">"cmt">// 关闭虚拟卖出仓位  
class="type">void                 Position_CloseShort(virtual_position &position);
class=class="str">"cmt">// 开启虚拟买入仓位
class="type">void                 Position_OpenLong(virtual_position &position);
class=class="str">"cmt">// 关闭虚拟买入仓位
class="type">void                 Position_CloseLong(virtual_position &position);
class=class="str">"cmt">// 关闭开启的虚拟仓位  
class="type">void                 Position_CloseOpenedPosition(virtual_position &position);
class=class="str">"cmt">// 把关闭的仓位添加到 m_deals_history[] 数组中 (交易历史)
class="type">void                 AddDealToHistory(virtual_position &position);
class=class="str">"cmt">//计算并且返回将用于交易的推荐的交易量
class="kw">virtual class="type">class="kw">double       MoneyManagement_CalculateLots(class="type">class="kw">double trade_volume);
class="kw">public:
class=class="str">"cmt">// 构造函数
class="type">void                 CSampleStrategy();
class=class="str">"cmt">// 析构函数
class="type">void                ~CSampleStrategy();
class=class="str">"cmt">//返回当前虚拟余额
class="type">class="kw">double               GetVirtualBalance() { class="kw">return(m_virtual_balance); }
class=class="str">"cmt">//返回当前虚拟净值
class="type">class="kw">double               GetVirtualEquity() { class="kw">return(m_virtual_equity); }
class=class="str">"cmt">//返回当前虚拟持仓利润
class="type">class="kw">double               GetVirtualProfit() { class="kw">return(m_virtual_profit); }
class=class="str">"cmt">//设置止损获利点数
class="type">void                 Set_Stops(class="type">int tp,class="type">int sl) {m_tp_points=tp; m_sl_points=sl;};
class=class="str">"cmt">//设置当前交易手数
class="type">void                 SetLots(class="type">class="kw">double trade_volume) {m_current_trade_volume=trade_volume;};
class=class="str">"cmt">//返回当前交易手数
class="type">class="kw">double               GetCurrentLots() { class="kw">return(m_current_trade_volume); }
class=class="str">"cmt">// 返回策略名称
class="type">class="kw">string               StrategyName() { class="kw">return(m_strategy_name); }
class=class="str">"cmt">// 返回策略编号
class="type">int                  StrategyID() { class="kw">return(m_strategy_id); }
class=class="str">"cmt">// 返回策略注释
class="type">class="kw">string               StrategyComment() { class="kw">return(m_strategy_comment); }
class=class="str">"cmt">// 返回策略详细信息 (策略的交易品种,名称,编号)
class="type">void                 SetStrategyInfo(class="type">class="kw">string symbol,class="type">class="kw">string name,class="type">int id,class="type">class="kw">string comment);
class=class="str">"cmt">// 设置虚拟交易标志 (是否允许虚拟交易)

◍ 虚拟交易类的接口与虚函数落点

上面这段是策略基类的尾部声明,把虚拟交易相关的读写接口和可供派生的虚函数一次性摊开。实盘跑 EA 前,先在 MT5 里把这些成员函数对照看一遍,能少踩一半继承坑。 SetVirtualTradeFlag 用 bool 开关控制是否允许虚拟成交,IsVirtualTradeAllowed 直接返回该标志位;这两个成对出现,是用来在回测和实盘之间切阀的。GetSignalState 与 SetSignalState 负责读取和写入策略状态,后者会顺带按需要改虚拟仓位。 ProceedSignalState 接收 virtual_position 引用去改虚拟仓位,SetVirtualCumulativeProfit 写累计虚拟利润,StrategyPerformance 回吐策略效率值——这几个没有内联实现,说明具体算法留给子类。UpdatePositionData、CloseVirtualPosition、PositionDirection、SaveVirtualDeals 则处理仓位数据维护、平仓、方向读取和成交落盘。 Initialization、CheckTradeConditions、Deinitialization 被标成 virtual,默认分别返回 0、false、0。你要接自己的逻辑,就 override 这三个,其余接口保持原签名,MT5 编译器才不会报派生不匹配。

MQL5 / C++
  class="type">void                SetVirtualTradeFlag(class="type">bool pFlag) { m_virtual_trade_allowed=pFlag; };
  class=class="str">"cmt">// 返回是否允许虚拟交易的标志
  class="type">bool                IsVirtualTradeAllowed() { class="kw">return(m_virtual_trade_allowed); };
  class=class="str">"cmt">// 返回策略的当前状态
  class="type">int                 GetSignalState();
  class=class="str">"cmt">// 设置策略的当前状态 (如有必要修改虚拟仓位)
  class="type">void                SetSignalState(class="type">int state);
  class=class="str">"cmt">// 根据状态修改虚拟仓位 
  class="type">void                ProceedSignalState(virtual_position &position);
  class=class="str">"cmt">// 设置累计虚拟利润值
  class="type">void                SetVirtualCumulativeProfit(class="type">class="kw">double cumulative_profit) { m_virtual_cumulative_profit=cumulative_profit; };
  class=class="str">"cmt">//返回策略效率
  class="type">class="kw">double              StrategyPerformance();
  class=class="str">"cmt">//更新仓位数据
  class="type">void                UpdatePositionData();
  class=class="str">"cmt">//关闭开启的仓位
  class="type">void                CloseVirtualPosition();
  class=class="str">"cmt">//返回当前虚拟仓位的方向
  class="type">int                 PositionDirection();
  class=class="str">"cmt">//初始化虚拟函数
  class="kw">virtual class="type">int         Initialization() {class="kw">return(class="num">0);};
  class=class="str">"cmt">//检查交易条件的虚拟函数
  class="kw">virtual class="type">bool        CheckTradeConditions() {class="kw">return(false);};
  class=class="str">"cmt">//去初始化的虚拟函数
  class="kw">virtual class="type">int         Deinitialization() {class="kw">return(class="num">0);};
  class=class="str">"cmt">//把虚拟交易保存到文件中
  class="type">void                SaveVirtualDeals(class="type">class="kw">string file_name);
};

常见问题

常见坑是周期排布重叠或对象初始化顺序错乱。建议在新柱事件里统一遍历策略池,按优先级挑出最优策略再执行,避免互相覆盖。
在OnTick或新柱回调中做一次轻量评分,比较各策略近期盈亏与波动适配度,只加载评分最高的策略实例,其余挂起。
可以。小布盯盘的AIGC会按品种页扫描策略表现,周期适配偏移时直接推送提示,你只需确认是否切换,不用自己盯日志。
把策略类拆出独立的虚拟持仓结构,实盘下单走另一风控接口。虚拟类只记录意向仓位,不直接调经纪商接口,隔离爆仓传导。
至少声明虚拟开平、持仓查询与风险上限三个虚函数,由子类落点实现。底层不碰真实账户,只做逻辑验证与回测闭环。