您现在的位置: 比特财富网 >> 财经 >  >> 外匯
外匯EA:MT4.0編程函數庫
外_匯_邦 WaiHuiBang.com

MT4.0和3.x相比,編程語言迥然不同,基本上是C語言的翻版,所以有一些C語言基礎是很容易學會MT編程的。www.emoneybtc.com

MT4.0可以編寫的程序有好幾類,主要是自動交易程序和指標,估計大家都是為了給自己的投資策略,由於我的精力有限,所以接下來只介紹自動交易程序。

1. MT程序的語法
MT程序既然是C語言的翻版,語法和C語言當然很接近了,用有限的篇幅來說明其語法似乎是一個不能完成的任務,我這裡只能告訴大家如何去學習。
語法說明可以在Meta Editor的幫助中找到,在工具欄上點MQL Navigator,就會彈出MT編程的導航,其中Dictionary就是語言和函數庫的幫助。
在這個樹狀幫助目錄下,語法的說明在Basic下,主要包括Syntax, Data type, Operations & Expressions, Operators, Functions, Variables, Preprocessor
如果會C的話,粗略看一下即可,如果不會,結合例程學習一遍吧。

由於幫助基本是英文的,所以剛開始學還是有難度的,不過沒有辦法,我也幫不上忙,大家有問題就提吧,我盡量回答。啥時候能出個中文版的就好了。
學習的時候,從網上搜一些現成的程序進行學習和修改是加快學習的一個辦法,上一次我貼的Grid的交易程序就是一個很好的學習的例子。

2. 函數庫
MT的函數庫幫助進行了分類,看起來還是比較方便的。這裡也沒有辦法詳細介紹,做一個扼要介紹。
還是在幫助的Dictionary下,看這些幫助要考驗一下大家的英文,特別要涉及到金融和計算機專業英語。
包括以下幾類:

(1) Stardard constants
也就是系統定義的標准常量,主要是一些枚舉類型和窗口常量等,一般先不用管它,在別的地方會鏈接過來。

(2) Predifined variables
一些系統常量,包括買入價,賣出價,最高、最低價等,還是很有用的,不過不太多,挨個兒看一下吧。

(3) Account Information
賬戶有關的函數

(4) Array functions
數組處理函數。

(5) Common functions
常用處理函數。

(6) Conversion functions
轉換函數,主要是字符串和主要類型之間的轉換函數。

(7) Custom Indicators
編寫自定義指標用到的函數,如果不編寫自定義指標的話,可以不管它。

(8) Date&Time functions
時間日期有關的函數

(9) File functions
文件處理函數

(10) Globle variables
全局變量有關的處理函數。

(11) Math & Trig
數學計算函數

(12)Object functions
對象處理函數,主要是在圖表中處理對象的函數,對象是指直線、文本等。

(13) String functions
字符串處理函數。

(14) Technical indicators
技術指標函數,相信大家一定會經常用到的。大家通過指標的英文,應該比較容易看出來誰是誰。

(15) Trading functions
交易函數。這一類對自動交易系統是很重要的。

(16) Window functions
窗口處理函數,基本不需要用到。

3. 創建程序
在MT的程序組中,有一個Meta Editor,這就是MT的編譯器,還是很容易上手的。用過Visual Studio C++的人一看,有點熟,對吧?
首先,點擊菜單File->New,彈出對話框,程序類型選擇Expert Advisor,後面按導航操作輸入名稱即可。
這樣一個簡單的MT空白交易程序就創建了,點按鈕Compile或直接按快捷鍵F5就可以編譯通過了。因為是空白的,這時候它什麼也不能干。
注意:自動交易程序一定要存放在安裝目錄下的Experts子目錄。

4. 修改
(1)全局變量
在程序的開頭,可以定義一下全局變量。前面加extern的全局變量的值,在自動交易程序啟動的時候可以直接在MT改,不需要重新編譯。

(2)入口函數
MT程序的調用入口是start()函數,和C程序的main()函數是一樣的,一般就在這裡寫處理過程即可。

(3) 子函數
比較復雜的過程,可以寫子函數,在start()函數裡調用子函數。

5. 例程:以下是在MT官方網站的論壇下hdb寫的Grid自動交易程序,供參考。

#property copyright "外匯聯盟 www.FXunion.com QQ群144033"

#property link      ""

//#property version      "1.8"
// DISCLAIMER ***** IMPORTANT NOTE ***** READ BEFORE USING *****
// This expert advisor can open and close real positions and hence do real trades and lose real money.
// This is not a 'trading system' but a simple robot that places trades according to fixed rules.
// The author has no pretentions as to the profitability of this system and does not suggest the use
// of this EA other than for testing purposes in demo accounts.
// Use of this system is free - but u may not resell it - and is without any garantee as to its
// suitability for any purpose.
// By using this program you implicitly acknowledge that you understand what it does and agree that
// the author bears no responsibility for any losses.
// Before using, please also check with your broker that his systems are adapted for the frequest trades
// associated with this expert.
// 1.8 changes
// made wantLongs and wantShorts into localvariables. Previously, if u set UseMACD to true,
//       it did longs and shorts and simply ignored the wantLongs and wantShorts flags.
//       Now, these flags are not ignored.
// added a loop to check if there are 'illicit' open orders above or below the EMA when the limitEMA34
//       flag is used. These accumulate over time and are never removed and is due to the EMA moving.
// removed the switch instruction as they dont seem to work - replaced with if statements
// made the EMA period variable
//
//
// modified by cori. Using OrderMagicNumber to identify the trades of the grid
extern int    uniqueGridMagic = 11111;   // Magic number of the trades. must be unique to identify
                                         // the trades of one grid   
extern double Lots = 0.1;              //
extern double GridSize = 6;            // pips between orders - grid or mesh size
extern double GridSteps = 12;          // total number of orders to place
extern double TakeProfit = 12 ;        // number of ticks to take profit. normally is = grid size but u can override
extern double StopLoss = 0;            // if u want to add a stop loss. normal grids dont use stop losses
extern double UpdateInterval = 1;      // update orders every x minutes
extern bool   wantLongs = true;        // do we want long positions
extern bool   wantShorts = true;       // do we want short positions
extern bool   wantBreakout = true;     // do we want longs above price, shorts below price
extern bool   wantCounter = true;      // do we want longs below price, shorts above price
extern bool   limitEMA = false;         // do we want longs above ema only, shorts below ema only
extern int    EMAperiod = 34;          // the length of the EMA.. was previously fixed at 34
extern double GridMaxOpen = 0;         // maximum number of open positions : not yet implemented..
extern bool   UseMACD = false;          // if true, will use macd >0 for longs only, macd >0 for shorts only
                                       // on crossover, will cancel all pending orders. This will override any
                                       // wantLongs and wantShort settings - at least for now.
extern bool CloseOpenPositions = false;// if UseMACD, do we also close open positions with a loss?
extern bool doHouseKeeping = true;     // just a test

 

// modified by cori. internal variables only
string GridName = "Grid";       // identifies the grid. allows for several co-existing grids
double LastUpdate = 0;          // counter used to note time of last update

 

#property copyright "外匯聯盟 www.FXunion.com QQ群144033"

#property link      ""

 

int init()
  {
//----
#property show_inputs                  // shows the parameters - thanks Slawa...   
//----
// added my corri and removed by hdb!! lol.. just to stay compatible with open grids...
//   GridName = StringConcatenate( "Grid", Symbol() );
   return(0);
  }
//+------------------------------------------------------------------------+
//| tests if there is an open position or order in the region of atRate    |
//|     will check for longs if checkLongs is true, else will check        |
//|     for shorts                                                         |
//+------------------------------------------------------------------------+

bool IsPosition(double atRate, double inRange, bool checkLongs )
  {
     int totalorders = OrdersTotal();
     for(int j=0;j      {
        OrderSelect(j, SELECT_BY_POS);
// modified by cori. Using OrderMagicNumber to identify the trades of the grid // hdb added or gridname for compatibility
        if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) )  // only look if mygrid and symbol...
         {  int type = OrderType();
            if (MathAbs( OrderOpenPrice() - atRate ) < (inRange*0.9)) // dont look for exact price but price proximity (less than gridsize) - added 0.9 because of floating point errors
              { if ( ( checkLongs && ( type == OP_BUY || type == OP_BUYLIMIT  || type == OP_BUYSTOP ) )  || (!checkLongs && ( type == OP_SELL || type == OP_SELLLIMIT  || type == OP_SELLSTOP ) ) )
                 {
                    return(true);
                 }
              }
         }
      }
   return(false);
  }

//+------------------------------------------------------------------------+
//| cancells all pending orders                                      |
//+------------------------------------------------------------------------+

void CloseAllPendingOrders( )
  {
     int totalorders = OrdersTotal();
&bsp;    for(int j=totalorders-1;j>=0;j--)                                // scan all orders and positions...
      {
        OrderSelect(j, SELECT_BY_POS);
// modified as per cori. Using OrderMagicNumber to identify the trades of the grid // hdb added or gridname for compatibility
        if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) )  // only look if mygrid and symbol...
         { 
          int type = OrderType();
          if ( type > 1 ) bool result = OrderDelete( OrderTicket() );
         }
      }
   return;
  }
//+------------------------------------------------------------------------+
//| cancells all pending orders    and closes open positions               |
//+------------------------------------------------------------------------+

void CloseOpenOrders()
{
  int total = OrdersTotal();
  for(int i=total-1;i>=0;i--)
{
    OrderSelect(i, SELECT_BY_POS);
    int type    = OrderType();
    bool result = false;
// modified by cori. Using OrderMagicNumber to identify the trades of the grid // hdb added or gridname for compatibility
    if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) )  // only look if mygrid and symbol...
     {
           //Close opened long positions
           if ( type == OP_BUY )  result = OrderClose( OrderTicket(), OrderLots(), 騙子Info(OrderSymbol(), MODE_BID), 5, Red );
           //Close opened short positions
           if ( type == OP_SELL )  result = OrderClose( OrderTicket(), OrderLots(), 騙子Info(OrderSymbol(), MODE_ASK), 5, Red );
           //Close pending orders
           if ( type > 1 ) result = OrderDelete( OrderTicket() );
      }
  }
  return;
}

//+------------------------------------------------------------------------+
//| cancells all open orders which fall on the wrong side of the EMA                                     |
//+------------------------------------------------------------------------+

void CloseOrdersfromEMA( double theEMAValue )
  {
     int totalorders = OrdersTotal();
     for(int j=totalorders-1;j>=0;j--)                                // scan all orders and positions...
      {
        OrderSelect(j, SELECT_BY_POS);
        if ( OrderSymbol()==Symbol() && ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) )  // only look if mygrid and symbol...
         { 
          int type = OrderType();
          bool result = false;
//if (type > 1) Print(type,"  ",theEMAValue,"  ",OrderOpenPrice());
          if ( type == OP_BUYLIMIT && OrderOpenPrice() <= theEMAValue ) result = OrderDelete( OrderTicket() );
          if ( type == OP_BUYSTOP && OrderOpenPrice() <= theEMAValue ) result = OrderDelete( OrderTicket() );
          if ( type == OP_SELLLIMIT && OrderOpenPrice() >= theEMAValue ) result = OrderDelete( OrderTicket() );
          if ( type == OP_SELLSTOP && OrderOpenPrice() >= theEMAValue ) result = OrderDelete( OrderTicket() );
         }
      }
   return;
  }
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
   int    i, j,k, ticket, entermode, totalorders;
   bool   doit;
   double point, startrate, traderate;
//---- setup parameters

if ( TakeProfit <= 0 )                 //
   { TakeProfit = GridSize; }

bool myWantLongs = wantLongs;
bool myWantShorts = wantShorts;

//----

  if (MathAbs(CurTime()-LastUpdate)> UpdateInterval*60)           // we update the first time it is called and every UpdateInterval minutes
   {
   LastUpdate = CurTime();
   point = 騙子Info(Symbol(),MODE_POINT);
   startrate = ( Ask + point*GridSize/2 ) / point / GridSize;    // round to a number of ticks pisible by GridSize
   k = startrate ;
   k = k * GridSize ;
   startrate = k * point - GridSize*GridSteps/2*point ;          // calculate the lowest entry point
   double myEMA=iMA(NULL,0,EMAperiod,0,MODE_EMA,PRICE_CLOSE,0);
  
   if (limitEMA)
     {
    if (doHouseKeeping) CloseOrdersfromEMA(myEMA);
     }
   if ( UseMACD ) 
     {
      double Macd0=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
      double Macd1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
      double Macd2=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,2);
       if( Macd0>0 && Macd1>0  &&  Macd2<0)     // cross up
        {
         CloseAllPendingOrders();
         if ( CloseOpenPositions == true ) { CloseOpenOrders(); }
        }
       if( Macd0<0 && Macd1<0  &&  Macd2>0)     // cross down
   &nbp;    {
         CloseAllPendingOrders();
         if ( CloseOpenPositions == true ) { CloseOpenOrders(); }
        }
       myWantLongs = false;
       myWantShorts = false;
       if( Macd0>0 && Macd1>0  &&  Macd2>0 && wantLongs )     // is well above zero
        {
         myWantLongs = true;
        }
       if( Macd0<0 && Macd1<0  &&  Macd2<0 && wantShorts )     // is well below zero
        {
         myWantShorts = true;
        }
   }
   for( i=0;i   {
     traderate = startrate + i*point*GridSize;
     if ( myWantLongs && (!limitEMA || traderate > myEMA))
       {
         if ( IsPosition(traderate,point*GridSize,true) == false )           // test if i have no open orders close to my price: if so, put one on
          {
            double myStopLoss = 0;
             if ( StopLoss > 0 )
               { myStopLoss = traderate-point*StopLoss ; }
             if ( traderate > Ask )
              { entermode = OP_BUYSTOP; }
              else
              { entermode = OP_BUYLIMIT ; }
              if ( ((traderate > Ask ) && (wantBreakout)) || ((traderate <= Ask ) && (wantCounter)) )
              {
                  // modified by cori. Using OrderMagicNumber to identify the trades of the grid
                ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate+point*TakeProfit,GridName,uniqueGridMagic,0,Green);
             }
          }
       }
     if ( myWantShorts && (!limitEMA || traderate < myEMA))
       {
         if (IsPosition(traderate,point*GridSize,false)== false )           // test if i have no open orders close to my price: if so, put one on
          {
             myStopLoss = 0;
             if ( StopLoss > 0 )
               { myStopLoss = traderate+point*StopLoss ; }
             if ( traderate > Bid )
              { entermode = OP_SELLLIMIT; }
              else
              { entermode = OP_SELLSTOP ; }
             
              if ( ((traderate < Bid ) && (wantBreakout)) || ((traderate >= Bid ) && (wantCounter)) )
                {
                   // modified by cori. Using OrderMagicNumber to identify the trades of the grid
                   ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate-point*TakeProfit,GridName,uniqueGridMagic,0,Red);
                }
          }
       }
    }
   }
   return(0);
  }
//+------------------------------------------------------------------+

自動交易系統的測試
很多人都想用歷史數據測試自己的自動交易系統結果怎麼樣。
在MT的View菜單下,有一個Strategy tester。
選定自己的交易系統,設定好幣種,歷史數據的時間周期,交易系統的屬性,勾上Recalculate,設定時間范圍,點Start按鈕即開始測試。
特別強調的是,由於歷史數據不能反映內部的波動情況,測試中可以選擇三種插值方式,但是因為要使用插值,測試結果可能是不准確的,尤其是在以下兩種情況下:
(1) 有止損的策略
(2) 使用的TimeFrame比較大
找了一個根據均線交易的例子,我自己擇主要的加了一些中文注釋,看看有沒有幫助。
//+------------------------------------------------------------------+
//|                                               Moving Average.mq4 |
//|                      Copyright ?2005, MetaQuotes Software Corp. |
//|                                   http://fxunion.com                |
//+------------------------------------------------------------------+
#define MAGICMA  20050610

// extern的全局變量,編譯後可以直接在MT中修改
extern double Lots               = 0.1;
extern double MaximumRisk        = 0.02;
extern double DecreaseFactor     = 3;
extern double MovingPeriod       = 12;
extern double MovingShift        = 6;

//+------------------------------------------------------------------+
//| 入口函數,程序從這裡開始運行                                                  |
//+------------------------------------------------------------------+
void start()  {
//----
   if(Bars<100 //如果歷史數據不足100根K線
         || IsTradeAllowed()==false) // 或者系統目前不允許交易
      return;  // 退出

//----
   if(CalculateCurrentOrders(Symbol())==0)// 調用子函數CalculateCurrentOrders檢查現有倉位,是否需要建倉
      CheckForOpen();                     // 調用子函數CheckForOpen開始建立倉位
   else                                   
      CheckForClose();                    // 否則檢查是否需要平倉
//----
}

//+------------------------------------------------------------------+
//| 檢查現有倉位|
//+------------------------------------------------------------------+
int CalculateCurrentOrders(string symbol)
  {
   int buys=0,sells=0;
//----
   for(int i=0;i     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) // 如果獲取Order失敗,則退出
         break;
      if(OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA) // 獲取倉位成功
        {
         if(OrderType()==OP_BUY)  buys++;    // 如果是買單,買單計數器加一
         if(OrderType()==OP_SELL) sells++;   // 如果是賣單,賣單計數器加一
        }
     }
//---- return orders volume
   if(buys>0) return(buys);   // 有至少一張買單,返回買單數量
   else       return(-sells); // 否則,返回賣單數量的負值
  }
 
//+------------------------------------------------------------------+
//| 計算最優倉位
//+http://blog.sina.com.cn/zhouxiaoyin18---------------------+
double LotsOptimized()
  {
   double lot=Lots;
   int    orders=HistoryTotal();     // history orders total
   int    losses=0;                  // number of losses orders without a break
//---- select lot size
   lot=NormalizeDouble(AccountFreeMargin()*MaximumRisk/1000.0,1);
//---- calcuulate number of losses orders without a break
   if(DecreaseFactor>0)
     {
      for(int i=orders-1;i>=0;i--)
        {
         if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false) { Print("Error in history!"); break; }
         if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL) continue;
         //----
         if(OrderProfit()>0) break;
         if(OrderProfit()<0) losses++;
        }
      if(losses>1) lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
     }
//---- return lot size
   if(lot<0.1) lot=0.1;
   return(lot);
  }
 
//+------------------------------------------------------------------+
//| 檢查是否建倉                                  |
//+------------------------------------------------------------------+
void CheckForOpen()
  {
   double ma;
   int    res;
//---- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//---- 指標調用,iMA就是均線(Moving Average)
   ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//---- sell conditions
   if(Open[1]>ma && Close[1]     {
     // 建立倉位
      res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red);
      return;
     }
//---- buy conditions
   if(Open[1]ma)  
     {
      res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);
      return;
     }
//----
  }
 
//+------------------------------------------------------------------+
//| 檢查是否平倉                                 |
//+------------------------------------------------------------------+
void CheckForClose()
  {
   double ma;
//---- go trading only for first tiks of new bar
   if(Volume[0]>1) return;
//---- get Moving Average
   ma=iMA(NULL,0,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE,0);
//----
   for(int i=0;i     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)        break;
      if(OrderMagicNumber()!=MAGICMA || OrderSymbol()!=Symbol()) continue;
      //---- check order type
      if(OrderType()==OP_BUY)
        {
         if(Open[1]>ma && Close[1]         break;
        }
      if(OrderType()==OP_SELL)
        {
         if(Open[1]ma) OrderClose(OrderTicket(),OrderLots(),Ask,3,White);
         break;
        }
     }
//----
  }

外_匯_邦 WaiHuiBang.com
  • 外匯智能交易軟件怎麼玩?

    外匯智能交易軟件怎麼玩?外匯智能交易軟件顧名思義就是在炒外匯時電腦會利用這個軟件給投資人進行智能化的自動化的交易,那麼我們就來詳細的介紹一下

  • 外匯交易風險第一課:不要重倉交易

    外_匯_邦 WaiHuiBang.com 經常在QQ群裡看到很多小散戶哭訴,又爆倉了!這樣的場景看到太多,都已經有點麻木了。尤其是每當

  • 主力資金的本質 沉著應對主力機構

       說機構投資者是滬深市場的柱石一點也不過分,市場的各參與方只有認識到這點才能更好的管理好這個市場、投資好這個市場,否

  • 股市幾點結束?

    最佳答案: 國內A股的交易時間是周一到周五的9點30到11點30、13點到15點,也就是交易日下午3

  • 保險可以退嗎?

    最佳答案: 近幾年,過久搭理發展保險行業,為了迎合市場保險產品更新迭代的速度非常快,常常是好產品還沒

  風險提示:比特財富網的各種信息資料僅供參考,不構成任何投資建議,不對任何交易提供任何擔保,亦不構成任何邀約,不作為任何法律文件,投資人據此進行投資交易而產生的後果請自行承擔,本網站不承擔任何責任,理財有風險,投資需謹慎。
比特財富網 版權所有 © www.emoneybtc.com