OnCalculate is designed to recalculate every tick. Add a flag to ensure that the calculation runs only once. Initially set the flag to false, and finally set it to true within the condition
//+------------------------------------------------------------------+ //| RecencyWeightedPerf.mq5 | //| Copyright 2024, Scott Allen | //+------------------------------------------------------------------+ #property indicator_separate_window #property indicator_buffers 1 #property indicator_color1 Blue //--- input parameters input bool Use_5_Days = true; // Use 5 days lookback input bool Use_21_Days = true; // Use 21 days lookback input bool Use_63_Days = true; // Use 63 days lookback input bool Use_126_Days = true; // Use 126 days lookback input bool Use_252_Days = true; // Use 252 days lookback input bool Use_756_Days = true; // Use 756 days lookback //--- indicator buffer double RecencyWeightedPerfBuffer[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffer mapping SetIndexBuffer(0, RecencyWeightedPerfBuffer); //--- name for DataWindow and indicator subwindow label IndicatorSetString(INDICATOR_SHORTNAME, "Recency Weighted Performance"); PlotIndexSetString(0, PLOT_LABEL, "RWP"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //--- check if enough bars int lookbackPeriods[] = {5, 21, 63, 126, 252, 756}; bool usePeriods[] = {Use_5_Days, Use_21_Days, Use_63_Days, Use_126_Days, Use_252_Days, Use_756_Days}; int periodsCount = ArraySize(lookbackPeriods); if (rates_total < 756 + 5) // At least the largest lookback period plus MA period { Print("Not enough bars for calculation."); return 0; } //--- calculate daily returns static double returns[]; ArraySetAsSeries(returns, true); ArrayResize(returns, rates_total); for (int i = 1; i < rates_total; i++) returns[i] = (close[i] - close[i - 1]) / close[i - 1]; //--- calculate Recency Weighted Performance int start = prev_calculated > 0 ? prev_calculated - 1: 756 + 5; // Start from the last calculated bar or the minimum required bars static bool completedProcessing = false; // Print("Start index: ", start); if(!completedProcessing){ for (int i = start; i < rates_total; i++) { double weightedSum = 0.0; int activePeriods = 0; for (int j = 0; j < periodsCount; j++) { if (usePeriods[j]) { double sum = 0.0; bool valid = true; for (int k = 0; k < 5; k++) { int index = i - lookbackPeriods[j] - k; if (index < 0) { valid = false; break; } sum += returns[index]; } if (valid) { double perfMA = sum / 5.0; double annualizedPerf = perfMA * 252 / lookbackPeriods[j]; weightedSum += annualizedPerf; activePeriods++; } } } if (activePeriods > 0) RecencyWeightedPerfBuffer[i] = weightedSum / activePeriods; else RecencyWeightedPerfBuffer[i] = 0.0; } } // Print("End index: ", rates_total); if(!completedProcessing){ //--- debug prints Print("rates_total: ", rates_total); Print("prev_calculated: ", prev_calculated); //for (int i = start; i < rates_total; i++) // { // Print("RecencyWeightedPerfBuffer[", i, "]: ", RecencyWeightedPerfBuffer[i]); // } Print("RWP: ", RecencyWeightedPerfBuffer[rates_total-1]); completedProcessing = true; } return rates_total; } //+------------------------------------------------------------------+
OnCalculate is designed to recalculate every tick. Add a flag to ensure that the calculation runs only once. Initially set the flag to false, and finally set it to true within the condition
Thanks! That took care of the seemingly endless loop.
It's still not displaying the indicator though. Apparently I'm missing something else.
Thanks! That took care of the seemingly endless loop.
It's still not displaying the indicator though. Apparently I'm missing something else.
That depends on what you want the indicator to display in the separate window. What should it display?
If it should just display the reading on the chart, you can use the Comment function (https://www.mql5.com/en/docs/common/comment) along with
#property indicator_chart_window
Add the required properties to the top of the script if it should display a line for example:
#property indicator_separate_window #property indicator_buffers 1 #property indicator_plots 1 #property indicator_color1 clrBlue #property indicator_type1 DRAW_LINE
then you can comment out the completedProcessing statement, because it's only prints which will keep looping in the journal
![Documentation on MQL5: Common Functions / Comment Documentation on MQL5: Common Functions / Comment](https://c.mql5.com/36/84/documentation-on-mql5-common-functions.png)
- www.mql5.com
![MQL5 - Language of trade strategies built-in the MetaTrader 5 client terminal](https://c.mql5.com/i/registerlandings/logo-2.png)
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
I'm trying to create a recency-weighted performance indicator that averages the annualized performance of various lookback periods. For each lookback period, it uses a 5-day moving average to avoid the problem of idiosyncratic results depending on the daily results of the specific lookback day.
I'm using my best understanding (such as it is) of keeping track of the previously calculated values to improve performance. Somehow or another, I've ended up with this in an infinite loop and I can't figure out why. What am I missing?