下载MetaTrader 5

价格行为. 自动化内含柱交易策略

24 十二月 2015, 12:14
Dmitry Iglakov
0
2 872

简介

所有的外汇交易者或多或少都接触过价格行为. 它不仅仅是一项图表分析技术, 而是包含了定义未来价格可能走向的整个系统. 在本文中, 我们将详细研究内含柱模式, 并且会基于该模式开发一个EA交易以跟踪内含柱信息及进行交易.


关于价格行为

价格行为是一种非指标的价格移动侦测方法, 它可以使用简单或者复杂的模式, 也可以使用辅助的图表元件(例如水平线, 垂直线, 趋势线, 斐波那契水平, 支撑/阻力水平等等).

乍一看来, 此方法貌似复杂, 但事实上并非如此. 这种方法现已日益流行, 因为和使用技术指标的方法相比较, 它的优势显而易见.


内含柱

内含柱也就是某个柱的柱体以及引线都包含在其前一个柱(母柱)的范围之内. 内含柱的最高价比其母柱的最高价要低, 而最低价比其母柱最低价要高. 母柱和内柱构成了潜在的进入市场的模式.

这是一个两面性的模式, 因为它可能指出趋势的反转或者持续.

图 1. 内含柱

图 1. 内含柱


图 2. 内含柱模式布局

图 2. 内含柱模式布局

内含柱规则:

  • 内含柱模式在更高时间框架内更有意义, 例如 H4 或 D1.
  • 此模式可能暗示趋势的反转, 也可能暗示趋势的持续.
  • 使用额外的图形分析工具, 包括趋势线, 支撑/阻力水平, 斐波那契水平以及其他的价格行为模式等等, 可以获得更加清晰的进场信号.
  • 使用挂单来避免过早或者错误地进入市场.
  • 不要在平缓的市场中重复使用内含柱作为进场信号.

图 3. 在 GBPUSD D1 图表上定义真正的内含柱

图 3. 在 GBPUSD D1 图表上定义真正的内含柱

把这些都记住后, 让我们尝试定义一个真正的内含柱. 在上图中, 我们可以看到在价格陡然下降之后出现一个牛势柱形. 但是, 这个柱整个位于前一个柱范围之内. 另外, 此柱也位于支撑水平之上, 进一步确认了该模式. 第三点确认是这并非平缓的市场环境. 因为此模式满足了这些规则, 它可以被确认为真实.


定义入场点并设置止损单

就这样, 我们已经在图表上发现了一个真正的内含柱 (图 3). 我们应该怎样进入市场?还有我们在哪里设置订单的止损位呢?让我们看图4.

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

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

首先, 我们应该使用上面的例子来考虑止损水平的设置:

  1. 设置一个比母柱最高价略高的止损买入挂单(只需要高几个点, 用于确认).
  2. 设置一个比支撑位, 也就是母柱的最低价略低的一个止损水平. 这是一个额外的保护, 以防挂单被触发以后, 价格又回到支撑水平而反弹后再向正确方向移动.
  3. 再在略低于阻力位的地方设置获利水平.
别忘了, 内含柱可能跟随着趋势的反转或者持续, 所以我们还要设置一个止损卖出订单.

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

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

首先, 我们应该使用上面的例子来考虑止损水平的设置:

  1. 设置一个比母柱最低价略低的止损卖出订单(只要低几个点, 以作确认).
  2. 在母柱最高价上方设置止损水平.
  3. 在最近的支撑水平略高处设置获利水平.


基于内含柱交易开发一个EA交易

现在我们已经了解了定义内含柱的所有规则, 进入市场及设置止损单, 我们最终可以使用内含柱模式来实现对应的EA交易了.

从MetaTrader 4终端开启 MetaEditor 并创建一个新的 EA 交易 (相信我不必在此方面涉及过多, 网站上已经有了很多如何创建EA交易的信息了). 在这个阶段把所有的参数设置成空. 您可以按照您的喜好对它们进行命名. 结果代码看起来如下:

//+------------------------------------------------------------------+
//|                                                    InsideBar.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之后, 我们需要在柱关闭后定义一个内含柱. 为此, 我们会引入新的变量并为它们赋值. 参照以下代码:

//+------------------------------------------------------------------+
//|                                                    InsideBar.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);
  }
//+------------------------------------------------------------------+

作为例子, 让我们考虑母柱是熊势柱 (柱 2), 而内含柱为牛势柱 (柱 1)的状况. 让我们在 OnTick()函数体中增加一系列条件:

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);
//--- 如果第二个柱为熊势而第一个柱为牛势
   if(open2>close2 && //第二个柱为牛势
      close1>open1 && //第一个柱是熊势
      high2>high1 &&  //第二柱的最高价高于第一个柱的最高价
      open2>close1 && //第二柱的开盘价高于第一柱的收盘价
      low2<low1)      //第二柱的最低价低于第一柱的收盘价
     {
      //--- 我们已经列出了第一柱内含于第二柱的所有条件
     }
  }
  • 创建可定制的变量: 止损单, 点差, 订单过期时间, EA 幻数, 交易手数. 止损值可以不用, 因为它决定于内含柱的原则.
  • 为这些变量增加代码中的局部变量.
  • 止损订单由距离柱价位的某个距离设置. 为了实现这一点, 增加Interval变量, 作为止损订单和最高/最低价的距离以及挂单的水平.
  • 增加timeBarInside变量以避免在此模式上重复开启订单.
  • 增加bar2size变量以确认母柱足够大, 是当前市场并不平缓的很好的标记.

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

//+------------------------------------------------------------------+
//|                                                    InsideBar.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          = 20;                               //距离
extern double  lot               = 0.1;                              //手数
extern int     TP                = 300;                              //获利
extern int     magic             = 555124;                           //幻数
extern int     slippage          = 2;                                //点差
extern int     ExpDate           = 48;                               //订单过期小时数
extern int     bar2size          = 800;                              //柱 2 的大小

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

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

datetime _ExpDate=0;          //定义订单过期时间的局部变量
double     _bar2size;
datetime timeBarInside;         //内含柱开启的时间, 用于防止重复开单
//+------------------------------------------------------------------+
//| 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);
//---
   _bar2size=NormalizeDouble(((high2-low2)/_point),0);
//--- 如果第二个柱为熊势而第一个柱为牛势
   if(timeBarInside!=iTime(Symbol(),Period(),1) && //此模式尚未开启订单
      _bar2size>bar2size && //第二个柱足够大, 说明市场并不平缓
      open2>close2 && //第二个柱为牛势
      close1>open1 && //第一个柱是熊势
      high2>high1 &&  //第二柱的最高价高于第一个柱的最高价
      open2>close1 && //第二个柱的开盘价高于第一个柱的收盘价
      low2<low1)      //第二个柱的最低价低于第一个柱的最低价
     {
      //--- 我们已经列出了第一柱内含于第二柱的所有条件
      timeBarInside=iTime(Symbol(),Period(),1); //表明已经为此模式开启订单
     }
  }
//+------------------------------------------------------------------+


定义止损订单水平

现在所有的准备工作都已完成, 我们只需要定义止损订单水平和订单价格了. 并且, 别忘了订单过期时间的计算.

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

buyPrice=NormalizeDouble(high2+interval*_point,Digits);       //根据距离定义订单价格
      buySL=NormalizeDouble(low2-interval*_point,Digits);     //根据距离定义止损
      buyTP=NormalizeDouble(buyPrice+TP*_point,Digits);       //定义获利价位
      _ExpDate=TimeCurrent()+ExpDate*60*60;                   //计算挂单过期时间
      sellPrice=NormalizeDouble(low2-interval*_point,Digits);
      sellSL=NormalizeDouble(high2+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);
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//|                                                    InsideBar.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          = 20;                               //距离
extern double  lot               = 0.1;                              //手数
extern int     TP                = 300;                              //获利
extern int     magic             = 555124;                           //幻数
extern int     slippage          = 2;                                //点差
extern int     ExpDate           = 48;                               //订单过期小时数
extern int     bar2size          = 800;                              //柱 2 的大小

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

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

datetime _ExpDate=0;          //定义订单过期时间的局部变量
double     _bar2size;
datetime timeBarInside;       //内含柱订单开启的柱的时间, 防止重复下单
//+------------------------------------------------------------------+
//| 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);
//---
   _bar2size=NormalizeDouble(((high2-low2)/_point),0);
//--- 如果第二个柱为熊势而第一个柱为牛势
   if(timeBarInside!=iTime(Symbol(),Period(),1) && //此模式尚未开启订单
      _bar2size>bar2size && //第二个柱足够大, 说明市场并不平缓
      open2>close2 && //第二个柱为牛势
      close1>open1 && //第一个柱是熊势
      high2>high1 &&  //第二柱的最高价高于第一个柱的最高价
      open2>close1 && //第二个柱的开盘价高于第一个柱的收盘价
      low2<low1)      //第二个柱的最低价低于第一个柱的最低价
     {
      buyPrice=NormalizeDouble(high2+interval*_point,Digits); //根据间隔定义的订单价格
      buySL=NormalizeDouble(low2-interval*_point,Digits);     //根据间隔定义的止损价格
      buyTP=NormalizeDouble(buyPrice+TP*_point,Digits);       //定义获利价位
      _ExpDate=TimeCurrent()+ExpDate*60*60;                   //挂单过期时间的计算
      sellPrice=NormalizeDouble(low2-interval*_point,Digits);
      sellSL=NormalizeDouble(high2+interval*_point,Digits);
      sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);
      OrderOpenF(Symbol(),OP_BUYSTOP,lot,buyPrice,slippage,buySL,buyTP,NULL,magic,_ExpDate,Blue);
      OrderOpenF(Symbol(),OP_SELLSTOP,lot,sellPrice,slippage,sellSL,sellTP,NULL,magic,_ExpDate,Blue);
      //--- we have listed all the conditions defining that the first bar is completely within the second one
      timeBarInside=iTime(Symbol(),Period(),1); //指出此模式已经下单
     }
  }
//+------------------------------------------------------------------+

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


测试EA交易

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

图 6. 测试的输入参数

图 6. 测试的输入参数

  1. 选择一个交易品种 (在我的例子中是 CADJPY ).
  2. 请确认使用"每一订单(Every tick)"模式, 并且定义测试将在历史数据上进行. 我已经选择了2014年整年的数据.
  3. 设置的时间框架是D1.
  4. 运行测试.
  5. 测试结束后检查记录. 我们可以看到, 过程中没有错误.

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

图 7. EA 交易测试日志

图 7. EA 交易测试日志

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


优化

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

图 8. 优化参数

图 8. 优化参数


图 9. 优化设置

图 9. 优化设置

就这样, 我们就拥有了可以使用的EA交易.


优化和测试结果

图 10. 测试结果

图 10. 测试结果


图 11. 测试结果图

图 11. 测试结果图


结论

  1. 我们已经开发了可用的基于内含柱交易的 EA 交易.
  2. 我们已经确认, 即使不使用额外的进场过滤器价格行为模式也是可行的.
  3. 没有使用特殊的技巧(例如马丁格尔或者平均).
  4. 通过止损单的正确设置, 回撤已经被减到最小.
  5. 没有使用技术指标. 此交易机器人仅仅依赖于读取基本图表.

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

本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/1771

附加的文件 |
insidebar.mq4 (38.7 KB)
怎样开发可以获利的交易策略 怎样开发可以获利的交易策略

本文为这样的问题提供解答: "是否可以通过神经网络技术,基于历史数据来构建自动交易策略?".

根据支撑位、阻力位和和价格行为确定交易策略 根据支撑位、阻力位和和价格行为确定交易策略

本文阐述了如何参考价格行为以及监控支撑位和阻力位来选择合适的入场时机。详细描述了一个交易系统如何有效结合两种交易策略。相应的MQL4代码可用于实现基于这些交易理念的EA策略。

拉布谢尔资金管理系统的统计学验证 拉布谢尔资金管理系统的统计学验证

在本文中, 我们将测试拉布谢尔(Labouchere)资金管理系统的统计学属性. 它可以看作是一种不那么激进的马丁格尔(Martingale), 因为它不是加倍下注, 而是提高一定的量下注.

通过动态链接库(DLL)管理 MetaTrader 终端 通过动态链接库(DLL)管理 MetaTrader 终端

这篇文章讲述了通过动态链接库(DLL)来管理MetaTrader的用户界面元件, 它使用的实例是对推送通知的传输设置做出修改. 库的代码以及例子脚本在文章的附件中.