🚀 AI One-Click Generation of quantconnect Strategy Code

How to Implement a Fixed Fractional Portfolio Sizing Model in QuantConnect (with Python Code)

quantconnect | Published on: 2025/12/5
The following content is generated by EasyQuant .

Problem Description

Please show me how to build a portfolio model that allocates a fixed 5% of my capital to every trade signal.

Solution

To implement a portfolio model that allocates a specific, fixed percentage (e.g., 5%) to every trade signal regardless of the number of active signals or total portfolio value, you need to create a custom Portfolio Construction Model.

Standard models (like EqualWeightingPortfolioConstructionModel) typically calculate weights based on the count of active insights to utilize 100% of the capital. To enforce a "hard" 5% limit per trade, we override the CreateTargets method.

Strategy Overview

  1. Custom Portfolio Model: We define FixedFractionPortfolioConstructionModel. It takes a fraction parameter (0.05). When it receives an Insight, it creates a PortfolioTarget of exactly that size.
  2. Alpha Model: For demonstration, I will use a simple Momentum logic (2-day positive returns) to generate signals.
  3. Execution: We use ImmediateExecutionModel to fill orders immediately.

Complete Strategy Code

# region imports
from AlgorithmImports import *
# endregion

class FixedAllocationStrategy(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2020, 1, 1)
        self.set_end_date(2023, 1, 1)
        self.set_cash(100000)
        
        # 1. Select a Universe of liquid ETFs to test the allocation
        self.tickers = ["SPY", "QQQ", "IWM", "TLT", "GLD", "VNQ", "EEM", "LQD"]
        self.symbols = [self.add_equity(ticker, Resolution.DAILY).symbol for ticker in self.tickers]
        
        # 2. Set the Custom Portfolio Construction Model
        # We pass 0.05 to allocate exactly 5% per signal
        self.set_portfolio_construction(FixedFractionPortfolioConstructionModel(fraction=0.05))
        
        # 3. Set Execution Model (Immediate fill)
        self.set_execution(ImmediateExecutionModel())
        
        # 4. Set a Null Alpha Model (We will emit insights manually for clarity, 
        # or you could use a framework Alpha model)
        self.set_alpha(ConstantAlphaModel(InsightType.PRICE, InsightDirection.FLAT, timedelta(days=1)))
        
        # Schedule a daily method to generate insights
        self.schedule.on(self.date_rules.every_day("SPY"), 
                         self.time_rules.after_market_open("SPY", 30), 
                         self.generate_momentum_insights)

    def generate_momentum_insights(self):
        """
        Simple logic: If an asset is up for 2 consecutive days, go Long.
        """
        insights = []
        
        # Get history for all symbols
        history = self.history(self.symbols, 3, Resolution.DAILY)
        if history.empty: return

        for symbol in self.symbols:
            if symbol not in history.index.get_level_values(0): continue
            
            # Get price series
            closes = history.loc[symbol]['close']
            if len(closes) < 3: continue
            
            # Check 2-day momentum
            # Today > Yesterday AND Yesterday > DayBefore
            if closes.iloc[-1] > closes.iloc[-2] and closes.iloc[-2] > closes.iloc[-3]:
                # Generate an Insight
                # The Portfolio Model will see this and assign exactly 5%
                insight = Insight.price(symbol, timedelta(days=5), InsightDirection.UP)
                insights.append(insight)
        
        # Emit insights to the framework
        if len(insights) > 0:
            self.emit_insights(insights)


class FixedFractionPortfolioConstructionModel(PortfolioConstructionModel):
    """
    Custom Model: Allocates a fixed % of Total Portfolio Value to every active Insight.
    """
    def __init__(self, fraction: float = 0.05):
        super().__init__()
        self.fraction = fraction

    def CreateTargets(self, algorithm, insights):
        """
        Called by the Engine when new insights are available.
        Returns a list of PortfolioTargets.
        """
        targets = []
        
        for insight in insights:
            # 1. Handle Flat/Neutral signals (Liquidate)
            if insight.Direction == InsightDirection.FLAT:
                targets.append(PortfolioTarget.percent(algorithm, insight.Symbol, 0.0))
                continue
            
            # 2. Determine direction (1 for Long, -1 for Short)
            direction = 1 if insight.Direction == InsightDirection.UP else -1
            
            # 3. Calculate fixed weight
            # If fraction is 0.05, Long = 0.05, Short = -0.05
            weight = direction * self.fraction
            
            # 4. Create the target
            targets.append(PortfolioTarget.percent(algorithm, insight.Symbol, weight))
            
        return targets

Key Implementation Details

  1. FixedFractionPortfolioConstructionModel Class:

    • This class inherits from PortfolioConstructionModel.
    • The CreateTargets method is the core engine. It iterates through every Insight received from your Alpha model.
    • Instead of calculating a weight based on the total number of insights (which would fluctuate), it applies the hardcoded self.fraction (0.05) to every single target.
  2. PortfolioTarget.percent:

    • This helper creates a target that tells the Execution model: "Make sure Symbol represents X% of my total portfolio value."
    • If you have $100,000 and the fraction is 0.05, it will buy $5,000 worth of shares.
  3. Risk Note:

    • This model does not check if you have enough cash. If you generate 25 signals at 5% each, you will attempt to allocate 125% of your equity, resulting in margin usage (leverage).
    • If you wish to prevent leverage, you would need to add logic inside CreateTargets to check algorithm.Portfolio.MarginRemaining or cap the sum of targets.

Q&A: Portfolio Construction in QuantConnect

Q: How does this differ from EqualWeightingPortfolioConstructionModel?
A: The EqualWeighting model looks at all active insights and divides 100% by that count. If you have 2 signals, it allocates 50% each. If you have 50 signals, it allocates 2% each. The FixedFraction model above allocates 5% regardless of whether you have 1 signal or 20.

Q: What happens if I have existing positions?
A: The PortfolioTarget system is state-aware. If you already hold 5% of SPY and the model emits a new 5% target for SPY, no new trade occurs (because you are already at the target). If the price moves and your holding drops to 4.8%, the Execution model will buy 0.2% to rebalance back to 5%.

Q: Can I use this for Shorting?
A: Yes. The code direction = 1 if insight.Direction == InsightDirection.UP else -1 handles this. If the signal is DOWN, the weight becomes -0.05, and the algorithm will short sell 5% of the portfolio value.