I have gone through every example I can find here and I can't seem to get past the below error. I am adding the lines and parameters, and I am initiating the column variable, what am I missing? I am just trying to get the extra columns into the data to make these vars available in the Strategy.
Traceback (most recent call last):
File "backtest1.py", line 171, in <module>
main()
File "backtest1.py", line 93, in main
thestrats = cerebro.run()
File "/usr/lib/python3.8/site-packages/backtrader/cerebro.py", line 1127, in run
runstrat = self.runstrategies(iterstrat)
File "/usr/lib/python3.8/site-packages/backtrader/cerebro.py", line 1217, in runstrategies
strat = stratcls(*sargs, **skwargs)
File "/usr/lib/python3.8/site-packages/backtrader/metabase.py", line 88, in __call__
_obj, args, kwargs = cls.doinit(_obj, *args, **kwargs)
File "/usr/lib/python3.8/site-packages/backtrader/metabase.py", line 78, in doinit
_obj.__init__(*args, **kwargs)
File "/home/krypterro/btcbot/Strategy.py", line 20, in __init__
self.order_act = self.datas[0].order_act
File "/usr/lib/python3.8/site-packages/backtrader/lineseries.py", line 461, in __getattr__
return getattr(self.lines, name)
AttributeError: 'Lines_LineSeries_DataSeries_OHLC_OHLCDateTime_Abst' object has no attribute 'order_act'
backtest.py
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import datetime # For datetime objects
import os.path # To manage paths
import sys # To find out the script name (in argv[0])
import pandas as pd
import btalib
from tqdm import tqdm
from colorama import init
from colorama import Fore, Back, Style
import backtrader as bt
import backtrader.analyzers as btanalyzers
import backtrader.feeds as btfeeds
import backtrader.strategies as btstrats
from DBA import Binance
from DB import DB1
from Strategy import TestStrategy
from Toolbox import Hammers
init()
db1 = DB1()
os.system('clear')
cash = 10000
def main():
cnt = 0
btc_list = Binance.get_btc_hours(db1)
row_count = len(btc_list)
new_list = []
print(Fore.GREEN)
for i in tqdm (range (row_count), desc="Processing"):
#for i in range(row_count):
if i > 2:
row_0_data = dict(btc_list[i])
back_1_data = dict(btc_list[i-1])
back_2_data = dict(btc_list[i-2])
# build indicators
row_0_data['decline'] = back_1_data['high'] - row_0_data['low']
row_0_data['rally'] = row_0_data['high'] - back_1_data['low']
row_0_data['buy_high'] = Hammers.get_buy_high(row_0_data['high'], back_1_data['high'])
row_0_data['buy_under'] = Hammers.get_buy_under(back_1_data['low'], row_0_data['low'])
row_0_data['btc_mi'] = row_0_data['close'] - back_2_data['close']
row_0_data['btc_mt'] = Hammers.get_mt(row_0_data['btc_mi'], back_1_data['btc_mi'], back_2_data['btc_mi'])
row_0_data['level'] = 0
row_0_data['level'] = Hammers.get_level(row_0_data, back_1_data)
new_list.append(row_0_data)
# setup order
row_0_data['pip_value'] = Hammers.get_pip_value(row_0_data)
order = Hammers.get_order(row_0_data, back_1_data)
row_0_data['order_act'] = order['act']
try:
row_0_data['order_target'] = round(order['target'],2)
except:
pass
data_df = pd.DataFrame(new_list)
data_df = data_df.set_index('stamp')
data = bt.feeds.PandasData(dataname=data_df)
#print(data_df.tail(10))
# Create a cerebro obj and populate
cerebro = bt.Cerebro()
#cerebro.addstrategy(btstrats.SMA_CrossOver)
cerebro.addstrategy(TestStrategy)
cerebro.adddata(data)
cerebro.broker.setcash(cash)
# Set the commission
cerebro.broker.setcommission(commission=0.002)
# Analyzer
cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='out_sharpe')
cerebro.addanalyzer(btanalyzers.DrawDown, _name='out_drawdown')
#cerebro.addanalyzer(btanalyzers.AnnualReturn, _name='out_annual')
# Add a FixedSize sizer according to the stake
#cerebro.addsizer(bt.sizers.FixedSize, stake=10)
# Print out the starting conditions
print('Starting Portfolio Value: ', as_currency(cerebro.broker.getvalue()))
start_cap = cerebro.broker.getvalue()
print(Fore.CYAN)
# Run over everything
thestrats = cerebro.run()
thestrat = thestrats[0]
sharpe_data = dict(thestrat.analyzers.out_sharpe.get_analysis())
sharpe_ratio = sharpe_data['sharperatio']
drawdown_data = dict(thestrat.analyzers.out_drawdown.get_analysis())
drawdown_data = drawdown_data['max']
#annual_data = dict(thestrat.analyzers.out_annual.get_analysis())
# format text
drawdown_percentage = int(drawdown_data['drawdown'])
drawdown_percentage = str(drawdown_percentage) + '%'
drawdown_money = as_currency(drawdown_data['moneydown'])
net_profit = (cerebro.broker.getvalue() - start_cap) / cerebro.broker.getvalue() * 100
net_profit = round(net_profit,2)
final_total = as_currency(cerebro.broker.getvalue())
# Print out the final result
print('Max Drawdown Length:', drawdown_data['len'], 'hours')
print('Max Drawdown Percentage:', drawdown_data['drawdown'])
print('Max Drawdown Money:', drawdown_money)
print(Fore.GREEN)
print('Sharpe Ratio:', sharpe_ratio)
print('Final Portfolio Value: ', final_total)
print('Net Profit: ', net_profit, '%')
print(Style.RESET_ALL)
print('BackTesting Complete')
def as_currency(amount):
if amount >= 0:
return '${:,.2f}'.format(amount)
else:
return '-${:,.2f}'.format(-amount)
class PandasData_Extend(btfeeds.PandasData):
lines = ('btc_id', 'btc_hour', 'symbol', 'open', 'high', 'low', 'close', 'range_usd', 'sma24', 'ema', 'volume_btc', 'volume_usd', 'decline', 'rally', 'buy_high', 'buy_under', 'btc_mi', 'btc_mt', 'level', 'pip_value', 'order_act', 'order_target')
params = (
('datetime', None),
('btc_id', 0),
('btc_hour', 1),
('symbol', 2),
('open', 3),
('high', 4),
('low', 5),
('close', 6),
('range_usd', 7),
('sma24', 8),
('ema', 9),
('volume_btc', 10),
('volume_usd', 11),
('decline', 12),
('rally', 13),
('buy_high', 14),
('buy_under', 15),
('btc_mi', 16),
('btc_mt', 17),
('level', 18),
('pip_value', 19),
('order_act', 20),
('order_target', 21)
)
def print_full(x):
pd.set_option('display.max_rows', len(x))
pd.set_option('display.max_columns', None)
pd.set_option('display.width', 2000)
pd.set_option('display.float_format', '{:20,.2f}'.format)
pd.set_option('display.max_colwidth', None)
print(x)
pd.reset_option('display.max_rows')
pd.reset_option('display.max_columns')
pd.reset_option('display.width')
pd.reset_option('display.float_format')
pd.reset_option('display.max_colwidth')
main()
Strategy.py
import backtrader as bt
from Toolbox import Hammers
class TestStrategy(bt.Strategy):
params = (
('maperiod', 240),
('period', 10),
('onlydaily', False)
)
def log(self, txt, dt=None):
''' Logging function fot this strategy'''
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def __init__(self):
# custom vars
self.order_act = self.datas[0].order_act
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
# To keep track of pending orders and buy price/commission
self.order = None
self.buyprice = None
self.buycomm = None
# Add a MovingAverageSimple indicator
self.sma = bt.indicators.SimpleMovingAverage(
self.datas[0], period=self.params.maperiod)
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
# Buy/Sell order submitted/accepted to/by broker - Nothing to do
return
# Check if an order has been completed
# Attention: broker could reject order if not enough cash
if order.status in [order.Completed]:
if order.isbuy():
self.log(
'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
self.order = None
def notify_trade(self, trade):
if not trade.isclosed:
return
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm))
def next(self):
# Simply log the closing price of the series from the reference
self.log('Close, %.2f' % self.dataclose[0])
# Check if an order is pending ... if yes, we cannot send a 2nd one
if self.order:
return
# Check if we are in the market
if not self.position:
# Not yet ... we MIGHT BUY if ...
if self.order_act == 'buy':
# BUY, BUY, BUY!!! (with all possible default parameters)
self.log('BUY CREATE, %.2f' % self.dataclose[0])
# Keep track of the created order to avoid a 2nd order
self.order = self.buy()
else:
if self.order_act == 'sell':
# SELL, SELL, SELL!!! (with all possible default parameters)
self.log('SELL CREATE, %.2f' % self.dataclose[0])
# Keep track of the created order to avoid a 2nd order
self.order = self.sell()