Getting running value of indicators in Multi Timeframe backtest

I am trying to code a multi timeframe strategy(base: 5min) where I will use an indiactor like MACD in the higher timeframe(15 min).

Suppose the market opens at 9:00 and I code something like this:

TimeFrameSet(in15Minute);
macdValue = MACD(12, 26);
TimeFrameRestore();

macdValue = TimeFrameExpand(macdValue, in15Minute, expandLast);

And I use macdValue array to make decisions on the base 5min timeframe at 9:20 then the values I will have inside this array will be from the last completion of 15min(9:00 - 9:15).

But I want the 15 minute running value of MACD, so I want the indicator to use the OHLC of 9:15-9:20 to calculate its value, so as Ref(macdValue, -1) points to the macd value between 9:00-9:15.

As I see it, it doesn't seem to be possible without coding a custom function for this. Is this possible any other wthere their is some fault in my understanding?

Yes, you would need to write your own function as there is no way for the standard timeframe compress/expand functions to do the "rolling 15 minutes" as you've described. However, you should be able to use SparseCompress to make the coding effort fairly minimal because in addition to the "standard" 15-minute compressed bars you just need two other arrays: the one where Minute() % 15 == 5 and the one where Minute() % 15 == 10.

1 Like

@sandeep: I don't believe your solution will work for @xterminator. If I understand correctly, at 9:20 he wants to calculate MACD using 15 minute bars that started at 5, 20, 35, and 50 minutes past each hour. With your solution, all bars start at 0, 15, 30, and 45 minutes past the hour, and if using a real time data provider then the last bar is potentially a partial bar which is what gives you a "running" MACD but not in the way @xterminator wants.

Yeah I didn't understand what @sandeep was trying to say. But to be sure, let me rephrase the question again:

My strategy works on 5 minute timeframe and it has to use 15 minute MACD values to determine some trends. Now at 9:20, when I try to access the MACD, I would only get the MACD value calculated between 9:00 - 9:15, whereas I would have wanted the "running" MACD value, that is the 15 minute value of MACD which uses the 9:20 as the closing price as it is most recent one which falls in the group 9:15 - 9:30.

Using expandFirst will cause a future leak as I will be using what the MACD value would have been at 9:30.

That is correct. In the context of a backtest (or anything other than the current in-progress bar), using expandFirst would be a future leak for exactly the reason you described.

@xterminator I don't have the coding solution that you are looking for but an alternative for you to investigate. If I understand you correctly, you want to compare a longer term MACD (calculated on 15 minute bars) to your shorter term signals (5 minute bars). But you want to recalculate your longer term trend every 5 minutes.

As you are aware, the MACD is based upon a couple of moving averages and you could consider that if you want to re-calculate your longer term trend every 5 minutes you could adjust the "lookback periods" of the MACD in the 5 minute timeframe.

Below is an example comparing the default MACD (using 12 and 26 bar periods) calculated on 15 minute bars vs a MACD with triple the look back periods, MACD(36, 78) calculated on 5 minute bars.
image

You can repeat this with the Signal() periods and find a similar looking chart. If you were to recalculate the 15 minute based MACD every 5 minutes then those two lines would get even closer together.

This may not be exactly what you are looking for but depending upon the details of your strategy you may get a similar result. You should have it clear in your mind what is the reason your strategy requires the longer time frame indicator, and do you really want to update the longer term indicator every 5 minutes.

3 Likes

Thank you for this. I was considering something like this and now I know this could be one of the ways I go forward. Will also try @mradtke suggestion and see where things go.

Here is a rough idea of what I was thinking. I am not getting exactly the values that I think I should, so you will probably need to do some additional debugging. Note that we need a version of the MACD function that accepts an array of prices, so I created my own. Also, this is targeted to 5m and 15m bars. It would be nice to make it more generic in terms of both the base and compressed timeframe.

function MyMACD(price, lenFast, lenSlow)
{
	emaFast = EMA(price, lenFast);
	emaSlow = EMA(price, lenSlow);
	return emaFast - emaSlow;
}

function Running15mMACD(lenFast, lenSlow)
{
	compPrice = SparseCompress(Minute() % 15 == 0, C);
	compMACD0 = MyMACD(compPrice, lenFast, lenSlow);
	
	compPrice = SparseCompress(Minute() % 15 == 5, C);
	compMACD5 = MyMACD(compPrice, lenFast, lenSlow);
	
	compPrice = SparseCompress(Minute() % 15 == 10, C);
	compMACD10 = MyMACD(compPrice, lenFast, lenSlow);
	
	runningMACD =	Nz(SparseExpand(Minute() % 15 == 0, compMACD0)) + 
					Nz(SparseExpand(Minute() % 15 == 5, compMACD5)) + 
					Nz(SparseExpand(Minute() % 15 == 10, compMACD10));
					
	return runningMACD;
}

Filter = True;
runMACD = Running15mMACD(12, 26);
AddColumn(runMACD, "15m Running MACD", 1.4);
2 Likes

FWIW, there isn't custom MACD function required

function RunningMACD(lenFast, lenSlow)
{
	sel_iv = 5;// selected interval
	dest_iv = 15;// destination interval
	//	
	mod = Minute() % dest_iv;	
	for ( i = 0; i < dest_iv; i+=sel_iv) {
		C = SparseCompress(mod == i, C);
		VarSet("compMACD"+i, MACD(lenFast, lenSlow));	
		RestorePriceArrays();
	}
	
	result = 0;
	for ( i = 0; i < dest_iv; i+=sel_iv)	 
		result += Nz(SparseExpand(mod == i, VarGet("compMACD"+i)));
	return result;
}

Filter = True;
runMACD = RunningMACD(12, 26);
AddColumn(runMACD, "15m Running MACD", 1.4);
6 Likes

Hi

I am aware that this thread is flagged as solved. However, its the same issue I am facing but for a different indicator. Hence, thought of posting it here instead of creating a new thread.

I am also facing similar issue with respect to running RSI. I tried to modify the function as follows but it returned incorrect result.

And How do I calculate Daily running RSI using the same function ? My market goes for 375 minutes so I tried to replace dest_iv with 375 but output was incorrect.

function RunningRSI15(Period)
{
	sel_iv = 5;// selected interval
	dest_iv = 15;// destination interval
	//	
	mod = Minute() % dest_iv;	
	for ( i = 0; i < dest_iv; i+=sel_iv) {
		C = SparseCompress(mod == i, C);
		VarSet("compRSI"+i, RSI(14));	
		RestorePriceArrays();
	}
	
	result = 0;
	for ( i = 0; i < dest_iv; i+=sel_iv)	 
		result += Nz(SparseExpand(mod == i, VarGet("compRSI"+i)));
	return result;
}

Thanks a Lot.

First in case of RSI you don't need to reassign Close because there is an RSIa( array, period) that takes input array as argument so you can just do:

VarSet("compRSI"+i, RSIa( SparseCompress( mod == i,  C), 14));	

You shouldn't just copy & paste without debugging.
You can not use that mod variable for Daily destination interval. Minute() function outputs minutes of hour but not minutes of day.The original guy was asking for 15 minute destination interval (which is minute within hour). So for daily interval you have to do differently (compressing per each selected interval's bar of day) by using different function.

14

Cool. Thanks for your inputs Tomasz and fxshrat.

I mostly do debugging with Exploration to fix my codes. Debugging link has many useful ideas to debug. Thanks again.

Hi @fxshrat
How can we use the same thing for daily and weekly instead of 5 min and 15 min
Thanks