Capping the Leverage

I just started, so can someone please share a simple example algorithm or some code with me that caps the leverage at 1.0 without using the order_optimizer? Thanks

2 responses

Account leverage is defined as the sum of the absolute value of long and short positions divided by the portfolio value. For a leverage of one, the sum of the absolute values of position weights must equal 1.

So, if one has a series with all the securities and weights one wishes to hold, then divide the series by the sum of the absolute value of the weights to ensure the gross leverage is 1 something like this

weights = weights / weights.abs().sum

The general ordering logic would look like this.

# Make two series of the longs and shorts and associated weights
# Ensure that all the short weights are negative (this is what tells order to short them)
# This would come from the algo's selection and weighting process
# Make sure to include any current securities if those are to be held

# Combine the two series
weights = pd.concat([longs, shorts])

# Divide by the sum of the abs value of the weights to ensure the gross leverage is 1
weights = weights / weights.abs().sum
# Order the stocks
for stock, weight in weights.iteritems():
order_target_percent(stock, weight)
# Close any positions not in our long or short list
for stock, position in context.portfolio.positions.iteritems():
if data.can_trade(stock) and stock not in weights.index:
order_target_percent(stock, 0)

Using the order_optimal_portfolio method is almost exactly the same but takes a few less lines of code and can be easily enhanced to incorporate other constraints. The attached algo shows a simple algo which incorporates both order approaches.

0
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
 Returns 1 Month 3 Month 6 Month 12 Month
 Alpha 1 Month 3 Month 6 Month 12 Month
 Beta 1 Month 3 Month 6 Month 12 Month
 Sharpe 1 Month 3 Month 6 Month 12 Month
 Sortino 1 Month 3 Month 6 Month 12 Month
 Volatility 1 Month 3 Month 6 Month 12 Month
 Max Drawdown 1 Month 3 Month 6 Month 12 Month
"""
This is a sample algorithm on Quantopian for you to test and adapt.

One can either use the plain order methods or the optimize methods.
"""

# Import necessary Pipeline modules
from quantopian.pipeline import Pipeline
from quantopian.algorithm import attach_pipeline, pipeline_output

# Import specific filters and factors which will be used
from quantopian.pipeline.filters import QTradableStocksUS, StaticAssets
from quantopian.pipeline.factors import RSI, SimpleMovingAverage

# Import datasets which will be used
from quantopian.pipeline.data.builtin import USEquityPricing

# import optimize
import quantopian.optimize as opt

# Import pandas
import pandas as pd

def initialize(context):
"""
Initialize constants, create pipeline, and schedule functions
This uses the default slippage and commission models
"""
# Universe we wish to trade
# Place one or more desired symbols below
context.MY_STOCKS = symbols('SPY', 'GLD')

# Create our weights (evenly weighted)
context.WEIGHT = 1.0 / len(context.MY_STOCKS)

# Constants for min and max RSI
context.MIN_RSI = 30
context.MAX_RSI = 70

# Make our pipeline and attach to the algo
attach_pipeline(make_pipeline(context), 'my_pipe')

# Place orders
schedule_function(
func=place_orders_using_order_method,
date_rule=date_rules.week_start(),
time_rule=time_rules.market_open()
)

def make_pipeline(context):
"""
Define a pipeline.
This not only defines the data but also the logic to determine longs and shorts

We break this code out into its own function to make it easier to
test and modify in isolation. In particular, this function can be
copy/pasted into research and run by itself.
Parameters
-------
context : AlgorithmContext

Returns
-------
pipe : Pipeline
Represents computations we would like to perform on the assets
"""
my_universe = StaticAssets(context.MY_STOCKS)

# Create any needed factors.
rsi = RSI(window_length=10)
sma_10 = SimpleMovingAverage([USEquityPricing.close], window_length=10)
sma_25 = SimpleMovingAverage([USEquityPricing.close], window_length=25)

# Create any filters based upon these factors
rsi_between_min_max = (rsi > context.MIN_RSI) & (rsi < context.MAX_RSI)

# Rules to long and short stocks
# Open (long or short) any securities meeting these rules
# Anything held which isn't in either of these will be closed
longs = (
my_universe
& rsi_between_min_max
& (sma_10 < sma_25)
)

shorts = (
my_universe
& rsi_between_min_max
& (sma_10 > sma_25)
)

# Create our pipeline
pipe = Pipeline(
columns={
'longs': longs,
'shorts': shorts,
},
screen=my_universe,
)

return pipe

"""
Run our pipeline to fetch the actual data.
It's a good practice to place the pipeline execution here.
This gets allocated more time than scheduled functions.
"""
context.output = pipeline_output('my_pipe')

def place_orders_using_optimize(context, data):
"""
Use Optimize to place orders all at once
"""
# Make a series of the longs and shorts and associated weights
# Ensure that all the short weights are negative (this is what tells opt to short them)
longs = pd.Series(context.WEIGHT, context.output.query('longs').index)
shorts = pd.Series(-context.WEIGHT, context.output.query('shorts').index)

# Combine the two
weights = pd.concat([longs, shorts])

# Create our TargetWeights objective
target_weights = opt.TargetWeights(weights)

# Execute the order_optimal_portfolio method with above objective and constraint
# No need to loop through the stocks.
# The order_optimal_portfolio does all the ordering at one time
# Also closes any positions not in 'all_alphas'
# As a bonus also checks for 'can_trade'
# Could set constraints here if desired
order_optimal_portfolio(
objective = target_weights,
constraints = []
)

def place_orders_using_order_method(context, data):
"""
Use order methods to place orders
"""
# Make a series of the longs and shorts and associated weights
# Ensure that all the short weights are negative (this is what tells order to short them)
longs = pd.Series(context.WEIGHT, context.output.query('longs').index)
shorts = pd.Series(-context.WEIGHT, context.output.query('shorts').index)

# Combine the two
weights = pd.concat([longs, shorts])

# Divide by the abs value of the weights to ensure the gross leverage is 1
weights = weights / weights.abs().sum()

# Order the stocks
for stock, weight in weights.iteritems():