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

Dmitry Iglakov | 24 十二月, 2015

简介

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


关于价格行为

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

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


内含柱

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

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

图 1. 内含柱

图 1. 内含柱


图 2. 内含柱模式布局

图 2. 内含柱模式布局

内含柱规则:

图 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)      //第二柱的最低价低于第一柱的收盘价
     {
      //--- 我们已经列出了第一柱内含于第二柱的所有条件
     }
  }

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

//+------------------------------------------------------------------+
//|                                                    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. 没有使用技术指标. 此交易机器人仅仅依赖于读取基本图表.

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