第六節交易函數平倉及修改止損止盈
俗話說進場是徒弟,出場是師傅,一款程序想要盈利,那就得學會如何出場,要出場那我們還是有必要學一學離場的函數。首先和大家說一下,離場一般就分為兩類,一種是主動離場,一種是被動離場。所謂主動離場,便是當價格達到某一個條件後主動平倉,被動離場便是打掉止損止盈或者被強行平倉。
如果做趨勢交易,我的建議是不要設置止盈,讓市場來決定我們可以盈利多少,主動平倉和移動止損最好都做,這個時候主動平倉也稱之為柔性止損,而止損稱為剛性止損。
下面我們為這兩類止損打一個基礎。
1平倉
平倉我們可以用OrderClose()函數來做,其實也沒有多麼複雜,最關鍵的還是要從一大堆單子中篩選出我們想要平掉的那個單子。那麼我們先從OrderClose()函數說起,打開幫助文件可以看到這個函數有5個參數:
第一個參數需要平倉的訂單的號碼,每個訂單都有一個識別碼,後面會講到;
第二個參數是訂單的手數;
第三個參數是訂單的平倉價格;
第四個參數是平倉的滑點控制;
第五個參數是平倉顯示的箭頭的顏色。
以上參數和之前的開單有點類似,所以不細講。
下面我們要在GBPUSD、USDJPY以及EURUSD這三個品種各開一個單子,然後從這些單子裡面篩選出EURUSD的單子並把它平掉。
在MQL4中,有一個函數能夠返回單子的總數量,這個函數是OrdersTotal()函數,還有一個函數可以用於選擇訂單,這個函數就是OrderSelect()函數。參考一下幫助文件我們發現OrderSelect()函數有三個參數:
第一個參數是訂單的標誌,這個根據第二參數不同而有變化;
第二個參數是選擇訂單的模式,SELECT_BY_POS是根據訂單的位置編號來選擇訂單,MT4把訂單從上往下依次從零開始編號,如下圖,這個模式就是依據這個編號來選擇訂單,採用這種模式時,第一個參數應該輸入訂單的位置編號。第二種模式是SELECT_BY_TICKET,這個模式是根據訂單號碼來選擇訂單,就如下圖的215325180號訂單,這個號碼就是第一個參數應該輸入的數字。

第三個參數是訂單的性質,MODE_TRADES是現有的訂單,MODE_HISTORY是歷史訂單,有時我們會根據歷史訂單來安排倉位,比如說上一單盈利了下一單就不做,這時我們就要參考上一個訂單了,這也是MODE_HISTORY的作用。默認的情況下第三個參數是MODE_TRADE,所以如果不涉及歷史訂單,這個參數我們可以不用填。
另外還有幾個函數如OrderTicket(),返回的是訂單的訂單號,OrderLots()返回的是訂單的手數,OrderType()返回的是訂單的類型(OP_BUY、OP_SELL、OP_BUYSTOP等等),OrderTakeProfit( )返回的是訂單的止盈價位,OrderStopLoss()返回的是訂單的止損價位,OrderMagicNumber()返回的是訂單的魔術號,還有一些Order系列的函數就不說了,大家可以通過幫助文件查看,以上的函數都是需要先選中了一個訂單才能使用的,也就是說必須先用OrderSelect()函數,以上幾個函數才有用。
有了這幾個函數,我們就能通過循環來選擇需要平掉的訂單了,代碼如下:
void OnStart() { int i; string sym= "EURUSD"; int huadian=10; int check; for(i=OrdersTotal()-1;i>=0;i--) { if(OrderSelect(i,SELECT_BY_POS)) { if(OrderSymbol()==sym && OrderType()==OP_SELL) { check=OrderClose(OrderTicket(),OrderLots(),MarketInfo(sym, MODE_ASK),huadian); } else if(OrderSymbol()==sym && OrderType()==OP_BUY) { check=OrderClose(OrderTicket(),OrderLots(),MarketInfo(sym, MODE_BID),huadian); } } } } 以上代碼將訂單的數量賦給了i,之所以要減1是因為MT4的訂單是根據位置從上到下來編號的,而第一個訂單的編號是0,那麼最後一個訂單的編號就是訂單總數減1了,注意,掛單也算在訂單總數里面,所以我們在循環時一定要注意把掛單區別開,否則會把掛單給刪掉。然後我們選擇位置為i的訂單,如果選中了,那麼就繼續判斷,沒有選中那就跳過。選中的情況下,如果這個訂單的品種是”EURUSD”而且是賣單,那麼我們就以買入價平倉,如果這個訂單品種是”EURUSD”而且是買單,那麼我們就以賣出價平倉。
我們運行一下這個腳本,結果如下:

可以看出我們把兩個歐美的訂單平掉了。
理解了這一段代碼其實可以注意到,我們平倉時是從最後一個訂單向前尋找的,那是因為如果需要平掉兩個以上的單子,從前向後尋找訂單有可能會出問題。現在我們來編寫一個從前向後找訂單平倉的腳本,代碼如下:
void OnStart() { int i; string sym= "EURUSD"; int huadian=10; int check; for(i=0;i=<OrdersTotal()-1;i++) { if(OrderSelect(i,SELECT_BY_POS)) { if(OrderSymbol()==sym && OrderType()==OP_SELL) { check=OrderClose(OrderTicket(),OrderLots(),MarketInfo(sym, MODE_ASK),huadian); } else if(OrderSymbol()==sym && OrderType()==OP_BUY) { check=OrderClose(OrderTicket(),OrderLots(),MarketInfo(sym, MODE_BID),huadian); } } } } 我們再試一下程序的效果。如下圖所示,現在有三個訂單,兩個歐美的單子和一個鎊美的單子,按MT4的編號那麼兩張歐美的單子編號分別是0和1,鎊美編號是2,現在從上往下循環平掉歐美的訂單。當i=0時,程序選中了一個單子,確實是歐美的單子,平掉了,結果很好,然後再往下走,i變成了1,接下來我們要選中的是編號為1的單子看看是不是歐美的單子。就在這個時候我們發現,由於之前我們選中的0號單子被平掉了,原來的1號單子變成了現在的0號單子,而原來的2號單子變成了現在的1號單子,於是我們選擇的1號單子就成了鎊美的單子,於是一個循環下來,我們發現我們只平掉了一個歐美的單子,另外一個單子沒有平掉。


那如果我非想用從上到下尋找訂單的方法可不可以?當然可以,你只要在循環的最後加一句i—就行了,原來由於平倉造成的位置錯位就被糾正回來了,代碼如下:
void OnStart() { int i; string sym= "EURUSD"; int huadian=10; int check; for(i=0;i=<OrdersTotal()-1;i++) { if(OrderSelect(i,SELECT_BY_POS)) { if(OrderSymbol()==sym && OrderType()==OP_SELL) { check=OrderClose(OrderTicket(),OrderLots(),MarketInfo(sym, MODE_ASK),huadian); } else if(OrderSymbol()==sym && OrderType()==OP_BUY) { check=OrderClose(OrderTicket(),OrderLots(),MarketInfo(sym, MODE_BID),huadian); } } i--; } } 以上說了這麼多是為了讓大家少走彎路,筆者在剛開始學的時候用的就是從上往下尋找訂單平倉的方法,過了很久才意識到這個方法是有問題的。
當然有人會問,如果是不同的EA下的單子,怎麼篩選出特定EA的單子並平倉?之前已經說過了,EA的單子是可以根據魔術號來識別的,只要在判定條件裡加入OrderMagicNumber()的判斷就可以實現區分不同EA的訂單了。
2修改訂單
有了以上選擇訂單的基礎,我們就可以開始後面的修改訂單的操作了。修改訂單還是比較簡單的,只不過把上面的OrderClose()函數換成OrderModify()函數。函數不用記,看字面意思就知道了,Modify是修改的意思,OrderModify就是修改訂單的意思了。
同樣打開幫助文件查找OrderModify函數,可以看到這個函數需要輸入6個參數,下面一一講解:
第一個參數是訂單的號碼,就是之前的Ticket;
第二個參數是修改後單子的價位,修改掛單的時候用得上;
第三個參數是修改後單子的止損位置;
第四個參數是修改後單子的止盈位置;
第五個參數是修改後單子的持續時間,一般不用,設置為0即可;
第六個參數是修改後顯示的箭頭顏色。
下面我們在EURUSD上開一個多單,然後把它的止損修改到市價以下10個點,再把止盈修改到市價以上10個點,代碼如下:
void OnStart() { int i; string sym= "EURUSD"; double sl=MarketInfo(sym,MODE_BID)-10* ( MarketInfo(sym,MODE_POINT)*10); double tp=MarketInfo(sym,MODE_BID)+10* ( MarketInfo(sym,MODE_POINT)*10); int check; for(i=OrdersTotal()-1;i>=0;i--) { if(OrderSelect(i,SELECT_BY_POS)) { if(OrderSymbol()==sym && OrderType()==OP_BUY) { check= OrderModify (OrderTicket(),OrderOpenPrice(), sl,tp, 0, clrAliceBlue); } } } } 以上代碼中將止損的價格賦給了sl,將止盈的價格賦給了tp,然後挑選訂單,選出歐美的的買單,然後將止損止盈的價格寫入單子中。
這是修改已經開倉的訂單,如果我們要修改掛單,只需要把OrderModify函數的第二個參數改成需要的掛單價格即可,在這裡不作介紹,權且當做大家的課後作業。
下節課我們會介紹一下移動止損和保平止損,之後我們會開始編寫一個簡單的雙均線策略並對其測試,希望之前的基本功大家好好掌握。
更多內容請關注公眾號【火象】~

