Hello all,

I wanted to share some useful code to make switching to, and working with, minute data easier.

The aim is to make it easy to get from one day to the next, so only your entry point during the day needs to be worried about. It tends to shorten your handle_data function too, which is nice.

This backtest was run on daily data with batch_transform, the next backtest is the same algorithm switched to minute data to give an example of making the switch.

The algorithm is an MPT tangency portfolio. It imports the 3 month t-bill rates from Quandl to be used as the risk free rate.

Dave

Clone Algorithm

15

Loading...

There was an error loading this backtest.

Backtest from
to
with
initial capital

Cumulative performance:

Algorithm
Benchmark

Custom data:

Total Returns

--

Alpha

--

Beta

--

Sharpe

--

Sortino

--

Max Drawdown

--

Benchmark Returns

--

Volatility

--

Returns | 1 Month | 3 Month | 6 Month | 12 Month |

Alpha | 1 Month | 3 Month | 6 Month | 12 Month |

Beta | 1 Month | 3 Month | 6 Month | 12 Month |

Sharpe | 1 Month | 3 Month | 6 Month | 12 Month |

Sortino | 1 Month | 3 Month | 6 Month | 12 Month |

Volatility | 1 Month | 3 Month | 6 Month | 12 Month |

Max Drawdown | 1 Month | 3 Month | 6 Month | 12 Month |

''' This algorithm uses the 3-month treasury bill rate as the risk free rate to construct a modern portfolio theory tangency portfolio. Ref: http://faculty.washington.edu/ezivot/econ424/portfolioTheoryMatrix.pdf ''' import pandas as pd import numpy as np import numpy.linalg as la import math import datetime from pytz import timezone # data accumulator for trailing window @batch_transform(window_length=50) def accumulate_data(data): return data ############## # Math Utils # ############## def tangent_portfolio(R, rfr=0.0, leverage=1.0): ''' Solves the efficient frontier problem given a risk free rate (rfr). ''' c_inv = np.linalg.inv(R.cov()) mu = R.mean() ones = np.ones(len(mu)) rf = rfr * ones t = c_inv.dot(mu - rf) / ones.T.dot(c_inv.dot(mu - rf)) return pd.Series(t, index=R.columns) * leverage ######################## # Quantopian Functions # ######################## def fetcher_pre_func(df): ''' This should convert % to decimals but it makes everything blow up ''' # df['Value'] = df['Value'] / 100.0 return df def initialize(context): ''' Called once at the very beginning of a backtest (and live trading). Use this method to set up any bookkeeping variables. The context object is passed to all the other methods in your algorithm. Parameters context: An initialized and empty Python dictionary that has been augmented so that properties can be accessed using dot notation as well as the traditional bracket notation. Returns None ''' # Set Account Leverage context.leverage = 1.0 # Initialize treasury yield variable context.t_yield = 0.0 # Define Universe context.sids = [ sid(19656), sid(19655), sid(19660), sid(19658), sid(19654), sid(19659), sid(19662), sid(19657), sid(19661), ] # Use the fetcher to import the 3 month t-bill rate fetch_csv('http://www.quandl.com/api/v1/datasets/FRED/DTB3.csv\ ?request_source=python&request_version=2&sort_order=asc', date_column='Date', symbol='treasury_yield', post_func=fetcher_pre_func, date_format='%Y-%m-%d' ) context.days_traded = 0 context.rebal_days = 21 def handle_data(context, data): ''' Called when a market event occurs for any of the algorithm's securities. Parameters data: A dictionary keyed by security id containing the current state of the securities in the algo's universe. context: The same context object from the initialize function. Stores the up to date portfolio as well as any state variables defined. Returns None ''' # Set the risk free rate to the latest treasury yield. # The first day throws an error, hence the try. try: context.t_yield = data['treasury_yield']['Value'] record(treasury_yield=context.t_yield) except KeyError as e: log.debug('KeyError in t_yield: %s'%e) # Get trailing window of data, return if not enough data is accumulated datapanel = accumulate_data(data) # Wait until batch_transform has accumulated enough bars if datapanel is None: return # Check if it's a rebalance day if context.days_traded % context.rebal_days != 0: context.days_traded += 1 return context.days_traded += 1 # Get target portfolio weights prices = datapanel['price'][context.sids] returns = prices.pct_change().dropna() weights = tangent_portfolio( returns, rfr=context.t_yield, leverage=context.leverage ) # Place orders for sec in context.sids: order_target_percent(sec, weights[sec])