A stock backtesting API, designed for hackers who love money
SetupYou specify a strategy in DJ Scrooge by extending the Strategy class. The execute method gets called
once each day by the backtest object. This object stores all the data about the current simulation, like the
current simulation date, the portfolio. You call its buy_shares and sell_shares methods to simulation transactions.
class BuyHoldSPY(Strategy):
def execute(self):
backtest = self.backtest
cash = backtest.portfolio.cash
data = backtest.get_end_of_day('SPY')
sdate = backtest.simulation_date
index = data.get_index_from_date(sdate)
open_price = data.open_prices[index]
if cash > open_price:
backtest.buy_shares('SPY', cash / open_price, open_price)
Extend the Taxes class to specify how sales and dividends are taxed.
class CaliforniaTaxes(Taxes):
def is_long_term(self, purchase_date):
if purchase_date.year % 4 == 0:
delta = timedelta(366)
else:
delta = timedelta(365)
sdate = self.backtest.simulation_date
one_year_off = purchase_date + delta
if (sdate >= one_year_off):
return True
return False
def sell_tax(self, symbol, shares, gain_per_share, purchase_date):
tax = 0.35 + 0.093
if self.is_long_term(purchase_date):
tax = 0.15 + 0.093
return int(tax * shares * gain_per_share)
def dividend_tax(self, symbol, amount, purchase_date):
tax = 0.35 + 0.093
if self.is_long_term(purchase_date):
tax = 0.15 + 0.093
return int(tax * amount)
Subclasses of the Commissions class specify the trade commissions and fees of your broker.
class WellsPMACommissions(Commissions):
year = 1900
trades_this_year = 0
def buy_commissions(self, symbol, shares, price_per_share):
syear = self.backtest.simulation_date.year
if self.year != syear:
self.year = syear
self.trades_this_year = 0
self.trades_this_year += 1
if self.trades_this_year >= 100:
return 495
return 0
def sell_commissions(self, symbol, shares, price_per_share):
return self.buy_commission(symbol, shares, price_per_share)
The Backtest class weaves all these peices together to form a simulation. The chart_backtest method gives
a convenient way to see the results. The full code and resulting chart for this example follows:
def main():
start_date = date(2002,1,1)
end_date = date(2012, 5, 15)
buy_hold_test = Backtest(start_date, end_date, commissions_class=WellsPMACommissions,
taxes_class=CaliforniaTaxes, strategy_class=BuyHoldSPY,
end_of_day_class=Yahoo)
chart_backtest(buy_hold_test, title='Buy & Hold S&P 500 Index (SPY)')
if __name__ == '__main__':
main()
Now you can see how well your strategy did.
Learn more