Back to Community
Mean Variance with SPX Vol Restriction

Simple Mean Variance with Vol Restriction. Automatically reduce position, when vol spikes up. Need to improve max drawback. Vol is too high.

Clone Algorithm
48
Loading...
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 template algorithm on Quantopian for you to adapt and fill in.
"""

from __future__ import division
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import AverageDollarVolume
import datetime
from sqlalchemy import or_
import numpy as np
import pandas as pd
import scipy

num_stk = 75
spx_num = 10
window = 252
rf = 0.02

def initialize(context):
    #get_spx(context)
    context.spx = sid(8554)
    set_commission(commission.PerShare(cost=0.013, min_trade_cost=1.3))
    
    context.x0 = 1.0*np.ones(num_stk)/num_stk
    
    schedule_function(weekly_balance, date_rules.month_end(), time_rules.market_close(minutes=30))
    return

def handle_data(context,data):

        

    return


def get_spx(context):
    
    #fundamental_df = get_fundamentals(query(fundamentals.valuation.market_cap).filter(or_(fundamentals.company_reference.primary_exchange_id == "NAS",fundamentals.company_reference.primary_exchange_id == "NYS")).filter(fundamentals.valuation.market_cap != None).order_by(fundamentals.valuation.market_cap.desc()).limit(num_stk))
    #context.securities = map(sid,[i.sid for i in fundamental_df.columns])
    
    #2003,1,1
    #context.securities = [sid(5061),sid(3951),sid(1900),sid(25317),sid(368),sid(1637),sid(1638),sid(7671),sid(6295),sid(2855),sid(337),sid(630),sid(24819),sid(1787),sid(5149),sid(7216),sid(1237),sid(122),sid(8655),sid(5767),sid(14848),sid(4485),sid(739),sid(2602),sid(5121),sid(7061),sid(7035),sid(4668),sid(16841),sid(13017),sid(1209),sid(1941),sid(5479),sid(6683),sid(4246),sid(8344),sid(25920),sid(13210),sid(3212),sid(1499),sid(10555),sid(24829),sid(967),sid(3166),sid(114),sid(4768),sid(838),sid(2853),sid(7272),sid(1551),sid(6199),sid(8677),sid(5787),sid(24),sid(328),sid(18529),sid(4965),sid(6935),sid(5509),sid(3806),sid(20387),sid(13905),sid(4966),sid(3472),sid(25169),sid(16723),sid(21197),sid(1314),sid(5166),sid(15213),sid(10829),sid(2618),sid(6994),sid(1385),sid(20374),sid(8399),sid(7590),sid(7468),sid(6872),sid(6546),sid(2663),sid(4501),sid(15516),sid(6774),sid(12652),sid(456),sid(8158),sid(4553),sid(26470),sid(1416),sid(13915),sid(22864),sid(16954),sid(14966),sid(26437),sid(2069),sid(13639),sid(2696),sid(19725),sid(5010)][:num_stk]


    return

def before_trading_start(context,data): 
    #Setup Tickers for NASDAQ's Largest 200 Companies by Market Cap #Pending

    fundamental_df = get_fundamentals(query(fundamentals.valuation.market_cap).filter(or_(fundamentals.company_reference.primary_exchange_id == "NAS",fundamentals.company_reference.primary_exchange_id == "NYS")).filter(fundamentals.valuation.market_cap != None).order_by(fundamentals.valuation.market_cap.desc()).limit(num_stk))
    try:
        context.old_sec = context.securities
    except:
        pass
    context.securities = map(sid,[i.sid for i in fundamental_df.columns])

    #context.fundamental_df = fundamental_df[context.securities]
    #update_universe(context.fundamental_df.columns.values)

def variance(x,cov_mat,ret_mat,rf):
    Acov = np.asarray(cov_mat)
    Aret = np.asarray(ret_mat)

    variance = np.dot(x,np.dot(Acov,x).T)
    ret = np.dot(np.sum(Aret,axis=0),x)
    util = (ret-rf)/variance

    return 1/util

def weekly_balance(context, data):
    #SPX Range
    spx_price = data.history(context.spx,"price", bar_count = spx_num, frequency='1d')
    spx_std = np.std(np.log(spx_price[1:].astype(float).values/(spx_price[:-1])))*np.sqrt(252)

    spx_range = max(1-(max(0.2 ,min(0.5 ,spx_std))-0.2)/0.3,0.0001)
    
    prices = data.history(context.securities,"price", bar_count = window+1, frequency='1d')
    ret = np.log(prices[1:].astype(float).values/(prices[:-1]))
    ret = ret.fillna(0)

    #Parameter
    context.cons = ({'type': 'eq', 'fun': lambda x:  spx_range - sum(x)})
    context.bnds = tuple((0,spx_range) for x in context.securities)
    context.x0 = context.x0[:len(context.securities)]
    
    ret_cov = np.asarray(ret.cov())
    ret = np.asarray(ret)
    res= scipy.optimize.minimize(variance, context.x0, (ret_cov,ret,rf),constraints=context.cons,bounds=context.bnds)
    allocation = res.x
    #print "spx_range: " + str(spx_range)
    #print sum(allocation)
    allocation[allocation<0]=0
    record(spx_vol = spx_std, alloc = sum(allocation))
    denom = np.sum(allocation)
    if denom != 0:
        allocation = allocation/denom
        
    context.x0 = allocation

    for stock in context.old_sec:
        if stock in context.securities:
            pass
        else:
            print "Clearing: " + str(stock.symbol)
            order_target(stock, 0)

    for i,stock in enumerate(context.securities):
        if data.can_trade(stock):
            order_target_percent(stock,allocation[i])
        else:
            print str(stock) + " not tradable" 
There was a runtime error.