-
Notifications
You must be signed in to change notification settings - Fork 0
/
portfolio_optimizationAPI.py
102 lines (77 loc) · 3.2 KB
/
portfolio_optimizationAPI.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
from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline.filters.morningstar import Q1500US
from quantopian.pipeline.data.sentdex import sentiment
def initialize(context):
"""
Called once at the start of the algorithm.
"""
# Rebalance every day, 1 hour after market open.
schedule_function(my_rebalance, date_rules.every_day(), time_rules.market_open(hours=1))
# Record tracking variables at the end of each day.
schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close())
# Create our dynamic stock selector.
attach_pipeline(make_pipeline(), 'my_pipeline')
set_commission(commission.PerTrade(cost=0.001))
def make_pipeline():
# 5-day sentiment moving average factor.
sentiment_factor = sentiment.sentiment_signal.latest
# Our universe is made up of stocks that have a non-null sentiment signal and are in the Q1500US.
universe = (Q1500US()
& sentiment_factor.notnull())
# A classifier to separate the stocks into quantiles based on sentiment rank.
sentiment_quantiles = sentiment_factor.rank(mask=universe, method='average').quantiles(2)
# Go short the stocks in the 0th quantile, and long the stocks in the 2nd quantile.
pipe = Pipeline(
columns={
'sentiment': sentiment_quantiles,
'longs': (sentiment_factor >= 4),
'shorts': (sentiment_factor <= 2),
},
screen=universe
)
return pipe
def before_trading_start(context, data):
try:
"""
Called every day before market open.
"""
context.output = pipeline_output('my_pipeline')
# These are the securities that we are interested in trading each day.
context.security_list = context.output.index.tolist()
except Exception as e:
print(str(e))
def my_rebalance(context, data):
"""
Place orders according to our schedule_function() timing.
"""
# Compute our portfolio weights.
long_secs = context.output[context.output['longs']].index
long_weight = 0.5 / len(long_secs)
short_secs = context.output[context.output['shorts']].index
short_weight = -0.5 / len(short_secs)
# Open our long positions.
for security in long_secs:
if data.can_trade(security):
order_target_percent(security, long_weight)
# Open our short positions.
for security in short_secs:
if data.can_trade(security):
order_target_percent(security, short_weight)
# Close positions that are no longer in our pipeline.
for security in context.portfolio.positions:
if data.can_trade(security) and security not in long_secs and security not in short_secs:
order_target_percent(security, 0)
def my_record_vars(context, data):
"""
Plot variables at the end of each day.
"""
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
record(num_long=long_count, num_short=short_count, leverage=context.account.leverage)