Coupler indicator issue with timeframe mixing
-
Hi there,
I've been working with an indicator to identify weekly resistances to use them over daily data.
The idea is that when the price goes above the resistance the indicator line should disappear since the resistance is broken.
The indicator works perfectly fine over the weekly chart but not on the daily chart. It prolongs the resistance one more week than what it should.
To build this I have followed the documentation here: https://www.backtrader.com/docu/mixing-timeframes/indicators-mixing-timeframes/
and here:
https://www.backtrader.com/docu/data-multitimeframe/data-multitimeframe/Below is the chart of the coupled indicator. In violet you can see the marks where the problem occurs
Has anybody faced this sort of problem already?
Thanks in advance for any help you could provide
-
We don't know what you are doing but it would seem obvious that you calculate the resistance/support at the end of the week, hence the first days of next week, do still follow the previous value.
But again: we don't know what you are doing.
-
Thanks for the answer. I am not posting the whole code because it would be too much.
Basically, I created an indicator that calculates resistances for each candle. Then I input in the indicator weekly data and used daily data to check if the resistance was broken or not. For all these I used the information provided in the links I posted before.
My question is related to the fact that the same indicator is plotting something different in the daily chart (the one at the top) than in the weekly chart (the one at the bottom).
In the daily chart is prolonging the resistances one whole week more than in the weekly.Is this the normal behavior?
-
Once again. If you calculate the resistances weekly and apply then daily, you probably carry the values yourself.
-
I don't fully understand what you mean.
This is the code, you might give me some advice?:
Many thanks!
from __future__ import (absolute_import, division, print_function, unicode_literals) from datetime import datetime, timedelta import backtrader as bt from collections import OrderedDict from backtrader import cerebro import time import pandas as pd import argparse def parse_args(): parser = argparse.ArgumentParser( description='RSI strategy') parser.add_argument('-nh', '--noheaders', action='store_true', default=False, required=False, help='Do not use header rows') parser.add_argument('-np', '--noprint', action='store_true', default=False, required=False, help='Print the dataframe') parser.add_argument('-e', '--exchange', default='binance', type=str, required=False, help='Exchange') parser.add_argument('-s', '--symbol', default='BTC/USDT', type=str, required=False, help='Symbol') parser.add_argument('-t', '--timeframe', type=str, default='1d', choices=['1m', '5m', '15m', '30m', '1h', '2h', '3h', '4h', '6h', '12h', '1d', '1M', '1w', '1y'], help='The timeframe to download') parser.add_argument('-t2', '--timeframe2', type=str, default='1w', choices=['1m', '5m', '15m', '30m', '1h', '2h', '3h', '4h', '6h', '12h', '1d', '1M', '1w', '1y'], help='The timeframe for second indicator') parser.add_argument('-fp', '--filepath', type=str, default='binance-BTCUSDT-1m-2019-01-01.csv', required=False, help='File path (../../filename.csv') parser.add_argument('-hi', '--history', type=int, default=30, required=False, help='Number of days to retrieve') parser.add_argument('-c', '--cash', type=int, default=10000, required=False, help='Starting Cash') return parser.parse_args() def readCVS(): # Get a pandas dataframe datapath = args.filepath # Simulate the header row isn't there if noheaders requested skiprows = 1 if args.noheaders else 0 header = None if args.noheaders else 0 dataframe = pd.read_csv(datapath, skiprows=skiprows, header=header, parse_dates=True, index_col=0) dataframe.index = pd.to_datetime(dataframe.index, unit='ms') if not args.noprint: print('--------------------------------------------------') print(dataframe) print('--------------------------------------------------') # Pass it to the backtrader datafeed and add it to the cerebro return bt.feeds.PandasData(dataname=dataframe, timeframe=bt.TimeFrame.Minutes, openinterest=None) def resismet(maxima, high ,resistances, resNum=15, tolPercRes=2, tolRestoSupPer=2 ): # creates a list of resistances with length resNum and elminates already broken resistances # within a tolerance of tolerancePerc toleranceResist = maxima * tolPercRes / 100 toleranceResSup = maxima * tolRestoSupPer / 100 if all(abs(maxima - i) > toleranceResist for i in resistances): resistances.append(maxima) else: removeResist = [i for i in resistances if maxima - i > 0 and maxima - i <= toleranceResist] if len(removeResist) != 0: for i in removeResist: resistances.remove(i) resistances.append(maxima) ResToSupport = [i for i in resistances if high - i > toleranceResSup] #this is reduntant if len(ResToSupport) != 0: for i in ResToSupport: resistances.remove(i) lenR = len(resistances) if resNum != None and lenR > resNum: resistances[0:lenR - resNum] = [] return (resistances) class SandR(bt.Indicator): params = ( ('nresist', 5), ('tolerance', 2), ('tolerance2',2), ('period', 1), ('barplot', False), ) nresist = params[0][1] linelist = list() for i in range(nresist): linelist.append('resistance' + str(i)) lines = tuple(linelist) # creates the lines based on the nresist parameter plotinfo = dict(subplot=False, ) def __init__(self): #look for local maxima higherthanlast = bt.And(self.data.high(-1) > self.data.high(-2), self.data.high(-1) > self.data.high(0)) self.maxima = higherthanlast * self.data.high(-1) def next(self, resdic=OrderedDict(resistances0 = list() , resistances1 = list())): # todo this only works for two timeframes, will edit to support more dataid = self.data._id-1 resistanceid = 'resistances'+str(dataid) resdic[resistanceid] = resismet(self.maxima[0], self.data0.high[0], resdic[resistanceid], self.params.nresist, self.params.tolerance, self.params.tolerance2) for j in resdic.values(): #to make sure that broken resistances get deteled as soon as they are broken on the daily chart ResToSupport = [i for i in j if self.data0.high[0] - i > 0] if len(ResToSupport) != 0: for k in ResToSupport: j.remove(k) resistances = resdic[resistanceid] if len(resistances) > 0: n = 0 for i in self.linelist: if len(resistances) > n: exec('self.lines.' + i + '[0]' '= resistances[-1 - n]') n = n + 1 class secondStrategy(bt.Strategy): def __init__(self): #resistance0 = self.resistance0 = SandR(self.data0, plotname='Resistencia 1D', plotvaluetags=False) resistance1 = self.resistance0 = SandR(self.data1, plotname='Resistencia 1W', plotvaluetags=False) resistance11=resistance1() self.buysig = self.data0.close > resistance11.resistance0 self.sellsig = self.data0.close < resistance11.resistance0 def next(self): #dum strategy, don't pay attention to it, only care about indicator if not self.position: if self.buysig[0]: self.buy(size=0.1) #pass else: if self.sellsig[0]: self.sell(size=0.1) msec = 1000 minute = 60 * msec hold = 30 tframes = { '1m': [bt.TimeFrame.Minutes, 1], '5m': [bt.TimeFrame.Minutes, 5], '15m': [bt.TimeFrame.Minutes, 15], '30m': [bt.TimeFrame.Minutes, 30], '1h': [bt.TimeFrame.Minutes, 60], '2h': [bt.TimeFrame.Minutes, 120], '3h': [bt.TimeFrame.Minutes, 180], '4h': [bt.TimeFrame.Minutes, 240], '6h': [bt.TimeFrame.Minutes, 360], '12h': [bt.TimeFrame.Minutes, 720], '1d': [bt.TimeFrame.Days, 1], '1w': [bt.TimeFrame.Weeks, 1], '1M': [bt.TimeFrame.Months, 1], '1y': [bt.TimeFrame.Years, 1] } # Variable for our starting cash startcash = 100000 if __name__ == '__main__': cerebro = bt.Cerebro() args = parse_args() if not args.filepath: data = loadExchange() cerebro.adddata(data) else: data = readCVS() cerebro.resampledata(data, timeframe=tframes[args.timeframe][0], compression=tframes[args.timeframe][1]) cerebro.resampledata(data, timeframe=tframes[args.timeframe2][0], compression=tframes[args.timeframe2][1]) cerebro.broker.setcash(args.cash) cerebro.addstrategy(secondStrategy) cerebro.run(runonce=False) # Get final portfolio Value portvalue = cerebro.broker.getvalue() pnl = portvalue - startcash # Print out the final result print('Final Portfolio Value: ${}'.format(portvalue)) print('P/L: ${}'.format(pnl)) # Finally plot the end results cerebro.plot(style='candlestick')
-
The larger timeframe
weeks
moves only once (1
) for each five (5
) ticks of the daily timeframe (let's simplify and forget that sometimes there are trading holidays)The indicator is calculated on the weekly timeframe, i.e.: when the week is complete and the
5
ticks of the week (5 days) have also been seen.When the next week kicks in, you coupling puts the latest calculated values from the weekly timeframe into the daily timeframe, until the end of the week is reached and new values can be calculated.
-
Many thanks for your answer.
I do see what you are explaining, but what I don't understand is why is plotting something different in the two charts.
BTW, is there a way to change the weekly count to 7 instead of 5? since I am working with crypto.
Thanks -
@Mariano-Bengeldorf
I got it. You don't need to answer. ThanksI still would like to know if it is possible to change the 5 count to 7.
Thanks!!!
-
@Mariano-Bengeldorf said in Coupler indicator issue with timeframe mixing:
I still would like to know if it is possible to change the 5 count to 7.
The platform doesn't carry any count, the count is dictated by the data itself. If your daily data is made up of
7
bars, it will tick7
times per week.