Configuring Time-Period Returns and Sharpe Ratio Analysis in Backtrader
Summary
This Backtrader example runs a simple moving-average crossover strategy on a CSV price feed and attaches analyzers for periodic returns and the Sharpe ratio. The user can choose daily, weekly, monthly, or yearly analysis periods, set starting cash and date bounds, and optionally write results or plot the data. Sharpe settings include annualization, a risk-free rate, a conversion factor, sample standard deviation, and whether to convert the risk-free rate to the selected timeframe.
The script illustrates how to configure and run these analyzers; it does not report results or evaluate the strategy's effectiveness. Interpretation depends on the input data, chosen timeframe, and Sharpe assumptions, including risk-free-rate conversion and standard deviation treatment. The example also relies on Backtrader's built-in crossover strategy, so it is principally a template for performance measurement rather than a new trading method. No transaction-cost model or other validation procedure is specified.
Key ideas
- The example calculates periodic returns and a Sharpe ratio for a moving-average crossover strategy.
- Return and Sharpe analysis can use daily, weekly, monthly, or yearly periods.
- Optional settings control annualization and the treatment of the risk-free rate and return variability.
- The script demonstrates analyzer setup but provides no strategy results or evidence of profitability.
Tags
Full text
# sharpe-timereturn.py
```py
#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
###############################################################################
#
# Copyright (C) 2015-2023 Daniel Rodriguez
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import argparse
import datetime
import backtrader as bt
def runstrat(pargs=None):
args = parse_args(pargs)
# Create a cerebro
cerebro = bt.Cerebro()
if args.cash is not None:
cerebro.broker.set_cash(args.cash)
# Get the dates from the args
fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
# Create the 1st data
data = bt.feeds.BacktraderCSVData(
dataname=args.data,
fromdate=fromdate,
todate=todate)
cerebro.adddata(data) # Add the data to cerebro
# Add the strategy
cerebro.addstrategy(bt.strategies.SMA_CrossOver)
tframes = dict(
days=bt.TimeFrame.Days,
weeks=bt.TimeFrame.Weeks,
months=bt.TimeFrame.Months,
years=bt.TimeFrame.Years)
# Add the Analyzers
cerebro.addanalyzer(bt.analyzers.TimeReturn,
timeframe=tframes[args.tframe])
shkwargs = dict()
if args.annualize:
shkwargs['annualize'] = True
if args.riskfreerate is not None:
shkwargs['riskfreerate'] = args.riskfreerate
if args.factor is not None:
shkwargs['factor'] = args.factor
if args.stddev_sample:
shkwargs['stddev_sample'] = True
if args.no_convertrate:
shkwargs['convertrate'] = False
cerebro.addanalyzer(bt.analyzers.SharpeRatio,
timeframe=tframes[args.tframe],
**shkwargs)
# Add a writer to get output
cerebro.addwriter(bt.WriterFile, csv=args.writercsv, rounding=4)
cerebro.run() # And run it
# Plot if requested
if args.plot:
pkwargs = dict(style='bar')
if args.plot is not True: # evals to True but is not True
npkwargs = eval('dict(' + args.plot + ')') # args were passed
pkwargs.update(npkwargs)
cerebro.plot(**pkwargs)
def parse_args(pargs=None):
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='TimeReturns and SharpeRatio')
parser.add_argument('--data', '-d',
default='../../datas/2005-2006-day-001.txt',
help='data to add to the system')
parser.add_argument('--cash', default=None, type=float, required=False,
help='Starting Cash')
parser.add_argument('--fromdate', '-f',
default='2005-01-01',
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--todate', '-t',
default='2006-12-31',
help='Starting date in YYYY-MM-DD format')
parser.add_argument('--writercsv', '-wcsv', action='store_true',
help='Tell the writer to produce a csv stream')
parser.add_argument('--tframe', '--timeframe', default='years',
required=False,
choices=['days', 'weeks', 'months', 'years'],
help='TimeFrame for the Returns/Sharpe calculations')
parser.add_argument('--annualize', required=False, action='store_true',
help='Annualize Sharpe Ratio')
parser.add_argument('--riskfreerate', required=False, action='store',
type=float, default=None,
help='Riskfree Rate (annual) for Sharpe')
parser.add_argument('--factor', required=False, action='store',
type=float, default=None,
help=('Riskfree Rate conversion factor for Sharpe '
'to downgrade riskfree rate to timeframe'))
parser.add_argument('--stddev-sample', required=False, action='store_true',
help='Consider Bessels correction for stddeviation')
parser.add_argument('--no-convertrate', required=False,
action='store_true',
help=('Upgrade returns to target timeframe rather than'
'downgrading the riskfreerate'))
# Plot options
parser.add_argument('--plot', '-p', nargs='?', required=False,
metavar='kwargs', const=True,
help=('Plot the read data applying any kwargs passed\n'
'\n'
'For example:\n'
'\n'
' --plot style="candle" (to plot candles)\n'))
if pargs is not None:
return parser.parse_args(pargs)
return parser.parse_args()
if __name__ == '__main__':
runstrat()
```Shown in full with attribution under the source's licence. Licence: GPL-3.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.