|
上節(jié)課我們介紹了子函數(shù),通過子函數(shù)我們可以將一些功能封裝起來,直接調(diào)用,能實現(xiàn)特定功能的子函數(shù)我們稱其為模塊。 一款EA往往都是由許多個功能模塊組合起來完成交易功能的,這些模塊中最基本的模塊有K線信號控制、開倉、平倉、掛單模塊,這些模塊的基礎之上,有移動止損、離場、移動掛單、倉位計算模塊等等,基礎的模塊每個EA用的都差不多,基礎之上的模塊根據(jù)策略的不同,模塊的功能也不盡相同。這節(jié)課我們就先把K線信號控制、開倉、平倉、掛單模塊實現(xiàn)封裝,以便后面的EA編程直接調(diào)用。 這個模塊控制程序只在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)容希望大家好好理解和掌握。
|