Back to Community
Style exposure constraint not being met

I am trying to understand why the style exposure is not met when I am utilizing the following constraint.

    factor_risk_constraints = opt.experimental.RiskModelExposure(  
        #context.risk_loading_pipeline,  
        context.risk_factor_betas,  
        version=opt.Newest  
    )

Is the constraint being ignored? Why is the algorithm not constraining the style exposure?

Clone Algorithm
5
Loading...
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
# V0.01 Klaus | initial version 

import numpy as np
# Import Algorithm API
import quantopian.algorithm as algo

# Import Optimize API
import quantopian.optimize as opt

# Pipeline imports
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.psychsignal import stocktwits
from quantopian.pipeline.factors import SimpleMovingAverage
from quantopian.pipeline.factors import Latest
from quantopian.pipeline.factors import VWAP
from quantopian.pipeline.data import USEquityPricing
from quantopian.pipeline import CustomFactor, Pipeline
import talib

# Import built-in universe and Risk API method
# from quantopian.pipeline.filters import Q500US
from quantopian.pipeline.filters import QTradableStocksUS
from quantopian.pipeline.experimental import risk_loading_pipeline

def initialize(context):
    # Constraint parameters
    context.max_leverage = 1.0
    context.max_pos_size = 0.015
    context.max_turnover = 0.64
    
    
    # Attach data pipelines
    algo.attach_pipeline(
        make_pipeline(),
        'data_pipe'
    )
    algo.attach_pipeline(
        risk_loading_pipeline(),
        'risk_pipe'
    )

    # Schedule rebalance function
    algo.schedule_function(
        rebalance,
        algo.date_rules.every_day(),
        algo.time_rules.market_open(),
    )


def before_trading_start(context, data):
    # Get pipeline outputs and
    # store them in context
    context.pipeline_data = algo.pipeline_output('data_pipe')

    context.risk_factor_betas = algo.pipeline_output('risk_pipe')
    
    #context.risk_loading_pipeline = algo.pipeline_output('risk_loading_pipeline')
    
# Pipeline definition
def make_pipeline():
    VWAP_score = VWAP(
        window_length=10,
        mask=QTradableStocksUS()
    )
    
    latest_close = USEquityPricing.close.latest
    
    VWAP_score = (VWAP_score-latest_close)/VWAP_score
    
    #is_tradable = alpha_adx.notnull() & QTradableStocksUS()

    return Pipeline(
        columns={
            'VWAP_score': VWAP_score,
            'latest_close':latest_close
        },
       screen=VWAP_score.notnull()
    )


def rebalance(context, data):
    # Retrieve alpha from pipeline output
    alpha = context.pipeline_data.VWAP_score
    alpha2 = context.pipeline_data.latest_close
    #latest_close_price = context.pipeline.data.latest_close_price

    if not alpha.empty:
        # Create MaximizeAlpha objective
        objective = opt.MaximizeAlpha(alpha)

        # Create position size constraint
        constrain_pos_size = opt.PositionConcentration.with_equal_bounds(
            -context.max_pos_size,
            context.max_pos_size
        )

        # Constrain target portfolio's leverage
        max_leverage = opt.MaxGrossExposure(context.max_leverage)

        # Ensure long and short books
        # are roughly the same size
        dollar_neutral = opt.DollarNeutral()

        # Constrain portfolio turnover
        max_turnover = opt.MaxTurnover(context.max_turnover)

        #constrain_sector_style_risk = opt.experimental.RiskModelExposure(  
        #risk_model_loadings=context.risk_loading_pipeline,  
        #version=0,
        #)
        
        # Constrain target portfolio's risk exposure
        # By default, max sector exposure is set at
        # 0.2, and max style exposure is set at 0.4
        factor_risk_constraints = opt.experimental.RiskModelExposure(
            context.risk_factor_betas,
            version=opt.Newest
        )

        # Rebalance portfolio using objective
        # and list of constraints
        algo.order_optimal_portfolio(
            objective=objective,
            constraints=[
                constrain_pos_size,
                max_leverage,
                dollar_neutral,
                max_turnover,
                #constrain_sector_style_risk,
                factor_risk_constraints
            ]
        )
There was a runtime error.
1 response

Hi Klaus, I'm assuming you ran a full backtest and saw you failed one of the 7 risk constraints. You can try manually constraining whichever style you were over/under exposed to by using the following (example: 0.01 = 1%). You can choose to set fixed values for all style type or specific to the one which go outside of the contest limits.

factor_risk_constraints = opt.experimental.RiskModelExposure(  
            context.risk_factor_betas,  
            version=opt.Newest,  
            min_momentum = -0.01,  
            max_momentum = 0.01,  
            min_size = -0.01,  
            max_size = 0.01,  
            min_value = -0.01,  
            max_value = 0.01,  
            min_short_term_reversal = -0.01,  
            max_short_term_reversal = 0.01,  
            min_volatility = -0.01,  
            max_volatility = 0.01,  
            )