//+------------------------------------------------------------------+ //| ProfitTrailing.mq4 | //| Moggy | //| moggylew@hotmail.com | //+------------------------------------------------------------------+ #property copyright "Moggy" #property link "moggylew@hotmail.com" #property version "1.00" #property strict #define MAXORDERSCNT 100 #define TICKET_INVALID -860228 #define ORDER_TYPE_INVALID -1 #define PROFIT_SL_INVALID -140523 #define PROFIT_TP_INVALID 140523 extern double minlots = 0.01; extern double minlotsprofittrailingsl = 2.20; extern double minlotsprofittp = 5.00; extern int slippage = 1; int arrOrderTicket[MAXORDERSCNT];//record all tickets double arrOrderOpenPrice[MAXORDERSCNT];//record all tickets open price int arrOrderType[MAXORDERSCNT];//record all tickets order type double arrOrderProfit[MAXORDERSCNT];//record all order profits double arrOrderProfitSL[MAXORDERSCNT];//record all order profits stoploss double arrOrderProfitTP[MAXORDERSCNT];//record all order profits takeprofit //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { InitOrderArr(); //--- create timer if(!EventSetTimer(2)) { printf("OnInit EventSetTimer error:" + (string)GetLastError()); return INIT_FAILED; } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- UpdateOrderArr(); CheckForCloseOrder(); } //+------------------------------------------------------------------+ //| Tester function | //+------------------------------------------------------------------+ double OnTester() { //--- double ret=0.0; //--- //--- return(ret); } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- } //+------------------------------------------------------------------+ void InitOrderArr() { //clear arrs for(int idx = 0;idx < MAXORDERSCNT;idx++) { arrOrderTicket[idx] = TICKET_INVALID; arrOrderOpenPrice[idx] = 0; arrOrderType[idx] = ORDER_TYPE_INVALID; arrOrderProfit[idx] = 0; arrOrderProfitSL[idx] = PROFIT_SL_INVALID; arrOrderProfitTP[idx] = PROFIT_TP_INVALID; } } //+------------------------------------------------------------------+ //| update all current tickets and other array | //| ***important:this should not be called inside some for clause*** | //| ***because the OrderSelect func maybe confused*** | //+------------------------------------------------------------------+ void UpdateOrderArr() { //local arr to record latest order ticket int latestarrOrderTicket[MAXORDERSCNT]; //init for(int latestinitidx = 0;latestinitidx < MAXORDERSCNT;latestinitidx++) { latestarrOrderTicket[latestinitidx] = TICKET_INVALID; } //fill the latestarrOrderTicket for(int latestidx = 0;latestidx < OrdersTotal();latestidx++) { if(OrderSelect(latestidx,SELECT_BY_POS,MODE_TRADES)==false) break; latestarrOrderTicket[latestidx] = OrderTicket(); } //reset arr when order closed(exist in arrOrderTicket but not in latestarrOrderTicket) for(int resetidx = 0;resetidx < MAXORDERSCNT;resetidx++) { if(TICKET_INVALID != arrOrderTicket[resetidx]) { bool shouldreset = true; for(int latestidx = 0;latestidx < MAXORDERSCNT;latestidx++) { if((arrOrderTicket[resetidx] == latestarrOrderTicket[latestidx]))//found,the order is still open { shouldreset = false; break; } } if(shouldreset)//not found,should reset { arrOrderTicket[resetidx] = TICKET_INVALID; arrOrderOpenPrice[resetidx] = 0; arrOrderType[resetidx] = ORDER_TYPE_INVALID; arrOrderProfit[resetidx] = 0; arrOrderProfitSL[resetidx] = PROFIT_SL_INVALID; arrOrderProfitTP[resetidx] = PROFIT_TP_INVALID; } } } //update exist order's arrOrderProfitSL,or insert if order newly opened for(int idx = OrdersTotal() - 1;idx >= 0;idx--) { if(OrderSelect(idx,SELECT_BY_POS,MODE_TRADES)==false) break; int orderticket = OrderTicket(); bool ticketexist = false; int ticketfindidx = 0; for(ticketfindidx = 0; ticketfindidx < MAXORDERSCNT;ticketfindidx++)//find if orderticket exist in arr { if((TICKET_INVALID != arrOrderTicket[ticketfindidx]) && (orderticket == arrOrderTicket[ticketfindidx])) { ticketexist = true; break; } } if(!ticketexist)//not exist,newly add { for(int ticketinvalid = 0; ticketinvalid < MAXORDERSCNT;ticketinvalid++)//find an invalid position and add it { if(TICKET_INVALID == arrOrderTicket[ticketinvalid])//find the first invalid ticket and add it { arrOrderTicket[ticketinvalid] = orderticket; arrOrderOpenPrice[ticketinvalid] = OrderOpenPrice(); arrOrderType[ticketinvalid] = OrderType(); arrOrderProfit[ticketinvalid] = OrderProfit(); if((OrderProfit() > 0) && (OrderProfit() > ((OrderLots()/minlots)*minlotsprofittrailingsl))) { arrOrderProfitSL[ticketinvalid] = OrderProfit() - ((OrderLots()/minlots)*minlotsprofittrailingsl); } arrOrderProfitTP[ticketinvalid] = (OrderLots()/minlots)*minlotsprofittp; break; } } }else//exist,update the arrOrderProfitSL if necessary { //import:ticketfindidx is the find ticket index,update here if((OrderProfit() > 0) && (OrderProfit() > ((OrderLots()/minlots)*minlotsprofittrailingsl)) && (PROFIT_SL_INVALID != arrOrderProfitSL[ticketfindidx]) && (arrOrderProfitSL[ticketfindidx] < OrderProfit() - ((OrderLots()/minlots)*minlotsprofittrailingsl)) ) { arrOrderProfitSL[ticketfindidx] = OrderProfit() - ((OrderLots()/minlots)*minlotsprofittrailingsl); } arrOrderProfitTP[ticketfindidx] = (OrderLots()/minlots)*minlotsprofittp;//if exist,this line could be deleted,no side effect } } //Testing /*for(int testidx = 0;testidx < MAXORDERSCNT;testidx++) { if(TICKET_INVALID != arrOrderTicket[testidx]) { printf("ticket:" + (string)arrOrderTicket[testidx] + " openprice:" + (string)arrOrderOpenPrice[testidx] + " sl:" + (string)arrOrderProfitSL[testidx] + " tp:" + (string)arrOrderProfitTP[testidx]); } if(PROFIT_SL_INVALID != arrOrderProfitSL[testidx]) { if(OrderSelect(arrOrderTicket[testidx],SELECT_BY_TICKET,MODE_TRADES)==false) break; printf("testidx:%d symbol:%s lot:%f arrOrderProfitSL:%f arrOrderProfitTP:%f",testidx,OrderSymbol(),OrderLots(),arrOrderProfitSL[testidx],arrOrderProfitTP[testidx]); } }*/ } void CheckForCloseOrder() { int idx = 0; printf("ProfitTrailing CheckForCloseOrder"); for(idx = 0;idx < MAXORDERSCNT;idx++) { if(TICKET_INVALID != arrOrderTicket[idx]) { if(OrderSelect(arrOrderTicket[idx], SELECT_BY_TICKET, MODE_TRADES)==false) break; if(OrderType() == OP_BUY || OrderType() == OP_SELL)//filled order { if(((PROFIT_SL_INVALID != arrOrderProfitSL[idx]) && (OrderProfit() < arrOrderProfitSL[idx])) || (OrderProfit() > arrOrderProfitTP[idx])) { double currsymbolbid = MarketInfo(OrderSymbol(),MODE_BID); double currsymbolask = MarketInfo(OrderSymbol(),MODE_ASK); if(OrderType() == OP_BUY) { if(!OrderClose(OrderTicket(), OrderLots(), currsymbolbid, slippage, CLR_NONE)) { printf("Buy Order %d close failed:%d",OrderTicket(),GetLastError()); } }else//sell order { if(!OrderClose(OrderTicket(), OrderLots(), currsymbolask, slippage, CLR_NONE)) { printf("Sell Order %d close failed:%d",OrderTicket(),GetLastError()); } } return ;//close one for each timer } } } } }