如何用 MQL5 创建自定义真实强度指数指标

Mohamed Abdelmaaboud | 14 十一月, 2023

概述

如果我们正确使用技术指标,它们会非常实用,因其也许会提供额外的见解,而这些见解很难通过查看价格行为来检测。 有许多现成的技术指标我们可以取用,但有时可能会发现我们需要自定义它们,以便为我们提供指示或特定的见解,或者我们需要根据自己的获胜思路创建一个新指标。 有一种途径能以 MQL5 创建此类自定义指标,并在 MetaTrader 5 交易平台中使用它们。 在本文中,我将与您分享如何从头开始创建真实强度指数指标。 我们将学习该指标的细节,并看到如何在我们的代码中计算它。 不仅如此,我们还将学习如何遵照交易策略,基于这个自定义指标创建智能系统。 我们将遍历以下主题涵盖所有这些内容:

在理解了前面提到的主题之后,我们就能够很好地理解如何使用和解释真实强度指数指标,并以 MQL5 语言计算和编写可在 MetaTrader 5 中使用的自定义指标。 您还可以在其它交易系统或 EA 中实现该指标。 如果您想拓展您的编程技能,我建议您尝试自行编写这里的内容,因为这种做法是任何学习过程或路线图中非常重要的一步。 我们将在 MetaTrader 5 内置的 IDE 中编写我们的 MQL5 代码。 如果您还没有该平台,或者您不知道如何下载和使用它,您可以阅读我之前文章中的 “在 MetaEditor 中编写 MQL5 代码” 主题。

免责声明:所有信息仅“按原样”提供,仅用于教学目的,并未准备用于交易目的或建议。 该信息不保证任何形式的结果。 如果您选择在您的任何交易账户上使用这些素材,您应自行承担风险,并且您将是唯一的责任人。


真实强度指数(TSI)定义

在这一部分中,我们将辨别真实强度指数(TSI)技术指标,以便正确理解它。 它是由威廉·布劳(William Blau)开发的,是一款衡量价格行为动量的技术指标,即它衡量金融产品的强度,是强势亦或弱势。 它围绕零轴振荡,因此它是一个动量振荡器指标。 信号线也可与它一起使用,基于这些线之间的交叉获得额外的买入或卖出信号。 不过,我们只能基于 TSI 线获得信号,即它与零轴的交叉。 如果高于零轴,则表示看涨动量,如果低于零轴,则表示看跌动量。 它可用于检测超买和超卖区域,并检测看涨和看跌背离。 由于我们知道,我们需要确认其信号,以便提升证据的权重;最好将其与其它技术工具配合使用,我们应该在价格行为相同的背景下使用这些工具,从而获得更好的见解。

现在我们来看看如何计算这个指标。 计算分几个步骤进行,分别是:

计算双重平滑动量:

计算双重平滑绝对动量:

计算 TSI = 100*(双重平滑动量 / 双重平滑绝对动量)

这种计算的后果是得到一条围绕零轴的振荡线,衡量价格行为的动量,并检测我们提到的超买和超卖区域。


自定义简单 TSI 指标

MQL5 编程语言有很多预定义的技术指标,我们可以在我们的系统中使用这些预定义的函数。 在本系列的前几篇文章中,我们已经讨论过很多这样的指标,讨论了如何基于这些流行的技术指标来设计交易系统。 您可以查阅以前的文章,也许会找到有用的东西。 现在的问题是,如果指标不存在,我们如何创建一个指标,就像标准平台交付包中一样,或者即使它存在,我们如何创建一个自定义指标来获得所需的信号或触发器。 简短的答案是利用主要编程语言创建一个自定义指标,这就是我们在这一部分中所要做的。

我们将学习如何利用 MQL5 创建我们的自定义真实强度指数指标。 然后,我们将在其它系统或 EA 中使用它的功能。 以下步骤就是为了创建此自定义指标。

创建其它参数要使用 #property,在它之后是我们指定的标识符和数值,以下这些是我们需要指定的参数:

#property indicator_separate_window
#property indicator_buffers 8
#property indicator_plots   1
#property indicator_label1  "TSI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  3

我们需要包含 MovingAverage.mqh 文件,以便在计算中调用它的组件,该文件存在于 Include 文件夹中,故需用 #include 命令。 请确保编写的文件名与实际文件名相同。

#include <MovingAverages.mqh>

我们需要输入两个平滑周期的设置,如果用户需要更新程序中指定的默认值,我们可用输入类输入这些值,并计算指标。 之后,我们用 uint(无符号整数型)声明我们需要的变量(InpSmPeriod1、InpSmPeriod2)的数据类型。 然后,我们将(25) 分配给 InpSmPeriod1,将(13)分配给 InpSmPeriod2,作为默认值。 

input uint     InpSmPeriod1   =  25;    // Smoothing period 1
input uint     InpSmPeriod2   =  13;   // Smoothing period 2

创建两个整数型变量(smperiod1,smperiod2)保存平滑周期。

int            smperiod1;
int            smperiod2;

为指标缓冲区创建 7 个数组

double         indBuff[];
double         momBuff[];
double         momSmBuff1[];
double         momSmBuff2[];
double         absMomBuff[];
double         absMomSmBuff1[];
double         absMomSmBuff2[];

在 OnInit() 函数中,我们将执行以下步骤:

声明变量(smperiod1,smperiod2),如果用户输入的 InpSmPeriod1 和 InpSmPeriod2 小于 2,则返回值 2;如果是其它数值,则返回 InpSmPeriod1 和 InpSmPeriod2 的值

   smperiod1=int(InpSmPeriod1<2 ? 2 : InpSmPeriod1);
   smperiod2=int(InpSmPeriod2<2 ? 2 : InpSmPeriod2);

调用(SetIndexBuffer)函数将指标缓冲区与数组绑定。 其参数为:

index: 在我们的程序中设置指标缓冲区的数量,其为从 0 开始到 7 的数字。

buffer[]: 指定自定义指标中声明的数组。

data_type: 指定存储在指标数组中的数据类型。

   SetIndexBuffer(0,indBuff,INDICATOR_DATA);
   SetIndexBuffer(2,momBuff,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,momSmBuff1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,momSmBuff2,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,absMomBuff,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,absMomSmBuff1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(7,absMomSmBuff2,INDICATOR_CALCULATIONS);

设置相应指标属性的数值时,指标属性(prop value)必须是字符串类型,方法是调用(IndicatorSetString)函数,仅按指定属性标识符调用该函数的不同变体。 此步骤设置指标的短名称,并确定在指标窗口左上角显示的周期。 其参数:

IndicatorSetString(INDICATOR_SHORTNAME,"True Strength Index ("+(string)smperiod1+","+(string)smperiod2+")");

以整数型数据类型设置指标的另一个属性值,调用 (IndicatorSetInteger)变体设置指定属性标识符,将指标的小数值规范化到指定位数。 其参数 

IndicatorSetInteger(INDICATOR_DIGITS,Digits());

调用(ArraySetAsSeries)为数组设置 AS_SERIES 标志。

   ArraySetAsSeries(indBuff,true);
   ArraySetAsSeries(momBuff,true);
   ArraySetAsSeries(momSmBuff1,true);
   ArraySetAsSeries(momSmBuff2,true);
   ArraySetAsSeries(absMomBuff,true);
   ArraySetAsSeries(absMomSmBuff1,true);
   ArraySetAsSeries(absMomSmBuff2,true);

在 OnCalculate 函数之后,

   ArraySetAsSeries(close,true);
   if(rates_total<2)
      return 0;

   int limit=rates_total-prev_calculated;
   if(limit>1)
     {
      limit=rates_total-2;
      ArrayInitialize(indBuff,EMPTY_VALUE);
      ArrayInitialize(momBuff,0);
      ArrayInitialize(momSmBuff1,0);
      ArrayInitialize(momSmBuff2,0);
      ArrayInitialize(absMomBuff,0);
      ArrayInitialize(absMomSmBuff1,0);
      ArrayInitialize(absMomSmBuff2,0);
     }

创建一个循环来更新 momBuff[i]、absMomBuff[i]。 此步骤中用到的新函数包括:

   for(int i=limit; i>=0 && !IsStopped(); i--)
     {
      momBuff[i]=close[i]-close[i+1];
      absMomBuff[i]=MathAbs(momBuff[i]);
     }

调用(MovingAverage)Include 文件中的 ExponentialMAOnBuffer 函数来检查以下内容。

   if(ExponentialMAOnBuffer(rates_total,prev_calculated,0,smperiod1,momBuff,momSmBuff1)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,0,smperiod1,absMomBuff,absMomSmBuff1)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,smperiod1,smperiod2,momSmBuff1,momSmBuff2)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,smperiod1,smperiod2,absMomSmBuff1,absMomSmBuff2)==0)
      return 0;

创建另一个 for 循环来更新 indBuff[i] 变量

   for(int i=limit; i>=0 && !IsStopped(); i--)
      indBuff[i]=(absMomSmBuff2[i]!=0 ? 100.0*momSmBuff2[i]/absMomSmBuff2[i] : 0);

在程序的末尾,是 return (rates_total) 函数

   return(rates_total);

如此这般,现在我们完成了创建 TSI 自定义指标的代码,您还可以编辑代码的首选项,以便进行更多自定义。 以下是在一个模块当中创建的指标完整代码:

//+------------------------------------------------------------------+
//|                                                   simple TSI.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 8
#property indicator_plots   1
#property indicator_label1  "TSI"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  3
#include <MovingAverages.mqh>
input uint     InpSmPeriod1   =  25;    // Smoothing period 1
input uint     InpSmPeriod2   =  13;   // Smoothing period 2
int            smperiod1;
int            smperiod2;
double         indBuff[];
double         momBuff[];
double         momSmBuff1[];
double         momSmBuff2[];
double         absMomBuff[];
double         absMomSmBuff1[];
double         absMomSmBuff2[];
int OnInit()
  {
   smperiod1=int(InpSmPeriod1<2 ? 2 : InpSmPeriod1);
   smperiod2=int(InpSmPeriod2<2 ? 2 : InpSmPeriod2);
   SetIndexBuffer(0,indBuff,INDICATOR_DATA);
   SetIndexBuffer(2,momBuff,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,momSmBuff1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,momSmBuff2,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,absMomBuff,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,absMomSmBuff1,INDICATOR_CALCULATIONS);
   SetIndexBuffer(7,absMomSmBuff2,INDICATOR_CALCULATIONS);
   IndicatorSetString(INDICATOR_SHORTNAME,"True Strength Index ("+(string)smperiod1+","+(string)smperiod2+")");
   IndicatorSetInteger(INDICATOR_DIGITS,Digits());
   ArraySetAsSeries(indBuff,true);
   ArraySetAsSeries(momBuff,true);
   ArraySetAsSeries(momSmBuff1,true);
   ArraySetAsSeries(momSmBuff2,true);
   ArraySetAsSeries(absMomBuff,true);
   ArraySetAsSeries(absMomSmBuff1,true);
   ArraySetAsSeries(absMomSmBuff2,true);
   return(INIT_SUCCEEDED);
  }
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   ArraySetAsSeries(close,true);
   if(rates_total<2)
      return 0;

   int limit=rates_total-prev_calculated;
   if(limit>1)
     {
      limit=rates_total-2;
      ArrayInitialize(indBuff,EMPTY_VALUE);
      ArrayInitialize(momBuff,0);
      ArrayInitialize(momSmBuff1,0);
      ArrayInitialize(momSmBuff2,0);
      ArrayInitialize(absMomBuff,0);
      ArrayInitialize(absMomSmBuff1,0);
      ArrayInitialize(absMomSmBuff2,0);
     }
   for(int i=limit; i>=0 && !IsStopped(); i--)
     {
      momBuff[i]=close[i]-close[i+1];
      absMomBuff[i]=MathAbs(momBuff[i]);
     }
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,0,smperiod1,momBuff,momSmBuff1)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,0,smperiod1,absMomBuff,absMomSmBuff1)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,smperiod1,smperiod2,momSmBuff1,momSmBuff2)==0)
      return 0;
   if(ExponentialMAOnBuffer(rates_total,prev_calculated,smperiod1,smperiod2,absMomSmBuff1,absMomSmBuff2)==0)
      return 0;
   for(int i=limit; i>=0 && !IsStopped(); i--)
      indBuff[i]=(absMomSmBuff2[i]!=0 ? 100.0*momSmBuff2[i]/absMomSmBuff2[i] : 0);
   return(rates_total);
  }

在编译此代码,且没有错误后,我们在导航器的 Indicators 文件夹中的可用指标中找到该指标,并将其拖放到所需的图表上,然后会发现指标的窗口和输入,如下所示:

简单 TSI 输入窗口

故此,我们有两个输入,可由用户确定第一个平滑周期的默认值为 25,第二个平滑周期的默认值为 13。 但是,正如我们提到的,用户仍然可以根据自己的喜好编辑它们。

 简单 TSI 颜色窗口

我们可以在上一张图片中看到,在颜色选项卡中,用户可以选择 TSI 线的颜色、宽度和样式。 在确定指标的喜好输入和样式后,我们可以在图表上找到与以下相同的指标:

 简单 TSI 加载

正如我们在上一张图表中看到的,我们在价格下方的单独窗口中得到 TSI 指标线,这条线围绕零轴振荡。 我们有指标的标签、它的平滑周期和指标的值。


自定义 TSI EA

在这一部分中,我们将以一种非常简单的方式学习如何在自动化系统中使用我们的自定义指标,如此即可在触发特定条件后,它可以生成特定的信号或举措。 我们将首先创建一个非常简单的系统,创建一个智能系统,它将在图表上生成一条含有 TSI 当前值的注释,然后再开发一个执行更复杂指令的 EA。

故此,以下就是创建我们的智能系统所需的步骤:

完整代码如下:

//+------------------------------------------------------------------+
//|                                           customSimpleTSI-EA.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
int TSI;
int OnInit()
  {
   TSI=iCustom(_Symbol,_Period,"My Files\\TSI\\simpleTSI");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("TSI System Removed");
  }
void OnTick()
  {
   double tsiVal[];
   CopyBuffer(TSI,0,0,1,tsiVal);
   Comment("TSI Value ",DoubleToString(tsiVal[0],_Digits));
  }

编译此代码,无错误,并执行后,它将加载到图表上。 以下是其测试信号的示例:

 自定义 TSI EA 信号

正如我们所看到的,我们在图表左上角得到一条注释,其中包含当前的 TSI 值。 如果我们想确保信号与我们基于指标的信号相同,我们可以加载 EA,并同时插入指标值。 以下是为了确保我们的工作:

自定义 TSI EA 加载 — 相同信号

正如我们在右上角看到的,我们加载了 EA,当前 TSI 值出现在左上角,同时我们加载 TSI 指标作为图表价格下方的单独窗口,其值与上面左上角那一行的 EA 信号相同。


TSI 系统 EA

在这一部分中,我们将基于创建的自定义 TSI 指标开发一个 EA,从而根据特定策略获取信号。 请注意,我们将要讨论的策略仅用于教学目的。 无论如何,它都需要优化,就像任何其它策略一样。 故此,您必须在将其用于真实帐户之前对其进行测试,并确保它对您有用。

我们将使用自定义 TSI 指标,与两条移动平均线相结合,根据特定策略获取买入和卖出信号,如下所示:

除了我们自定义的 TSI 指标外,我们还用到两条简单移动平均线,一条是快速的,周期为 10,另一条是慢速的,周期为 20。 如果前期的快速均线值小于前期的慢速均线值,同时当期快速均线值大于当期的慢速均线值,这意味着我们得到一个看涨的均线交叉,那么我们应检查当期的 TSI 值是否大于零,我们需要在图表上将得到的买入信号作为注释。 如果前期的快速均线值大于前期的慢速均线值,同时当期快速均线值小于当期的慢速均线值,这意味着我们得到一个看跌的均线交叉,那么我们应检查当期的 TSI 值是否小于零,我们需要在图表上将得到的卖出信号作为注释。

简单说,

如果 fastMA[1]<slowMA[1] && fastMA[0]>slowMA[0] && tsiVal[0]>0 ==> 买入信号
如果 fastMA[1]>slowMA[1] && fastMA[0]<slowMA[0] && tsiVal[0]<0 ==> 卖出信号

以下是创建此类系统的完整代码:

//+------------------------------------------------------------------+
//|                                                TSI System EA.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
input ENUM_MA_METHOD inpMAType = MODE_SMA; //Moving Average Type
input ENUM_APPLIED_PRICE inpPriceType = PRICE_CLOSE; //Price type
input int inpFastMAPeriod = 10; // Fast moving average period
input int inpSlowMAPeriod = 20; //Slow moving average period
int tsi;
double fastMAarray[], slowMAarray[];
int OnInit()
  {
   tsi=iCustom(_Symbol,_Period,"My Files\\TSI\\simpleTSI");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("TSI System Removed");
  }
void OnTick()
  {
   double tsiVal[];
   CopyBuffer(tsi,0,0,1,tsiVal);
   int fastMA =iMA(_Symbol,_Period,inpFastMAPeriod,0,inpMAType,inpPriceType);
   int slowMA =iMA(_Symbol,_Period,inpSlowMAPeriod,0,inpMAType,inpPriceType);
   ArraySetAsSeries(fastMAarray,true);
   ArraySetAsSeries(slowMAarray,true);
   CopyBuffer(fastMA,0,0,3,fastMAarray);
   CopyBuffer(slowMA,0,0,3,slowMAarray);
   if(fastMAarray[1]<slowMAarray[1]&&fastMAarray[0]>slowMAarray[0])
     {
      if(tsiVal[0]>0)
        {

         Comment("Buy Signal",
                 "\nTSI Value ",DoubleToString(tsiVal[0],_Digits),
                 "\nfastMA ",DoubleToString(fastMAarray[0],_Digits),
                 "\nslowMA ",DoubleToString(slowMAarray[0],_Digits));
        }
     }
   if(fastMAarray[1]>slowMAarray[1]&&fastMAarray[0]<slowMAarray[0]&&tsiVal[0]<0)
     {
      if(tsiVal[0]<0)
        {
         Comment("Sell Signal",
                 "\nTSI Value ",DoubleToString(tsiVal[0],_Digits),
                 "\nfastMA ",DoubleToString(fastMAarray[0],_Digits),
                 "\nslowMA ",DoubleToString(slowMAarray[0],_Digits));
        }
     }
  }

此代码中的差异与以下内容相同:

用户为移动平均线类型、应用价格类型、快速 MA 周期和慢速 MA 周期创建四个输入,并为其分配默认值。

input ENUM_MA_METHOD inpMAType = MODE_SMA; //Moving Average Type
input ENUM_APPLIED_PRICE inpPriceType = PRICE_CLOSE; //Price type
input int inpFastMAPeriod = 10; // Fast moving average period
input int inpSlowMAPeriod = 20; //Slow moving average period

为快速 MA 数组和慢速 MA 创建两个数组。

double fastMAarray[], slowMAarray[];

调用预定义的 iMA 函数定义两条移动平均线,并返回移动平均线的句柄,其参数为:

   int fastMA =iMA(_Symbol,_Period,inpFastMAPeriod,0,inpMAType,inpPriceType);
   int slowMA =iMA(_Symbol,_Period,inpSlowMAPeriod,0,inpMAType,inpPriceType);

调用 ArraySetAsSeries 函数为慢速和快速 MA 设置 AS_SERIES 标志

   ArraySetAsSeries(fastMAarray,true);
   ArraySetAsSeries(slowMAarray,true);

调用 CopyBuffer 函数从两条移动平均线的缓冲区获取数据

   CopyBuffer(fastMA,0,0,3,fastMAarray);
   CopyBuffer(slowMA,0,0,3,slowMAarray);

定义策略条件,

买入信号情况:

如果前期 fastMA 小于前期 slowMA,且当期 fastMA 大于当期 slowMA,同时当期 tsiVal 大于零,我们需要 EA 将买入信号作为图表上的注释返回,顺序如下:

   if(fastMAarray[1]<slowMAarray[1]&&fastMAarray[0]>slowMAarray[0])
     {
      if(tsiVal[0]>0)
        {

         Comment("Buy Signal",
                 "\nTSI Value ",DoubleToString(tsiVal[0],_Digits),
                 "\nfastMA ",DoubleToString(fastMAarray[0],_Digits),
                 "\nslowMA ",DoubleToString(slowMAarray[0],_Digits));
        }
     }

卖出信号情况:

如果前期 fastMA 大于前期 slowMA,而当期 fastMA 小于当期 slowMA,同时当期 tsiVal 小于零,我们需要 EA 将卖出信号作为图表上的注释返回,顺序如下:

   if(fastMAarray[1]>slowMAarray[1]&&fastMAarray[0]<slowMAarray[0]&&tsiVal[0]<0)
     {
      if(tsiVal[0]<0)
        {
         Comment("Sell Signal",
                 "\nTSI Value ",DoubleToString(tsiVal[0],_Digits),
                 "\nfastMA ",DoubleToString(fastMAarray[0],_Digits),
                 "\nslowMA ",DoubleToString(slowMAarray[0],_Digits));
        }
     }

编译此代码,没有错误,并拖放执行,获取其信号后,我们可以在“输入”选项卡中找到与如下窗口:

TSI 系统 EA 输入窗口

正如我们所看到的,我们有 MA 类型、价格类型、快速 MA 周期和慢速 MA 周期的四个输入。 设置好首选项,并按确定后,我们可以发现 EA 已加载到图表上,其信号如下:

买入信号情况

 TSI 系统 EA — 买入信号

正如我们在上图中看到的,根据我们的策略条件,我们在左上角有一个买入信号作为注释,如下所示:

卖出信号情况:

 TSI 系统 EA — 卖出信号

正如我们在上图中看到的,根据我们的策略条件,我们在左上角有一个卖出信号作为注释。 如下:

结束语

在本文中,我们学习了如何创建自己的真实强度指数技术指标,来实现您的特定设置和偏好。 我们已经看到了该指标提供了哪些信息和见解,这些信息和见解在交易中非常有帮助。 我们还学习了如何在一个简单的交易系统中使用此自定义指标,来取 TSI 指标的当前值生成图表上的注释。 我们还通过创建 EA 来了解如何在自动交易系统中使用该指标,该 EA 利用 TSI 数据与另一种技术工具相结合,在我们的例子中是移动平均线。 自定义 TSI 和两条移动平均线的组合后,根据特定策略生成买入和卖出信号,我们在 TSI 系统 EA 主题中详细研究了这些信号。

希望本文对您的交易和编程学习有所帮助。 如果您想阅读有关指标的其它文章,并学习如何基于最流行的技术指标创建交易系统,请参阅我之前的文章,其中我介绍了流行的指标,例如移动平均线、布林带、RSI、MACD、随机指标、抛物线转向指标、ATR、等等。