from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import SimpleMovingAverage, CustomFactor, RSI, Latest
from quantopian.pipeline.filters.morningstar import Q1500US, Q500US
import quantopian.pipeline.data.morningstar as mstar
import math
import datetime
import numpy as np
import talib as ta
import pandas as pd
quarter_lenght = 65
latest = -1
one_year_ago = -4*quarter_lenght
two_year_ago = -8*quarter_lenght
ttm = [ -1, -quarter_lenght, -2*quarter_lenght, -3*quarter_lenght]
ttm_py = [-4*quarter_lenght, -5*quarter_lenght, -6*quarter_lenght, -7*quarter_lenght]
class Sector(CustomFactor):
inputs = [mstar.asset_classification.morningstar_sector_code]
window_length = 1
def compute(self, today, asset_ids, out, sector):
out[:] = sector
class Volatility(CustomFactor):
inputs = [USEquityPricing.close]
window_length = 252
def compute(self, today, assets, out, close):
close = pd.DataFrame(data=close, columns=assets)
out[:] = np.log(close).diff().std()
class Value(CustomFactor):
inputs = [mstar.valuation_ratios.fcf_ratio,
mstar.valuation_ratios.ps_ratio,
mstar.valuation_ratios.pe_ratio,
mstar.valuation_ratios.pb_ratio,
mstar.valuation_ratios.peg_ratio]
window_length = 1
def compute(self, today, assets, out, fcf, ps, pe, pb, peg):
value_table = pd.DataFrame(index=assets)
value_table["fcf"] = fcf[-1]
value_table["ps"] = ps[-1]
value_table["pe"] = pe[-1]
value_table["pb"] = pb[-1]
value_table["peg"] = peg[-1]
out[:] = value_table.rank(ascending=True).mean(axis=1)
class FinancialStrength(CustomFactor):
inputs = [mstar.cash_flow_statement.cash_flowsfromusedin_operating_activities_direct, mstar.balance_sheet.current_liabilities, mstar.cash_flow_statement.free_cash_flow, mstar.balance_sheet.long_term_debt]
window_length =1
def compute(self, today, assets, out, cfo, current_liabilities, fcf, lt_debt):
value_table = pd.DataFrame(index=assets)
value_table["current_liability_coverage"] = (cfo[latest]/current_liabilities[latest])
value_table["fcf_cur_liability_cov"] = (fcf[latest]/current_liabilities[latest])
value_table["cfo_ltdebt"] = cfo[latest]/lt_debt[latest]
value_table["fcf_ltdebt"] = fcf[latest]/lt_debt[latest]
out[:] = value_table.rank().mean(axis=1)
class Quality(CustomFactor):
inputs = [mstar.operation_ratios.roe,
mstar.operation_ratios.roa,
mstar.operation_ratios.roic,
mstar.operation_ratios.net_margin,
mstar.operation_ratios.operation_margin,
mstar.cash_flow_statement.cash_flowsfromusedin_operating_activities_direct,
mstar.income_statement.total_revenue]
window_length = 1
def compute(self, today, assets, out, roe, roa, roic, net_margin, operation_margin, ocf, sales):
value_table = pd.DataFrame(index=assets)
value_table["roe"] = roe[-1]
value_table["roa"] = roa[-1]
value_table["roic"] = roic[-1]
value_table["net_margin"] = net_margin[-1]
value_table["operation_margin"] = operation_margin[-1]
value_table["op_cashflow_ratio"] = ocf[-1] / sales[-1]
out[:] = value_table.rank().mean(axis=1)
class Growth(CustomFactor):
inputs = [mstar.earnings_ratios.diluted_eps_growth, mstar.earnings_ratios.dps_growth, mstar.earnings_ratios.equity_per_share_growth, mstar.operation_ratios.net_income_growth, mstar.operation_ratios.operation_income_growth, mstar.operation_ratios.revenue_growth]
window_length = 1
def compute(self, today, assets, out, eps_growth, dps_growth, eqps_growth, net_income_growth, operation_income_growth, revenue_growth):
value_table = pd.DataFrame(index=assets)
value_table["eps_growth"] = eps_growth[-1]
value_table["dps_growth"] = dps_growth[-1]
value_table["eqps_growth"] = eqps_growth[-1]
value_table["net_income_growth"] = net_income_growth[-1]
value_table["operation_income_growth"] = operation_income_growth[-1]
value_table["revenue_growth"] = revenue_growth[-1]
out[:] = value_table.rank().mean(axis=1)
def initialize(context):
# Schedule our rebalance function to run at the start of each week.
schedule_function(my_rebalance, date_rules.week_start(), time_rules.market_open(hours=1))
# Record variables at the end of each day.
schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close())
# Create our pipeline and attach it to our algorithm.
pipe = make_pipeline(context)
attach_pipeline(pipe, 'pipeline')
def make_pipeline(context):
"""
A function to create our dynamic stock selector (pipeline). Documentation on
pipeline can be found here: https://www.quantopian.com/help#pipeline-title
"""
# Base universe set to the Q500US
base_universe = Q1500US()
quality = Quality(mask=base_universe)
rankedQual = quality.rank(ascending=True)
value = Value(mask=base_universe)
rankedVal = value.rank(ascending=True)
finStrength = FinancialStrength(mask=base_universe)
RankedFinStrength = finStrength.rank(ascending=True)
growth = Growth(mask=base_universe)
rankedGrowth = growth.rank(ascending=True)
longs = base_universe & rankedVal.percentile_between(50, 100) & rankedQual.percentile_between(75, 100) & rankedGrowth.percentile_between(50,100) & RankedFinStrength.percentile_between(60,100) & Volatility().rank().percentile_between(0,70) & (mScore < -2.22) & (altmanZ > 2.6)
shorts = base_universe & rankedVal.percentile_between(0, 30) & rankedGrowth.percentile_between(0,50) & rankedQual.percentile_between(0,25) & RankedFinStrength.percentile_between(0, 40)
#BullCross = SimpleMovingAverage(inputs=[USEquityPricing.close], mask=base_universe, window_length=50) > SimpleMovingAverage(inputs=[USEquityPricing.close], mask=base_universe, window_length=200)
#ShortBull = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=10, mask=base_universe) > SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=50, mask=base_universe)
#if context.bear == True:
# longs = base_universe & rankedQual.percentile_between(90,100) & (ShortBull)
#else:
# longs = base_universe & rankedQual.percentile_between(95,100) & (BullCross)
pipe = Pipeline(
screen = base_universe,
columns = {
'longs': longs,
'shorts': shorts,
}
)
return pipe
def my_compute_weights(context):
"""
Compute ordering weights.
"""
# Compute even target weights for our long positions and short positions.
#S&P 500 EMA calculations
'''context.bear = False
spy = symbol('SPY')
historydata = history(bar_count = 201, frequency='1d', field='close_price')
moving_average10 = ta.EMA(historydata[spy].values, timeperiod=10)[-1]
moving_average50 = ta.EMA(historydata[spy].values, timeperiod=50)[-1]
moving_average200 = ta.EMA(historydata[spy].values, timeperiod=200)[-1] '''
if(moving_average10 < moving_average50 < moving_average200):
target_long_weight = 0.1
target_short_weight = -0.8
context.bear=True
elif(moving_average10 > moving_average50 < moving_average200):
target_long_weight = 1.0
target_short_weight = -0.3
elif(moving_average10 > moving_average50 > moving_average200):
target_long_weight = 1.4
target_short_weight = -0.3
elif(moving_average10 < moving_average50 > moving_average200):
target_long_weight = 1.3
target_short_weight = -0.3
if(len(context.longs) == 0):
long_weight = 0
else:
long_weight = 1.3 /len(context.longs)
if(len(context.shorts) == 0):
short_weight = 0
else:
short_weight = -0.3 / len(context.shorts)
return long_weight, short_weight
def before_trading_start(context, data):
context.output = pipeline_output('pipeline')
# Go long in securities for which the 'longs' value is True.
context.longs = context.output[context.output['longs']].index.tolist()
# Go short in securities for which the 'shorts' value is True.
context.shorts = context.output[context.output['shorts']].index.tolist()
context.long_weight, context.short_weight = my_compute_weights(context)
def my_rebalance(context, data):
"""
Rebalance weekly.
"""
# Gets our pipeline output every day.
for security in context.portfolio.positions:
if security not in context.longs and security not in context.shorts and data.can_trade(security) and security != symbol('SPY'):
order_target_percent(security, 0)
for security in context.longs:
if data.can_trade(security):
order_target_percent(security, context.long_weight)
for security in context.shorts:
if data.can_trade(security):
order_target_percent(security, context.short_weight)
def my_record_vars(context, data):
"""
Record variables at the end of each day.
"""
longs = shorts = 0
for position in context.portfolio.positions.itervalues():
if position.amount > 0:
longs += 1
elif position.amount < 0:
shorts += 1
# Record our variables.
record(leverage=context.account.net_leverage, long_count=longs, short_count=shorts, target_longs=len(context.longs), target_shorts=len(context.shorts))
def handle_data(context,data):
"""
Called every minute.
"""
pass
Hi, so I've been checking out QuantConnect for a bit, and I'm wondering if there's any equivalent of Quantopian's pipeline API? I've been using Quantopian for a little bit but I'm still new to Quant algorithms. I've had some problems with timeouts and wanted to see if they'd run better here. Haven't looked very indepth so forgive me if I missed something. Pipeline let's you easily filter stocks by different factors instead of having to do queries and it simplifies things and takes care of any delistings and a bunch of that basic stuff. So if someone could show how to implement a version of my "Quality" factor, and a buy the top 25% and short the bottom 25%, rebalancing that every week for example? And then I'd probably get it and be able to finish the rest, I don't have much experience with python other than some really basic projects I did 4 years ago so if I'm making any big mistakes or if there are obvious optimizations, let me know too.
Thank you,
Steven
Steven Williams
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!