请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  量化策略 帖子:3364794 新帖:30

价格行为. 自动化吞噬模式的交易策略

不做外汇索罗斯发表于:4 月 17 日 19:22回复(1)

简介

所有的外汇交易者或多或少都接触过价格行为. 它不仅仅是一项图表分析技术, 而是包含了定义未来价格可能走向的整个系统. 本文中, 我们将分析吞噬模式, 并且根据此模式创建一个 EA 交易以进行相关的交易.

在之前的文章中, 我们已经尝试了使用称为"内含柱交易"的模式进行自动化交易. 该文章为价格行为. 自动化内含柱交易策略.


吞噬模式的规则

所谓吞噬模式就是, 某个柱的柱体和影线全部被前面一个柱的柱体和影线包含. 有两种类型的吞噬:

  • BUOVB — 垂直柱的牛势外包;
  • BEOVB — 垂直柱的熊势外包.

图 1. 图表上显示的模式类型

图 1. 图表上显示的模式类型

让我们仔细研究一下此模式.

BUOVB. 此图表显示, 外部柱形的最高价高于前一个柱形的最高价, 而且外部柱形的最低价低于前一柱形的最低价.

BEOVB. 此模式也很容易在图表上找出. 外部柱形的最高价高于前一柱的最高价, 并且外部柱形的最低价低于前一柱的最低价.

它们的区别是每个模式指明了市场可能的不同方向.

图 2. 模式的结构

图 2. 模式的结构

吞噬模式的规则:

  • 此模式要求在较高的时间框架内运行, 例如: H4, D1.
  • 为了更加优化地进场, 应该使用额外的图表分析元件, 例如趋势线, 支撑/阻力水平, 斐波那契水平线, 以及其他的价格行为模式等等.
  • 使用挂单来避免过早或者错误地进入市场.
  • 在平缓交易市场中出现的模式不应该用作进入市场的信号.


为"BUOVB"模式设置入场点, 设置止损单

图 3. 设置止损买入订单并设置止损

图 3. 设置止损买入 订单并设置止损

我们将使用上面的例子来分析进场规则, 即基于BUOVB (牛势外部垂直柱形)的模式下止损订单:

  1. 我们在外部柱形最高价的上方少许(几个点以作确认)设置止损买入订单.
  2. 止损水平设置为外部柱形的最低价下方.
  3. 获利水平则设置为即将达到下一个阻力位水平.


为"BEOVB"模式设置入场点, 设置止损单

图 4. 设置止损卖出订单及止损

图 4. 设置止损卖出订单及止损

再让我们检查一下上面例子中的针对BEOVB (熊势外部垂直柱形)模式进场并设置止损订单的规则:

  1. 我们会在低于外部柱形最低价(几个点,用于确认)之处设置止损卖出挂单.
  2. 其止损价位设置高于外部柱形的最高价.
  3. 而获利价位设置为即将到达下一个支撑水平.


为吞噬模式创建EA交易

我们已经了解了吞噬模式, 学习了怎样安全地进入市场, 并且已经决定了止损订单的设置以限制亏损和锁定利润.

下一步我们将尝试在EA交易中实现这些算法以把吞噬交易模式自动化.

我们在MetaTrader 4终端中打开MetaEditor 并且创建一个新的EA交易 (我们将不详细介绍怎样新建EA交易, 因为网站上已经有了足够的信息). 在创建阶段, 我们把参数设为全空. 您可以根据您的喜好进行命名. 最终, 您应该得到下面的结果:

//+------------------------------------------------------------------+
//|                                              BEOVB_BUOVB_Bar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| EA 初始化函数                                                     |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| EA 终止化函数                                                     |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| EA 订单处理函数                                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+


把模式转换为MQL4算法

在创建EA交易之后, 我们需要在柱形关闭之后来定义吞噬模式. 为此, 我们引入了新的变量并且为它们赋值. 参照以下代码:

//+------------------------------------------------------------------+
//|                                              BEOVB_BUOVB_Bar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict

double open1,//第一个柱的开盘价
open2,      //第二个柱的开盘价
close1,     //第一个柱的收盘价
close2,     //第二个柱的收盘价
low1,       //第一个柱的最低价
low2,       //第二个柱的最低价
high1,      //第一个柱的最高价
high2;      //第二个柱的最高价
//+------------------------------------------------------------------+
//| EA 初始化函数                                                     |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| EA 终止化函数                                                     |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| EA 订单处理函数                                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- 定义所需柱形的价格
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
  }
//+------------------------------------------------------------------+

我们寻找两种吞噬模式:

void OnTick()
  {
//--- 定义所需柱形的价格
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
//--- 寻找熊势模式 BEOVB
   if(low1 < low2 &&// 第一个柱的最低价在第二柱最低价之下
      high1 > high2 &&// 第一个柱的最高价在第二柱最高价之上
      close1 < open2 &&	//第一个柱的收盘价低于第二柱的开盘价
      open1 > close1 && //第一个柱是熊势柱
      open2 < close2)	//第二个柱是牛势柱
     {
      //--- 我们已经定义了全部条件, 即第一柱完全吞噬了第二柱并且是熊势柱
     }

我们使用相同方法寻找牛势模式:

//--- 寻找牛势模式 BUOVB
   if(low1 < low2 &&// 第一个柱的最低价低于第二柱的最低价 
      high1 > high2 &&// 第一个柱的最高价高于第二柱的最高价
      close1 > open2 && //第一个柱的收盘价高于第二柱的开盘价
      open1 < close1 && //第一个柱是牛势柱
      open2 > close2)   //第二个柱是熊势柱
     {
      //--- 我们已经定义了全部条件, 即第一柱完全吞噬了第二柱并且是牛势柱 
     }
  • 我们接着创建可修改的参数: 止损单, 点差, 订单过期时间, EA幻数, 交易手数. 止损可以被忽略, 因为会根据模式的规则进行设置.
  • 我们引入局部变量来把这些变量做转换.
  • 另外, 我们需要记住的是, 止损单是根据与柱价格之间的距离来设置的. 在代码实现中, 我们增加了Interval变量来表示最高/最低价格与止损定单的价格之间的距离, 挂单的价格也是如此.
  • 我们增加了timeBUOVB_BEOVB变量来避免在模式下重复开单.
  • 我们增加了bar1size变量来检查外部柱形大小是否足够. 这样, 我们就可以认定当前市场并不平缓.

结果我们可以获得如下代码:

//+------------------------------------------------------------------+
//|                                              BEOVB_BUOVB_bar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict

extern int     interval          = 25;                               //距离
extern double  lot               = 0.1;                              //手数
extern int     TP                = 400;                              //获利
extern int     magic             = 962231;                           //幻数
extern int     slippage          = 2;                                //点差
extern int     ExpDate           = 48;                               //订单过期小时数
extern int     bar1size          = 900;                              //第一个柱形大小

double buyPrice,//定义止损买入订单的价格
buyTP,      //止损买入单的获利价位
buySL,      //止损买入单的止损价位
sellPrice,  //定义止损卖出订单的价格
sellTP,     //止损卖出单的获利价位
sellSL;     //止损卖出单的止损价位

double open1,//第一个柱的开盘价
open2,    //第二个柱的开盘价
close1,   //第一个柱的收盘价
close2,   //第二个柱的收盘价
low1,     //第一个柱的最低价
low2,     //第二个柱的最低价
high1,    //第一个柱的最高价
high2;    //第二个柱的最高价

datetime _ExpDate =0; // 用于定义挂单过期时间的局部变量
double _bar1size;// 用于避免平缓市场的局部变量
datetime timeBUOVB_BEOVB;// 模式订单下单柱的时间, 用于避免重复开单
//+------------------------------------------------------------------+
//| EA 初始化函数                                                     |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| EA 终止化函数                                                     |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| EA 订单处理函数                                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
   double   _bid = NormalizeDouble(MarketInfo (Symbol(), MODE_BID), Digits); // 定义最低价
   double   _ask     = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //定义最高价
   double   _point   = MarketInfo(Symbol(), MODE_POINT);
//--- 定义所需柱形的价格
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
//---
   _bar1size=NormalizeDouble(((high1-low1)/_point),0);
//--- 寻找熊势模式 BEOVB
   if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //此模式尚未下单 
      _bar1size > bar1size && //第一个柱足够大, 所以市场并不平缓
      low1 < low2 &&//第一个柱的最低价低于第二柱的最低价
      high1 > high2 &&//第一个柱的最高价高于第二柱的最高价
      close1 < open2 && //第一个柱的收盘价低于第二柱的开盘价
      open1 > close1 && //第一个柱是熊势柱
      open2 < close2)   //第二个柱是牛势柱
     {
      //--- 我们已经定义了全部条件, 即第一柱完全吞噬了第二柱并且是熊势柱
      timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); // 指出此模式下已经下单
     }
//--- 寻找牛势模式 BUOVB
   if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //此模式尚未下单 
      _bar1size > bar1size && //第一个柱足够大, 并非平缓市场
      low1 < low2 &&//第一个柱的最低价低于第二柱的最低价
      high1 > high2 &&//第一个柱的最高价高于第二柱的最高价
      close1 > open2 && //第一个柱的收盘价高于第二柱的开盘价
      open1 < close1 && //第一个柱是牛势柱
      open2 > close2)   //第二个柱是熊势柱
     {
      //--- 我们已经定义了全部条件, 即第一柱完全吞噬了第二柱并且是牛势柱 
      timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); // 指出此模式已经下单
     }
  }
//+------------------------------------------------------------------+


定义止损订单水平

我们已经处理了寻找模式的全部条件. 现在所需要的就是为每个模式设置止损订单的止损以及价格水平, 还有订单的过期时间.

让我们把以下代码加入OnTick()函数体:

//--- 定义下单的价格和止损价格
   buyPrice =NormalizeDouble(high1 + interval * _point,Digits); //根据距离定义下单的价格
   buySL =NormalizeDouble(low1-interval * _point,Digits); //根据距离定义止损
   buyTP =NormalizeDouble(buyPrice + TP * _point,Digits); //定义获利
   _ExpDate =TimeCurrent() + ExpDate*60*60; //计算挂单过期时间
//--- 我们同样计算卖出订单 
   sellPrice=NormalizeDouble(low1-interval*_point,Digits);
   sellSL=NormalizeDouble(high1+interval*_point,Digits);
   sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);


执行错误的修正

如果您曾经开发过EA交易, 您可能知道, 当关闭或者设置订单, 包括等待的时间以及不正确的止损价位都可能出现错误. 为了消除此类错误, 我们应该使用简单的内部基本错误处理写一个独立的函数.

//+----------------------------------------------------------------------------------------------------------------------+
//| 开启和设置订单的函数                                                                                                    |
//| symbol      - 订单的交易品种                                                                                           |
//| cmd         - 交易类型 (可能等于任何交易类型值).                                                                         |
//| volume      - 手数.                                                                                                  |
//| price       - 开单价格.                                                                                               |
//| slippage    - 市场买入或者卖出订单的最大点差.                                                                            |
//| stoploss    - 当亏损达到某种水平关闭仓位的价位 (如果不设止损则为0).                                                         |
//| takeprofit  - 当获利达到某种水平关闭仓位的价位 (如果不设获利则为0).                                                         |
//| comment     - 订单注释. 注释的最后部分可能被交易服务器修改.                                                                |
//| magic       - 订单幻数. 可以使用用户自定义的ID.                                                                          |
//| expiration  - 挂单的过期时间.                                                                                          |
//| arrow_color - 图表上开启订单的箭头颜色. 如果此参数空缺或者等于CLR_NONE,                                                     |
//|               开单的箭头在图表上则不做显示.                                                                              |
//+----------------------------------------------------------------------------------------------------------------------+
int OrderOpenF(string     OO_symbol,
               int        OO_cmd,
               double     OO_volume,
               double     OO_price,
               int        OO_slippage,
               double     OO_stoploss,
               double     OO_takeprofit,
               string     OO_comment,
               int        OO_magic,
               datetime   OO_expiration,
               color      OO_arrow_color)
  {
   int result = -1;// 下单的结果
   int Error = 0; // 下单时出现的错误
   int attempt = 0; // 已经进行过的重试次数 
   int attemptMax = 3; // 最大重试次数
   bool exit_loop = false; // 退出循环
   string lang =TerminalInfoString(TERMINAL_LANGUAGE);// 交易终端的语言, 用于定义信息的语言
   double stopllvl =NormalizeDouble(MarketInfo (OO_symbol, MODE_STOPLEVEL) * MarketInfo (OO_symbol, MODE_POINT),Digits);// 最小的止损/获利点数
                                                                                                                     //用于安全下单的模块
//--- 检查买入订单
   if(OO_cmd==OP_BUY || OO_cmd==OP_BUYLIMIT || OO_cmd==OP_BUYSTOP)
     {
      double tp = (OO_takeprofit - OO_price)/MarketInfo(OO_symbol, MODE_POINT);
      double sl = (OO_price - OO_stoploss)/MarketInfo(OO_symbol, MODE_POINT);
      if(tp>0 && tp<=stopllvl)
        {
         OO_takeprofit=OO_price+stopllvl+2*MarketInfo(OO_symbol,MODE_POINT);
        }
      if(sl>0 && sl<=stopllvl)
        {
         OO_stoploss=OO_price -(stopllvl+2*MarketInfo(OO_symbol,MODE_POINT));
        }
     }
//--- 检查卖出订单
   if(OO_cmd==OP_SELL || OO_cmd==OP_SELLLIMIT || OO_cmd==OP_SELLSTOP)
     {
      double tp = (OO_price - OO_takeprofit)/MarketInfo(OO_symbol, MODE_POINT);
      double sl = (OO_stoploss - OO_price)/MarketInfo(OO_symbol, MODE_POINT);
      if(tp>0 && tp<=stopllvl)
        {
         OO_takeprofit=OO_price -(stopllvl+2*MarketInfo(OO_symbol,MODE_POINT));
        }
      if(sl>0 && sl<=stopllvl)
        {
         OO_stoploss=OO_price+stopllvl+2*MarketInfo(OO_symbol,MODE_POINT);
        }
     }
//--- while 循环
   while(!exit_loop)
     {
      result=OrderSend(OO_symbol,OO_cmd,OO_volume,OO_price,OO_slippage,OO_stoploss,OO_takeprofit,OO_comment,OO_magic,OO_expiration,OO_arrow_color); //尝试使用指定的参数下单
      //--- 如果开启订单出错
      if(result<0)
        {
         Error = GetLastError();                                     //给错误码赋值
         switch(Error)                                               //枚举错误
           {                                                         //关闭订单出错的枚举, 并尝试修复错误
            case  2:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //再多尝试一次
                  Sleep(3000);                                       //延迟3秒
                  RefreshRates();
                  break;                                             //退出 switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;                                         //把尝试次数重设为0 
                  exit_loop = true;                                  //退出 while
                  break;                                             //退出 switch
                 }
            case  3:
               RefreshRates();
               exit_loop = true;                                     //退出 while
               break;                                                //退出 switch   
            case  4:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //再多尝试一次
                  Sleep(3000);                                       //延迟3秒
                  RefreshRates();
                  break;                                             //退出 switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //把尝试次数重设为0
                  exit_loop = true;                                  //退出 while
                  break;                                             //退出 switch
                 }
            case  5:
               exit_loop = true;                                     //退出 while
               break;                                                //退出 switch   
            case  6:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //再多尝试一次
                  Sleep(5000);                                       //延迟5秒
                  break;                                             //退出 switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //把尝试次数重设为0
                  exit_loop = true;                                  //退出 while
                  break;                                             //退出 switch
                 }
            case  8:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //再多尝试一次
                  Sleep(7000);                                       //延迟7秒
                  break;                                             //退出 switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //把尝试次数重设为0
                  exit_loop = true;                                  //退出 while
                  break;                                             //退出 switch
                 }
            case 64:
               exit_loop = true;                                     //退出 while
               break;                                                //退出 switch
            case 65:
               exit_loop = true;                                     //退出 while
               break;                                                //退出 switch
            case 128:
               Sleep(3000);
               RefreshRates();
               continue;                                             //退出 switch
            case 129:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //再多尝试一次
                  Sleep(3000);                                       //延迟3秒
                  RefreshRates();
                  break;                                             //退出 switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //把尝试次数重设为0
                  exit_loop = true;                                  //退出 while
                  break;                                             //退出 switch
                 }
            case 130:
               exit_loop=true;                                       //退出 while
               break;
            case 131:
               exit_loop = true;                                     //退出 while
               break;                                                //退出 switch
            case 132:
               Sleep(10000);                                         //延迟10秒
               RefreshRates();                                       //更新数据
               //exit_loop = true;                                   //退出 while
               break;                                                //退出 switch
            case 133:
               exit_loop=true;                                       //退出 while
               break;                                                //退出 switch
            case 134:
               exit_loop=true;                                       //退出 while
               break;                                                //退出 switch
            case 135:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //再多尝试一次
                  RefreshRates();
                  break;                                             //退出 switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //把尝试次数设为0 
                  exit_loop = true;                                  //退出 while
                  break;                                             //退出 switch
                 }
            case 136:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;                                 //再多尝试一次
                  RefreshRates();
                  break;                                             //退出 switch
                 }
               if(attempt==attemptMax)
                 {
                  attempt = 0;                                       //把尝试次数设为0 
                  exit_loop = true;                                  //退出 while
                  break;                                             //退出 switch
                 }
            case 137:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  Sleep(2000);
                  RefreshRates();
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 138:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  Sleep(1000);
                  RefreshRates();
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 139:
               exit_loop=true;
               break;
            case 141:
               Sleep(5000);
               exit_loop=true;
               break;
            case 145:
               exit_loop=true;
               break;
            case 146:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  Sleep(2000);
                  RefreshRates();
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 147:
               if(attempt<attemptMax)
                 {
                  attempt=attempt+1;
                  OO_expiration=0;
                  break;
                 }
               if(attempt==attemptMax)
                 {
                  attempt=0;
                  exit_loop=true;
                  break;
                 }
            case 148:
               exit_loop=true;
               break;
            default:
               Print("错误: ",Error);
               exit_loop=true; //退出 while 
               break;          //其他选项 
           }
        }
      //--- 如果没有发现出错
      else
        {
         if(lang == "Russian") {Print("Ордер успешно открыт. ", result);}
         if(lang == "English") {Print("The order is successfully opened.", result);}
         Error = 0;                                //把错误码重设为0
         break;                                    //退出 while
         //errorCount =0;                          //把尝试次数设为0
        }
     }
   return(result);
  }
//+------------------------------------------------------------------+

结果我们可以获得如下代码:

//+------------------------------------------------------------------+
//|                                              BEOVB_BUOVB_bar.mq4 |
//|                                  Copyright 2015, Iglakov Dmitry. |
//|                                               cjdmitri@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Iglakov Dmitry."
#property link      "cjdmitri@gmail.com"
#property version   "1.00"
#property strict

extern int     interval          = 25;                               //距离
extern double  lot               = 0.1;                              //手数
extern int     TP                = 400;                              //获利
extern int     magic             = 962231;                           //幻数
extern int     slippage          = 2;                                //点差
extern int     ExpDate           = 48;                               //订单过期小时数
extern int     bar1size          = 900;                              //第一个柱形大小

double buyPrice,//define BuyStop price
buyTP,      //止损买入单的获利价位
buySL,      //止损买入单的止损价位
sellPrice,  //定义止损卖出价位
sellTP,     //止损卖出单的获利价位
sellSL;     //止损卖出单的止损价位

double open1,//第一个柱的开盘价
open2,    //第二个柱的开盘价
close1,   //第一个柱的收盘价
close2,   //第二个柱的收盘价
low1,     //第一个柱的最低价
low2,     //第二个柱的最低价
high1,    //第一个柱的最高价
high2;    //第二个柱的最高价

datetime _ExpDate =0; // 用于定义挂单过期时间的局部变量
double _bar1size;// 用于避免在平缓市场交易的局部变量
datetime timeBUOVB_BEOVB;// 模式订单下单柱的时间, 用于避免重复开单
//+------------------------------------------------------------------+
//| EA 初始化函数                                                     |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| EA 终止化函数                                                     |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+
//| EA 订单处理函数                                                    |
//+------------------------------------------------------------------+
void OnTick()
  {
   double   _bid = NormalizeDouble(MarketInfo (Symbol(), MODE_BID), Digits); // 定义最低价
   double   _ask     = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //定义最高价
   double   _point   = MarketInfo(Symbol(), MODE_POINT);
//--- 定义所需柱形的价格
   open1        = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits);
   open2        = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits);
   close1       = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits);
   close2       = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits);
   low1         = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits);
   low2         = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits);
   high1        = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits);
   high2        = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits);
   
//--- 定义下单的价格和止损价格
   buyPrice =NormalizeDouble(high1 + interval * _point,Digits); //根据距离定义下单的价格
   buySL =NormalizeDouble(low1-interval * _point,Digits); //根据距离定义止损价格
   buyTP =NormalizeDouble(buyPrice + TP * _point,Digits); //定义获利
   _ExpDate =TimeCurrent() + ExpDate*60*60; //计算挂单过期时间
//--- 我们同样计算卖出订单 
   sellPrice=NormalizeDouble(low1-interval*_point,Digits);
   sellSL=NormalizeDouble(high1+interval*_point,Digits);
   sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);
//---
   _bar1size=NormalizeDouble(((high1-low1)/_point),0);
//--- 寻找熊势模式 BEOVB
   if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //此模式尚未下单 
      _bar1size > bar1size && //第一个柱足够大, 故市场并不平缓
      low1 < low2 &&//第一个柱的最低价低于第二柱的最低价
      high1 > high2 &&//第一个柱的最高价高于第二柱的最高价
      close1 < open2 && //第一个柱的收盘价低于第二个柱的开盘价
      open1 > close1 && //第一个柱是熊势柱
      open2 < close2)   //第二个柱是牛势柱
     {
      //--- 我们已经定义了全部条件, 即第一柱完全吞噬了第二柱并且是熊势柱
      OrderOpenF(Symbol(),OP_SELLSTOP,lot,sellPrice,slippage,sellSL,sellTP,NULL,magic,_ExpDate,Blue);
      timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); //指出此模式上已经下单
     }
//--- 寻找牛势模式 BUOVB
   if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //此模式尚未下单 
      _bar1size > bar1size && //第一个柱足够大, 故市场并不平缓
      low1 < low2 &&//第一个柱的最低价低于第二柱的最低价
      high1 > high2 &&//第一个柱的最高价高于第二柱的最高价
      close1 > open2 && //第一个柱的收盘价高于第二柱的开盘价
      open1 < close1 && //第一个柱是牛势柱
      open2 > close2)   //第二个柱是熊势柱
     {
      //--- 我们已经定义了全部条件, 即第一柱完全吞噬了第二柱并且是牛势柱 
      OrderOpenF(Symbol(),OP_BUYSTOP,lot,buyPrice,slippage,buySL,buyTP,NULL,magic,_ExpDate,Blue);
      timeBUOVB_BEOVB = iTime(Symbol(),Period(),1); //指出此模式下已经下单
     }
  }
//+------------------------------------------------------------------+

现在让我们进行编译并在记录中检查错误信息.


测试EA交易

现在是时候测试我们的EA交易了. 让我们运行策略测试器并设置输入参数.

图 5. 用于测试的输入参数

图 5. 用于测试的输入参数

  1. 选择用于测试的货币对. 我选择了EURAUD.
  2. 请确保设置为"每一订单"模式并定义测试将在历史数据上进行. 我已经选择了2014年整年的数据.
  3. 设置的时间框架是D1.
  4. 运行测试.
  5. 测试结束后检查记录. 我们可以看到, 过程中没有错误.

图 6. 设置测试条件

图 6. 设置测试条件

以下是EA交易测试的日志:

图 7. EA 交易测试日志

图 7. EA 交易测试日志

确认没有出错后优化EA交易.


优化

我选择了如下的参数进行优化:

图 8. 优化参数

图 8. 优化参数


图 9. 优化设置

图 9. 优化设置

就这样, 作为优化和测试的结果, 我们现在已经有了可用的EA交易.


优化和测试结果

在最常用的货币对上做过优化之后, 我们获得了如下的结果:

货币对 净利润 利润指数 回撤 (%) 毛利  毛损 
EURAUD 523.90$ 3.70 2.13  727,98$ 196.86$
USDCHF 454.19$ - 2.25  454.19$ 0.00$
GBPUSD 638.71$ - 1.50  638.71$ 0.00$
EURUSD 638.86$ - 1.85  638.86$ 0.00$
USDJPY 423.85$ 5.15 2.36  525.51$ 102.08$
USDCAD 198.82$ 2.41 2.74  379.08$ 180.26$
AUDUSD 136.14$ 1.67 2.39  339.26$ 203.12$

 表 1. 优化结果

在货币对EURAUD上得到的详细测试结果:

图 10. 测试结果

图 10. 测试结果


图 11. 测试结果图表

图 11. 测试结果图表


结论

  1. 在本文中, 我们使用吞噬交易模式创建了一个EA交易.
  2. 我们已经确认, 即使没有使用更多的入场过滤器, 价格行为模式也是可行的.
  3. 没有使用特殊的技巧(例如马丁格尔或者平均).
  4. 通过止损单的正确设置, 回撤已经被减到最小.
  5. 没有使用技术指标. 本 EA 交易只是基于对"空白"图表的读取.

感谢您的阅读, 我希望本文会有所帮助.

全部回复

0/140

量化课程

    移动端课程