Trying to create an Expert using Envelopes. Cant get it to work as I am a newb. Please help - page 2

 
Tobias Johannes Zimmer #:
The last posts were about this: A buy position is opened by a buy deal with ask price, but closed by a sell deal with bid price and vis versa.

So you have to calculate tp/sl from bid price for a buy and from ask price for a sell position.
Otherwise it would be inaccurate by the span of the spread which can be quite considerate.
ceejay1962 #:

Not related to your question, but I note that you are calling iBands/iEnvelopes in the OnTick() loop. This is not recommended - You should only call them once from OnInit() then reference the handle in OnTick().

Thank you for your time and the responses. Please bear with me as I'm trying to understand how this works. 

@ceejay1962 Thanks for the advice, ill take it into consideration. I am going to figure out how that works.

@Tobias Johannes Zimmer Thank you for clearing that out for me.

 
Welcome.
 

I managed to get it somewhat working how I'd like it to :)

//+------------------------------------------------------------------+
//|                                                        LMRv2.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include<Trade/Trade.mqh>

//-- Order Info
CTrade trade;
CPositionInfo positionInfo;
double AccountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
int TotalOpenOrders = PositionsTotal();
datetime m_previous_bars = 0;
bool OpenOnNewBar = true;
datetime ArrayTime[], LastTime;
input double TakeProfit = 1000;
//double StopLoss = 100;
//-- Order Management
input double TrailingStopStart = 60;
input double TrailingStop = 10;
bool AutoLot = true;
double MaxLot = 100;
double Lots;
double LotsPer5K = 0.01;
//--Indi Input Param
input int BBperiod = 5;
input int BBdev = 2;
input int BBshift = -1;
input int ENVperiod = 3;
input double ENVpercent = 0.07;
input int ENVshift = 0;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool NewBar(int period)
  {
   bool firstRun = false, newBar = false;
   ArraySetAsSeries(ArrayTime, true);
   CopyTime(Symbol(), Period(), 0, 2, ArrayTime);
   if(LastTime == 0)
      firstRun = true;
   if(ArrayTime[0] > LastTime)
     {
      if(firstRun == false)
         newBar = true;
      LastTime = ArrayTime[0];
     }
   return newBar;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//-- Automatic Lot Sizing
double MM_Size()
  {
   if(AutoLot==false)
      Lots=MaxLot;
   if(AutoLot==true && Lots < MaxLot)
      Lots = ((AccountBalance / 100)*LotsPer5K);
   if(Lots < 0.01)
      Lots=0.01;
   return(Lots);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
//-- Price Information Array
   MqlRates PriceInformation[];
   ArraySetAsSeries(PriceInformation,true);
   int PriceData = CopyRates(Symbol(),Period(),0,Bars(Symbol(),Period()),PriceInformation);
//-- Opened Positions
   double Bid;
   double Ask;
   double Spread;
   Bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
   Ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   Spread = (Bid-Ask);
//-- Order SL/TP Calc
   double BUYTakeProfitLVL = Bid + TakeProfit*Point();
   double BUYStopLossLVL = PriceInformation[1].low - Spread;
   double SELLTakeProfitLVL = Ask - TakeProfit*Point();
   double SELLStopLossLVL = PriceInformation[1].high + Spread;
//-- TrailingStop                
   if(TrailingStop > 0 && TrailingStopStart > 0)
      for(int i = PositionsTotal()-1; i >=0; i--)
        {
         ulong ticket = PositionGetTicket(i);
         if(PositionSelectByTicket(ticket))
           {
            double posOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
            double possl = PositionGetDouble(POSITION_SL);
            double postp = PositionGetDouble(POSITION_TP);
            if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
              {
               if(Bid > posOpenPrice + TrailingStopStart * Point())
                 {
                  double sl = Bid - TrailingStop * Point();
                  if(sl > possl)
                    {
                     trade.PositionModify(ticket, sl, postp);
                    }
                 }
              }
            else
               if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
                 {
                  if(Ask < posOpenPrice - TrailingStopStart * Point())
                    {
                     double sl = Ask + TrailingStop * Point();
                     if(sl < possl)
                       {
                        trade.PositionModify(ticket, sl, postp);
                       }
                    }
                 }
           }
        }

//ENVELOPE SIGNAL
//-- Envelope Array
   bool EnvelopePriceAtUpperBand = false;
   bool EnvelopePriceAtLowerBand = false;
   double ENVUpperBandArray[];
   double ENVLowerBandArray[];
   ArraySetAsSeries(ENVUpperBandArray,true);
   ArraySetAsSeries(ENVLowerBandArray,true);
//-- Envelope Indicator
   int Envelopes = iEnvelopes(Symbol(),Period(),ENVperiod,ENVshift,MODE_SMA,PRICE_CLOSE,ENVpercent);
   CopyBuffer(Envelopes,0,0,3,ENVUpperBandArray);
   CopyBuffer(Envelopes,1,0,3,ENVLowerBandArray);
   double ENVUpperBandValue=NormalizeDouble(ENVUpperBandArray[0],6);
   double ENVLowerBandValue=NormalizeDouble(ENVLowerBandArray[0],6);
//-- Envelope Signal
   if(PriceInformation[1].high > ENVUpperBandValue)
      EnvelopePriceAtUpperBand = true; // sell
   if(PriceInformation[1].low < ENVLowerBandValue)
      EnvelopePriceAtLowerBand = true; // buy
//BOLLINGERBANDS
//-- Bollinger Bands Array
   bool BBPriceAtUpperBand = false;
   bool BBPriceAtLowerBand = false;
   double BBUpperBandArray[];
   double BBLowerBandArray[];
   ArraySetAsSeries(BBUpperBandArray,true);
   ArraySetAsSeries(BBLowerBandArray,true);
//-- Bollinger Bands Indi
   int BollingerBands = iBands(Symbol(),Period(),BBperiod,BBshift,BBdev,PRICE_CLOSE);
   CopyBuffer(BollingerBands,1,0,3,BBUpperBandArray);
   CopyBuffer(BollingerBands,2,0,3,BBLowerBandArray);
   double BBUpperBandValue = NormalizeDouble(BBUpperBandArray[0],6);
   double BBLowerBandValue = NormalizeDouble(BBLowerBandArray[0],6);
//-- Bollinger Bands Signal
   if(PriceInformation[1].high > BBUpperBandValue)       //BB 1 or 2???
      BBPriceAtUpperBand = true; // sell
   if(PriceInformation[1].low < BBLowerBandValue)
      EnvelopePriceAtLowerBand = true; // buy

   if(NewBar(_Period))
     {
      if(EnvelopePriceAtUpperBand == true && BBPriceAtUpperBand == true)
         trade.Sell(MM_Size(),NULL,Bid,SELLStopLossLVL,SELLTakeProfitLVL,NULL);
      if(EnvelopePriceAtLowerBand == true && BBPriceAtLowerBand == true)
         trade.Buy(MM_Size(),NULL,Ask,BUYStopLossLVL,BUYTakeProfitLVL,NULL);
     }


// its not placing buy orders!!




  }




//+------------------------------------------------------------------+

// not opening orders when i think it should
// mm lotsizing prob not correct, wont update
//grid
//time filter (1500-2200)??




//+------------------------------------------------------------------+

I thought I would just share it with the community as it turns out to be a pretty decent strategy.. according to backtest.. Im still trying to figure out on how to optimise the code so it can Backtest quicker.. im assuming its due to me putting everything on the OnTick function? 

 
Quick update! I finally got it exactly how i wanted! Thank you all for the advice, it really kept me going. The expert is definitely worth checking out. I got some insane back tests 100% history quality.
//+------------------------------------------------------------------+
//|                                                          LMR.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <Trade/Trade.mqh>

//-- Positions
input string POSITION_INPUT = "POSITION PARAMETERS";
input bool AutomaticLot = true;
input double MaxLot = 900;
input double LotsPer1K = 0.1;
input string MM_OFF = "Lot sizing when Automatic Lot = False";
input double Lots = 0.1;
input double TakeProfit = 100000;
input double TrailingStopStart = 50;
input double TrailingStop = 10;
//-- Indicator Inputs
//bollinger bands
input string BB_SETTINGS = "BOLLINGER BANDS";
input ENUM_TIMEFRAMES bbTimeframe = PERIOD_CURRENT;
input int bbPeriod = 3;
input int bbShift = -1;
input int bbDeviation = 2;
//envelope
input string ENVELOPE_SETTINGS = "ENVELOPE";
input ENUM_TIMEFRAMES envTimeframe = PERIOD_CURRENT;
input int envPeriod = 3;
input int envShift = 0;
input double envDeviation = 0.07;
//indicator handles
int handleBB;
int handleENV;
int barsTotal;
int TotalOpenOrders = PositionsTotal();
//-- New Bar Check
datetime m_previous_bars = 0;
bool OpenOnNewBar = true;
datetime ArrayTime[], LastTime;

double bid;
double ask;
CTrade trade;
CPositionInfo positionInfo;


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//--check for new candle to open trade
bool NewBar(int period)
  {
   bool firstRun = false, newBar = false;
   ArraySetAsSeries(ArrayTime, true);
   CopyTime(Symbol(), Period(), 0, 2, ArrayTime);
   if(LastTime == 0)
      firstRun = true;
   if(ArrayTime[0] > LastTime)
     {
      if(firstRun == false)
         newBar = true;
      LastTime = ArrayTime[0];
     }
   return newBar;
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   barsTotal = iBars(Symbol(),PERIOD_CURRENT);
   handleBB = iBands(Symbol(),bbTimeframe,bbPeriod,bbShift,bbDeviation,PRICE_CLOSE);
   handleENV = iEnvelopes(Symbol(),envTimeframe,envPeriod,envShift,MODE_SMA,PRICE_CLOSE,envDeviation);

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {


  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   double MM_Size = 0.01;
   if(AutomaticLot == false)
     {
      MM_Size = Lots;
     }
     else
   if(AutomaticLot == true)
     {
      MM_Size = MathRound(AccountInfoDouble(ACCOUNT_BALANCE)  / 1000 * LotsPer1K * 100) / 100;
      if(MM_Size > MaxLot)
         MM_Size = MaxLot;
      if(MM_Size < 0.01)
         MM_Size = 0.01;
     }
     
   bid = SymbolInfoDouble(Symbol(),SYMBOL_BID);
   bid = NormalizeDouble(bid,_Digits);
   ask = SymbolInfoDouble(Symbol(),SYMBOL_ASK);
   ask = NormalizeDouble(ask,_Digits);

   if(TrailingStop > 0 && TrailingStopStart > 0)
      for(int i = PositionsTotal()-1; i >=0; i--)
        {
         ulong ticket = PositionGetTicket(i);
         if(PositionSelectByTicket(ticket))
           {
            double posOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
            double possl = PositionGetDouble(POSITION_SL);
            double postp = PositionGetDouble(POSITION_TP);
            if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
              {
               if(bid > posOpenPrice + TrailingStopStart * Point())
                 {
                  double sl = bid - TrailingStop * Point();
                  if(sl > possl)
                    {
                     trade.PositionModify(ticket, sl, postp);
                    }
                 }
              }
            else
               if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
                 {
                  if(ask < posOpenPrice - TrailingStopStart * Point())
                    {
                     double sl = ask + TrailingStop * Point();
                     if(sl < possl)
                       {
                        trade.PositionModify(ticket, sl, postp);
                       }
                    }
                 }
           }
        }
//-- New bar
   if(NewBar(_Period))
     {
      double bbUpper[], bbLower[], bbMiddle[];
      double envUpper[], envLower[];
      CopyBuffer(handleBB,1,0,2,bbUpper);
      CopyBuffer(handleBB,2,0,2,bbLower);
      CopyBuffer(handleENV,0,0,2,envUpper);
      CopyBuffer(handleENV,1,0,2,envLower);
      //-- Bar Information
      double open = iOpen(Symbol(),PERIOD_CURRENT,1);
      double close = iClose(Symbol(),PERIOD_CURRENT,1);
      double low = iLow(Symbol(),PERIOD_CURRENT,1);
      double high = iHigh(Symbol(),PERIOD_CURRENT,1);

      double spread = (ask - bid); // = positive value
      spread = NormalizeDouble(spread,_Digits);
      //SL and TP lvl
      double BUYTakeProfitLVL = bid + TakeProfit*Point();
      double BUYStopLossLVL = low /*- Spread*/;
      double SELLTakeProfitLVL = ask - TakeProfit*Point();
      double SELLStopLossLVL = high /*+ Spread*/;

      //--Indicator signal trades
      if(high > bbUpper[0] && high > envUpper[0]) //sell
         trade.Sell(MM_Size,Symbol(),bid,SELLStopLossLVL,SELLTakeProfitLVL,NULL);
      if(low < bbLower[0] && low < envLower[0]) //buy
         trade.Buy(MM_Size,Symbol(),ask,BUYStopLossLVL,BUYTakeProfitLVL,NULL);
     }






  }
//+------------------------------------------------------------------+
Reason: