Notebook

## Using the NetExposure constraint to limit short¶

In [1]:
# Pipeline imports
from quantopian.pipeline import CustomFactor, Pipeline
from quantopian.pipeline.factors import DailyReturns

# Import run_pipeline method
from quantopian.research import run_pipeline

# Import optimize
import quantopian.experimental.optimize as opt

In [2]:
# Pipeline definition
# Make a pipeline with defined percent of longs and shorts
def  make_pipeline(universe_size=100, short_percent=50):

# Some random data. Universe with highest returns.

# Filter for specific assets to pass to CompareAssets factor
# Could be the result of some calculation but just using a static filter for testing
longs = my_universe & ~shorts

return Pipeline(
columns={
'shorts': shorts,
'longs': longs,
},
screen=my_universe
)

In [4]:
def get_weights(universe_size=100, short_percent=50, date='2019-01-02'):
df = run_pipeline(make_pipeline(universe_size=universe_size,
short_percent=short_percent), date, date)

# Create a column for weight - equal weight longs and shorts
weight = 1.0 / df.index.size
df.loc[df.longs, 'weights'] = weight
df.loc[df.shorts, 'weights'] = -weight

return df.xs(date, level=0).weights

In [35]:
# Lets run optimize to limit our short exposure
# Create a set of weights with 90% short
orig_weights = get_weights(universe_size=100, short_percent=90)

# One issue is that the optimize constraint defines 'net exposure' and not 'short weight'
# So, we need to do a bit of conversion. Start with our max desired short weight
max_percent_shorts = .8

# This implies the following max short exposure
max_short_exposure = (max_percent_shorts * -1.0) + (1.0-max_percent_shorts)

weights = orig_weights
loop = 0
while True:
# Now calculate an optimized portfolio using a net_exposure_constraint
objective = opt.TargetWeights(weights)
net_exposure_constraint = opt.NetExposure(max_short_exposure, 1.0)
opt_weights = opt.calculate_optimal_portfolio(objective, constraints=[net_exposure_constraint])
gross_exposure = opt_weights.abs().sum()
weights = opt_weights / gross_exposure
loop += 1
if gross_exposure > .99:
break

# Let's get some information about our results
short_percent = opt_weights.where(opt_weights<0).sum()
long_percent = opt_weights.where(opt_weights>0).sum()
net_exposure = short_percent + long_percent
gross_exposure = abs(short_percent) + abs(long_percent)

display('number of iterations: {}'.format(loop))
display('gross exposure: {}'.format(gross_exposure))
display('net exposure: {}'.format(net_exposure))
display('short percent: {}'.format(short_percent))
display(opt_weights)


Pipeline Execution Time: 0.49 Seconds
'number of iterations: 6'
'gross exposure: 0.994177152131'
'net exposure: -0.599999998959'
'short percent: -0.797088575545'
Equity(301 [ALKS])     -0.008857
Equity(351 [AMD])      -0.008857
Equity(2385 [DY])      -0.008857
Equity(3436 [HAE])     -0.008857
Equity(3885 [IMGN])    -0.008857
Equity(4031 [IONS])    -0.008857
Equity(4413 [AXGN])    -0.008857
Equity(5847 [PDLI])    -0.008857
Equity(6924 [SKY])     -0.008857
Equity(8910 [ANIK])    -0.008857
Equity(9693 [BKS])      0.019709
Equity(10417 [ARWR])   -0.008857
Equity(13601 [THG])    -0.008857
Equity(14379 [GEF])    -0.008857
Equity(14927 [FCN])    -0.008857
Equity(14972 [NBIX])   -0.008857
Equity(15622 [ANF])    -0.008857
Equity(17908 [PGNX])   -0.008857
Equity(19336 [WFT])     0.019709
Equity(19973 [EXTR])   -0.008857
Equity(20306 [UTHR])   -0.008857
Equity(21413 [LXRX])   -0.008857
Equity(21447 [SGMO])   -0.008857
Equity(21666 [MRVL])   -0.008857
Equity(22091 [ATTU])   -0.008857
Equity(22418 [ATRS])   -0.008857
Equity(22651 [HRTX])    0.019709
Equity(23709 [NFLX])   -0.008857
Equity(25660 [TRQ])    -0.008857
Equity(25972 [DVAX])   -0.008857
...
Equity(47432 [LOXO])   -0.008857
Equity(47845 [DERM])    0.019709
Equity(48015 [VRAY])    0.019709
Equity(48029 [UPLD])   -0.008857
Equity(48077 [PRAH])   -0.008857
Equity(48254 [WK])     -0.008857
Equity(48543 [SHAK])   -0.008857
Equity(48628 [NVTA])   -0.008857
Equity(49000 [BPMC])   -0.008857
Equity(49016 [COLL])   -0.008857
Equity(49060 [SHOP])   -0.008857
Equity(49189 [LNTH])   -0.008857
Equity(49236 [NTRA])   -0.008857
Equity(49572 [KURA])   -0.008857
Equity(49736 [EDIT])    0.019709
Equity(49934 [NTLA])   -0.008857
Equity(49995 [RETA])   -0.008857
Equity(50077 [TWLO])   -0.008857
Equity(50169 [TCMD])   -0.008857
Equity(50264 [EVBG])   -0.008857
Equity(50400 [CRSP])   -0.008857
Equity(50713 [GOOS])   -0.008857
Equity(50758 [OKTA])   -0.008857
Equity(50839 [BHVN])   -0.008857
Equity(50927 [SSTI])   -0.008857
Equity(50978 [MGY])    -0.008857
Equity(51124 [KL])     -0.008857
Equity(51314 [MDB])    -0.008857
Equity(51428 [BAND])   -0.008857
Equity(51542 [DNLI])   -0.008857
dtype: float64
In [36]:
# IT WORKS!
# But notice one had to iterate 6 times to get leverage above .99

In [ ]: