Smart Trend Follower

Author: Copyright 2024, Robotop.
Price Data Components
Orders Execution
It automatically opens orders when conditions are reachedChecks for the total of open orders
Indicators Used
Moving average indicatorStochastic oscillator
Miscellaneous
It issuies visual alerts to the screen
0 Views
0 Downloads
0 Favorites
Smart Trend Follower
//+------------------------------------------------------------------+
//|                                         Smart Trend Follower.mq5 |
//|                                         Copyright 2024, Robotop. |
//|                                        https://www.robotop.my.id |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Robotop."
#property link      "https://www.robotop.my.id"
#property version   "1.00"

#property description   "Mengikuti arah tren pasar secara cerdas menggunakan kombinasi sinyal Moving Average dan Stochastic Oscillator"
#property description   "My Telegram : @AutoBotFX"
#property description   "Code MQL : https://t.me/codeMQL"


enum enumJnsSignal{
   eTypeCrossMA,  //Cross 2 MA
   eTypeTrend,    //Follow Trend
};

enum enumOrderType{
   eBuy,    //BUY
   eSell,   //SELL
   eNone = 99, //None
};

input    int         inMagicNumber  = 778899;   //Magic Number
input    double      inLotSize      = 0.01;     //Initial Lot Size
input    double      inMultiply     = 2.0;      //Multiplier
input    int         inJarakLayer   = 200;       //Jarak Layer (pips)

input    enumJnsSignal  inJnsSignal = eTypeCrossMA;    //Signal Type

input    string      strMA          = "===================";      //Moving Average
input    int         inMAPeriodFast = 14;       //MA Fast
input    int         inMAPeriodSlow = 28;       //MA Slow

input    string      strStochastic  = "===================";      //Stochastic Oscillator
input    int         inSTOKPeriod   = 10;       //Sto %K
input    int         inSTODPeriod   = 3;       //Sto %D
input    int         inSTOSlowing   = 3;       //Slowing

input    string      strExit        = "===================";       //Exit Management
input    int         inTakeProfit   = 500;      //Take Profit
input    int         inStopLoss     = 0;       //Stop Loss


struct dataTrades{
   int ttlPos;
   double hargaTA, hargaTB;
   double ttlValue, ttlLot;
   void initial(){
      ttlPos   = 0;
      hargaTA  = hargaTB = 0.0;
      ttlValue = ttlLot = 0.0;
   }
};

int gMAFastHandle, gMASlowHandle, gSTOHandle;
dataTrades trades[2];

double gLotMin, gLotMax,gLotStep, gLotLimit;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{

   if (inLotSize < 0.01){
      Alert ("Initial Lot Size tidak boleh lebih kecil dari 0.01");
      return (INIT_PARAMETERS_INCORRECT);
   }
   
   if (inMAPeriodFast >= inMAPeriodSlow){
      Alert("WARNING:: Period Fast tidak boleh lebih kecil dari Period Slow");
      return (INIT_PARAMETERS_INCORRECT);
   }
   
   gLotMin  = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
   gLotMax  = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
   gLotStep = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
   gLotLimit= SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_LIMIT);
   
   
   gMAFastHandle  = iMA(Symbol(), PERIOD_CURRENT, inMAPeriodFast, 0, MODE_SMA, PRICE_CLOSE);
   gMASlowHandle  = iMA(Symbol(), PERIOD_CURRENT, inMAPeriodSlow, 0, MODE_SMA, PRICE_CLOSE);
   gSTOHandle     = iStochastic(Symbol(), PERIOD_CURRENT, inSTOKPeriod, inSTODPeriod, inSTOSlowing, MODE_SMA, STO_LOWHIGH);
   
   return(INIT_SUCCEEDED);
}
  
  
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   Print ("EA berhenti. Selamat belajar Code EA di MT5");
}
  
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
//---
   ENUM_ORDER_TYPE signal = -1;
   if (isNewCandle() ){
      signal = (ENUM_ORDER_TYPE)GetSignal();
   }
   
   if (signal >= 0){
      manageTrading(signal);
   }
   
   setTPSL();
}
//+------------------------------------------------------------------+


bool isNewCandle(){
   static datetime wktCandle = TimeCurrent();
   bool isNew = false;
   
   if (wktCandle < iTime(Symbol(), PERIOD_CURRENT, 0) ){
      isNew = true;
      wktCandle   = TimeCurrent();
   }
   return (isNew);
}

int GetSignal(){
   int signal = -1;
   
   if (inJnsSignal == eTypeCrossMA){
      //CrossMA
      double maFast[3], maSlow[3];
      CopyBuffer(gMAFastHandle, 0, 0, 3, maFast);
      CopyBuffer(gMASlowHandle, 0, 0, 3, maSlow);
      if (maFast[0] < maSlow[0] && maSlow[1] < maFast[1] ){
         signal   = POSITION_TYPE_BUY;
      }else if (maFast[0] > maSlow[0] && maSlow[1] > maFast[1] ){
         signal   = POSITION_TYPE_SELL;
      }
      
   }else if (inJnsSignal == eTypeTrend){
      //Trending by MA and Confirmed by Stochastic
      double maFast[1], maSlow[1], stoMain[1]; //, stoSignal[1];
      CopyBuffer(gMAFastHandle, 0, 1, 1, maFast);
      CopyBuffer(gMASlowHandle, 0, 1, 1, maSlow);
      CopyBuffer(gSTOHandle, MAIN_LINE, 1, 1, stoMain);
      //CopyBuffer(gSTOHandle, SIGNAL_LINE, 1, 1, stoSignal);
      
      MqlRates rate[];
      CopyRates(Symbol(), PERIOD_CURRENT, 1, 1, rate);
      
      double lvLow = 30.0, lvUp = 70.0;
      if (maFast[0] > maSlow[0] && rate[0].open < rate[0].close && stoMain[0] <= lvLow){
         signal = ORDER_TYPE_BUY;
      }else if (maFast[0] < maSlow[0] && rate[0].open > rate[0].close && stoMain[0] >= lvUp){
         signal = ORDER_TYPE_SELL;
      }
      
   }
   
   return (signal);
}

void manageTrading(ENUM_ORDER_TYPE signal){
   
   if (signal < 0) return;
   
   updateDataTrades();
   double lot  = 0.0;
   if (trades[signal].ttlPos == 0){
      lot   = getLotSize(signal, inLotSize, 0);
      if (lot>=gLotMin) openTrade(signal, lot);
   }else {
      lot   = getLotSize(signal, inLotSize, trades[signal].ttlPos);
      if (signal == ORDER_TYPE_BUY){
         if (trades[signal].hargaTB-(inJarakLayer * Point()) >= SymbolInfoDouble(Symbol(), SYMBOL_ASK) ){
            if (lot>=gLotMin) openTrade(signal, lot);
         }
      }else if (signal == ORDER_TYPE_SELL){
         if (trades[signal].hargaTA+(inJarakLayer * Point()) <= SymbolInfoDouble(Symbol(), SYMBOL_BID) ){
            if (lot>=gLotMin) openTrade(signal, lot);
         }
      }
      
   }
}


void updateDataTrades(){
   int tPos = PositionsTotal();
   trades[eBuy].initial();
   trades[eSell].initial();
   
   for (int i=tPos-1; i>=0; i--){
      if (PositionGetTicket(i) > 0 ){
         if (PositionGetString(POSITION_SYMBOL) == Symbol() && PositionGetInteger(POSITION_MAGIC) == inMagicNumber ){
            ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
            if (trades[type].hargaTA < PositionGetDouble(POSITION_PRICE_OPEN)){
               trades[type].hargaTA = PositionGetDouble(POSITION_PRICE_OPEN);
            }
            if (trades[type].hargaTB > PositionGetDouble(POSITION_PRICE_OPEN) || trades[type].hargaTB == 0.0){
               trades[type].hargaTB = PositionGetDouble(POSITION_PRICE_OPEN);
            }
            trades[type].ttlPos++;
            trades[type].ttlLot  += PositionGetDouble(POSITION_VOLUME);
            trades[type].ttlValue   += PositionGetDouble(POSITION_PRICE_OPEN) * PositionGetDouble(POSITION_VOLUME);
         }
      }
   }
   
}

void openTrade(ENUM_ORDER_TYPE signal, double lotSize){
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};
   
   request.action = TRADE_ACTION_DEAL;
   request.symbol = Symbol();
   request.magic  = inMagicNumber;
   request.type   = signal;
   request.volume = lotSize;
   request.price  = (signal==ORDER_TYPE_BUY)?SymbolInfoDouble(Symbol(), SYMBOL_ASK) : SymbolInfoDouble(Symbol(), SYMBOL_BID);
   if (OrderSend(request, result)){
      Print ("Open berhasil");
   }else{
      Print ("Open Gagal, code: ", result.retcode);
   }

}

void setTPSL(){
   updateDataTrades();
   double bepBuy  = 0.0, bepSell = 0.0;
   double tpBuy = 0.0, slBuy = 0.0, tpSell = 0.0, slSell = 0.0;
   if (trades[eBuy].ttlPos > 0){
      bepBuy   = trades[eBuy].ttlValue / trades[eBuy].ttlLot;
      if (inTakeProfit > 0) tpBuy   = NormalizeDouble(bepBuy + (inTakeProfit * Point() ), Digits() );
      if (inStopLoss > 0) slBuy   = NormalizeDouble(bepBuy - (inStopLoss * Point() ), Digits() );
      
   }
   
   if (trades[eSell].ttlPos > 0){
      bepSell  = trades[eSell].ttlValue / trades[eSell].ttlLot;
      if (inTakeProfit > 0) tpSell   = NormalizeDouble(bepSell - (inTakeProfit * Point() ), Digits() );
      if (inStopLoss > 0) slSell   = NormalizeDouble(bepSell + (inStopLoss * Point() ), Digits() );
   }
   
   int tPos = PositionsTotal();
   for (int i=tPos-1; i>=0; i--){
      ulong ticket   = PositionGetTicket(i);
      //double tp = PositionGetDouble(POSITION_TP);
      //double sl = PositionGetDouble(POSITION_SL);
      if (ticket > 0 && PositionGetString(POSITION_SYMBOL) == Symbol() && PositionGetInteger(POSITION_MAGIC) == inMagicNumber ){
         if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && (PositionGetDouble(POSITION_TP) != tpBuy || PositionGetDouble(POSITION_SL) != slBuy)){
            modifTPSL(ticket, slBuy, tpBuy);
         }else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && (PositionGetDouble(POSITION_TP) != tpSell || PositionGetDouble(POSITION_SL) != slSell)){
            modifTPSL(ticket, slSell, tpSell);
         }
      
      }
   }
   
}

void modifTPSL(ulong ticket, double sl, double tp){
   MqlTradeRequest request = {};
   MqlTradeResult  result = {};
   
   request.action = TRADE_ACTION_SLTP;
   request.position  = ticket;
   //request.symbol = Symbol();
   request.sl     = NormalizeDouble(sl, Digits() );
   request.tp     = NormalizeDouble(tp, Digits() );
   if (OrderSend(request, result) ){
      Print ("Modif TP/SL berhasil");
   }else{
      Print ("Modif TP/SL gagal. ErrCode: ", result.retcode);
   }
}

void validateLot(double &lot){
   lot= MathRound(lot / gLotStep) * gLotStep;
   lot   = (gLotMin > lot )? gLotMin : (gLotMax < lot) ? gLotMax : lot;
   lot   = NormalizeDouble(lot, 2);
}

double getLotSize(ENUM_ORDER_TYPE orderType, double initLotSize, int tPos, string pair=""){
   double lot = 0.0;
   pair = (pair == "")?Symbol() : pair;
   
   lot = initLotSize * MathPow(inMultiply, tPos);
   validateLot (lot);
   if (gLotLimit - (getTotalVolume(pair, orderType)+lot) < 0) lot = 0.0;
   
   lot = CheckMoneyForTrade(pair, lot, orderType)?lot : 0.0;
   
   return (lot);
}

double getTotalVolume(string symbol, int orderType)
{
   double tVol = 0.0;
   string pair;
   int type;
   int tPos = PositionsTotal();
   for (int pos=0; pos<tPos; pos++){
      ulong ticket = PositionGetTicket(pos);
      if (ticket > 0){
         pair  = PositionGetString(POSITION_SYMBOL);
         type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
         if (pair == symbol && type == orderType){
            tVol  += PositionGetDouble(POSITION_VOLUME);
         }
      }
   }
   
   int tOrder = OrdersTotal();
   for (int ord=0; ord<tOrder; ord++){
      ulong ticket = OrderGetTicket(ord);
      if (ticket > 0){
         pair  = OrderGetString(ORDER_SYMBOL);
         type = (ENUM_ORDER_TYPE) OrderGetInteger(ORDER_TYPE);
         if (pair == symbol && (type % 2 == orderType) ){
            tVol  += PositionGetDouble(POSITION_VOLUME);
         }
      }
   }
   
   return (tVol);
}

bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type)
{
   //--- Getting the opening price
   MqlTick mqltick;
   SymbolInfoTick(symb,mqltick);
   double price=mqltick.ask;
   if(type==ORDER_TYPE_SELL)
   price=mqltick.bid;
   //--- values of the required and free margin
   double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   //--- call of the checking function
   if(!OrderCalcMargin(type,symb,lots,price,margin))
   {
      //--- something went wrong, report and return false
      Print("Error in ",__FUNCTION__," code=",GetLastError());
      return(false);
   }
   //--- if there are insufficient funds to perform the operation
   if(margin>free_margin)
   {
      //--- report the error and return false
      Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError());
      return(false);
   }
   //--- checking successful
   return(true);
}

Comments

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---