English Русский Español Deutsch 日本語 Português
对冲 Expert Advisor 编码基础

对冲 Expert Advisor 编码基础

MetaTrader 4示例 | 26 二月 2016, 16:13
3 042 0
chayutra sriboonruang
chayutra sriboonruang

简介

我将介绍一个简单的对冲 expert advisor。对冲 EA 基础大注:

  • 对冲(金融)(来自自由的百科全书 - 维基百科)

    (重定向自对冲

    金融学上,对冲指特意用于降低另一项投资的风险的投资。对冲是一种在减低商业风险的同时仍然能在投资活动中获利的策略。通常,对冲者可能会投资他认为价格相对于其“公允价值”被低估的证券(例如之后他会做抵押借款),然后将其与相关证券的卖空相结合。因此对冲者不关心整个市场价值的上扬或下跌,只关注被低估证券相对于对冲的估值。对冲理论的先行者 Holbrook Working 称此策略为“对基础的投机” "[1],其中的基础指的是对冲的理论价值与其实际价值之间的差异(或 Working 所说的现货与期货价格之间的差额)。

    要承担的某些形式的风险是任何商业活动的固有风险。一些风险被视为特定业务的“自然”风险,例如油价涨跌的风险对于石油开采和炼油企业来说就是自然风险。其他形式的风险虽然不受欢迎,但不进行对冲的话也无法避免。比如某人有间店,那么就要注意竞争风险、劣质或非流行产品风险等自然风险。店主库存因火灾损毁的风险无可避免,但可通过火险契约进行对冲。并非所有对冲都是金融工具:例如,做产品出口的生产商在销售时,可以通过将费用关联到所需货币来对冲其货币风险。
    单击此处了解更多

  • 我们要从服务器中获得的所有东西都必须通过 MarketInfo(字符串符号,int 类型)函数调用。此函数允许我们调用任何数据,包括但不限于活动图表窗口中显示的数据。它还允许我们任何符号的任何种类的订单,包括但不限于活动图表窗口中主动显示的符号。这让我们可以轻松对冲两个符号。感谢上苍和 MT4 团队成员,这个函数能帮的忙太大了。

  • 对冲所需的一个必要条件是两个监控符号之间的关联,可用下文中要介绍的一些小函数找到这个关联。

    在金融界中,关联是对两个证券之间关系的统计度量。关联系数范围为 -1 到 +1。关联系数 +1 意味着两个货币对将始终朝同一个方向运动。关联系数 -1 意味着两个货币对将始终朝反方向运动。关联系数 0 意味着货币对之间的关系完全是随机的。单击此处了解更多


上述都是 Forex 对冲者使用 MT4 Expert Advisor 时需要了解的一些简单内容。现在我们开始制作一个对冲 EA。



逐步进行对冲 EA 的编码工作

步骤 1:输入参数

在开始写入对冲 EA 之前,我们需要选择两个关联符号,即:

  • 始终朝同一方向移动的 GBPUSD 与 EURUSD;
  • 始终朝反方向移动的 EURUSD 与 USDCHF;
  • 等。

本文中,我将选择我自己很喜欢的对冲对,即 EURJPY 与 GBPJPY。此对冲对的运作方式始终相同,能较为方便地设置对冲订单类型。现在让我们开始吧。要开始制作一个对冲 EA,先要了解以下输入变量。

// this is to block the order sending function but 
// not to block the close function.
extern bool BlockOpening = false; 
 
extern string BaseSymbol = "EURJPY";//the 1st symbol 
 
extern string H_Symbol = "GBPJPY";//the 2nd symbol 
 
extern bool MoveSameWay = true;//they move the same way or not 
 
extern int CorPeriod = 5;//your favorite correlation period 
 
extern double BaseLotSize = 1.5;//1st symbol lotsize 
 
extern double H_LotsSize = 1.0;//2nd symbol lotsize 
 
extern double ExpectProfit$ = 137;//your expect profit in USD 
//your acceptable loss in USD in case any error occurred 
extern double AcceptableLoss$ = -77; 
 
extern string ExpectCor = "______";//your expect correlation to hedge 
//this is the upper expect cor value and has to be greater than "And" 
extern double Between = 1.05; 
 
extern double And = 0.9;//this is the lower expect cor level 
 
extern string MISC = "______";//some thing more 
 
extern int MagicNo = 318;//your favorite magic number 
 
extern bool ShowStatus = true;//to show the present hedging status 
//to play sound when SendH and CloseH function done 
extern bool PlayAudio = false;

步骤 2:变量声明

以下是此 EA 中使用的变量,我只解释必要的变量以便您了解 EA 的工作方式。

int BSP       // the spread of base symbol 
 
    , HSP      // the spread of hedge symbol 
 
    , gsp 
 
    , BOP = -1 // base symbol order type 
 
    , HOP = -1 // hedge symbol order type 
 
    , up = 0 
 
    , Hcnt = 0 
 
    , u = 0 
 
    , d = 0 
 
    , day = 0 
 
    , sent=0 
 
    , firstopen 
 
    , expire; 
 
double Lot 
 
       , BaseOpen // base symbol order open price 
 
       , HOpen    // hedge symbol order open price 
 
       , BPt      // base symbol Point value 
 
       , HPt      // hedge symbol Point value 
 
       , BSwapL   // base symbol swap long value 
 
       , BSwapS   // base symbol swap short value 
 
       , HSwapL   // hedge symbol swap long value 
 
       , HSwapS;  // hedge symbol swap short value 
 
 
bool SResult = false, BResult = false, H1.profitswap, 
     H2.profitswap, H3.profitswap; 
 
bool SwapMode = true, allmeetcor = false, BlockOpen = false, 
     buy,sell,cleared = false; 
 
string H1.string = "", H2.string = "", H3.string = "", 
       OrdComment = "", candletxt,tdstxt = "";

步骤 3:获取所有必要的静态参数

现在我们制定一些要在 init() 部分中声明的静态值。

//+------------------------------------------------------------------+ 
//| expert initialization function                                   | 
//+------------------------------------------------------------------+ 
 
int init() 
  { 
    //---- 
    BSP = MarketInfo(BaseSymbol,MODE_SPREAD); 
    HSP = MarketInfo(H_Symbol ,MODE_SPREAD); 
    BPt = MarketInfo(BaseSymbol,MODE_POINT); 
    HPt = MarketInfo(H_Symbol ,MODE_POINT); 
    BSwapL = MarketInfo(BaseSymbol,MODE_SWAPLONG); 
    BSwapS = MarketInfo(BaseSymbol,MODE_SWAPSHORT);
    HSwapL = MarketInfo(H_Symbol,MODE_SWAPLONG); 
    HSwapS = MarketInfo(H_Symbol,MODE_SWAPSHORT); 
//---- 
    return(0); 
  }


步骤 4:有用的函数

在讨论 "start()" 函数这个我们一直等待着的最有趣的部分之前,让我们先从此 EA 中使用的函数说起。但请注意,所有函数都将与 start() 函数区分开来。


1.关联函数

首先我们需要从关联计算函数着手。以下函数来自一位提供免费关联指标的好心人 (igorad2004@list.ru),我对这些函数进行了修改,以便在此 EA 中使用,这样我们就不再需要从外部指标中调用关联值了。好主意,不是吗?

//+------------------------------------------------------------------+ 
//|  CORRELATION                                                     |
//+------------------------------------------------------------------+ 
double symboldif(string symbol, int shift) 
  { 
    return(iClose(symbol, 1440, shift) - 
           iMA(symbol, 1440, CorPeriod, 0, MODE_SMA, 
               PRICE_CLOSE, shift)); 
  } 
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double powdif(double val) 
  { 
    return(MathPow(val, 2)); 
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+ 
double u(double val1,double val2) 
  { 
    return((val1*val2)); 
  }
//+------------------------------------------------------------------+
//|  The real correlation function to call is here.                  |
//+------------------------------------------------------------------+
double Cor(string base, string hedge) 
  { 
    double u1=0,l1=0,s1=0; 
    for(int i = CorPeriod - 1; i >= 0; i--) 
      { 
        u1 += u(symboldif(base, i), symboldif(hedge, i)); 
        l1 += powdif(symboldif(base, i)); 
        s1 += powdif(symboldif(hedge, i)); 
      } 
    if(l1*s1 > 0) 
        return(u1 / MathSqrt(l1*s1)); 
  } 
//+------------------------------------------------------------------+

CorPeriod变量将作为外部的输入变量,允许我们对其进行调整。如要计算两个符号之间的关联,只需调用Cor(string base,string hedge) 函数,例如这个 Cor(EURJPY,GBPJPY)。很简单,不是吗?


2.发送对冲函数

我认为通过创建一个 SendH 函数可以更方便地管理对冲订单的发送方式,如下所示。

//+------------------------------------------------------------------+
//| SEND HEDGE                                                       |
//+------------------------------------------------------------------+
bool SendH(string symbol, int op, double lots,
           double price, int sp, string comment, int magic) 
  { 
    if(OrderSend(symbol 
                 , op 
                 , lots 
                 , price 
                 , sp 
                 , 0 
                 , 0 
                 , comment 
                 , magic 
                 , 0 
                 , CLR_NONE) 
                 > 0) 
      {
        return(true); 
        if(PlayAudio)
            PlaySound("expert.wav"); 
      } 
    else 
      {
        Print(symbol, ": ", magic, " : " 
              , ErrorDescription(GetLastError())); 
        return(false); 
      } 
  } 
//+------------------------------------------------------------------+

可单击此处阅读有关 OrderSend 函数的更多信息。

ErrorDescription(GetLastError())上述 ErrorDescription(GetLastError()) 函数让我们的 EA 能够告诉我们交易函数工作时出现了什么错误。要使用该函数,需要将“stdlib.mqh"文件包括在内,代码如下:

//+------------------------------------------------------------------+ 
//|                                                     MyHedge.mq4  | 
//|                                                         myHedge  | 
//|                                     http://dailyh.blogspot.com/  | 
//+------------------------------------------------------------------+ 
#property copyright "myHedge" 
#property link "http://dailyh.blogspot.com/" 
#include <stdlib.mqh>
//+------------------------------------------------------------------+

使用时只需调用按上述方法调用“ErrorDescription() "函数。


3.关闭对冲函数

除了发送订单,我们还需要一个用于在对冲订单达到预期利润时关闭这些订单的函数。如下所示:

//+------------------------------------------------------------------+
//|  CLOSE HEDGE                                                     |
//+------------------------------------------------------------------+
bool CloseHedge(int magic) 
  { 
   for(int i = OrdersTotal() - 1; i >= 0; i--) 
     { 
       if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && 
                      OrderMagicNumber() == magic) 
         { 
           if(OrderClose(OrderTicket() 
              , OrderLots() 
              , OrderClosePrice() 
              , MarketInfo(OrderSymbol(), MODE_SPREAD) 
              , CLR_NONE))
                SResult = true; 
         } 
     } 
   if(SResult)
     {
       return(true);
       if(PlayAudio)
         {
           PlaySound("ok.wav");
         }
     } 
   else 
       Print("CloseHedge Error: ", ErrorDescription(GetLastError())); 
   RefreshRates(); 
   // return(0); 
  } 
//+------------------------------------------------------------------+

此函数仅关闭使用同一幻数的订单,不会干涉使用其他不同幻数的对冲订单。这是小事,无需担心。在使用该关闭函数之前,我们需要用以下函数定义“目前盈利”。


4.查找利润总额函数
//+------------------------------------------------------------------+
//|  TOTAL PROFIT                                                    |
//+------------------------------------------------------------------+ 
double TotalCurProfit(int magic) 
  { 
   double MyCurrentProfit = 0; 
   for(int cnt = 0 ; cnt < OrdersTotal() ; cnt++) 
     { 
       OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); 
       if(OrderMagicNumber() == magic) 
         { 
           MyCurrentProfit += (OrderProfit() + OrderSwap()); 
         } 
     } 
   return(MyCurrentProfit); 
  } 
//+------------------------------------------------------------------+

像使用关闭函数一样,要了解对冲利润金额,我们仅需监控使用同一幻数的订单,以便正确地关闭它们。要使用这些函数,仅需按以下方式进行编码:

if(TotalCurProfit(318) > 100) 
    CloseHedge(318);

所有利润金额值都将以美元为单位计算。在上行中,当幻数为 318 的订单的总体利润超过 $100 时,这些订单就将被关闭。就是这样。要打开对冲订单,我们需要确定在需要发送对冲时没有任何其他使用同一符号和幻数的浮动订单。这可通过此函数进行定义。



5.获取现有价位的金额

//+------------------------------------------------------------------+
//| EXISTING POSITIONS                                               |
//+------------------------------------------------------------------+
int ExistPositions(string symbol, int magic) 
  { 
    int NumPos = 0; 
    for(int i = 0; i < OrdersTotal(); i++) 
      { 
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) 
                       && OrderSymbol() == symbol 
                       && OrderMagicNumber() == magic) 
          {  
            NumPos++; 
          } 
      }
    return(NumPos); 
 
  } 
//+------------------------------------------------------------------+ 

此函数使用方式如下:

ExistPositions("GBPJPY",318)

此时此函数将返回“幻数为 318 的 GBPJPY 浮动开放订单数量”。这又是一个定义浮动订单类型的函数。


6.查找特定现有价位的订单类型
//+------------------------------------------------------------------+  
//| EXISTING OP POSITION                                             |
//+------------------------------------------------------------------+
int ExistOP(string symbol, int magic) 
  { 
    int NumPos = -1; 
    for(int i = 0; i < OrdersTotal(); i++) 
      { 
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) 
                       && OrderSymbol() == symbol 
                       && OrderMagicNumber() == magic) 
          {  
            NumPos = OrderType();
          } 
      } 
    return(NumPos); 
  } 
//+------------------------------------------------------------------+

此函数返回当时浮动的指定符号和幻数的订单类型的整数值。如果 GBPJPY 的浮动订单为 OP_BUY,返回值为“0”。此函数不仅可与交易函数配合使用,还可与一个函数一同用于显示当前对冲状态。这个函数名为“OP2Str”。



7.显示交易状态

//+------------------------------------------------------------------+
//| Transform OP Value To string                                     |
//+------------------------------------------------------------------+ 
string OP2Str(int op) 
  { 
    switch(op) 
      { 
        case OP_BUY : return("BUY"); 
        case OP_SELL: return("SELL"); 
        default : return("~~"); 
      } 
  }
//+------------------------------------------------------------------+

此函数的使用方式已一目了然,不必多说了。


8.关闭所有特定订单类型

这又是一个可在发送或关闭对冲期间出现错误的情况下,直接关闭任何单个订单的函数。

//+------------------------------------------------------------------+
//| CLOSE SCRAP                                                      |
//+------------------------------------------------------------------+ 
bool CloseScrap(string sym, int op, int magic) 
  { 
    for(int i = OrdersTotal() - 1; i >= 0; i--) 
      { 
        if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) 
           && amp; OrderMagicNumber() == magic 
           && OrderSymbol() == sym 
           && OrderType() == op) 
          { 
            if(OrderClose(OrderTicket() 
               , OrderLots() 
               , OrderClosePrice() 
               , MarketInfo(OrderSymbol(), MODE_SPREAD) 
               , CLR_NONE))
                BResult = true; 
          } 
      } 
    if(BResult)
      {
        return(true);
        if(PlayAudio)
          {
            PlaySound("ok.wav");
          }
      } 
    else 
        Print("CloseScrap Error: ", ErrorDescription(GetLastError())); 
    RefreshRates(); 
    // return(0); 
  }

也就是说,CloseScrap("GBPJPY",OP_BUY,318)这将仅关闭幻数为 318 的浮动长“GBPJPY”。很简单。最后一个要了解的函数。


9.根据需要显示任何布尔状态
//+------------------------------------------------------------------+
//| Translate bool to string                                         |
//+------------------------------------------------------------------+
string bool2str( bool boolval) 
  { 
    if(boolval == true) 
        return("Yes"); 
    if(boolval == false)
        return("No"); 
  }
//+------------------------------------------------------------------+

这个函数没有什么特别之处,它的用途是显示一些参数的布尔状态,例如 BlockOpening 值。将此函数设置为 true 时,它将在您的屏幕上返回“是”。如果设置为 false,则范围“否”。以上就是我们所需函数的所有相关信息。现在我们要开始进行对冲流程的编码工作了。


步骤 5:Expert Advisor 代码为:

首先进行以下编码:

//+------------------------------------------------------------------+ 
//| expert start function                                            | 
//+------------------------------------------------------------------+ 
int start() 
  {

然后指定关联范围:

if(Cor(BaseSymbol, H_Symbol) > Between || 
   Cor(BaseSymbol, H_Symbol) < And) 
// Block opening when the correlation is out of 
// expected range. 
    BlockOpen = true; 
else 
    BlockOpen = false;
下一步,定义对冲方式(此处仅为示例),本文中我将按互换价值选择交易风格,然后仅用每天都可从互换中获利的方式进行交易。
// if they move the same way we will open long & short 
if(MoveSameWay) 
  { 
    if(((BSwapL*BaseLotSize) + (HSwapS*H_LotSize)) > 0) 
      {  
        BOP = OP_BUY; 
        HOP = OP_SELL; 
      } 
    else 
        if(((BSwapS*BaseLotSize) + (HSwapL*H_LotSize)) > 0) 
          { 
            BOP = OP_SELL; 
            HOP = OP_BUY; 
          } 
  } // end MoveSameWay
// if the move the opposite way we will open short & short or long & long
else 
  { 
    if(((BSwapL*BaseLotSize) + (HSwapL*H_LotSize)) > 0) 
      { 
        BOP = OP_BUY; 
        HOP = OP_BUY; 
      } 
    else 
        if(((BSwapS*BaseLotSize) + (HSwapS*H_LotSize)) > 0) 
          { 
            BOP = OP_SELL; 
            HOP = OP_SELL; 
          } 
  }

现在要发送对冲:

// if they meet the correlation range and 
// you're not blocking them
if(!BlockOpen && !BlockOpening)  
  { 
    if(BOP == OP_BUY) 
    // define the opening price    
        BaseOpen = MarketInfo(BaseSymbol, MODE_ASK); 
    else 
        BaseOpen = MarketInfo(BaseSymbol, MODE_BID); 
    if(HOP == OP_BUY)
        HOpen = MarketInfo(H_Symbol, MODE_ASK); 
    else 
        HOpen = MarketInfo(H_Symbol, MODE_BID); 
    // In case there is no any swap condition to gain 
    // from BOP & HOP will be -1.
    if(BOP >= 0 && HOP >= 0) 
      {
        if(ExistPositions(BaseSymbol, MagicNo) == 0 && 
           ExistPositions(H_Symbol, MagicNo) == 0) 
          { 
            SendH(BaseSymbol, BOP, BaseLotSize, BaseOpen, 
                  BSP, "COR : " +
                  DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), 
                  MagicNo); 
            SendH(H_Symbol, HOP, H_LotsSize, HOpen, HSP, 
                  "COR : " +
                  DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), 
                  MagicNo); 
          } 
        else // in case ping failed or requote 
          { 
            if(ExistPositions(BaseSymbol, MagicNo) == 1&&
               TotalCurProfit(MagicNo)>AcceptableLoss$) 
              { 
                CloseScrap(BaseSymbol, ExistOP(BaseSymbol, 
                           MagicNo), MagicNo); 
              } 
            else 
                if(ExistPositions(H_Symbol, MagicNo) == 1&&
                   TotalCurProfit(MagicNo) > AcceptableLoss$) 
                  { 
                    CloseScrap(H_Symbol, ExistOP(H_Symbol, 
                               MagicNo), MagicNo); 
                  } 
          } 
 
      }
    else // if one of BOP and HOP is less than 0
      {
        string swaptxt = "No Swap Condition To Gain From :" + 
                   "pls modify one or more input parameter(s).";
      }
  }

然后,在达到预期利润时关闭这些订单。


if((TotalCurProfit(MagicNo) > ExpectProfit$)
  {
    CloseHedge(MagicNo);
  }

更有趣的是这个:ShowStatus 部分。

if(ShowStatus)
  {
    Comment("\nCorrel: " + DoubleToStr(Cor(BaseSymbol
            , H_Symbol), 2)
            , "\nBlockOpen : " + bool2str(BlockOpen 
            || BlockOpening)
            , "\n" + swaptxt
            , "\n~~~~~~~"
            , "\nB/H [sp] : " + BaseSymbol + " [" 
            + BSP + "]" + " / " 
            + H_Symbol+" ["+HSP+"]"
            , "\nCurOp [Lots]: " 
            + OP2Str(ExistOP(BaseSymbol, MagicNo)) 
            + " [" + DoubleToStr(BaseLotSize, 2) + "]"
            + " ~ " + OP2Str(ExistOP(H_Symbol, MagicNo)) 
            + " [" 
            + DoubleToStr(H_LotsRatio*BaseLotSize, 2) + "]"
            , "\nCurPF [Expect]: $" 
            + DoubleToStr(TotalCurProfit(MagicNo), 2) 
            + " [$"+DoubleToStr(ExpectProfit$, 2) + "]");
  }
else 
    Comment("");

每个 EA 末尾加上这个。

return(0);
}

步骤 6:将它们全部聚集起来

以下便是 myHedge.mq4 的全貌。

//+------------------------------------------------------------------+
//|                                                      MyHedge.mq4 |
//|                                                          myHedge |
//|                                      http://dailyh.blogspot.com/ |
//+------------------------------------------------------------------+
#property copyright "myHedge"
#property link "http://dailyh.blogspot.com/"
//----
#include <stdlib.mqh>
// this is to block the order sending function but not to block the 
// close function.
extern bool BlockOpening = false;
extern string BaseSymbol = "EURJPY"; // the 1st symbol
extern string H_Symbol = "GBPJPY";   // the 2nd symbol
extern bool MoveSameWay = true; // they move the same way or not
extern int CorPeriod = 5; // your favorite correlation period
extern double BaseLotSize = 1.5; // 1st symbol lotsize
extern double H_LotSize = 1.0; // 2nd symbol lotsize
extern double ExpectProfit$ = 137; // your expect profit in USD
// your acceptable loss in USD in case any error occurred
extern double AcceptableLoss$ = -77; 
extern string ExpectCor = "______"; // your expect correlation to 
// hedge this is the upper expect cor value and has to be greater 
// than "And"
extern double Between = 1.05;
extern double And = 0.9; // this is the lower expect cor level
extern string MISC = "______"; // some thing more
extern int MagicNo = 318; // your favorite magic number
extern bool ShowStatus = true; // to show the present hedging status
// to play sound when SendH and CloseH function done
extern bool PlayAudio = false; 
//----
int BSP  // the spread of base symbol
    ,HSP // the spread of hedge symbol
    ,gsp
    ,BOP = -1 // base symbol order type
    ,HOP = -1 // hedge symbol order type
    ,up = 0
    ,Hcnt = 0
    ,u = 0
    ,d = 0
    ,day = 0
    ,sent = 0
    ,firstopen
    ,expire;
double Lot
       ,BaseOpen // base symbol order open price
       ,HOpen // hedge symbol order open price
       ,BPt // base symbol Point value
       ,HPt // hedge symbol Point value
       ,BSwapL // base symbol swap long value
       ,BSwapS // base symbol swap short value
       ,HSwapL // hedge symbol swap long value
       ,HSwapS; // hedge symbol swap short value
bool SResult = false, BResult = false, H1.profitswap, H2.profitswap, 
     H3.profitswap;
bool SwapMode = true, allmeetcor = false, BlockOpen = false, buy, 
     sell, cleared = false;
string H1.string = "", H2.string = "", H3.string = "", 
       OrdComment = "", candletxt,tdstxt = "";
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
   BSP = MarketInfo(BaseSymbol, MODE_SPREAD);
   HSP = MarketInfo(H_Symbol, MODE_SPREAD);
//----
   BPt = MarketInfo(BaseSymbol, MODE_POINT);
   HPt = MarketInfo(H_Symbol, MODE_POINT);
//----
   BSwapL = MarketInfo(BaseSymbol, MODE_SWAPLONG);
   BSwapS = MarketInfo(BaseSymbol, MODE_SWAPSHORT);
//----
   HSwapL = MarketInfo(H_Symbol, MODE_SWAPLONG);
   HSwapS = MarketInfo(H_Symbol, MODE_SWAPSHORT);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
   if(Cor(BaseSymbol, H_Symbol) > Between || 
      Cor(BaseSymbol, H_Symbol) < And)
   // Block opening when the correlation is out of expected range.
       BlockOpen = true;
   else 
       BlockOpen = false;
//----
   if(MoveSameWay)
     {
       if((BSwapL*BaseLotSize) + (HSwapS*H_LotSize) > 0)
         {
           BOP = OP_BUY;
           HOP = OP_SELL;
         }
       else 
           if((BSwapS*BaseLotSize) + (HSwapL*H_LotSize) > 0)
             {
               BOP = OP_SELL;
               HOP = OP_BUY;
             }
     }
   else
     {
       if((BSwapL*BaseLotSize) + (HSwapL*H_LotSize) > 0)
         {
           BOP = OP_BUY;
           HOP = OP_BUY;
         }
       else 
           if((BSwapS*BaseLotSize) + (HSwapS*H_LotSize) > 0)
             {
               BOP = OP_SELL;
               HOP = OP_SELL;
             }
     }
   if(!BlockOpen && !BlockOpening)
     {
       if(BOP == OP_BUY) 
           BaseOpen = MarketInfo(BaseSymbol, MODE_ASK);
       else            
           BaseOpen = MarketInfo(BaseSymbol, MODE_BID);
       if(HOP == OP_BUY)
           HOpen = MarketInfo(H_Symbol, MODE_ASK);
       else
           HOpen = MarketInfo(H_Symbol, MODE_BID);
       // In case there is no any swap condition that we can gain from.
       if(BOP >= 0 && HOP >= 0) 
         {
           if(ExistPositions(BaseSymbol, MagicNo) == 0 && 
              ExistPositions(H_Symbol,MagicNo) == 0)
             {
               SendH(BaseSymbol, BOP, BaseLotSize, BaseOpen, BSP, 
                     "COR : " + DoubleToStr(Cor(BaseSymbol, H_Symbol), 
                     2), MagicNo);
               SendH(H_Symbol, HOP, H_LotSize, HOpen, HSP, "COR : " + 
                     DoubleToStr(Cor(BaseSymbol, H_Symbol), 2), MagicNo);
             }     
           else // in case ping failed or requote
             {
               if(ExistPositions(BaseSymbol, MagicNo) == 1 && 
                  TotalCurProfit(MagicNo) > AcceptableLoss$)
                 {
                   CloseScrap(BaseSymbol, ExistOP(BaseSymbol, 
                              MagicNo), MagicNo);
                 }
               else 
                   if(ExistPositions(H_Symbol, MagicNo) == 1 && 
                      TotalCurProfit(MagicNo) > AcceptableLoss$)
                     {
                       CloseScrap(H_Symbol, ExistOP(H_Symbol, 
                                  MagicNo), MagicNo);
                     }
             }
         }
       else
         {
           string swaptxt = "No Swap Condition To Gain From : pls " + 
                            "modify one or more input parameter(s).";
         }
     }
   if(TotalCurProfit(MagicNo) > ExpectProfit$)
     {
       CloseHedge(MagicNo);
     }
   if(ShowStatus)
     {
       Comment("\nCorrel: "+DoubleToStr(Cor(BaseSymbol, H_Symbol), 2)
               , "\nBlockOpen : " + bool2str(BlockOpen || BlockOpening)
               , "\n" + swaptxt
               , "\n~~~~~~~"
               , "\nB/H [sp] : " + BaseSymbol + " [" + BSP + "]" + 
                 " / " + H_Symbol + " [" + HSP + "]"
               , "\nCurOp [Lots]: " + OP2Str(ExistOP(BaseSymbol, 
                 MagicNo)) + " [" + DoubleToStr(BaseLotSize, 2) + "]"
                 + " ~ " + OP2Str(ExistOP(H_Symbol, MagicNo)) + " [" + 
                 DoubleToStr(H_LotSize, 2) + "]"
               , "\nCurPF [Expect]: $" + 
                 DoubleToStr(TotalCurProfit(MagicNo), 2) + " [$" + 
                 DoubleToStr(ExpectProfit$, 2) + "]");
     }
   else 
       Comment("");
   return(0);
  }
//+------------------------------------------------------------------+
//| CORRELATION                                                      |
//+------------------------------------------------------------------+
double symboldif(string symbol, int shift)
  {
   return(iClose(symbol, 1440, shift) - 
          iMA(symbol, 1440, CorPeriod, 0, MODE_SMA, PRICE_CLOSE, shift));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double powdif(double val)
  {
   return(MathPow(val, 2));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double u(double val1, double val2)
  {
   return((val1*val2));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Cor(string base, string hedge)
  {  
   double u1 = 0, l1 = 0, s1 = 0;
   for(int i = CorPeriod - 1; i >= 0; i--)
     {
       u1 += u(symboldif(base, i), symboldif(hedge, i));
       l1 += powdif(symboldif(base, i));
       s1 += powdif(symboldif(hedge, i));
     }
   if(l1*s1 > 0) 
       return(u1 / MathSqrt(l1*s1));
  }
//+------------------------------------------------------------------+
//| SEND HEDGE                                                       |
//+------------------------------------------------------------------+
bool SendH(string symbol, int op, double lots, double price, int sp, 
           string comment, int magic)
  {
   if(OrderSend(symbol
                ,op
                ,lots
                ,price
                ,sp
                ,0
                ,0
                ,comment
                ,magic
                ,0
                ,CLR_NONE)
                >0)
     {
       return(true);
       if(PlayAudio)
           PlaySound("expert.wav");
     }
   else 
     {
       Print(symbol, ": ", magic, " : "
             ,ErrorDescription(GetLastError()));
       return(false);      
     }      
  }
//+------------------------------------------------------------------+
//| CLOSE HEDGE                                                      |
//+------------------------------------------------------------------+
bool CloseHedge(int magic)
  {  
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {         
       if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) && 
                      OrderMagicNumber() == magic)
         {
           if(OrderClose(OrderTicket()
                         , OrderLots()
                         , OrderClosePrice()
                         , MarketInfo(OrderSymbol(), MODE_SPREAD)
                         , CLR_NONE))
               SResult = true;
         }
     }
   if(SResult)
     {
       return(true);
       if(PlayAudio)
         {
           PlaySound("ok.wav");
         }
     }
   else 
       Print("CloseHedge Error: ", ErrorDescription(GetLastError()));
   RefreshRates();
//  return(0);
  }  
//+------------------------------------------------------------------+
//| TOTAL PROFIT                                                     |
//+------------------------------------------------------------------+
double TotalCurProfit(int magic)
  {   
   double MyCurrentProfit = 0;
   for(int cnt = 0; cnt < OrdersTotal(); cnt++)
     {
       OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
       if(OrderMagicNumber() == magic)
         {
           MyCurrentProfit += (OrderProfit() + OrderSwap());
         }   
     }
   return(MyCurrentProfit);
  }
//+------------------------------------------------------------------+
//| EXISTING POSITION                                                |
//+------------------------------------------------------------------+
int ExistPositions(string symbol,int magic) 
  {
   int NumPos = 0;
   for(int i = 0; i < OrdersTotal(); i++) 
     {
       if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) 
          && OrderSymbol() == symbol
          && OrderMagicNumber() == magic)
         { 
           NumPos++;
         }
     }
   return(NumPos);
  }
//+------------------------------------------------------------------+
//| EXISTING OP POSITION                                             |
//+------------------------------------------------------------------+
int ExistOP(string symbol,int magic) 
  {
   int NumPos = -1;
   for(int i = 0; i < OrdersTotal(); i++) 
     {
       if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) 
          && OrderSymbol() == symbol
          && OrderMagicNumber() == magic)
         { 
           NumPos = OrderType();
         }
     }
   return(NumPos);
  }
//+------------------------------------------------------------------+
//| Transform OP Value To string                                     |
//+------------------------------------------------------------------+
string OP2Str(int op)
  {
   switch(op)
     {
       case OP_BUY : return("BUY");
       case OP_SELL: return("SELL");
       default     : return("~~");
     }
  }
//+------------------------------------------------------------------+
//| CLOSE SCRAP                                                      |
//+------------------------------------------------------------------+
bool CloseScrap(string sym,int op,int magic)
  {  
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {         
       if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) 
          && OrderMagicNumber() == magic
          && OrderSymbol() == sym
          && OrderType() == op)
         {
           if(OrderClose(OrderTicket()
                         , OrderLots()
                         , OrderClosePrice()
                         , MarketInfo(OrderSymbol(), MODE_SPREAD)
                         , CLR_NONE))
               BResult = true;
         }
     }
   if(SResult || BResult)
     {
       return(true);
       if(PlayAudio)
         {
           PlaySound("ok.wav");
         }
     }
   else 
       Print("CloseScrap Error: ", ErrorDescription(GetLastError()));
   RefreshRates();
//  return(0);
  }  
//+------------------------------------------------------------------+
//| Translate bool to string                                         |
//+------------------------------------------------------------------+
string bool2str(bool boolval)
  {
   if(boolval == true) 
       return("Yes");
   if(boolval == false)
       return("No");
  }
//+------------------------------------------------------------------+

总结

这仅仅是一个简单的对冲 Expert Advisor 的示例。您需要对其进行修改,以符合您自己的对冲风格。我知道大家使用的对冲风格有很多种。请注意,这种 EA 有其自身的限制,因此不可用策略测试器进行测试。请注意,这种 EA 有其自身的限制,因此不可用策略测试器进行测试。您仅可对其进行现场测试。以下是一个对冲 EA 的示范结果。


ShowStatus 函数将如下所示:

希望您喜欢我的文章,也强烈希望它能帮助您创建您自己的对冲 EA。

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/1479

附加的文件 |
myHedge.mq4 (13.75 KB)
通过 RSS 馈送发送交易信号 通过 RSS 馈送发送交易信号
将交易信号作为 RSS 馈送发出是当下与你社区成员沟通的流行方式,在此我要向你介绍我对这种方式的个人理解。
虚拟专用服务器(VPS)进行自动交易的实际应用 虚拟专用服务器(VPS)进行自动交易的实际应用
使用 VPS 进行自动交易。本文特别面向自动交易员和自动交易支持者。
什么是马丁格尔?使用马丁格尔是否合理? 什么是马丁格尔?使用马丁格尔是否合理?
本文内容包括了马丁格尔系统的详细描述,精确的数学计算,足以回答这些问题:"使用马丁格尔是否合理?"
嘉盛市场可否预测?如何制定自己的交易策略? 嘉盛市场可否预测?如何制定自己的交易策略?
每个开始进入嘉盛的人都会尝试回答这些问题。但是,并非每个人都找到了答案,甚至在经过了多年的努力钻研和寻找之后仍未找到答案。我个人已经回答了上述问题以及本文提到的很多其他问题。根据这些答案,制定了一种高效交易策略的方式。