电竞比分网-中国电竞赛事及体育赛事平台

分享

MQL4課程——模塊編寫

 Levy_X 2020-05-28

上節(jié)課我們介紹了子函數(shù),通過子函數(shù)我們可以將一些功能封裝起來,直接調(diào)用,能實現(xiàn)特定功能的子函數(shù)我們稱其為模塊。

一款EA往往都是由許多個功能模塊組合起來完成交易功能的,這些模塊中最基本的模塊有K線信號控制、開倉、平倉、掛單模塊,這些模塊的基礎之上,有移動止損、離場、移動掛單、倉位計算模塊等等,基礎的模塊每個EA用的都差不多,基礎之上的模塊根據(jù)策略的不同,模塊的功能也不盡相同。這節(jié)課我們就先把K線信號控制、開倉、平倉、掛單模塊實現(xiàn)封裝,以便后面的EA編程直接調(diào)用。



K線信號控制


這個模塊控制程序只在K線開盤的時候運行一次,這使得策略的回測相對來說更加準確和可靠,要實現(xiàn)則個功能很簡單,只要判斷K線的根數(shù)有沒有增加就行了,如果K線增加了一根那說明新的K線開盤了。模塊代碼如下:

int bar=0;
int Barjudge()
{
if(Bars!=bar)
{
   bar=Bars;
   return(1);
}
else return(0);
}



如果這個函數(shù)返回了1,那么說明有新的K線開盤,采用這個模塊的EA就可以通過模塊的返回值來判斷當下是否運行。注意以上的bar這個變量是個全局變量,需要在主函數(shù)前聲明。

開倉模塊


要實現(xiàn)開倉當然非常簡單,只要一個開倉函數(shù)就可以了,但是實際交易的時候可沒有這么容易,我們會碰到兩個問題。

第一個問題就是手數(shù)的問題,我們的EA計算出來的手數(shù)有可能會小于最小手數(shù),也有可能會大于最大手數(shù),當小于最小手數(shù)時,我們不做單,當大于最大手數(shù)時我們把單子拆開來分成幾單來做,這一部分內(nèi)容可以參考第五節(jié)課。

第二個問題就是開倉遇到的問題,比如說由于卡頓導致訂單沒有成交等等,此時我們需要立即再發(fā)送開單命令,直到成交為止。

根據(jù)以上問題我們把程序?qū)懗鰜?,代碼如下:

int orderopen(string sym,string direction,double lot,double sl,double tp,int mag,string comment)
{
  int check;
  double lot_min=MarketInfo(sym,MODE_MINLOT);
  double lot_max=MarketInfo(sym,MODE_MAXLOT);
  double lot_last=0;
  int err=0;
  int huadian=10;
  double amount;
  int i;
  if(lot<lot_min)
  {
     Print('lot is too small');
     return(1);
  }
  else if(lot>lot_max)
  {
     amount=MathCeil(lot/lot_max);
     lot_last=lot-(amount-1)*lot_max;
     for(i=(int)amount;i>0;i--)
{
     if (i!=1)
     {
        if(direction=='BUY')
        {
           do
           {
check=OrderSend(sym,OP_BUY,lot_max,MarketInfo(sym,
MODE_ASK),huadian,sl,tp,comment,mag,0,clrBlue);
                 if(check==-1)
                 {
                    err=GetLastError();
                 }
                 else
                 {
                    break;
                 }
              }while(err==146 || err==135);
           }
           else if(direction=='SELL')
           {
           do
           {
check=OrderSend(sym,OP_SELL,lot_max,MarketInfo(sym,
MODE_BID),huadian,sl,tp,comment,mag,0,clrRed);
                 if(check==-1)
                 {
                    err=GetLastError();
                 }
                 else
                 {
                    break;
                 }
              }while(err==146 || err==135);
           }
     }
     else
     {
        if(direction=='BUY')
        {
           do
           {
check=OrderSend(sym,OP_BUY,lot_last,MarketInfo(sym,
MODE_ASK),huadian,sl,tp,comment,mag,0,clrBlue);
                 if(check==-1)
                 {
                    err=GetLastError();
                 }
                 else
                 {
                    break;
                 }
              }while(err==146 || err==135);
           }
           else if(direction=='SELL')
           {
           do
           {
check=OrderSend(sym,OP_SELL,lot_last,MarketInfo(sym,
MODE_BID),huadian,sl,tp,comment,mag,0,clrRed);
                 if(check==-1)
                 {
                    err=GetLastError();
                 }
                 else
                 {
                    break;
                 }
              }while(err==146 || err==135);
           }
     }
     }
  }
  else
  {
     if(direction=='BUY')
     {
     do
     {
check=OrderSend(sym,OP_BUY,lot,MarketInfo(sym,
MODE_BID),huadian,sl,tp,comment,mag,0,clrBlue);
           if(check==-1)
           {
              err=GetLastError();
           }
           else
           {
              break;
           }
        }while(err==146 || err==135);
     }
     if(direction=='SELL')
     {
     do
     {
check=OrderSend(sym,OP_SELL,lot,MarketInfo(sym,
MODE_BID),huadian,sl,tp,comment,mag,0,clrRed);
           if(check==-1)
           {
              err=GetLastError();
           }
           else
           {
              break;
           }
        }while(err==146 || err==135);
     }
  }
  return(0);
}


以上程序中對于手數(shù)小于最小手數(shù)以及手數(shù)大于最大手數(shù)的情況的處理方式參照第五課,對于卡頓導致訂單沒有成交的問題,我們采用do while循環(huán)語句來解決,在程序中如果訂單沒有成交,那么OrderSend()函數(shù)會返回-1,我們將這個返回值賦給check這個變量,如果check等于-1那么檢查錯誤的原因,然后將這個原因?qū)木幪栙x值給err,如果err=146或者135那么程序會再循環(huán)一次直到check不等于-1跳出循環(huán)為止。


平倉模塊


平倉模塊主要解決的是平臺因為卡頓無法平倉的問題,思路和開倉模塊一樣,代碼如下:

void ordercl(string sym,int ticket)
  {
     int i;
     bool result=false;
     double price;
     double lot;
     int err=0;
     int huadian=10;
     for(i=OrdersTotal()-1;i>=0;i--)
     {
        if(OrderSelect(i,SELECT_BY_POS))
        {
           if(OrderSymbol()==sym && OrderTicket()==ticket)
           {
              if(OrderType()==OP_SELL)
              {
                 lot=OrderLots();
                 price=MarketInfo(sym,MODE_ASK);
                 do
                 {
                    result=OrderClose(ticket,lot,price,huadian);
                    if(result==false)
                    {
                       err=GetLastError();
                    }
                 }while(err==146 || err==135);
              }
              else if(OrderType()==OP_BUY)
              {
                 lot=OrderLots();
                 price=MarketInfo(sym,MODE_BID);
                 do
                 {
                    result=OrderClose(ticket,lot,price,huadian);
                    if(result==false)
                    {
                       err=GetLastError();
                    }
                 }while(err==146 || err==135);
              }
              if(result==false)
              {
                 err=GetLastError();
                 Print('order close failed,err=' (string)err);
                 Print('Ticket Number=' (string)OrderTicket());
              }
           }
        }
     }
  }



以上平倉模塊中我們需要輸入的參數(shù)有需要平倉的訂單對應的品種和訂單號,實際上如果只根據(jù)訂單號來平倉也是可以的,這里增加品種的識別是為了防止

掛單模塊


掛單模塊一般來說不會存在延遲的問題,所以它只需要解決拆單的問題,但是需要解決價格錯誤的問題,比如說掛突破買單,當掛單的價格小于當前買價時,掛單是掛不了的,所以要排除這種價格錯誤的情況。代碼如下:

int pendingorder(string sym,string direction,double price,double lot,double sl,
double tp,int mag,string comment)
{
  int check;
  double lot_min=MarketInfo(sym,MODE_MINLOT);
  double lot_max=MarketInfo(sym,MODE_MAXLOT);
  double lot_last=0;
  int huadian=10;
  double amount;
  int i;
  if(lot<lot_min)
  {
     Print('lot is too small');
     return(1);
  }
  if(direction=='BUYSTOP' && price<MarketInfo(sym,MODE_ASK)
MarketInfo(sym,MODE_SPREAD)*MarketInfo(sym,MODE_POINT))
  {
     Print('Price is too low for BUYSTOP order');
     return(1);
  }
  else if(direction=='BUYLIMIT' && price>MarketInfo(sym,MODE_ASK)-
MarketInfo(sym,MODE_SPREAD)*MarketInfo(sym,MODE_POINT))
  {
     Print('Price is too high for BUYLIMIT order');
     return(1);
  }
  else if(direction=='SELLSTOP' && price>MarketInfo(sym,MODE_BID)-
MarketInfo(sym,MODE_SPREAD)*MarketInfo(sym,MODE_POINT))
  {
     Print('Price is too high for SELLSTOP order');
     return(1);
  }
  else if(direction=='SELLLIMIT' && price<MarketInfo(sym,MODE_BID)
MarketInfo(sym,MODE_SPREAD)*MarketInfo(sym,MODE_POINT))
  {
     Print('Price is too low for SELLLIMIT order');
     return(1);
  }

  if(lot>lot_max)
  {
     amount=MathCeil(lot/lot_max);
     lot_last=lot-(amount-1)*lot_max;
     for(i=(int)amount;i>0;i--)
{
     if (i!=1)
     {
         if(direction=='BUYSTOP')
          {
             check=OrderSend(sym,OP_BUYSTOP,lot_max,price,huadian,sl,tp,
comment,mag,0,clrBlue);
           }
           else if(direction=='BUYLIMIT')
           {
             check=OrderSend(sym,OP_BUYLIMIT,lot_max,price,huadian,sl,tp,
comment,mag,0,clrBlue);
           }
           else if(direction=='SELLSTOP')
           {
             check=OrderSend(sym,OP_SELLSTOP,lot_max,price,huadian,sl,tp,
comment,mag,0,clrRed);
           }
           else if(direction=='SELLLIMIT')
           {
             check=OrderSend(sym,OP_SELLLIMIT,lot_max,price,huadian,sl,tp,
comment,mag,0,clrRed);
           }
     }
     else
     {
           if(direction=='BUYSTOP')
        {
             check=OrderSend(sym,OP_BUYSTOP,lot_last,price,huadian,sl,tp,
comment,mag,0,clrBlue);
           }
           else if(direction=='BUYLIMIT')
           {
             check=OrderSend(sym,OP_BUYLIMIT,lot_last,price,huadian,sl,tp,
comment,mag,0,clrBlue);
           }
           else if(direction=='SELLSTOP')
           {
             check=OrderSend(sym,OP_SELLSTOP,lot_last,price,huadian,sl,tp,
comment,mag,0,clrRed);
           }
           else if(direction=='SELLLIMIT')
           {
             check=OrderSend(sym,OP_SELLLIMIT,lot_last,price,huadian,sl,tp,
comment,mag,0,clrRed);
           }
       }
     }
  }
  else
  {
     if(direction=='BUYSTOP')
     {
          check=OrderSend(sym,OP_BUYSTOP,lot,price,huadian,sl,tp,
comment,mag,0,clrBlue);
     }
     else if(direction=='BUYLIMIT')
     {
          check=OrderSend(sym,OP_BUYLIMIT,lot,price,huadian,sl,tp,
comment,mag,0,clrBlue);
     }
     else if(direction=='SELLSTOP')
     {
          check=OrderSend(sym,OP_SELLSTOP,lot,price,huadian,sl,tp,
comment,mag,0,clrRed);
     }
     else if(direction=='SELLLIMIT')
     {
          check=OrderSend(sym,OP_SELLLIMIT,lot,price,huadian,sl,tp,
comment,mag,0,clrRed);
     }
  }
  return(0);
}


以上代碼中,我們對輸入的一些錯誤進行了處理,輸出了問題以備交易者參考,接下來我們將大訂單拆開來,分解成了小單子再根據(jù)掛單的種類掛上去,雖然程序看起來有點多,實際上都是對掛單類型的識別,原理比較簡單。

那么以上四個模塊就是我們以后可以使用的通用模塊了,接下來的課會講解幾個EA的編程,在這個過程中我們會反復用到這幾個模塊,以上內(nèi)容希望大家好好理解和掌握。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多