Request for code review
-
Hello,
since these are my first lines of code in backtrade(and Python),can anyone run a quick code review and post comments?
a few words about the logic:- rank the stocks in a list according to volatility(r_squared of last 90 days linear regression)
- open the first ones with positive linear regression slope
- close the ones with negative linear regression slope
comments are highly appreciated,go brutal...
imports ... class TestStrategy(bt.Strategy): params = ( ('atr_parameter', 20), ('rank_period', 90), ) def __init__(self): self.atrs = {data._name: bt.indicators.ATR(data, period=self.p.atr_parameter) for data in self.datas} def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: return dt = self.datas[0].datetime.date(0) order_type = None order_value = None if order.status in [order.Completed]: if order.isbuy(): order_type= 'buy' order_value = order.executed.value else: # Sell order_type= 'sell' order_value = order.executed.pnl print('%s : %s %s, (#%d@%.2f$),%.2f$' %(dt.isoformat(), order_type, order.data._name, order.executed.size, order.executed.price, order_value)) elif order.status in [order.Canceled, order.Margin, order.Rejected]: print('Order Canceled/Margin/Rejected') def next(self): open_candiates = [] close_positions = [] for ticker in self.getdatanames(): symbol_quotes = self.getdatabyname(ticker) rank_period_quotes=list(symbol_quotes)[-self.p.rank_period:] x = np.arange(len(rank_period_quotes)) slope, intercept, r_value, p_value, std_err = stats.linregress(x, rank_period_quotes) if(slope <= 0): close_positions.append(ticker) else: ticker_values = {} ticker_values['ticker_r'] = r_value**2 ticker_values['position_size'] = 0.001 * self.broker.getvalue()/self.atrs[ticker][0] ticker_values['ticker']=ticker open_candiates.append(ticker_values) open_candiates.sort(key=itemgetter('ticker_r'), reverse=True) # close positions for ticker in close_positions: if(0 != self.broker.getposition(data = self.getdatabyname(ticker)).size): self.close(data=self.getdatabyname(ticker)) # open position for ticker in open_candiates: ticker_data = self.getdatabyname(ticker['ticker']) current_size = self.broker.getposition(data = ticker_data).size if(0 == current_size): self.buy(data = ticker_data, size=ticker['position_size']) if __name__ == '__main__': isOptimizing = False # backtesting and not optimizing # Create a cerebro entity cerebro = bt.Cerebro() # load symbol list from file with open('ticker_list.txt', 'r') as f: reader = csv.reader(f) tickers = list(reader) for ticker in tickers: print("Loading .csv for %s" % ticker[0]) # Create a Data Feed data = bt.feeds.QuandlCSV( dataname=ticker[0]+'.csv', fromdate=datetime.datetime(2013, 1, 1), todate=datetime.datetime(2016, 12, 29), adjclose=False, reverse=True) # Add the Data Feed to Cerebro cerebro.adddata(data=data,name=ticker[0]) # Add a strategy if(isOptimizing): strats = cerebro.optstrategy(TestStrategy,maperiod=range(10, 31)) else: cerebro.addstrategy(TestStrategy) cerebro.broker.setcash(100000.0) cerebro.broker.setcommission(commission=0.0015) cerebro.run()
-
go brutal...
You've asked. Why don't you debug your code by yourself?
-
Thank you for the reply,
I'm not looking to debug the code, I'm looking for reviews, such as :-
could I have done things differently? using other backtrader (excellent) components?
-
Could the purpose of ranking be done another way?
-
What are the potential pitfalls in the code?
-
Did I use backtrader the way it was supposed to be used?
-
-
@Trade-Prophet said in Request for code review:
symbol_quotes = self.getdatabyname(ticker) rank_period_quotes=list(symbol_quotes)[-self.p.rank_period:]
Out of curiosity ... what's the intention of that. I imagine:
list(symbolquotes)
uses the fact that a data feed has a__len__
(one can saylen(data)
) and__getitem__
(one can usedata[x]
But given that backtrader doesn't use standard indexing (starting and
0
and growing), but the built-in mechanisms in Python don't know it and will construct the list by iterating from0 -> len(data)
... this probably won't deliver the expected result ... which seems to gather all data and then slice.@Trade-Prophet said in Request for code review:
if(0 == current_size):
That isn't very Pythonic ...
if not current_size
would be. But each uses his/her own patterns. -
Thank you very much for your reply
and you are absolutely right! the lines you have mentioned do not produce the expected result, I'm constructing an indicator to provide linear regression data(slope,r squared) instead of the current code.
coming from C++ lines like "if(0 == current_size):" make sense to me but I will gladly honor the Pythonic tradition.
Thanks for the time and the professional review -
@Paska-Houso said in Request for code review:
list(symbolquotes)
uses the fact that a data feed has a__len__
(one can saylen(data)
) and__getitem__
(one can usedata[x]
)
See this recent thread. You probably want to use
data.get(ago=x, size=y)
. The results will be in the expected order.