Overall Statistics
Total Orders
29
Average Win
0%
Average Loss
0%
Compounding Annual Return
429.561%
Drawdown
10.700%
Expectancy
0
Start Equity
1000000
End Equity
1746019.22
Net Profit
74.602%
Sharpe Ratio
5.499
Sortino Ratio
8.861
Probabilistic Sharpe Ratio
90.900%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
2.312
Beta
3.028
Annual Standard Deviation
0.448
Annual Variance
0.201
Information Ratio
6.366
Tracking Error
0.379
Treynor Ratio
0.814
Total Fees
$72.19
Estimated Strategy Capacity
$1300000000.00
Lowest Capacity Asset
TSLA UNU3P8Y3WFAD
Portfolio Turnover
1.68%
Drawdown Recovery
14
# 2025-11-22 07:40:22.963 | CodeBlock(path='./03 Writing Algorithms/34 Algorithm Framework/06 Execution/01 Key Concepts/99 Examples.html', div=1, pre=0, language=csharp, url='quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/execution/key-concepts#99-Examples')
# 2025-11-22 07:40:22.963 |  -> Backtest failed. Error: Failed queries: ['Insufficient buying power to complete orders', '']
# 2025-11-22 07:40:22.963 | 
# 2025-11-22 08:57:12.452 | CodeBlock(path='./03 Writing Algorithms/34 Algorithm Framework/06 Execution/01 Key Concepts/99 Examples.html', div=1, pre=1, language=python, url='quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/execution/key-concepts#99-Examples')
# 2025-11-22 08:57:12.453 |  -> Backtest failed. Error: Failed queries: ['Insufficient buying power to complete orders', '']

# 2025-11-22 07:40:22.963 | CodeBlock(path='./03 Writing Algorithms/34 Algorithm Framework/06 Execution/01 Key Concepts/99 Examples.html', div=1, pre=0, language=csharp, url='quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/execution/key-concepts#99-Examples')
# 2025-11-22 07:40:22.963 |  -> Backtest failed. Error: Failed queries: ['Insufficient buying power to complete orders', '']
# 2025-11-22 07:40:22.963 | 
# 2025-11-22 08:57:12.452 | CodeBlock(path='./03 Writing Algorithms/34 Algorithm Framework/06 Execution/01 Key Concepts/99 Examples.html', div=1, pre=1, language=python, url='quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/execution/key-concepts#99-Examples')
# 2025-11-22 08:57:12.453 |  -> Backtest failed. Error: Failed queries: ['Insufficient buying power to complete orders', '']

# region imports
from AlgorithmImports import *
# endregion

class FrameworkExecutionModelAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 31)
        self.set_cash(1000000)
        self.universe_settings.resolution = Resolution.DAILY

        # Add a universe of the most liquid stocks since their trend is more capital-supported.
        self.add_universe(self.universe.top(2))
        # Emit insights all for selected stocks.
        self.add_alpha(ConstantAlphaModel(InsightType.PRICE, InsightDirection.UP, timedelta(7)))
        # Equal weighting on each insight is needed to dissipate capital risk evenly.
        self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())

        # To place bracket orders besides basic orders as well.
        self.set_execution(StopLossExecutionModel(0.05))

class StopLossExecutionModel(ExecutionModel):
    def __init__(self, stop_loss: float = 0.05) -> None:
        self.targets_collection = PortfolioTargetCollection()
        self.stop_loss = stop_loss
        self.stop_loss_tickets = {}
        # Track market order tickets waiting for fill to set stop-loss
        self.pending_stop_loss = {}

    def execute(self, algorithm: QCAlgorithm, targets: List[IPortfolioTarget]) -> None:
        self.targets_collection.add_range(targets)
        if not self.targets_collection.is_empty:
            for target in self.targets_collection.order_by_margin_impact(algorithm):
                security = algorithm.securities[target.symbol]
                quantity = target.quantity - security.holdings.quantity
                if quantity == 0: continue

                above_minimum_portfolio = BuyingPowerModelExtensions.above_minimum_order_margin_portfolio_percentage(
                    security.buying_power_model,
                    security,
                    quantity,
                    algorithm.portfolio,
                    algorithm.settings.minimum_order_margin_portfolio_percentage)
                
                if above_minimum_portfolio:
                    # Cancel existing stop-loss orders
                    if target.symbol in self.stop_loss_tickets:
                        for ticket in self.stop_loss_tickets[target.symbol]:
                            if ticket.status == OrderStatus.SUBMITTED or ticket.status == OrderStatus.PARTIALLY_FILLED:
                                ticket.cancel()
                        self.stop_loss_tickets[target.symbol] = []
                    
                    # Place market order and track it for stop-loss placement
                    if quantity > 0:
                        market_ticket = algorithm.market_order(security.symbol, quantity)
                        self.pending_stop_loss[market_ticket.order_id] = (target.symbol, quantity)
                        
                elif not PortfolioTarget.minimum_order_margin_percentage_warning_sent:
                    PortfolioTarget.minimum_order_margin_percentage_warning_sent = False

            self.targets_collection.clear_fulfilled(algorithm)

    def on_order_event(self, algorithm: QCAlgorithm, order_event: OrderEvent) -> None:
        if order_event.status == OrderStatus.FILLED:
            # Check if this is a market order we need to set a stop-loss for
            if order_event.order_id in self.pending_stop_loss:
                symbol, quantity = self.pending_stop_loss.pop(order_event.order_id)
                # Use the actual fill price to calculate stop-loss
                stop_loss_price = order_event.fill_price * (1 - self.stop_loss)
                ticket = algorithm.stop_market_order(symbol, -quantity, stop_loss_price)
                
                if symbol not in self.stop_loss_tickets:
                    self.stop_loss_tickets[symbol] = []
                self.stop_loss_tickets[symbol].append(ticket)
            
            # Handle stop-loss fills
            elif order_event.ticket.order_type == OrderType.STOP_MARKET:
                algorithm.insights.cancel([order_event.symbol])
                if order_event.symbol in self.stop_loss_tickets:
                    self.stop_loss_tickets[order_event.symbol] = [
                        t for t in self.stop_loss_tickets[order_event.symbol] 
                        if t.order_id != order_event.order_id
                    ]