Could someone check me on this code using CopyBuffer() and ArrayCopy()?

 

Again, cloned from https://www.mql5.com/en/docs/indicators/ima, modified because I'm going to try doing calculations on the series of iMA values, so I need to save new data as they develop every tick and I'd rather not copy the entire timeseries once for every tick (which could be some incredible overhead when ticks are flying in fast and furious, lol.)

The whole code is here, but the code I'm asking about is lines 147-152 (set off with white space).

(EDIT: no idea why the spacing turned out like it did, I fixed it. Would be nice if the input code feature had an option so that it showed line numbers. I had to put them in elsewhere and paste the results.)


1   //+------------------------------------------------------------------+
2   //|                                                     Test iMA.mq5 |
3   //|                                  Copyright 2021, MetaQuotes Ltd. |
4   //|                                             https://www.mql5.com |
5   //+------------------------------------------------------------------+
6   #property copyright "Copyright 2021, MetaQuotes Ltd."
7   #property link      "https://www.mql5.com"
8   #property version   "1.00"
9   #property indicator_separate_window
10   #property strict
10   
11   #property indicator_buffers 1
12   #property indicator_plots   1
13   //--- the iMA plot
14   #property indicator_label1  "iMA Slope"
15   #property indicator_type1   DRAW_LINE
16   #property indicator_color1  clrRed
17   #property indicator_style1  STYLE_SOLID
18   #property indicator_width1  3
19   enum Creation
20     {
21      Call_iMA,               // use iMA
22      Call_IndicatorCreate    // use IndicatorCreate
23     };
24   input Creation             type=Call_iMA;                // type of the function 
25   input int                  ma_period=15;                 // period of ma
26   input int                  ma_shift=0;                   // shift
27   input ENUM_MA_METHOD       ma_method=MODE_EMA;           // type of smoothing
28   input ENUM_APPLIED_PRICE   applied_price=PRICE_CLOSE;    // type of price
29   input int                  slope_period=3;               // Period for calculating slope, # periods (price points -1)
30   input string               symbol=" ";                   // symbol 
31   input ENUM_TIMEFRAMES      period=PERIOD_CURRENT;        // timeframe
32   double         dBfr_iMA[];
33   double         dBfr_iMA_Slope[];
34   int    iHndl_iMA;
35   int    iInd_BFRX = 0;
36   string sSym=symbol;
37   string sShortName;
38   int    iBars_Calc_CNT=0;
39   //+------------------------------------------------------------------+
40   //| Custom indicator initialization function                         |
41   //+------------------------------------------------------------------+
42   int OnInit()
43   {
44      SetIndexBuffer(0,dBfr_iMA_Slope,INDICATOR_DATA);
45      PlotIndexSetInteger(0,PLOT_SHIFT,ma_shift);   
46      sSym=symbol;
47      StringTrimRight(sSym);
48      StringTrimLeft(sSym);
49      if(StringLen(sSym)==0)
50        {
51         sSym=_Symbol;
52        }
53      if(type==Call_iMA)
54         iHndl_iMA=iMA(sSym,period,ma_period,ma_shift,ma_method,applied_price);
55      if(iHndl_iMA==INVALID_HANDLE)
56      {
57         PrintFormat("Failed to create iHndl_iMA of the iMA indicator for the symbol %s/%s, error code %d",
58                     sSym,
59                     EnumToString(period),
60                     GetLastError());
61         return(INIT_FAILED);
62      }
63      sShortName=StringFormat("iMA(%s/%s, %d, %d, %s, %s)",sSym,EnumToString(period),
64                              ma_period, ma_shift,EnumToString(ma_method),EnumToString(applied_price));
65      IndicatorSetString(INDICATOR_SHORTNAME,sShortName);
66      return(INIT_SUCCEEDED);
67   }
68   //+------------------------------------------------------------------+
69   //| Custom indicator iteration function                              |
70   //+------------------------------------------------------------------+
71   int OnCalculate(const int rates_total,
72                   const int prev_calculated,
73                   const datetime &time[],
74                   const double &open[],
75                   const double &high[],
76                   const double &low[],
77                   const double &close[],
78                   const long &tick_volume[],
79                   const long &volume[],
80                   const int &spread[])
81     {
82      int values_to_copy;
83      int iCopyCNT;
84      int calculated=BarsCalculated(iHndl_iMA);
85      if(calculated<=0)
86        {
87         PrintFormat("BarsCalculated() returned %d, error code %d",calculated,GetLastError());
88         return(0);
89        }
90      if(prev_calculated==0 || calculated!=iBars_Calc_CNT || rates_total>prev_calculated+1)
91        {
92         if(calculated>rates_total) values_to_copy=rates_total;
93         else                       values_to_copy=calculated;
94        }
95      else
96        {
97         values_to_copy=(rates_total-prev_calculated)+1;
98        }
99      iCopyCNT = FillArrayFromBuffer(iHndl_iMA,iInd_BFRX,values_to_copy,dBfr_iMA,ma_shift);
100      if(iCopyCNT<=0) return(0);
101      iBars_Calc_CNT=calculated;
102      return(rates_total);
103     }
104   //+------------------------------------------------------------------+
105   //| Timer function                                                   |
106   //+------------------------------------------------------------------+
107   void OnTimer()
108     {
109   //---
110      
111     }
112   //+------------------------------------------------------------------+
113   //| ChartEvent function                                              |
114   //+------------------------------------------------------------------+
115   void OnChartEvent(const int id,
116                     const long &lparam,
117                     const double &dparam,
118                     const string &sparam)
119     {
120   //---
121      
122     }
123   //+------------------------------------------------------------------+
124   //+------------------------------------------------------------------+
125   //| Filling indicator buffers from the MA indicator                  |
126   //+------------------------------------------------------------------+
127   int FillArrayFromBuffer(
128                               int piIndHndl,     // iHndl_iMA of the iMA indicator
129                               int piIndBFRX,      // Indicator buffer (e.g., MAIN_LINE, SIGNAL_LINE for iStochastic)
130                               int piCopyCNT,      // number of copied values
131                              double &pdData[],   // indicator buffer of Moving Average values
132                               int piStartPsn=0  // compensates for iMA shift, if any
133                               )
134     {
135      ResetLastError();
136      double dCpyBfr[];
137      int iCopyCNT = CopyBuffer(piIndHndl,piIndBFRX,piStartPsn,piCopyCNT,dCpyBfr);
138      int iErr=_LastError;
139      if(iCopyCNT<0)
140      {
141         PrintFormat("Failed to copy data from the iMA indicator, error code %d",iErr);
142      }
143      
144      
145      
146      
147      if(iCopyCNT>0) {
148         bool bResetArray = ArrayGetAsSeries(pdData);
149         ArraySetAsSeries(pdData,false);
150         ArrayCopy(pdData,dCpyBfr,ArraySize(pdData)+1,0,iCopyCNT);
151         ArraySetAsSeries(pdData,bResetArray);
152      }      
153      
154      
155      
156      
157      return(iCopyCNT);
158     }
159   //+------------------------------------------------------------------+
160   //| Indicator deinitialization function                              |
161   //+------------------------------------------------------------------+
162   void OnDeinit(const int reason)
163     {
164      if(iHndl_iMA!=INVALID_HANDLE)
165         IndicatorRelease(iHndl_iMA);
166      Comment("");
167     }     

Since the logical compliment to ArrayCopy(pdData,dCpyBfr,ArraySize(pdData)+1,0,iCopyCNT); (i.e.,  ArrayCopy(pdData,dCpyBfr,-1,0,iCopyCNT);) does not work with arrays whose timeseries flag==true, I must make sure that the target array's  timeseries flag==false, copy the source array to the target array at the last index+1, then reset the timeseries flag to its original value in case it was set ==true.

Is all this necessary? Or is there a cleaner way to append new data to my array of moving average values, since CopyBuffer doesn't seem to give the option of appending new data directly?

Documentation on MQL5: Technical Indicators / iMA
Documentation on MQL5: Technical Indicators / iMA
  • www.mql5.com
iMA - Technical Indicators - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 
Millard Melnyk:
whose timeseries flag==true, I must make sure that the target array's  timeseries flag==false, copy the source array to the target array at the last index+1, then reset the timeseries flag to its original value in case it was set ==true.

Is all this necessary?

yes,

this influence either to the right or to the left tail of arrayBuffer you add elements: if to the index+1 (it is to the left side)

because the newest bar from right-side has index 0) - Timeseries - general use

ArraySetAsSeries(Buffer,false); 
ArrayResize(Buffer,Bars); // and make your copy
ArraySetAsSeries(Buffer,true);
Timeseries and Indicators Access - MQL4 Reference
Timeseries and Indicators Access - MQL4 Reference
  • docs.mql4.com
Timeseries and Indicators Access - MQL4 Reference
 
JeeyCi #:

yes,

this influence either to the right or to the left tail of arrayBuffer you add elements: if to the index+1 (it is to the left side)

because the newest bar from right-side has index 0) - Timeseries - general use

Thank you!

Reason: