Skip to content

Instantly share code, notes, and snippets.

@joelschopp
Created May 5, 2023 19:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joelschopp/192976e992c2179131ce9fb4c004e56a to your computer and use it in GitHub Desktop.
Save joelschopp/192976e992c2179131ce9fb4c004e56a to your computer and use it in GitHub Desktop.
rebalance royalty backtest
import datetime
import backtrader as bt
import backtrader.analyzers as btanalyzers
class Strategy(bt.Strategy):
params = (
("buffer", 0.05),
("threshold", 0.05),
)
def log(self, txt, dt=None):
""" Logging function fot this strategy"""
dt = dt or self.data.datetime[0]
if isinstance(dt, float):
dt = bt.num2date(dt)
print("%s, %s" % (dt.date(), txt))
def print_signal(self):
self.log(
f"o {self.datas[0].open[0]:7.2f} "
f"h {self.datas[0].high[0]:7.2f} "
f"l {self.datas[0].low[0]:7.2f} "
f"c {self.datas[0].close[0]:7.2f} "
f"v {self.datas[0].volume[0]:7.0f} "
)
def notify_order(self, order):
""" Triggered upon changes to orders. """
# Suppress notification if it is just a submitted order.
if order.status == order.Submitted:
return
# Print out the date, security name, order number and status.
type = "Buy" if order.isbuy() else "Sell"
#self.log(
# f"{order.data._name:<6} Order: {order.ref:3d} "
# f"Type: {type:<5}\tStatus"
# f" {order.getstatusname():<8} \t"
# f"Size: {order.created.size:9.4f} Price: {order.created.price:9.4f} "
# f"Position: {self.getposition(order.data).size:5.2f}"
#)
if order.status == order.Margin:
return
# Check if an order has been completed
#if order.status in [order.Completed]:
# self.log(
# f"{order.data._name:<6} {('BUY' if order.isbuy() else 'SELL'):<5} "
# # f"EXECUTED for: {dn} "
# f"Price: {order.executed.price:6.2f} "
# f"Cost: {order.executed.value:6.2f} "
# f"Comm: {order.executed.comm:4.2f} "
# f"Size: {order.created.size:9.4f} "
# )
def notify_trade(self, trade):
"""Provides notification of closed trades."""
#if trade.isclosed:
# self.log(
# "{} Closed: PnL Gross {}, Net {},".format(
# trade.data._name,
# round(trade.pnl, 2),
# round(trade.pnlcomm, 1),
# )
# )
def next(self):
track_trades = dict()
total_value = self.broker.get_value() * (1 - self.p.buffer)
for d in self.datas:
track_trades[d] = dict()
value = self.broker.get_value(datas=[d])
allocation = value / total_value
units_to_trade = (d.target - allocation) * total_value / d.close[0]
track_trades[d]["units"] = units_to_trade
# Can check to make sure there is enough distance away from ideal to trade.
track_trades[d]["threshold"] = abs(d.target - allocation) > self.p.threshold
rebalance = False
for values in track_trades.values():
if values['threshold']:
rebalance = True
if not rebalance:
return
# Sell shares first
for d, value in track_trades.items():
if value["units"] < 0:
self.sell(d, size=value["units"])
# Buy shares second
for d, value in track_trades.items():
if value["units"] > 0:
self.buy(d, size=value["units"])
if __name__ == "__main__":
cerebro = bt.Cerebro()
#tickers = {"FNV": 0.3333, "WPM": 0.3333, "RGLD": 0.3333, "GDXJ": -.25}
#tickers = {"FNV": 0.5, "WPM": 0.5, "RGLD": 0.5, "GDXJ":-0.5}
#tickers = {"SPY": 0.375, "FNV": 0.375, "WPM": 0.375, "RGLD": 0.375, "GDXJ":-0.5}
tickers = {"SPY": 0.25, "FNV": 0.25, "WPM": 0.25, "RGLD": 0.25, "GDXJ":-0.25}
for ticker, target in tickers.items():
data = bt.feeds.YahooFinanceCSVData(
dataname="/Users/joelschopp/Google Drive/My Drive/stockdata/yahoofinance/" + ticker + ".csv",
timeframe=bt.TimeFrame.Days,
fromdate=datetime.datetime(2008, 2, 1),
todate=datetime.datetime(2023, 5, 2),
reverse=False,
)
data.target = target
cerebro.adddata(data, name=ticker)
cerebro.addstrategy(Strategy)
# Analyzer
cerebro.addanalyzer(btanalyzers.SharpeRatio, _name='mysharpe')
cerebro.addanalyzer(btanalyzers.DrawDown, _name='mydrawdown')
cerebro.addanalyzer(btanalyzers.Returns, _name='myreturns')
thestrats = cerebro.run()
thestrat = thestrats[0]
print('Sharpe Ratio:', thestrat.analyzers.mysharpe.get_analysis())
print('Drawdown:', thestrat.analyzers.mydrawdown.get_analysis())
print('Returns:', thestrat.analyzers.myreturns.get_analysis())
cerebro.plot()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment