量化交易软件:依据 Heiken-Ashi 指标的交易系统示例

简介

二十多年前烛形图在美国出现之后,对牛熊如何在西方市场中角力的理解出现了一场革命。烛形图成为一种流行的交易工具,交易者开始使用它们,从而让对图表的理解更加容易。但是对烛形图的判读因人而异。

这些方法中的一种改变传统的烛形图,有利于对其的理解,称为 Heikin Ashi 技术。

1. «Nani Desu Ka?»*

有关此主题的第一篇文章出于在 2004 年二月期的《股票与商品技术分析》杂志中,在该期杂志中 Dan Valcu 发表了一篇名为《使用 Heikin Ashi 技术》的文章(到原文的链接)

在他的网站上,作者指出在 2003 年夏天,他研究了 Ichimoku 技术,并且因为经常出现,意外地发现有一些图展现出清晰可见的市场趋势。这演变为 Heikin-Ashi 图,是更为精确、有一定变化的烛形图。

这种分析方法是一名日本人发明的,到目前为止,他用此方法变得非常成功。让作者感到惊讶的是,他在书箱或互联网中找不到其他相关信息,因此决定通过在杂志中发表该方法来让所有交易者都能运用此方法。

Heikin-Ashi 方法(heikin 在日语中表示“中间”或“平衡”,ashi 表示“脚”或“柱”)是用于评估趋势及其方向与强度的可视化工具。这不是交易的“圣杯”,但它是一个非常优秀且易于使用的可视化趋势工具。

让我们考虑一下 OHLC 烛形图数值的计算是如何进行的:

当前柱的收盘价:haClose = (Open + High + Low + Close) / 4 当前柱的开盘价:haOpen = (haOpen [before.]+ HaClose [before]) / 2 当前柱的最高价:haHigh = Max (High, haOpen, haClose) 当前柱的最低价:haLow = Min (Low, haOpen, haClose)

"Open"、"High"、"Low" 和 "Close" 的值都是指与当前柱有关的值。前缀 "ha" 表示 heikin-ashi 的对应修改值。

为了便于理解市场信息,Heikin-Ashi 技术通过创建所谓的合成烛形来修改传统的烛形图,从普通烛形图中去除不规则的烛,从而提供更好的趋势与平台整理图形。看一看用此方法创建的烛形图,您就可以对市场及其风格一目了然:

编辑切换为居中

添加图片注释,不超过 140 字(可选)

图 1. 左侧是常规烛形图 (a),右侧是 Heikin-Ash 烛形图 (b)

图 1 显示了传统日本烛形图与 Heiken Ashi 烛形图之间的区别。这些图形的明显特征是在向上趋势中,大多数的白色烛没有影线。在下降趋势中,大多数的黑色烛没有上影线。Heiken Ashi 烛形图没有缺口,因此新烛在上一烛的中间水平开盘。

Heiken-Ashi 烛形图上的烛显示了比传统烛形图更广泛的趋势指示。当趋势减弱时,烛的主体变短,影线变长。烛颜色的改变是买/卖的信号。依据这些图表确定纠正移动的结束是最方便的。

此指标是 赫兹量化的一部分,您可以在文件夹 Indicators \\ Examples \\ Heiken_Ashi.mq5 中找到它。在将指标安装到图表之前,我建议使图形线性化。同样,在图形的属性中,在 "General"(常规)选项卡中,取消选中 "from the top graph"(从顶部图形)一项。

我想再一次将您的注意力聚焦到 Heiken-Ashi 方法不是“圣杯”这一事实上。为了证明这一点,我将尝试仅使用这一技术创建一个简单的交易系统 (TS)。

为此,赫兹量化需要使用 MQL5 编程语言和标准库中的类创建一个简单的 EA 交易程序,然后使赫兹量化客户端的策略测试程序用历史数据对其进行测试。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

2. 交易系统算法

不需要太复杂,赫兹量化使用 Dan Valcu 在以下网站中提出的 Heiken-Ashi 程序的六个基本原则创建算法:

  1. 上升趋势 - 蓝色烛 haClose> haOpen

  2. 下降趋势 - 红色烛 haClose <haOpen

  3. 强的上升趋势 - 蓝色烛,其中没有 Low haOpen == haLow

  4. 强的下降趋势 - 红色烛,其中没有 High haOpen == haHigh

  5. 平台整理 - 一系列具有短主体(任意颜色)和长影线的烛

  6. 趋势改变 - 具有相反颜色的短主体和长影线的烛。它并不始终都是一个可靠的信号,有时可能仅是平台整理 (5) 的一部分。

(1,2) 趋势容易理解 - 如果在交易之中,赫兹量化只需要保持仓位,将止损移到低于/高于上一烛的 1-2 个点即可。

对于强的趋势 (3,4),我们以相同的方式操作 - 增大止损。

对于平台整理 (5) 和趋势改变 (6),平仓(如果没有通过止损平仓的话),然后我们需要决定是否建立一个相反的仓位。为了做出决定,赫兹量化需要以某种方式确定是出现平台整理还是出现反向。我们需要一个依据指标、烛形图分析或图形分析建立的过滤器。

本文的目标不包括建立一个能够盈利的策略,但是谁知道作为一个结果我们会实现什么呢?因此,让我们考虑以下相反颜色的烛的出现,我们将平仓并以相反方向建立新仓。

那么,我们的算法如下所示:

  1. 在相反颜色的烛形成之后,赫兹量化平以前的仓位(如果有的话),并且在新烛开盘时建仓,将止损设置为低于/高于上一烛的最低价/最高价 2 个点。

  2. 趋势 - 我们将止损移到低于/高于上一烛的最低价/最高价 2 个点。

  3. 对于强的趋势,我们采取与趋势相同的步骤,即移动止损。

整体而言,所有事情都很简单,并且对读者也可能很清晰。现在,我们将用 MQL5 语言实现这一目的。

3. 用 MQL5 编写 EA 交易程序

要创建 EA 交易程序,赫兹量化仅需要一个输入参数 - 手数、两个事件处理函数 OnInit ()、OnTick (),和我们自己的函数 CheckForOpenClose ()。

要用 MQL5 设置输入参数,我们使用 Input 变量。

 
 

//--- 输入参数 input double Lot=0.1; // 交易量大小

函数 OnInit () 是事件处理程序 Init。Init 事件在加载 EA 交易程序之后立即生成。

在这个函数的代码里,赫兹量化会将指标连接到 EA 交易程序。如我在前文所述,标准赫兹量化包含一个 Heiken_Ashi.mq5 指标。

如果我们有用于计算指标的公式,并且我们能够在 EA 交易程序的代码中计算值,也许您会疑惑为什么还要这么复杂?是的,我承认,是可以这样做,但是如果您仔细看一看它们:

haOpen=(haOpen[prev.]+haClose[prev])/2

您将看到它使用以前的值,这样会对独立计算造成一定的不便,使我们的生活变得复杂。因此,代替独立计算,我们将开发 MQL5 连接我们的自定义指标的能力,即函数 iCustom。

为此,我们向函数 OnInit () 的主体添加以下代码行:

 
 

hHeiken_Ashi=iCustom(NULL,PERIOD_CURRENT,"Examples\\Heiken_Ashi");

并且我们获得一个全局变量 hHeiken_Ashi - Heiken_Ashi.mq5 指标的句柄,我们在将来会需要该变量 。

函数 OnTick () 是 NewTick () 事件的处理程序,该事件在新的价格变动出现时发生。

 
 

//+------------------------------------------------------------------+ //| EA订单函数 | //+------------------------------------------------------------------+ void OnTick() { //--- 检查能否交易以及计算的柱数 if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) if(BarsCalculated(hHeiken_Ashi)>100) { CheckForOpenClose(); } //--- }

函数 TerminalInfoInteger (TERMINAL_TRADE_ALLOWED) 检查是否允许交易。使用函数 BarsCalculated (HHeiken_Ashi),赫兹量化检查所请求指标(在我们的例子中为 Heiken_Ashi.mq5)的计算数据的量。

如果两个条件都满足,我们将看到函数 CheckForOpenClose () 的执行,主要工作就在该函数中进行。让我们更加仔细地看一看。

因为我们的交易系统条款指定订单的成交发生在新烛开盘之时,我们需要确定新烛是否已经开盘。有很多方式可以实现此目的,但是最简单的方式是检查价格变动的量。因此,如果价格变动量等于 1,则表示新柱的开盘,您应检查交易系统的条款并发布订单。

我们按以下方式实施:

 
 

//--- 只有在收到新烛形的第一笔订单号时处理订单 MqlRates rt[1]; if(CopyRates(_Symbol,_Period,0,1,rt)!=1) { Print("CopyRates ",_Symbol," 失败,没有历史"); return; } if(rt[0].tick_volume>1) return;

创建一个类型为 MqlRates、大小为一个元素的变量数组。使用函数 CopyRates () 将最后一根柱的值加入该变量数组。然后检查价格变动量,并且在变动量大于 1 时终止函数,否则继续进行计算。

接下来,使用指令 #define 声明几个记忆常量:

 
 

//--- 为了检查条件我们需要最后3个柱 #define BAR_COUNT 3 //--- 用于保存开盘价的指标缓冲区编号 #define HA_OPEN 0 //--- 用于保存最高价的指标缓冲区编号 #define HA_HIGH 1 //--- 用于保存最低价的指标缓冲区编号 #define HA_LOW 2 //--- 用于保存收盘价的指标缓冲区编号 #define HA_CLOSE 3

再然后,我们声明数组:

 
 

double haOpen[BAR_COUNT],haHigh[BAR_COUNT],haLow[BAR_COUNT],haClose[BAR_COUNT];

并且使用函数 CopyBuffer () 获取相应数组中的指标值。

 
 

if(CopyBuffer(hHeiken_Ashi,HA_OPEN,0,BAR_COUNT,haOpen)!=BAR_COUNT || CopyBuffer(hHeiken_Ashi,HA_HIGH,0,BAR_COUNT,haHigh)!=BAR_COUNT || CopyBuffer(hHeiken_Ashi,HA_LOW,0,BAR_COUNT,haLow)!=BAR_COUNT || CopyBuffer(hHeiken_Ashi,HA_CLOSE,0,BAR_COUNT,haClose)!=BAR_COUNT) { Print("从 Heiken_Ashi CopyBuffer 失败, 没有数据"); return; }

我想将您的注意力聚焦到数据是如何存储在变量数组中的。

“最旧的”(历史顺序)柱存储在数组的第一个元素(零)中。

“最新的”(当前)柱存储在后面,BAR_COUNT-1(图 2)。

编辑

添加图片注释,不超过 140 字(可选)

图 2. 烛的顺序和数组索引的值

因此,我们已经获得了 OHLC Heiken-Ashi 值,剩下的是验证建仓或持仓的条件。

详细考虑买入信号的处理。

如我在前面所指出,赫兹量化获得了三个 Heiken-Ashi 烛的值。当前值位于编号 [BAR_COUNT-1 = 2] 的单元格中,并且对我们而言并不是必不可少的。先前的值位于单元格 [BAR_COUNT-2 = 1] 中,更早的烛位于 [BAR_COUNT-3 = 0] 中(见图 2),并且依据这两根烛,我们将检查进行交易的条款与条件。

然后,我们需要检查工具上的未平仓位。为此,我们将使用默认库中交易类的 CPositionInfo 类。此类允许我们获得有关未平仓位的信息。我们使用方法 Select (_Symbol) 确定在我们的工具上是否存在未平仓位,如果存在,则使用方法 Type () 确定未平仓位的类型。

如果目前我们有要买入的未平仓位,则我们需要平仓。

为此,赫兹量化使用标准类库中专为执行交易操作而设计的 CTrade 类的方法。

赫兹量化将使用方法 PositionClose (const string symbol, ulong deviation) 来平仓,其中 symbol 是工具的名称,第二个参数 deviation 是平仓价的允许偏差。

然后,我们依据我们的交易系统检查烛形图组合。因为我们已经检查了新形成的烛(索引为 [BAR_COUNT-2]),我们仅需要检查它前面的烛(索引为 [BAR_COUNT-3]),并且执行建仓所需的步骤。

 
 

//--- 检查是否有持仓,如果有,则平掉 if(posinf.Select(_Symbol)) { if(posinf.Type()==POSITION_TYPE_BUY) { // lot=lot*2; trade.PositionClose(_Symbol,3); } } //--- 检查和设置止损水平 double stop_loss=NormalizeDouble(haHigh[BAR_COUNT-2],_Digits)+_Point*2; double stop_level=SymbolInfoDouble(_Symbol,SYMBOL_ASK)+SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)*_Point; if(stop_loss<stop_level) stop_loss=stop_level; //--- 检查组合: 相反颜色的烛形已经生成 if(haOpen[BAR_COUNT-3]<haClose[BAR_COUNT-3]) { if(!trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,lot,SymbolInfoDouble(_Symbol,SYMBOL_BID),stop_loss,0)) Print(trade.ResultRetcodeDescription()); } else if(posinf.Select(_Symbol)) { if(!trade.PositionModify(_Symbol,stop_loss,0)) Print(trade.ResultRetcodeDescription()); }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值