AI自動交易 #3 – 你必須知道的外匯3種追賺策略 (3/3)

Forex Forest > 程式交易 > AI自動交易 #3 – 你必須知道的外匯3種追賺策略 (3/3)
forexforest.net你必須知道的外匯 3 種追賺策略3.3
forexforest.net你必須知道的外匯 3 種追賺策略3.3

市場上常常充斥著各種追賺策略,但沒有人會告訴你背後的原理,以下將會簡單介紹 3 種你未必清楚了解的追賺策略。

  1. 以步距追賺 (Trailing in Pips)
  2. 以浮盈追賺 (Trailing in Money)
  3. 以隱密步距追賺 (Hidden Trailing in Pips)

3. 以隱密步距追賺 (Hidden Trailing in Pips)

以隱密步距追賺,是“市場上不會告訴你”的追賺策略。為求避免交易商作出不當價位跳動,而導致無故蝕本,以程式監控市場,不經交易商檢查,由程式提出止賺止損,最能保障投資者。

原理跟 (1) 一樣,計算止損盈利目標,隨著盈利上升而推高止損目標,從而達至最佳利潤,並像 (2) 一樣把計算好的價位都儲存起來。以MQL4實現的話則會是以下方式:

  • 設定2個參數,啟動門檻5 pips,追賺距離2 pips

extern double TrailingStart = 5;
extern double TrailingDist = 2;

  • 啟動程式前,先計算價位實際距離(與 (1) 步距追賺同樣做法)
    然而這次不用檢查最低止損距離
    因為止損不會由交易商計算,而是程式內部計算

int pipAdj;
double tstartPipDelta, tslPipDelta;

int init(){
 //PIPS TO PRICE (50 --> 0.00050)
 pipAdj = (Digits%2==1) ? 10 : 1;
 double M_Point = MarketInfo(OrderSymbol(), MODE_POINT);
 double tstartPipDelta = TrailingStart * M_Point * pipAdj;
 double tslPipDelta = TrailingDist * M_Point * pipAdj;
 return(0);
}

  • 準備好儲存當刻的訂單賺價的空間
    (賺價同樣可分3種: 全體賺價、每邊賺價、每單賺價;
     這次選擇了每單賺價作結算,因此儲存格數為1000)

int oCnt; int oTicket[1000]; double tslPrice[1000];

  • 為了方便,設立使用儲存格的指令 (CRUD)
    • find, add, remove, modify

int findRecord(int ticket){
 for(int i = 0; i < oCnt; i++) if(oTicket[i]==ticket) return i;
 return -1;
}

void addRecord(int ticket, double price){
 oTicket[oCnt] = ticket;
 tslPrice[oCnt] = price;
 oCnt++;
}

void removeRecord(int ticket){
 int k = findRecord(ticket);
 if(k == -1) return;
 for(int i = k; i < oCnt - 1; i++){
  oTicket[i] = oTicket[i+1];
  tslPrice[i] = tslPrice[i+1];
 }
 oCnt--;
}

void modifyRecord(int ticket, double price){
 int k = findRecord(ticket);
 if(k == -1) return;
 oTicket[k] = ticket;
 tslPrice[k] = price;
}

  • 每次報價時,檢查現價是否已達到啟動門檻
    (與 (1) 步距追賺同樣做法)

//UPDATE TRAILING
if (OrderType() == OP_BUY){
 int index = findRecord(OrderTicket());
 //TRAILING IF HIT START
 if (Bid - OrderOpenPrice() > tstartPipDelta){ ... }
}else if (OrderType() == OP_SELL){
 int index = findRecord(OrderTicket());
 //TRAILING IF HIT START
 if (OrderOpenPrice() - Ask > tstartPipDelta){ ... }
}

  • 如追賺距離不足,則修改儲存格數值,緊貼價位,保障利潤
    (與 (1) 步距追賺同樣做法,只是修改對象變為內置儲存格)

int index = findRecord(OrderTicket());
//TRAILING IF HIT START
if (Bid - OrderOpenPrice() > tstartPipDelta){
 if(index != -1){
  if (Bid - tslPrice[index] > tslPipDelta){
   modifyRecord(OrderTicket(), Bid - tslPipDelta);
  }
 }else{
  addRecord(OrderTicket(), Bid - tslPipDelta);
 }
}

  • 如市場稍為回調,就作結單,獲取利潤
    (與 (2) 浮盈追賺同樣做法,只是檢查對象變為賺價)

//CLOSE IF HIT TRAILING STOPLOSS
if(index != -1 && Bid < tslPrice[index]){
 OrderClose(OrderTicket(), OrderLots(), Bid, 30, clrYellow);
}

  • 注意事項1: 沽單計算方法略有不同

int index = findRecord(OrderTicket());
//TRAILING IF HIT START
if (OrderOpenPrice() - Ask > tstartPipDelta){
 if(index != -1){
  if (tslPrice[index] - Ask > tslPipDelta){
   modifyRecord(OrderTicket(), Ask + tslPipDelta);
  }
 }else{
  addRecord(OrderTicket(), Ask + tslPipDelta);
 }
}
//CLOSE IF HIT TRAILING STOPLOSS
if(index != -1 && Ask > tslPrice[index]){
 OrderClose(OrderTicket(), OrderLots(), Ask, 30, clrYellow);
}

  • 最後清理儲存格,移除已結訂單

//CLEAR USELESS RECORDS
for (int i = 0; i < oCnt; i++){
 //SELECT ORDER
 if(!OrderSelect(oTicket[i], SELECT_BY_TICKET)) continue;
 if(OrderSymbol() != Symbol()) continue;
 //CLEAR RECORD IF ORDER CLOSED
 if(OrderCloseTime() > 0) removeRecord(oTicket[i]);
}

  • 注意事項2: OrderCloseTime() 可作為判斷結單與否的工具
         未結單是 Close Time = 0; 已結單是 Close Time > 0

//CLEAR RECORD IF ORDER CLOSED
if(OrderCloseTime() > 0) removeRecord(oTicket[i]);

以下是完整代碼 (點擊下載: T01C_Hidden_Trailing_in_Pips)

//+------------------------------------------------------------------+
// Tutorial 1c on Hidden Trailing in Pips
// Copyright 2019, Forex Forest
// http://www.forexforest.net
//+------------------------------------------------------------------+
#property copyright "Forex Forest 2019"
#property link "http://www.forexforest.net/"
#property strict

extern double TrailingStart = 5;  //Trailing Start in Pips
extern double TrailingDist = 2;  //Trailing Distance in Pips

int pipAdj;
double tstartPipDelta, tslPipDelta;
int oCnt; int oTicket[1000]; double tslPrice[1000];

int init(){
 //PIPS TO PRICE (50 --> 0.00050)
 pipAdj = (Digits%2==1) ? 10 : 1;
 double M_Point = MarketInfo(OrderSymbol(), MODE_POINT);
 tstartPipDelta = TrailingStart * M_Point * pipAdj;
 tslPipDelta = TrailingDist * M_Point * pipAdj;
 //CHECK VALID DISTANCE
 /*double MinDist = MarketInfo(Symbol(), MODE_STOPLEVEL) * M_Point;
 if(tslPipDelta < MinDist){
  Alert("Trailing Distance must bigger than Broker Limit: "+MinDist);
  ExpertRemove();
 }*/
 return(0);
}

int deinit(){
 return(0);
}

int findRecord(int ticket){
 for(int i = 0; i < oCnt; i++) if(oTicket[i]==ticket) return i;
 return -1;
}

void addRecord(int ticket, double price){
 oTicket[oCnt] = ticket;
 tslPrice[oCnt] = price;
 oCnt++;
}

void removeRecord(int ticket){
 int k = findRecord(ticket);
 if(k == -1) return;
 for(int i = k; i < oCnt - 1; i++){
  oTicket[i] = oTicket[i+1];
  tslPrice[i] = tslPrice[i+1];
 }
 oCnt--;
}

void modifyRecord(int ticket, double price){
 int k = findRecord(ticket);
 if(k == -1) return;
 oTicket[k] = ticket;
 tslPrice[k] = price;
}

int start(){
 for (int i = 0; i < OrdersTotal(); i++){
  //SELECT ORDER
  if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
  if(OrderSymbol() != Symbol()) continue;

  //UPDATE TRAILING
  if (OrderType() == OP_BUY){
   int index = findRecord(OrderTicket());
   //TRAILING IF HIT START
   if (Bid - OrderOpenPrice() > tstartPipDelta){
    if(index != -1){
     if (Bid - tslPrice[index] > tslPipDelta){
      modifyRecord(OrderTicket(), Bid - tslPipDelta);
     }
    }else{
     addRecord(OrderTicket(), Bid - tslPipDelta);
    }
   }
   //CLOSE IF HIT TRAILING STOPLOSS
   if(index != -1 && Bid < tslPrice[index]){
    OrderClose(OrderTicket(), OrderLots(), Bid, 30, clrYellow);
   }
  }else if (OrderType() == OP_SELL){
   int index = findRecord(OrderTicket());
   //TRAILING IF HIT START
   if (OrderOpenPrice() - Ask > tstartPipDelta){
    if(index != -1){
     if (tslPrice[index] - Ask > tslPipDelta){
      modifyRecord(OrderTicket(), Ask + tslPipDelta);
     }
    }else{
     addRecord(OrderTicket(), Ask + tslPipDelta);
    }
   }
   //CLOSE IF HIT TRAILING STOPLOSS
   if(index != -1 && Ask > tslPrice[index]){
    OrderClose(OrderTicket(), OrderLots(), Ask, 30, clrYellow);
   }
  }
 }

 //CLEAR USELESS RECORDS
 for (int i = 0; i < oCnt; i++){
  //SELECT ORDER
  if(!OrderSelect(oTicket[i], SELECT_BY_TICKET)) continue;
  if(OrderSymbol() != Symbol()) continue;
  //CLEAR RECORD IF ORDER CLOSED
  if(OrderCloseTime() > 0) removeRecord(oTicket[i]);
 }

 return(0);
}

以上純粹興趣分享和介紹,報讀我們的程式交易課程並不需要認識和學習如何編程,我們是教已編好的程式在市場上獲利的方法和技巧,程式的使用方法比編程更重要,歡迎了解我們的簡介活動或入門班。

請即報讀

自動交易程式課程 (全方位課程)