English Русский 日本語
preview
重构经典策略(第十五部分):日线突破交易策略

重构经典策略(第十五部分):日线突破交易策略

MetaTrader 5 — 示例 |
45 0
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

在本系列文章中,我们经常使用机器学习模型来提升交易策略表现。但我们常常忽略一点:这类模型会对现有数据做出大量先验假设。此外,传统统计学习无法帮我们证明,我们想要建模的这些关联关系在真实市场中是否真的存在。

反观人工交易者,在常年与市场打交道的过程中,悟出了一种可以被称为市场逻辑的底层本质。这种认知,也就是我们所说的市场逻辑,只能从实战经验中获得。我们希望能够把人工交易者总结的经验融入数值驱动的交易程序中。早在计算机诞生之前,主观交易者就活跃在金融市场。因此,他们多年总结并奉为圭臬的经验法则里,很可能蕴含着有价值的真知,这些法则值得我们拿来使用。

如前文所述,我们通常借助机器学习算法挖掘规律,用历史数据推演未来。但我们几乎总是默认:这样的关联真实存在,并且能够从数据中学习得到。我们很少花时间先去验证这些关系是否真实成立。而主观交易者为了生存,必须去寻找能够支撑长期交易生涯的可靠市场规律。从这个角度来看,可以说人工交易者完成了前期的人工探索工作,为机器学习模型打下基础。

因此,我们希望搭建起机器学习与金融交易之间的桥梁,利用交易者在多年市场实践中总结的经验与启发式规则。交易者普遍遵循的这些规则,可以作为一套框架,让模型以更结构化的方式学习金融市场。不必让模型从零开始挖掘市场关系;我们可以复用那些经过时间检验有效的原理。这相当于给模型一个良好起点,而不是让它白手起家。

本次测试最重要的环节,就是验证这套基础策略的有效性。为此,我们选取了一套知名的突破策略,核心依据是连续交易日之间的价格关系。这套策略本质上相当简单。


我们的交易策略概述

在每个交易日开始时,我们标记出前一日的最高价与最低价。

图 1:绘制前一日高低价位线,搭建日内突破策略

当价格向上突破前一日高点时,我们做空,止盈位设为前一日低点。反之,当价格向下跌破前一日低点时,我们做多,止盈位设为前一日高点。本质上这是一套逆势交易策略,每日只寻找一次突破交易机会。

图 2:价格首次击穿前一日极值价位,触发开仓信号

有意思的是,即便没有预测模型、也不使用复杂神经网络,对金融市场运行规律的深刻理解本身就是一笔无价的财富。这套日内突破策略的原始版本,尽管看起来朴素,仅依靠主观交易者沉淀下来的市场逻辑,就能取得媲美深度神经网络的胜率。

图 3:价格击穿另一侧极值价位时策略平仓。但从上图可以看出,该策略存在一定误差

我们同时发现,该策略交易风格过于激进,稳定性差。如图 3 所示,策略预设的平仓条件并不总能完全达成。因此必须对策略进行修改,控制其净值波动。这里所说的波动,指回测过程中账户盈利的起伏变化。

在后续章节中我们会看到:首先,我们严格按照大多数交易者熟知的原始描述,实现最简版本的交易策略,以此建立基准绩效。之后对策略进行修改,对比优化前后的差异,确保调整方向符合预期。本次优化从三个核心维度改动策略:

盈利能力

原始策略在五年回测周期内仅盈利 40 美元。无论从哪个角度看,这个结果都不算亮眼。但值得关注的是,全部交易中 68% 都是盈利的。对于长达五年的样本外测试而言,这个胜率相当出色,尤其是该策略没有可调参数,完全依靠市场逻辑与交易直觉。遗憾的是,单笔亏损的平均金额大于单笔盈利,最终只得到微薄的 40 美元收益。

经过多轮迭代优化后,同一回测周期内,改进版策略盈利 162 美元,提升幅度达 300%。除此之外,夏普比率由原来的 0.13 提升至 0.40,相比原版提升 207%。读者请注意:以最小手数固定下单,是为了在更苛刻条件下检验该交易程序是否具备真实能力。

交易效率

原始策略一共执行 886 笔交易,才赚到 40 美元;而优化版本仅需 246 笔交易,即可盈利 162 美元。这意味着优化后的策略交易频次降低 72%,减少不必要的市场暴露,同时获得更高收益。这是所有交易程序梦寐以求的特性:承担更少风险,获取更多收益。

原始策略单笔平均盈利 3.64 美元,单笔平均亏损 7.87 美元。我们改善了这个问题。优化版本单笔平均盈利 14.82 美元,同时单笔平均亏损基本维持在 7.95 美元。 

交易胜率

遗憾的是,上述改动提升了盈利能力与交易效率,但对胜率造成负面影响。盈利交易占比从原版的 68% 下降至优化版的 37%,胜率降幅 45%。高胜率原本是原始策略最吸引人的特点之一,想要人工调参,同时不牺牲胜率,难度很大。

因此,我们可以考虑引入反馈控制器来解决这个问题,正如前文所演示(此处附链接)。我们同时认为,继续测试更多久经实战的主观交易规则很有价值,从中筛选天然具备高胜率的策略,就像我们本次的原始策略一样。通过这种方式,这些策略能够为机器学习模型提供一套结构化框架,学习人工交易直觉的优势与局限。下面正式开始。


在 MQL5 中实现

和我们大多数交易程序一样,首先定义策略所需的全局变量。我们需要标识变量,用来跟踪两个关键价位:前一日最高价、前一日最低价。同时要在图表上绘制水平横线标记这两个价位,因此还需要字符串变量存储价位线条的名称。

//+------------------------------------------------------------------+
//|                                                         UB 2.mq5 |
//|                                               Gamuchirai Ndawana |
//|                    https://www.mql5.com/en/users/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Ndawana"
#property link      "https://www.mql5.com/en/users/gamuchiraindawa"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
double last_high,last_low;
string h,l;
bool rest;
int atr_handler;
double atr[];

同样,我们引入交易库,用于在回测期间管理持仓。

//+------------------------------------------------------------------+
//| Libraries                                                        |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
CTrade Trade;

程序首次加载时,我们会为这两个跟踪价位设置名称标识,为风险管理设置平均真实波幅(ATR)指标,最后初始化一个名为 rest 的系统标记。顾名思义,在 rest 标记设为 true 之前,系统会持续寻找交易机会。一旦 rest 为 true,系统就会停止寻找新的开仓机会,转而只管理已开立的持仓。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   h="high";
   l="low";
   rest = false;
   atr_handler = iATR(Symbol(),PERIOD_H8,4*14);
//---
   return(INIT_SUCCEEDED);
  }

当程序不再使用时,我们需要释放 ATR 指标资源,完成清理,将内存交还给系统其他模块使用。 

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   IndicatorRelease(atr_handler);
  }

在每个交易日的起始阶段,我们会保存前一个交易日的最高价与最低价。

//---
   datetime cd = iTime(Symbol(),PERIOD_D1,0);
   static datetime ds;

   if(cd != ds)
     {
      ds = cd;
      last_high = iHigh(Symbol(),PERIOD_D1,1);
      last_low = iLow(Symbol(),PERIOD_D1,1);

      if((rest==true) && (PositionsTotal() == 0))
         rest = false;

      Comment("Last High: ",last_high,"\nLast Low: ",last_low);

      ObjectDelete(0,l);
      ObjectDelete(0,h);

      ObjectCreate(0,h,OBJ_HLINE,0,0,last_high);
      ObjectCreate(0,l,OBJ_HLINE,0,0,last_low);
      CopyBuffer(atr_handler,0,0,1,atr);
     }

随着当日行情推进,当价格首次突破极值价位时,我们开立逆势仓位;我通常认为,第一次突破往往揭示了当日更真实的运行方向。

   datetime ch = iTime(Symbol(),PERIOD_H1,0);
   static datetime hs;

   if(ch != hs)
     {
      hs = ch;
      double bid,ask,close,padding;

      close = iClose(Symbol(),PERIOD_H1,0);
      ask = SymbolInfoDouble(Symbol(),SYMBOL_ASK);
      bid = SymbolInfoDouble(Symbol(),SYMBOL_BID);
      padding = atr[0] * 2;

      if(rest == false)
        {
         if(PositionsTotal() == 0)
           {

            if(close<last_low)
               Trade.Buy(0.01,Symbol(),ask,(bid-(padding)),last_high);
               
            else
               if(close>last_high)
                  Trade.Sell(0.01,Symbol(),bid,(ask+(padding)),last_low);
                  
            rest = true;
           }
        }
     }
  }
//+------------------------------------------------------------------+

这套策略主要基于交易经验直觉,所以逻辑组件不多。至此,交易程序的基础环境搭建完毕,我们可以开始对这个交易程序进行回测。

我们先选取五年的欧元兑美元(EUR/USD)历史数据,以此观察程序的运行表现。  

图 4:使用原始版本交易策略,建立基准绩效水平

随后,我们设置延迟选项,启用随机延迟,用来模拟真实交易中执行延迟的不可预测性。

图 5:启用随机延迟设置,保证模拟环境可靠

绘制账户净值随时间变化曲线后可以看到:这套策略虽然朴素简单,净值整体确实向上。但净值曲线波动的峰谷差距过大,我们需要增加控制手段,降低策略激进程度,让交易行为更可控。

图 6:原始策略生成的净值曲线稳定性不足,波动剧烈

即便如此,原始策略在五年回测中总共只盈利 40 美元。但亮眼之处在于胜率极高:策略所有成交订单里,68% 的交易都是盈利的。可问题在于,平均盈利单笔收益小于平均亏损,亏损幅度几乎是盈利的两倍。

图 7:原始策略详细统计结果,最突出特点就是天然的高盈利订单占比


策略优化改进

因此,想要改进原始策略,我们需要创造性地思考策略分析市场的方式,寻找可以预判行情的方法,而不是等待价格全天运行直至突破目标价位。经过思考,我想到可以在每个交易日的第一个小时,对比当日开盘价与前一日高低极值点之间的价差。

通过这个方法,我们就能得到昨日高低点与新开盘价之间的缺口大小。我们的思路是:价格倾向于朝着缺口更大的一侧运行。规则如下:如果当日开盘价更靠近前一日低点,则做多。反之,如果开盘价更靠近前一日高点,则做空。

图 8:可视化展示我们对原始策略做出的优化方案

引入这项改进后,策略总净利润相比原始的 40 美元有所提升。我们无需等待传统策略的突破条件,就可以预判当日行情方向。只需要小幅修改开仓规则:现在我们要计算当前收盘价(以首小时收盘价近似当日早盘位置)距离前一日高点、低点的绝对价差。如果到高点的价差更大,则开多单;否则开空单。每开一笔仓位后,重置标记参数;只有这笔交易了结之后,程序才会继续寻找新交易机会。

      if(rest == false)
        {
         if(PositionsTotal() == 0)
           {
            //High Gap Is Bigger
            if(MathAbs(close - last_high) > MathAbs(close - last_low))
               Trade.Buy(0.01,Symbol(),ask,(bid-(padding)),last_high);
	       rest = true;

            
            //Low Gap Is Bigger
            else
               if(MathAbs(close - last_high) < MathAbs(close - last_low))
                  Trade.Sell(0.01,Symbol(),bid,(ask+(padding)),last_low);
	          rest = true;
           }
        }

组合在一起,我们新的程序如下:

//+------------------------------------------------------------------+
//|                                                         UB 2.mq5 |
//|                                               Gamuchirai Ndawana |
//|                    https://www.mql5.com/en/users/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Ndawana"
#property link      "https://www.mql5.com/en/users/gamuchiraindawa"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
double last_high,last_low;
string h,l;
bool rest;
int atr_handler;
double atr[];

//+------------------------------------------------------------------+
//| Libraries                                                        |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
CTrade Trade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   h="high";
   l="low";
   rest = false;
   atr_handler = iATR(Symbol(),PERIOD_H8,4*14);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   IndicatorRelease(atr_handler);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   datetime cd = iTime(Symbol(),PERIOD_D1,0);
   static datetime ds;

   if(cd != ds)
     {
      ds = cd;
      last_high = iHigh(Symbol(),PERIOD_D1,1);
      last_low = iLow(Symbol(),PERIOD_D1,1);

      if((rest==true) && (PositionsTotal() == 0))
         rest = false;


      Comment("Last High: ",last_high,"\nLast Low: ",last_low);

      ObjectDelete(0,l);
      ObjectDelete(0,h);

      ObjectCreate(0,h,OBJ_HLINE,0,0,last_high);
      ObjectCreate(0,l,OBJ_HLINE,0,0,last_low);
      CopyBuffer(atr_handler,0,0,1,atr);
     }

   datetime ch = iTime(Symbol(),PERIOD_H1,0);
   static datetime hs;

   if(ch != hs)
     {
      hs = ch;
      last_high = iHigh(Symbol(),PERIOD_D1,1);
      last_low = iLow(Symbol(),PERIOD_D1,1);
      double bid,ask,close,padding;

      close = iClose(Symbol(),PERIOD_H1,0);
      ask = SymbolInfoDouble(Symbol(),SYMBOL_ASK);
      bid = SymbolInfoDouble(Symbol(),SYMBOL_BID);
      padding = atr[0] * 2;

      if(rest == false)
        {
         if(PositionsTotal() == 0)
           {
            if(MathAbs(close - last_high) > MathAbs(close - last_low))
               Trade.Buy(0.01,Symbol(),ask,(bid-(padding)),last_high);

            else
               if(MathAbs(close - last_high) < MathAbs(close - last_low))
                  Trade.Sell(0.01,Symbol(),bid,(ask+(padding)),last_low);

            rest = true;
           }
        }
     }
  }
//+------------------------------------------------------------------+

整合全部改动之后,我们的新版程序如下所示。优化后策略生成的净值曲线创出原版从未达到过的新高。总净利润从原先的 40 美元上涨至 148 美元。但我们已经能够观察到,盈利交易的占比开始出现下滑。

图 9:可视化展示原始策略经过优化之后生成的净值曲线

一方面,策略交易效率得到提升,多赚了 108 美元。原版策略需要完成 886 笔交易才能赚到 40 美元,而新版本仅需 469 笔交易就实现 148 美元收益。策略的改进方向是正确的,但仍然还有进一步优化的空间。

图 10:对比原版策略,本次优化效果的统计分析


继续做出更多改进

为继续探究优化思路,请看下面示意图。图中绿色矩形代表向上缺口,蓝色矩形代表向下缺口。我们目前的理论假设是:价格会朝着缺口更大的方向运行。当前策略是,一旦价格击穿前一日的极值价位就执行止盈。 

图 11:绿色、蓝色矩形分别代表昨日的高点价差和低点价差

但我们可以看到,价格并不总能完全突破这些极值点位;有时价格接近该位置,却始终无法完成突破。

图 12:原版策略的平仓条件,无法适配所有市场行情

因此我们可以思考:不要把止盈位设置在前一日极值的外侧,而是设置在极值内侧,例如,在前一日高点下方,按一定 ATR 比例设置止盈。这样一来,只要价格足够靠近目标位置,我们依然可以落袋为安。

除此之外,当持仓朝着有利于我们的方向运行时,我们希望把止损向上收紧,尽可能多地锁定利润。为实现该效果,我们修改交易规则:不再给止损和止盈设置相同的缓冲偏移量,止盈使用比止损更小的 ATR 系数。这样,止损可以预留更大容错空间,而止盈设置得更紧凑,以此抓取行情动量。

在持仓存续期间,我们还会做条件判断,检查新的止损建议位置是否比当前止损更有利。理想情况下,只要条件允许,我们希望止损位始终绑定最新的极值价格。

   if(ch != hs)
     {
      hs = ch;
      last_high = iHigh(Symbol(),PERIOD_D1,1);
      last_low = iLow(Symbol(),PERIOD_D1,1);
      double bid,ask,close,padding;

      close = iClose(Symbol(),PERIOD_H1,0);
      ask = SymbolInfoDouble(Symbol(),SYMBOL_ASK);
      bid = SymbolInfoDouble(Symbol(),SYMBOL_BID);
      padding = atr[0] * 2;

      if(rest == false)
        {
         if(PositionsTotal() == 0)
           {

            if((MathAbs(close - last_high) > MathAbs(close - last_low)))
               Trade.Buy(0.01,Symbol(),ask,(bid-(padding)),last_high+(padding*0.9));

            else
               if((MathAbs(close - last_high) < MathAbs(close - last_low)))
                  Trade.Sell(0.01,Symbol(),bid,(ask+(padding)),last_low-(padding*0.9));

            rest = true;
           }
        }

      if(rest == true)
        {
         if(PositionsTotal() > 0)
           {
            if(PositionSelectByTicket(PositionGetTicket(0)))
              {
               double sl,tp;

               sl = PositionGetDouble(POSITION_SL);
               tp = PositionGetDouble(POSITION_TP);

               //--- Buy
               if(sl < tp)
                 {
                  if(last_low > sl)
                     Trade.PositionModify(Symbol(),last_low,tp);
                 }

               if(tp < sl)
                 {
                  if(last_high < sl)
                     Trade.PositionModify(Symbol(),last_high,tp);
                 }
              }
           }
        }
     }

把以上所有改动整合起来,就得到了目前为止程序的最终版本:

//+------------------------------------------------------------------+
//|                                                         UB 2.mq5 |
//|                                               Gamuchirai Ndawana |
//|                    https://www.mql5.com/en/users/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Ndawana"
#property link      "https://www.mql5.com/en/users/gamuchiraindawa"
#property version   "1.00"

//+------------------------------------------------------------------+
//| Global Variables                                                 |
//+------------------------------------------------------------------+
double last_high,last_low;
string h,l;
bool rest;
int atr_handler;
double atr[];

//+------------------------------------------------------------------+
//| Libraries                                                        |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
CTrade Trade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   h="high";
   l="low";
   rest = false;
   atr_handler = iATR(Symbol(),PERIOD_H8,4*14);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
      IndicatorRelease(atr_handler);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   datetime cd = iTime(Symbol(),PERIOD_D1,0);
   static datetime ds;

   if(cd != ds)
     {
      ds = cd;
      last_high = iHigh(Symbol(),PERIOD_D1,1);
      last_low = iLow(Symbol(),PERIOD_D1,1);

      if((rest==true) && (PositionsTotal() == 0))
         rest = false;

      Comment("Last High: ",last_high,"\nLast Low: ",last_low);

      ObjectDelete(0,l);
      ObjectDelete(0,h);

      ObjectCreate(0,h,OBJ_HLINE,0,0,last_high);
      ObjectCreate(0,l,OBJ_HLINE,0,0,last_low);
      CopyBuffer(atr_handler,0,0,1,atr);
     }

   datetime ch = iTime(Symbol(),PERIOD_H1,0);
   static datetime hs;

   if(ch != hs)
     {
      hs = ch;
      last_high = iHigh(Symbol(),PERIOD_D1,1);
      last_low = iLow(Symbol(),PERIOD_D1,1);
      double bid,ask,close,padding;

      close = iClose(Symbol(),PERIOD_H1,0);
      ask = SymbolInfoDouble(Symbol(),SYMBOL_ASK);
      bid = SymbolInfoDouble(Symbol(),SYMBOL_BID);
      padding = atr[0] * 2;

      if(rest == false)
        {
         if(PositionsTotal() == 0)
           {

            if((MathAbs(close - last_high) > MathAbs(close - last_low)))
               Trade.Buy(0.01,Symbol(),ask,(bid-(padding)),last_high+(padding*0.9));

            else
               if((MathAbs(close - last_high) < MathAbs(close - last_low)))
                  Trade.Sell(0.01,Symbol(),bid,(ask+(padding)),last_low-(padding*0.9));

            rest = true;
           }
        }

      if(rest == true)
        {
         if(PositionsTotal() > 0)
           {
            if(PositionSelectByTicket(PositionGetTicket(0)))
              {
               double sl,tp;

               sl = PositionGetDouble(POSITION_SL);
               tp = PositionGetDouble(POSITION_TP);

               //--- Buy
               if(sl < tp)
                 {
                  if(last_low > sl)
                     Trade.PositionModify(Symbol(),last_low,tp);
                 }

               if(tp < sl)
                 {
                  if(last_high < sl)
                     Trade.PositionModify(Symbol(),last_high,tp);
                 }
              }
           }
        }
     }
  }

此时的净值曲线相比前两个策略版本,能够攀升至更高位置。盈亏之间的波动幅度,也得到了更好的控制。

图 13:这套交易策略最终版本生成的净值曲线,具备原始版本所没有的理想形态

查看详细统计数据可以发现,总净利润再度提升,从上一版的 148 美元增加到本版本的 162 美元。但盈利交易占比继续下降,同时也低于原始策略。这表明我们的优化调整,不仅影响盈利订单,也会以我们不希望的方式作用于亏损订单。

这凸显出一个更深层次的难题:单纯依靠人工经验直觉,很难持续优化基于主观交易逻辑搭建的策略。想要取得实质性突破,我们必须考虑人工判断之外的其他优化手段。

图 14:仔细分析后我们发现,各项修改同时对系统的交易胜率带来负面影响


结论

人工交易者能在金融市场中长期生存,并非依靠运气,也不是一笔一笔盲目试错。出于生存压力和对亏损的规避本能,他们不得不去寻找真实、可靠的市场规律。如今这一严谨思路常常被忽视:机器学习领域的从业者一味追求更大规模的数据、更复杂的模型,却不去反思各项指标是否真的代表有效的进展。

我们的研究提出另一条思路。将策略建立在主观交易总结的市场逻辑之上,我们从已经验证有效的基础起步,而非建立在盲目的假设之上。这些策略的残差,也就是策略本身产生的误差,会成为机器学习模型绝佳的训练素材。如此一来,我们不再要求算法从零去挖掘市场关联;而是为模型提供一套输入与输出已经建立联系的框架。

这种思路转变,也更贴近模型所依赖的统计假设。固定策略在变化的市场中产生的输出,近似于稳健学习所要求的独立同分布(IID)条件。现实市场永远无法达到完美的独立同分布状态,但该方法能够向这个理想条件靠拢,让模型不再脆弱,可信度更高。我们认为,以人类总结的市场逻辑作为起点,再利用这套逻辑产生的误差来训练模型,可以让机器学习站在更高的起点开展学习。


文件名 文件详情
Daily Breakout Strategy V1.mq5 策略最初的激进版本,拥有很高的初始交易胜率。 
Daily Breakout Strategy V2.mq5 交易程序的第二版,胜率略有下降,但盈利能力大幅提升。
Daily Breakout Strategy V3.mq5 策略最终版本,实现最高收益,但交易胜率最低。

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/19130

梦境优化算法(DOA) 梦境优化算法(DOA)
这是一种基于种群的优化算法,其灵感源自一种尚存争议、研究较少的现象 —— 人类梦境的机制。该算法拥有一个具备不同“记忆”的智能体种群,用余弦波调制移动步长,并采用独特的99/1时间分配比例。让我们看一下这些特性会如何影响交易策略的优化效率。
决斗者算法 决斗者算法
如果您的交易策略能像真实的决斗者一样互相较量、彼此学习,会怎样?决斗者算法(Duelist Algorithm)是一种新的优化方法:在该算法中,不同的参数组合会像决斗者一样相互较量,争夺最优解的位置。
神经网络在交易中的应用:概率时间序列预测(K²VAE) 神经网络在交易中的应用:概率时间序列预测(K²VAE)
我们诚邀您探索 K²VAE 框架的原始实现 — 这是一个灵活的模型,能够线性近似潜在空间中的复杂动态。本文将演示如何在 MQL5 中实现关键组件,包括参数化矩阵,以及如何在标准神经网络层之外对这些矩阵进行管理。对于任何寻求构建可解释时间序列模型实用方法的人来说,本文材料都将大有裨益。
MQL5自优化智能交易系统(第十二部分):利用矩阵分解构建线性分类器 MQL5自优化智能交易系统(第十二部分):利用矩阵分解构建线性分类器
本文探讨矩阵分解在算法交易中的强大作用,重点介绍其在 MQL5 程序里的应用。从回归模型到多目标分类器,我们通过实战示例演示如何借助 MQL5 内置函数轻松集成这类技术。无论你是预测价格方向,还是构建指标行为模型,这份教程都为你使用矩阵方法搭建智能交易系统打下坚实基础。