Hi @backtrader
Thanks for your answer. I was just trying to make things simpler for you, I am sorry if it turned out to be the other way. Not my intention.
BTW, I love what your are doing and thanks for sharing with all of us.
I took a bit to answer because I was trying to figure it out by my self, but no luck at all.
Here goes the code, thanks for any advise you can provide:
from __future__ import (absolute_import, division, print_function, unicode_literals)
import backtrader as bt
from collections import OrderedDict
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('-t', '--timeframe',
type=str,
nargs='+',
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')
parser.add_argument('-st', '--stats',
action='store_true',
default=False,
required=False,
help='Print the stats')
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')
# 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,resistances, resNum=15, tolPercRes=2):
# creates a list of resistances with length resNum and elminates already broken resistances
# within a tolerance of tolerancePerc
toleranceResist = maxima * tolPercRes / 100 #todo mejorar este calculo
if maxima > 0:
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)
lenR = len(resistances)
if resNum != None and lenR > resNum:
resistances[0:lenR - resNum] = []
return (resistances)
class SandR(bt.Indicator):
params = OrderedDict([
('nresist', 20),
('tolerance', 2),
('tolerance2', 2),
('period', 1),
('barplot', False),
('timeframeslen', 4)
])
nresist = params['nresist']
mlinelist = list()
for i in range( nresist * 2):
mlinelist.append('mresistance' + str(i))
lines = tuple(mlinelist) # creates the lines based on the nresist parameter
plotinfo = dict(subplot=False,
)
resdic = OrderedDict()
for i in range(params['timeframeslen']-1,-1,-1):
j = 'resistances' + str(i)
resdic[j] = list()
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 = resdic):
dataid = self.data._id-1
resistancesid = 'resistances'+str(dataid)
resdic[resistancesid] = resismet(self.maxima[0], resdic[resistancesid], self.params.nresist,
self.params.tolerance)
tolRestoSupPer = self.params.tolerance2/100
if dataid == 0:
inputhigh = self.data.high[-1]
for j in resdic.values():
ResToSupport = [i for i in j if inputhigh - i > i*tolRestoSupPer]
if len(ResToSupport) != 0:
for k in ResToSupport:
j.remove(k)
mresistances = [i for j in resdic.values() for i in j]
for i in (range(len(mresistances)-1,-1,-1)):
if mresistances.count(mresistances[i]) > 1:
del mresistances[i]
if dataid == 0:
if len(mresistances) > 0:
n = 0
for i in self.mlinelist:
if len(mresistances) > n:
exec('self.lines.' + i + '[0]' '= mresistances[n]')
n = n + 1
class secondStrategy(bt.Strategy):
def __init__(self):
self.mresistance0 = SandR(self.data0, plotname='Resistance', plotvaluetags=False, timeframeslen = 2)
def next(self):
print('=========')
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()
timeframes = args.timeframe
if not args.filepath:
data = loadExchange(timeframes[0])
cerebro.adddata(data)
for i in range(1,len(timeframes)):
cerebro.resampledata(data, timeframe=tframes[timeframes[i]][0], compression=tframes[timeframes[i]][1])
else:
data = readCVS()
for i in range(len(timeframes)):
cerebro.resampledata(data, timeframe=tframes[timeframes[i]][0], compression=tframes[timeframes[i]][1])
cerebro.broker.setcash(args.cash)
cerebro.addstrategy(secondStrategy)
cerebro.run()
# 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')
Again, thanks