context is a variable for maintaing parameters
The data Object
The data object contains functions that allow us to look up current or historical pricing and volume data for any security. data is available in handle_data() and before_trading_start(), as well as any scheduled functions.
can be used to retrieve the most recent value of a given field(s) for a given asset(s). data.current() requires two arguments: the asset or list of assets, and the field or list of fields being queried. Possible fields include ‘price’, ‘open’, ‘high’, ‘low’, ‘close’, and ‘volume’. The output type will depend on the input types.
This returns the most recent price
This returns a Panda series indexed by asset, field is price
data.current([sid(24), sid(8554)], ‘price’)
This returns a Panda frame indexed by assets and fields as columns
data.current([sid(24), sid(8554)], [‘low’, ‘high’])
is used to determine if an asset(s) is currently listed on a supported exchange and can be ordered. If data.can_trade() returns True for a particular asset in a given minute bar, we are able to place an order for that asset in that minute. This is an important guard to have in our algorithm if we hand-pick the securities that we want to trade. It requires a single argument: an asset or a list of assets. The following example checks if AAPL is currently listed on a major exchange:
allows us to get trailing windows of historical pricing or volume data. data.history() requires 4 arguments: an asset or list of assets, a field or list of fields, an integer lookback window length, and a lookback frequency. Possible fields include ‘price’, ‘open’, ‘high’, ‘low’, ‘close’, and ‘volume’. Possible frequencies are ‘1d’ for daily and ‘1m’ for minutely.
The following example returns a pandas Series containing the price history of AAPL over the last 10 days and uses pandas.Series.mean() to calculate the mean.
# Get the 10-day trailing price history of AAPL in the form of a Series.
hist = data.history(sid(24), ‘price’, 10, ‘1d’)
# Mean price over the last 10 days.
mean_price = hist.mean()
Note: With ‘1d’ frequency, the most recent value in the result from data.history() will include a value for the current date in the simulation, which can sometimes be a value for a partial day. For example, if data.history() is called in the first minute of the day, the last row of the returned DataFrame will represent values from 9:31AM, whereas the previous 9 rows will represent end-of-day values.
To get the past 10 complete days of data, we can get an extra day of data, and drop the most recent row. The following example gets the trading volume of SPY from the last 10 complete days:
data.history(sid(8554), ‘volume’, 11, ‘1d’)[:-1].mean()
return type of data.history() depends on the input types. In the next example, the return type is a pandas DataFrame indexed by date, with assets as columns:
# Get the last 5 minutes of volume data for each security in our list.
hist = data.history([sid(24), sid(8554), sid(5061)], ‘volume’, 5, ‘1m’)
# Calculate the mean volume for each security in our DataFrame.
mean_volumes = hist.mean(axis=0)
If we pass a list of fields, we get a pandas Panel indexed by field, having date as the major axis, and assets as the minor axis:
# Low and high minute bar history for each of our securities.
hist = data.history([sid(24), sid(8554), sid(5061)], [‘low’, ‘high’], 5, ‘1m’)
# Calculate the mean low and high over the last 5 minutes
means = hist.mean()
mean_lows = means[‘low’]
mean_highs = means[‘high’]
The portfolio object stores important information about our portfolio. The portfolio object is stored in context, and as such, is accessible in each of our core functions and our scheduled functions. In this lesson, we are going to focus on the positions attribute of the portfolio object.
Our current positions are stored in context.portfolio.positions. which is similar to a Python dictionary having assets as keys, and Position objects (including information such as the number of shares and price paid) as values.
One example of when it can be useful to reference our current positions, is if we want to close out all of our open positions. To do so, we can iterate over the keys in context.portfolio.positions, and close out each position:
for security in context.portfolio.positions:
initialize() is a compulsory function.
it is called only once when algo starts and requires context as input
# Reference to AAPL
context.aapl = sid(24)
context.security_list = [sid(24), sid(8554), sid(5061)]
scheduled function takes a long position in SPY at the start of the week, and closes out the position at 3:30pm on the last day of the week:
schedule_function(open_positions, date_rules.week_start(), time_rules.market_open())
schedule_function(close_positions, date_rules.week_end(), time_rules.market_close(minutes=30))
# example of using record()
schedule_function(record_vars, date_rules.every_day(), time_rules.market_close())
set_slippage() is set in initialize()
Using the default model, if an order of 60 shares is placed for a given stock, then 1000 shares of that stock trade in each of the next several minutes and the volume_limit is 0.025, then our trade order will be split into three orders (25 shares, 25 shares, and 10 shares) that execute over the next 3 minutes.
At the end of each day, all open orders are canceled, so trading liquid stocks is generally a good idea. Additionally, orders placed exactly at market close will not have time to fill, and will be canceled.
set_commission is set in initialize()
The default commission model charges $0.0075 per share, with a minimum trade cost of $1.
custom functions written by user for the purpose of schedule_function
def open_positions(context, data):
def close_positions(context, data):
In the IDE, the record() function allows us to plot time series charts updated as frequently as daily in backtesting or as frequently as minutely in live trading. Up to 5 series can be recorded and plotted. To record a variable, we can pass it as a keyword argument to record(). The name of the argument will be the name of the series in the plot. Recorded time series are then displayed in a chart below the returns chart.
def record_vars(context, data):
long_count = 0
short_count = 0
for position in context.portfolio.positions.itervalues():
if position.amount > 0:
long_count += 1
if position.amount < 0:
short_count += 1
# Plot the counts
handle_data is called once at the end of each minute and requires context and data as input
def handle_data(context, data):
# Position 100% of our portfolio to be long in AAPL
# different types of order method here https://www.quantopian.com/help#api-order-methods
hist = data.history(context.security_list, ‘volume’, 10, ‘1m’).mean()
# print out value
Orders do not always fill instantaneously. Large orders, or orders placed for illiquid securities can take some time to fill. On Quantopian, the time it takes for an order to fill is determined by the slippage model being used. If an order takes more than one minute to fill, it’s considered open until it fills. When placing new orders, it’s sometimes necessary to consider open orders.
when placing orders multiple times in the same day, open orders need to be taken into account each time a new order is placed. order_target_percent() doesn’t consider open orders when calculating the number of shares to order. Placing a new order for a security that has an outstanding open order can lead to over-ordering (ordering past the target). This can lead to an algorithm spending more money than intended.
To avoid over-ordering, we can look at open orders using get_open_orders() which returns a dictionary of open orders keyed by assets. We can use this to ensure that we don’t have an open order for a security before we place a new order for it.
Get all open orders.
open_orders = get_open_orders()
if context.aapl not in open_orders and data.can_trade(context.aapl):
before_trading_start is called once per day and requires context and data as input
often used to select securities to order
def before_trading_start(context, data):
# do something
Quantopian’s example in full