My MQL4 Journal

Discussion in 'Journals' started by expiated, Jul 14, 2021.

  1. expiated

    expiated

    MQL4 Technical Indicator Functions

    All indicator functions have at least 2 parameters: symbol and period. The NULL value of the symbol means the current symbol, and the 0 value of the period means the current time frame.

    ScreenHunter_10683 Aug. 29 06.21.jpg

    What's new in MQL5?

    In MQL5, the number of built-in technical indicators has been increased from 30 to 38. The indicators are generated and managed using handles to avoid unnecessary copies and reduce memory consumption. For the same purpose, new functions for working with indicators and timeseries are presented—they allow receiving indicator values in entire arrays rather than by a single value.
     
    #61     Aug 29, 2021
  2. expiated

    expiated

    BACK TO CODING A BOLLINGER BAND RE-ENTRY EXPERT ADVISOR STEP BY STEP:

    upload_2021-8-30_9-19-10.png


    As you can see from the above image, I am declaring two variables inside this bool IsNewBar() function, beginning with the open time for the current bar.

    I start by indicating that this variable type is datetime, which is followed by the currentBarTime, and I am using the iTime function, passing in the Symbol from the current chart, with the Period from the current chart as the time frame; and finally, I am asking for the open time of bar number zero (0), with bar zero being the currently open bar.

    (Of course, bar number 1 is the bar that preceded it, and bar number 2 is the bar that closed before bar number 1, and so on.)

    And then, I am also declaring a datetime variable called Previous Bar Time (or prevBarTime). And I am declaring this to be a static. I have initialized this prevBarTime to be (equal to or the same as) currentBarTime, which is coming from the currentBarTime value in the statement directly above. But, by calling it static, once the expert advisor is started, this initialization only happens the FIRST time that this function is called.

    Each time the program comes to this function AFTER that, prevBarTime will have the same value it had when the function was exited earlier.

    So, the function is simply saying: "If the previous bar time is less than the current bar time, then we must have opened a new bar." And in that case, I am updating previous bar time to be the new current bar time.

    Again, this value is going to be stored and will be the same the next time that the EA comes into this loop. So, it is updated to be the new current bar time, and returns true. And this informs the program that the new bar has formed.

    If prev bar time is not less than the current bar time, then it simply returns false, and this will not change.

    So, that is the new bar function. And by making this call (if !IsNewBar) then the EA is simply going to return (which means the OnTick will be called) and exit, and will not flow through to the next statement until it has a new bar.
     
    #62     Aug 30, 2021
  3. expiated

    expiated

    CODING A BOLLINGER BAND RE-ENTRY EXPERT ADVISOR STEP BY STEP CONTINUED:

    Now I need to go back up to if (!IsNewBar()) return; and begin to capture some values from the candle that has just closed, starting with the candle’s closing price. So, here I am calling the iCLose function, passing the Symbol and the Period, and I am looking at bar number 1, the bar that has just closed.

    upload_2021-8-31_9-19-16.png

    And then I also want the high and the low values, because if I do execute a trade, I will be trading buy just above the high of the bar that is closed, and I will be trading sell just before the low of the bar that was closed. So accordingly, I am calling the iHigh and the iLow functions.

    Again, I am passing in the chart symbol and period, and I am looking at bar number 1. So, this will give me the high, low, and close values of the bar that has just closed.

    Next, I want to get the value of the upper line of the Bollinger band...

    upload_2021-8-31_9-23-49.png

    So, I have declared a type double and named it upper1, because this is going to be the upper bar that has just closed. There is an inbuilt technical indicator function called iBands that takes arguments of the Symbol and the time frame (Period). I also input the number of periods for the bands (InpBandsPeriods) as well as the number of deviations (InpBandsDeviations). There is also a shift which is more applicable if you are viewing this on screen, which I set to zero (0) because I do not need it. On the next line I input the applied price as well (InpBandsAppliedPrice), after which I called MODE_UPPER to get the upper band. And finally, I am saying I want this for bar number 1, which of course, is the bar that just closed.

    I also want the lower band (lower1). Again, this is type double and is almost exactly the same, except that here I am changing MODE_UPPER to MODE_LOWER, and that will give me the lower Bollinger band.

    And then because I will be making a comparison with the bar before this in order to see if the asset has first closed outside the Bollinger bands and then closed back inside the Bollinger bands, I also want to calculate the close for the bar number 2. This is the same as before, but I am just using 2 as the input for bar number.

    double close2 = iClose(Symbol(), Period(), 2)

    Again, I want the upper and lower bands for bar number 2, and will again have mode upper and mode lower. But, at the very end of these lines of code, I am passing bar number 2 rather than bar number 1.

    upload_2021-8-31_9-58-21.png

    And now I need a test for trading: If bar number 2 closed above the upper band number two, AND bar number 1 closed below the upper band number 1, then I am looking at a re-entry from above, and that means that I am executing sell...

    if (close2>upper2 && close1<upper1)

    So then, I am going to call my open order function, passing in order type sell stop. And the price that I am going to be executing the sell stop at is low number 1, which is the low of the bar just closed. And I am also passing in this difference between the upper and the lower, because I want to calculate the take profit and stop loss based on number of bands.

    OpenOrder(ORDER_TYPE_SELL_STOP, low1, (upper1-lower1))

    This open order is not another custom function, so I am going to go down and look at that now before I go any further...

    upload_2021-8-31_10-3-31.png

    This is the beginning of the open order function. It is a type integer because it will return the ticket number for the order that is opened.

    First argument is the order type that I want to execute. Then I have the price that I want to open the order at, and the channel width, which on line #78 you will see I passed in upper1 minus lower1...

    upload_2021-8-31_10-6-57.png

    ...so, it is the total channel width.

    Then I want to calculate the size of one deviation, because my take profit and stop loss are based on one deviation.

    upload_2021-8-31_10-9-46.png

    So, single deviation is the total channel width divided by two times the input for number of deviations. So, by default, I am saying that I am setting the bands at two deviation. That means that the upper band is two above the middle, and the lower band is two below the middle. So, that would give me a total width of four deviations.

    (A single deviation is two times the band deviation.)

    So then, the take profit amount is just a single deviation multiplied by the number of take profit deviations, and the stop loss size is a single deviation multiplied by the number of stop-loss deviations.

    And then I am also calculating the expiry time. (Remember that these stop orders are going to expire at the end of the current candle.) So, for the expiry time I am getting the iTime ( Symbol, Period, ); which is the open time for the current chart symbol for the current period for bar number 0.

    And PeriodSeconds with no arguments "()" will give me the total number of seconds in this bar. And then I am just subtracting one second (-1). So, this is for the bar start time plus the number of seconds in this bar, minus one, which means that this expiry time is just before the next bar opens.
     
    Last edited: Aug 31, 2021
    #63     Aug 31, 2021
  4. I fear that you have some mistakes in line #81. It looks like that you copied line #76 and forgot to inverse > and <. I think that the two conditions should be "close2<lower2" and "close1>lower1" as you want to determine that the price went from below the Bollinger band to into the band.

    MQL5 has a built-in function called OpenOrder() but I don't know whether it is available in MQL4. So at first I thought you were going to use that one. From your description it seems that you are defining a function yourself, using the same name.
     
    #64     Aug 31, 2021
    expiated likes this.
  5. There is OrderOpen() in MQL5 (not OpenOrder) which is an operation of the CTrade class.
     
    #65     Aug 31, 2021
  6. Indeed, that's the one I was referring to. I must have remembered the function name incorrectly.
     
    #66     Aug 31, 2021
  7. expiated

    expiated

    Thanks, you're right. (I did the same thing on line #136 when I copied it from line #125.).:(
     
    #67     Sep 1, 2021
  8. Don't worry: you didn't share line #136 with us, so we didn't see that.
     
    #68     Sep 1, 2021
  9. expiated

    expiated

    Wednesday /September 1, 2021

    This morning, in the process of looking for ways to quantify my manual trades such that they might be automated, I stumbled across a strategy that I think could work on my one-hour charts. This resulted in a strong desire to be able to code the corresponding expert advisor right now!

    I failed to find a step-by-step "code an EA" instructional video on YouTube that was close enough to my own system that it might enable me to figure out how to adapt it to the way I trade with what little I know at this time, but I did happen across an EABuilder video that led me to check out their website.

    Using their free service, I was able to generate the indicator below for the first half of my strategy—the position entries—and I was able to do so in just a couple of minutes...

    upload_2021-9-1_11-39-46.png

    For the other half of the strategy—the position exits—I am going to need an EA, and given that their software seemed to worked pretty much as designed, requiring only a couple of minor corrections on my part, I am very likely to risk shelling out the $97 for full access.

    If the service turns out to be legitimate (and every indication suggests this is the case), in the long run, it will be a lot cheaper than paying freelancers at Upwork or Fiverr every time I come up with another idea for a profitable expert advisor, plus I won't have to worry about anyone else stealing my intellectual property, not to mention that the service should quickly pay for itself if this first EA is as profitable as I believe it will be.
     
    #69     Sep 1, 2021
  10. expiated

    expiated

    CODING A BOLLINGER BAND RE-ENTRY EXPERT ADVISOR STEP BY STEP CONTINUED:

    Next, I am going to set up my prices...

    upload_2021-9-1_18-14-56.png

    For the entry price, I am performing this NormalizedDouble, because the entryPrice passed in might not be exactly the right format for MetaTrader to use, so it is always a good idea to use NormalizedDouble.

    entryPrice = NormalizeDouble(entryPrice, Digits());

    So, I am applying the NormalizedDouble function against the passed in entryPrice, and Digits() is a standard function that will tell me how many digits are applicable to the current symbol. This will create a price that I can use for executing new trades.

    Next I am creating three variables: take profit price, stop loss price, and a working value of price. I am just initializing those to zero...

    double tpPrice = 0.0;
    double slPrice = 0.0;
    double price = 0.0;


    Next, I am calculating this double value that I am calling stopsLevel.

    double stopsLevel = Point()*SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);

    In MetaTrader4 there is a certain limit where you cannot execute a stop order if the current market price is too close to the price where you want to place that trade. So, I need to know how far away that is, and this stopsLevel is multiplying the internal variable Point(), which gives me the size of a point for the current symbol.

    And then I am using the SymbolInfoInteger, passing in the current Symbol, and asking for this SYMBOL_TRADE_STOPS_LEVEL.

    That SymbolInfoInteger returns the number of points away from the market price where I can place a stop order. So, by multiplying that by Point(), I get a double value that tells me how close the current price can be.
     
    #70     Sep 1, 2021