Generate code in 3 minutes
Enter your idea and AI generates runnable code.
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.
FixedFractionPortfolioConstructionModel. It takes a fraction parameter (0.05). When it receives an Insight, it creates a PortfolioTarget of exactly that size.ImmediateExecutionModel to fill orders immediately.# 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
FixedFractionPortfolioConstructionModel Class:
PortfolioConstructionModel.CreateTargets method is the core engine. It iterates through every Insight received from your Alpha model.self.fraction (0.05) to every single target.PortfolioTarget.percent:
Symbol represents X% of my total portfolio value."Risk Note:
CreateTargets to check algorithm.Portfolio.MarginRemaining or cap the sum of targets.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.