-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathlong_short_equity.py
127 lines (96 loc) · 4.25 KB
/
long_short_equity.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import numpy as np
import pandas as pd
from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.factors import CustomFactor, SimpleMovingAverage, AverageDollarVolume
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.filters import Q1500US
# Constraint Parameters
NUM_LONG_POSITIONS = 5
NUM_SHORT_POSITIONS = 5
class Momentum(CustomFactor):
inputs = [USEquityPricing.close]
window_length = 252
def compute(self, today, assets, out, prices):
out[:] = ((prices[-21] - prices[-252])/prices[-252] -
(prices[-1] - prices[-21])/prices[-21])
def make_pipeline():
# define alpha factors
momentum = Momentum()
growth = morningstar.operation_ratios.revenue_growth.latest
pe_ratio = morningstar.valuation_ratios.pe_ratio.latest
# Screen out non-desirable securities by defining our universe.
mkt_cap_filter = morningstar.valuation.market_cap.latest >= 500000000
price_filter = USEquityPricing.close.latest >= 5
universe = Q1500US() & price_filter & mkt_cap_filter & \
momentum.notnull() & growth.notnull() & pe_ratio.notnull()
combined_rank = (
momentum.rank(mask=universe).zscore() +
growth.rank(mask=universe).zscore() +
pe_ratio.rank(mask=universe).zscore()
)
longs = combined_rank.top(NUM_LONG_POSITIONS)
shorts = combined_rank.bottom(NUM_SHORT_POSITIONS)
long_short_screen = (longs | shorts)
# Create pipeline
pipe = Pipeline(columns = {
'longs':longs,
'shorts':shorts,
'combined_rank':combined_rank,
'momentum':momentum,
'growth':growth,
'pe_ratio':pe_ratio
},
screen = long_short_screen)
return pipe
def initialize(context):
set_slippage(slippage.VolumeShareSlippage(volume_limit=0.025, price_impact=0.1))
set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1))
attach_pipeline(make_pipeline(), 'long_short_factors')
# Schedule my rebalance function
schedule_function(func=rebalance,
date_rule=date_rules.month_start(),
time_rule=time_rules.market_open(hours=1,minutes=30),
half_days=True)
# record my portfolio variables at the end of day
schedule_function(func=recording_statements,
date_rule=date_rules.every_day(),
time_rule=time_rules.market_close(),
half_days=True)
def before_trading_start(context, data):
# Call pipeline_output to get the output
context.output = pipeline_output('long_short_factors')
context.longs = context.output[context.output['longs']].index.tolist()
context.shorts = context.output[context.output['shorts']].index.tolist()
context.long_weight, context.short_weight = assign_weights(context)
# These are the securities that we are interested in trading each day.
context.security_list = context.output.index
def assign_weights(context):
"""
Assign weights to securities that we want to order.
"""
long_weight = 0.5 / len(context.longs)
short_weight = -0.5 / len(context.shorts)
return long_weight, short_weight
def rebalance(context, data):
for security in context.portfolio.positions:
if security not in context.longs and \
security not in context.shorts and data.can_trade(security):
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 recording_statements(context, data):
# Check how many long and short positions we have.
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.leverage, long_count=longs, short_count=shorts)