English Русский Español Deutsch 日本語 Português
preview
您应该知道的 MQL5 向导技术(第 06 部分):傅里叶(Fourier)变换

您应该知道的 MQL5 向导技术(第 06 部分):傅里叶(Fourier)变换

MetaTrader 5测试者 | 3 十一月 2023, 09:55
918 0
Stephen Njuki
Stephen Njuki

概述

傅里叶变换是将一个数据波分解为可能的组成部分的一种方法,由约瑟夫·傅立叶(Joseph Fourier)引入。 在傅里叶变换中对所有可能的频率进行积分,为我们提供了一个分量频谱,因为它将原始函数分解为其分量,每个分量对应于不同的频率分量。

根据定义,傅里叶变换的范围从负无穷大到正无穷大:


其中 F(w) 是函数 f(t) 的傅里叶变换,i 是虚部单位,w 是角频率,e 是指数函数。

在实践中,当运用变换时,周转的数量被预先确定为一个可管控的小数字。 越多周转(分量频率),它就越能准确地描述原始曲线,然而,在某个点上,它变得低效,因为更多的周转对于曲线之中已分解的分量,也不会产生任何有意义的差异。

因此,这导致变换的用户会求助于离散的有限周转 n 次。 这需要略微修改我们上面的公式。

当我们把所有可能的频率相加时,我们汇总每个频率对原始函数的贡献。 每个频率分量都由一个复数表示,该复数包括幅度和相位信息。 幅度表示波的振幅,而相位表示波的时间偏移。 因此,我们上面的修正方程汇总 n 个分量,这 n 个分量中的每一个都对应时间 t 处波的不同值。

在求解组成分量时,关键是找到构成实部和虚部两者的每个分量的 f(t)。 傅里叶系统用复数(如“无限和”)重写 0 到 2 pi 区间的任何函数 f(t)。 “无限”放在引号里,因为它加起来为零


根据我们上面的方程,求解系数时:C2

我们将等式的两边乘以:e-2it

积分后,会把我们的方程式简化为:



因此,可以将 2(而不是 2 pi 中的 2!)替换为 n,从而得到上述 f(t) 方程中的任何其它系数。 所有这些计算都由 'Math\Alglib\fasttransforms.mqh' 文件中列出的类 'CFastFourierTransform' 处理,所以我们所要做的就是使用这个代码库。


应用

在我们举出非常具体的例子之前,更实用的做法也许是首先从更广泛的角度来看,交易者如何从这种把数据波分解为组成分量的能力中受益。 有非常多的应用。 此处是可能的简短列表:

  1. 分析股价走势:如果我们收集股票价格数据,并以时间序列格式排列,我们可以将傅里叶变换应用于序列数据,从而获得其频率分量。分析这些单独的频率分量,就可识别数据中的形态和趋势,这有助于制定更明智的交易决策。 例如,交易者可能会注意到某只股票在其频谱中以特定频率反复出现的峰值,这表明该股票的价格变动存在重复形态。 此观察结果可用于在股价处于低位时买入,在股价处于高位时卖出,这是基于价格将遵循所观察形态的预期。 不过,随着时间的推移,需要经常监控,并确保形态仍然适用。
  1. 分析长期周期:我们需要在商业周期或市场周期之间做出选择。 如果我们选择一个商业周期,我们可能的数据源包括:

  • 国内生产总值(GDP):经济增长最重要的指标之一,衡量一个国家在给定时期(通常是一年)内生产的商品和服务的总价值。
  • 就业数据:例如失业率和/或创造就业机会的数字,可以提供对劳动力市场健康状况的洞察。 失业率上升,或就业增长停滞,均可能预示着经济疲软。
  • 工业生产数据:其中可能包括衡量制造业、采矿业和公用事业部门产出的工业生产指数,可以表明经济的整体健康状况、采购经理人指数、产能利用率、耐用品订单、制造业就业、以及许多其它的。
  • 消费者信心数据:这包括消费者信心指数、密歇根大学消费者信心指数、世界大型企业联合会消费者信心指数、零售销售、消费者信贷、名目众多但仅举少量。
  • 利率数据:利率会影响企业投资和消费者支出,这两者都可能影响经济表现。 利率上升往往会抑制投资和支出,而利率下降会鼓励投资和支出比例,这些往往会最终影响上市公司股票的价格。
  • 通货膨胀数据:这衡量了商品和服务价格的增长率,因此可以为经济状况提供一些清晰度。 高通胀可能预示着经济过热,而低通胀可能预示着经济疲软。 这也是另一个可以影响交易者购买各种股票决策的数据集,因此是一个关键的数据源。
  • 住房数据:这可能涵盖房屋销售和开工,并可以揭示房地产市场的健康状况,这是经济的重要组成部分,与交易者投资组合中的特定股票相关。

市场周期数据的一些来源可能包括:

  • 市盈率(P/E):这个通用指标将公司的股价与其每股收益(EPS)进行比较,可衡量市场是否高估了该只股票(读数较高),或者市场是否低估了该只股票,典型是读数通常低于 15 甚至 10,具体取决于所处的市场地位。
  • 股息分红:这衡量每股价格支付的股息金额。 低股息分红率可能表明股票被高估,而高股息分红率可能表明被低估。
  • 技术指标:清单包含移动平均线、动量指标、和相对强弱指标,可以帮助汇总股票的当前价格走势。 例如,当股价高于其 200 天移动平均线时,它可能表明看涨趋势,而交易低于 200 天移动平均线则可能预示看跌趋势,故在这种情况下,我们的数据可能是价格与其 200 天移动平均线之间的价差。
  • 市场广度:此处,我们衡量在给定市场中上涨的股票数量与下跌的股票数量。 当大量股票上涨时,它可能表明市场是健康的,而下降则可能表明疲软。 此类数据可能来自第三方,这些第三方通常将其与其它数据流捆绑在一起,收取一次性费用,或者在某些情况下需订阅。
  • 波动率:这是通过 VIX 等指标来衡量的,有助于评估市场风险和投资者情绪。 它通常与市场风险和负面情绪呈正相关。

一旦我们从上述可能的来源收集到相关的财务数据,我们就会按时间序列将其排序,然后应用傅里叶变换将其分解为频率分量。 通过寻找数据中的重复周期,分析这些组成分量,可以改善我们的交易决策。 举例,交易者可能会利用它来发现利率数据中的循环周期,该周期往往会持续数年,并且与其交易的股票或 ETF 具有滞后的正相关性。 靠这些知识装备,他可以在市场处于低点时投资长期仓位,并长期持有缩水持仓,只有在利率数据相关性变为负值或预示着经济衰退时才离场。

  1. 信号处理:在查看信号时,我们可以参考在主要突破之前的价格波浪形态,无论是上行还是下行。 举例,这里更具体的数据源只能查看特定股票价格历史中的加特利(gartley)形态,而忽略其它数据。 波浪价格数据将以时间序列记录(尽管由于该形态很少见,因此要考虑存在缺口)。 傅里叶变换将应用于此系列中的每个波形。 然后,我们可以为分量傅里叶波形设置一个频率阈值(基于我们的观察结果,与最终突破相关),并忽略那些与阈值不匹配的频率。 然后,我们将使用这些过滤后的少量波形来做出往前的预测。 这个价格缓冲可以是股票、外汇对、亦或是商品。 原理是一样的。
  1. 风险管理:如果我们专注于信用风险,因为其它类型的风险(如市场风险)可能与我们上面已经介绍的风险重叠,那么以下这些可能是我们的数据来源: 

  • 违约率:特定银行市场(例如美国)的季度或年度违约率可用于分析美国的信用风险,从而分析标准普尔 500 指数的表现。
  • 信用利差:公司债券和国债之间的信用利差的每日或每周数据,有助于评估市场内信用度感知变化相关的信用风险。
  • 贷款拖欠:与违约率不是一回事儿,可以每月或每季度为特定银行或贷方提供,如果交易者正在考虑购买该特定银行股票,则用于研究与该银行贷款组合相关的信用风险。
  • 信用评级:这些数据虽然不像大多数数据那样序列化,但它仍然可以在合理的历史时期内每季度或每年针对特定公司收集,并用于评估公司商业票据甚至其长期债券的价值。
  • 信用违约掉期(CDS):通常相当于贷方为其贷款提供的保险,可以每天或每周根据其合约价格进行购置,并用于分析市场内对信誉度感知变化相关的信用风险。

来自这些来源中的任何一个的数据将被组合成一个时间序列,然后针对时间序列数据应用傅里叶变换,从而获得频率分量。 分析哪个组成分量与最终的金融冲击或更具体的股价波动相关性最佳,这有助于制定有效的风险管理策略。

  1. 期权定价:期权标的价格、执行价格、到期时间、波动性、利率和股息的历史数据可以从数个来源获得,例如彭博(Bloomberg)终端。 请注意,这些数据集合中的每一个都是期权价格的“频率分量”。 依据这么多个数据集,人们可以通过多种方式进行分析。 请记住,在任何给定时间,对于期权价格本身都不会达成共识,我们所拥有的是“最佳实践”定价模型,例如布莱克-斯科尔斯(Black-Scholes)。 但这些并不总是可靠的。 一种方式可能会简单地在到期前的固定时间段分解标的价格,并查看哪个频率分量与到期时标的和执行价格之间的差异相关性最佳。 这种分析可能对欧式期权有用,但美式期权,因为它们可以在到期前行使,确实会带来更复杂的挑战。
  1. 情绪分析:就抓取网络数据而言,我们已经走了很长一段路,如今社交媒体管理软件是一门大生意。 名为 Zoho Social、Hootsuite、Khoros Marketing 等少数公司正在迅速站稳脚跟。 数日子已经一去不复返了,好、恶、以及草草了事;今天,文本分析(并与人工智能相结合)令企业能够更好地量化其客户参与度和对其产品/服务的满意度。 故此,可以收集大量数据。 作为交易者,若是对两家竞争对手公司感兴趣,您可能想知道审查产品的参与时间与 3 个月或 6 个月后产品的最终销售之间是否存在任何相关性。 将参与度数据转换为时间序列,并将其分解为组成分量,可以判定哪个组成分量与我们的目标(在本例中为未来销售)相关性最佳,然后该系统指导我们决定购买股票,以及购买数量。
  1. 机器学习:此应用程序(以及多个其它应用程序)的傅里叶变换可以通过将输入数据分解为分量频率来帮助矢量化输入数据。 如果我们只是将不同的收盘价波形作为输入数据,那么这些波形中的每一个都可以分解为 n 个波形,其中每个新波形现在都是旧的未分解波形的波形向量的一部分。 这为我们提供了更多需要评估的新数据点的识别信息,并且可以在评估未知波形时与已经训练的数据进行更准确的比较,而不仅仅是原始的单个波形。 故此,例如,训练这些矢量化数据,并将其与测试数据进行比较,例如使用欧几里得距离,可以帮助提高对模型的预测。


实现

为了讲述以 MQL5 实现傅里叶变换,我们将研究分解区间定价的时间序列(高点减去低点)。 然后,我们将检查这些分量频率,看看其中任何一个特定的频率在通过指数识别时,是否与价格范围的下一个变化拥有实用的相关性。 我们将用此信息来指导我们在自定义实现的 “CExpertTrailing” 类中调整持仓止损。 我们将用 “SignalRSI.mqh” 中列出的简单内置信号,资金管理正如则采用固定保证金。

 

如果列出我们的自定义尾随类,如下所示。 在提取“函数 f(t)” 的实系数和虚系数时,我们使用结构体 “a1_complex” 的实例来存储函数 “FFTR1D”处理后的信息。 为了使用这些系数,我们需要“整合”它们,为此我即兴创作了一个矩阵 “_output”。该矩阵具有每个数据点上每个周转的系数。 我们使用 6 个数据点和 5 次周转。此外,我们使用预测数据点指数 “m_points-1” 是因为傅里叶周期是重复的,如此下一站将是周期中最久的

//+------------------------------------------------------------------+
//|                                                   TrailingCT.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Math\Alglib\fasttransforms.mqh>
#include <Expert\ExpertTrailing.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trailing Stop based on 'Fourier Transform' v3              |
//| Type=Trailing                                                    |
//| Name=CategoryTheory                                              |
//| ShortName=CT                                                     |
//| Class=CTrailingFT                                                |
//| Page=trailing_ct                                                 |
//| Parameter=Step,double,0.5,Trailing Step                          |
//| Parameter=Index,int,0,FT-Index                                   |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CTrailingFT.                                               |
//| Appointment: Class traling stops with 'Fourier Transform' v3     |
//|               relative-sets concepts.                            |
//| Derives from class CExpertTrailing.                              |
//+------------------------------------------------------------------+
#define     __PI 245850922/78256779

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTrailingFT : public CExpertTrailing
  {
protected:
   CFastFourierTransform   FFT;
   
   //--- adjusted parameters
   
   double            m_step;                    // trailing step

   int               m_index;                    // the epicycle index

public:
   //--- methods of setting adjustable parameters
   
   
   
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual bool      CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
   virtual bool      CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
   //---
                     CTrailingFT(void);
                    ~CTrailingFT(void);
   //--- methods of setting adjustable parameters
   void              Step(double value)                  { m_step=value;      }
   void              Index(int value)                    { m_index=value;     }

protected:
   
   double            ProcessFT(int Index);

  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CTrailingFT::CTrailingFT(void)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_TIME+USE_SERIES_SPREAD+USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CTrailingFT::~CTrailingFT(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CTrailingFT::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertTrailing::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_index<0 || m_index>=5)
     {
      printf(__FUNCTION__+": index must be greater than 0 and less than epicycles");
      return(false);
     }

//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CTrailingFT::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertTrailing::InitIndicators(indicators))
      return(false);
//--- 
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for long position.          |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
      
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
      
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_low.GetData(_x)-(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl>base && new_sl<level)
         sl=new_sl;
//---
   return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for short position.         |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
   
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
   
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_high.GetData(_x)+(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl<base && new_sl>level)
         sl=new_sl;
//---
      return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Fourier Transform                                                |
//| INPUT PARAMETERS                                                 |
//|     Index   -   int, read index within price buffer.             |
//| OUTPUT                                                           |
//|     double  -   forecast change in price                         |
//+------------------------------------------------------------------+
double CTrailingFT::ProcessFT(int Index)
   {
      double _ft=0.0;
      
      int _index=Index;//+StartIndex();
      
      m_close.Refresh(-1);
      
      double _a[];
      matrix _output;
      al_complex _f[];
      
      //6 data points, 5 epicycles
   
      ArrayResize(_a,6);ArrayInitialize(_a,0.0);
      _output.Init(6,5);_output.Fill(0.0);
      
      for(int p=0;p<6;p++)
      {
         _a[p]=m_close.GetData(_index+p)-m_close.GetData(_index+p+1);
      }
      
      FFT.FFTR1D(_a,5,_f);
       
      for(int p=0;p<6;p++)
      {
         for(int s=0;s<5;s++)
         {
            double _divisor=(1.0/5),_angle=(p);_angle/=6;
            _output[p][s]=(_divisor*_a[p]*MathExp(-2.0*__PI*(_f[s].im/_f[s].re)*_angle));
         }
      }
      
      double _close=m_close.GetData(_index)>m_close.GetData(_index+1);
      
      _ft=(_output[5][m_index]/fmax(m_symbol.Point(),fabs(_output[5][m_index])+fabs(_close)))*100.0;
      
      return(_ft);
   }
//+------------------------------------------------------------------+


在使用内置的 RSI 信号类,和内置的固定保证金资金管理进行编译时,我们确实得到了以下结果: EURJPY 覆盖此区间:2022.01.01 至 2023.01.01 时间帧:4 小时。 在运行这个测试时,我们既不设置盈利目标,也不使用默认止损设置,因此这两个输入均为零。 我们希望离场完全依据信号反转或触发尾随停止设置的止损来判定。


r_1


对于第二个/比较实现,我们将研究具有最高振幅的分量频率与上述价格范围变化的相关性。

 

下面列出了此实现:

//+------------------------------------------------------------------+
//|                                                   TrailingCT.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Math\Alglib\fasttransforms.mqh>
#include <Expert\ExpertTrailing.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trailing Stop based on 'Fourier Transform' v3              |
//| Type=Trailing                                                    |
//| Name=CategoryTheory                                              |
//| ShortName=CT                                                     |
//| Class=CTrailingFT                                                |
//| Page=trailing_ct                                                 |
//| Parameter=Points,int,6,FT-Points                                 |
//| Parameter=Epicycles,int,5,FT-Epicycles                           | 
//| Parameter=Step,double,0.5,Trailing Step                          |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CTrailingFT.                                               |
//| Appointment: Class traling stops with 'Fourier Transform' v3     |
//|               relative-sets concepts.                            |
//| Derives from class CExpertTrailing.                              |
//+------------------------------------------------------------------+
#define     __PI 245850922/78256779

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTrailingFT : public CExpertTrailing
  {
protected:
   CFastFourierTransform   FFT;
   
   //--- adjusted parameters
   
   double            m_step;                    // trailing step

public:
   //--- methods of setting adjustable parameters
   
   
   
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual bool      CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
   virtual bool      CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
   //---
                     CTrailingFT(void);
                    ~CTrailingFT(void);
   //--- methods of setting adjustable parameters
   void              Step(double value)                  { m_step=value;      }

protected:
   
   double            ProcessFT(int Index);

  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CTrailingFT::CTrailingFT(void)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_TIME+USE_SERIES_SPREAD+USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CTrailingFT::~CTrailingFT(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CTrailingFT::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertTrailing::ValidationSettings())
      return(false);
//--- initial data checks

//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CTrailingFT::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertTrailing::InitIndicators(indicators))
      return(false);
//--- 
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for long position.          |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
      
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
      
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_low.GetData(_x)-(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl>base && new_sl<level)
         sl=new_sl;
//---
   return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for short position.         |
//+------------------------------------------------------------------+
bool CTrailingFT::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
   
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      double _ft=ProcessFT(_x);
      double _type=_ft/100.0;
   
      double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
      
      double _sl=m_high.GetData(_x)+(m_step*_atr);
      
      double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
      double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
      double pos_sl=position.StopLoss();
      double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
      
      sl=EMPTY_VALUE;
      tp=EMPTY_VALUE;
      if(new_sl<base && new_sl>level)
         sl=new_sl;
//---
      return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Fourier Transform                                                |
//| INPUT PARAMETERS                                                 |
//|     Index   -   int, read index within price buffer.             |
//| OUTPUT                                                           |
//|     double  -   forecast change in price                         |
//+------------------------------------------------------------------+
double CTrailingFT::ProcessFT(int Index)
   {
      double _ft=0.0;
      
      int _index=Index;//+StartIndex();
      
      m_close.Refresh(-1);
      
      double _a[];
      matrix _output;
      al_complex _f[];
      
      //6 data points, 5 epicycles
   
      ArrayResize(_a,6);ArrayInitialize(_a,0.0);
      _output.Init(6,5);_output.Fill(0.0);
      
      for(int p=0;p<6;p++)
      {
         _a[p]=m_close.GetData(_index+p)-m_close.GetData(_index+p+1);
      }
      
      FFT.FFTR1D(_a,5,_f);
       
      for(int p=0;p<6;p++)
      {
         for(int s=0;s<5;s++)
         {
            double _divisor=(1.0/5),_angle=(p);_angle/=6;
            _output[p][s]=(_divisor*_a[p]*MathExp(-2.0*__PI*(_f[s].im/_f[s].re)*_angle));
         }
      }
      
      double _close=m_close.GetData(_index)>m_close.GetData(_index+1);
      
      int _max_index=0;
      double _max=fabs(_output[5][_max_index]);
      for(int s=0;s<5;s++)
      {
         if(_max<fabs(_output[5][s]))
         {
            _max_index=s;
            _max=fabs(_output[5][s]);
         }
      }
      
      _ft=(_output[5][_max_index]/fmax(m_symbol.Point(),fabs(_output[5][_max_index])+fabs(_close)))*100.0;
      
      return(_ft);
   }
//+------------------------------------------------------------------+


使用与上述相同的信号和资金管理文件进行编译时,测试运行会产生以下报告:


r_2


最终实现当中我们使用最小振幅分量而不是最大,其代码也附在本文文后,它为我们提供了以下报告:


r_3


从我们的三份样本报告中可以清楚地看出,使用相同的入场信号,并略微改变我们的尾随停止系统,对于报告结果具有重要意义。


结束语

总而言之,我们从外行交易者的角度研究了什么是傅里叶变换。 我们还强调了这种变换对于交易者的一些可能的广泛应用。 然后,我们继续演示了以 MQL5 简单实现此转换,同时重点介绍如何利用波动率预测来管理持仓的止损。 这种变换还有许多其它应用,我在这里没有列出,故邀请读者在探索这些应用时做一些研究。 此外,这里分享的代码不是圣杯、或任何“实盘账户就绪”的智能系统,但再次鼓励读者进行一些尽职的独立调查,并找出对他/她有用的内容。

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

附加的文件 |
TrailingFT_3_.mqh (8.72 KB)
TrailingFT_2_.mqh (8.72 KB)
TrailingFT_1_.mqh (8.84 KB)
在类中包装 ONNX 模型 在类中包装 ONNX 模型
面向对象编程可以创建更紧凑、易于阅读和修改的代码。 在此,我们将会看到三个 ONNX 模型的示例。
以 MQL5 实现 ARIMA 训练算法 以 MQL5 实现 ARIMA 训练算法
在本文中,我们将实现一种算法,该算法应用了 Box 和 Jenkins 的自回归集成移动平均模型,并采用了函数最小化的 Powells 方法。 Box 和 Jenkins 表示,大多数时间序列可以由两个框架中之一个或两个来建模。
MQL5 中的矩阵和向量:激活函数 MQL5 中的矩阵和向量:激活函数
在此,我们将只讲述机器学习的一个方面 — 激活函数。 在人工神经网络中,神经元激活函数会根据一个或一组输入信号的数值,计算输出信号值。 我们将深入研究该过程的内部运作。
开发回放系统 — 市场模拟(第 08 部分):锁定指标 开发回放系统 — 市场模拟(第 08 部分):锁定指标
在本文中,我们将亲眼见证如何在简单地利用 MQL5 语言锁定指标,我们将以一种非常有趣和迷人的方式做到这一点。