This notebook constructs an example pipeline on German equities containing factors from both pricing and various FactSet datasets. A custom-defined factor is then analyzed with the Alphalens API and used to construct an example target portfolio.
# Import various Dataset Libraries:
from quantopian.pipeline.data import EquityPricing
from quantopian.pipeline.data.factset import Fundamentals, GeoRev, RBICSFocus, EquityMetadata
# Import 2 built-in factors for returns and average dollar volume:
from quantopian.pipeline.factors import Returns, AverageDollarVolume
# 1-day returns:
returns = Returns(window_length=2)
CustomFactors allow you to build your own factors. Below is an example using short-term momentum:
# Import CustomFactor:
from quantopian.pipeline.factors import CustomFactor
# Creating CustomFactor for short-term momentum:
class st_mom(CustomFactor):
inputs=[EquityPricing.close]
window_length = 22
def compute(self, today, assets, out, price):
out[:] = (price[-1] - price[0]) / price[0]
# CustomFactor using short-term momentum:
st_momentum = st_mom()
Below are additional factors created from FactSet's Fundamentals, RBICS Focus, Geographic Revenue, and Equity Metadata datasets:
# Annual sales factor from FS Fundamentals converted to USD with currency conversion:
annual_sale_usd = Fundamentals.sales_af.fx('USD').latest
# RBICS sector classification factor:
sector = RBICSFocus.l2_name.latest
# Create country-level revenue exposure DataSets by slicing GeoRev:
GeoRevUS = GeoRev.slice('US')
# Create estimated revenue percentage factors for the geographic locations referenced above:
rev_exposure_US = GeoRevUS.est_pct.latest
# Show listing currency:
listing_currency = EquityMetadata.listing_currency.latest
An example Pipeline, set to the German equities domain, is defined below for most of the factors defined above:
# Import libraries needed to run Pipeline as well as chosen equity domain (German equities):
from quantopian.pipeline.domain import DE_EQUITIES
from quantopian.pipeline import Pipeline
from quantopian.research import run_pipeline
# Define our pipeline output with the factors (defined above):
pipe = Pipeline(
columns={
'returns': returns,
'annual_sales_usd': annual_sale_usd,
'st_momentum': st_momentum,
'sector': sector,
#'rev_exposure_DE': rev_exposure_US,
'listing_currency': listing_currency
},
domain=DE_EQUITIES, # Set the pipeline domain to equities traded on German exchanges
screen=AverageDollarVolume(inputs=[EquityPricing.close.fx('EUR'), EquityPricing.volume], window_length=20) > 1000000 # Screen out equities of low trading volumes
)
# Set the dates that the pipeline should run between:
start_date = '2016-01-01'
end_date = '2016-10-01'
# Run the pipeline:
results = run_pipeline(
pipe,
start_date= start_date,
end_date= end_date
)
results.head()
results.listing_currency.unique()
Alphalens is a Quantopian open source library for performance analysis of predictive (alpha) factors. The main function of Alphalens is to surface the most relevant statistics and plots about an alpha factor.
# Import Alphalens and pandas libraries:
import alphalens as al
import pandas as pd
# Define and run a Pipeline for 1-day returns data:
returns_pipe = Pipeline(
columns={
'1D': Returns(window_length=2),
},
domain=DE_EQUITIES,
)
returns_data = run_pipeline(returns_pipe, '2016-01-01', '2016-10-01')
# Convert backward-looking returns into a forward-returns series:
shifted_returns = al.utils.backshift_returns_series(returns_data['1D'], 2)
al_returns = pd.DataFrame(
data=shifted_returns,
index=results.index,
columns=['1D'],
)
al_returns.index.levels[0].name = "date"
al_returns.index.levels[1].name = "asset"
# Print both returns and shifted returns for asset RAA:
display(returns_data.xs(symbols(1178883552065623), level=1).head(5),
al_returns.xs(symbols(1178883552065623), level=1).head(5)
)
# Format the factor and forward returns data into a format suitable for Alphalens functions:
al_data = al.utils.get_clean_factor(
results['st_momentum'],
al_returns,
quantiles=5,
)
# Create a full alphalens tearsheet:
from alphalens.tears import create_full_tear_sheet
create_full_tear_sheet(al_data)
The Optimize API makes it easy to turn the output of a pipeline into an objective and a set of constraints. The order_optimal_portfolio
function can be used to transition a current portfolio to a target portfolio that satisfies specifications.
This example constructs an example target portfolio from the st_momentum
factor of the pipeline results with a chosen objective and set of constraints.
# Import the Optimize API:
import quantopian.optimize as opt
# Retrieve a particular day's worth of pipeline data on which we'd like to
# calculate an optimal portfolio:
date = '2016-08-30'
results_date_to_optimize = results.loc[date].dropna()
# Define the MaximizeAlpha Objective function:
objective = opt.MaximizeAlpha(results_date_to_optimize.st_momentum)
# Define threshold values to set constraints:
MAX_GROSS_LEVERAGE = 1.0
MAX_POSITION_WEIGHT = .025
# Set max gross exposure, dollar neutral, position concentration constraints with threshold values:
max_gross = opt.MaxGrossExposure(MAX_GROSS_LEVERAGE)
dollar_neutral = opt.DollarNeutral()
position_concentration = opt.PositionConcentration.with_equal_bounds(
-MAX_POSITION_WEIGHT,
MAX_POSITION_WEIGHT
)
constraints = [max_gross,
dollar_neutral,
position_concentration]
The objective and list of constraints can be passed to the calculate_optimal_portfolio function to calculate a target portfolio - a Series containing weights that maximize the objective without violating any constraints.
portfolio_weights = opt.calculate_optimal_portfolio(objective, constraints)
portfolio_weights.head()
# Constraint report:
print " Gross exposure: {:.2f}".format(portfolio_weights.abs().sum())
print " Net exposure: {:.2f}\n".format(portfolio_weights.sum())
print " Largest long position: {:.3f}".format(portfolio_weights.max())
print " Largest short position: {:.3f}".format(portfolio_weights.min())
print " Number of Positions: {:}\n".format(portfolio_weights[portfolio_weights != 0].count())