Overall Statistics
Total Orders
242
Average Win
3.46%
Average Loss
-2.66%
Compounding Annual Return
78.846%
Drawdown
25.400%
Expectancy
0.255
Start Equity
1000
End Equity
2046.66
Net Profit
104.666%
Sharpe Ratio
1.54
Sortino Ratio
2.003
Probabilistic Sharpe Ratio
67.461%
Loss Rate
45%
Win Rate
55%
Profit-Loss Ratio
1.30
Alpha
0.139
Beta
3.026
Annual Standard Deviation
0.345
Annual Variance
0.119
Information Ratio
1.476
Tracking Error
0.272
Treynor Ratio
0.176
Total Fees
$242.00
Estimated Strategy Capacity
$7500000.00
Lowest Capacity Asset
TQQQ UK280CGTCB51
Portfolio Turnover
52.72%
# region imports
from AlgorithmImports import *
# endregion

class BreakOutStrategy(QCAlgorithm):
    # Initialize Algorithm
    def Initialize(self):
    
        self.SetStartDate(2023, 5, 2)
        self.SetEndDate(2024, 7, 24)
        self.SetCash(1000)  
        self.Symbol = self.AddEquity("tQQQ", Resolution.Minute).Symbol

        # Strategy Status
        self.first_five_high = None
        self.first_five_low = None
        self.waiting_for_breakout = False
        
        # Program de five first minute candles 
        self.Schedule.On(self.DateRules.EveryDay(self.Symbol), 
                         self.TimeRules.AfterMarketOpen(self.Symbol, 5), 
                         self.SetOpeningRange)

    def SetOpeningRange(self):
        # Reset the range every day
        self.first_five_high = None
        self.first_five_low = None
        self.waiting_for_breakout = True

        # Obtain the candles for the first five minutes once market opens
        history = self.History(self.Symbol, 5, Resolution.Minute)
        
        if not history.empty:
            # Calculate the maxiumum and minimum level
            self.first_five_high = history['high'].max()
            self.first_five_low = history['low'].min()

            self.Debug(f"First 5-minute range set: High={self.first_five_high}, Low={self.first_five_low}")

    def OnData(self, data: Slice):
        if not self.waiting_for_breakout or not data.Bars.ContainsKey(self.Symbol):
            return
        
        # Actutal price
        current_price = data[self.Symbol].Close
        
        # Entry signal
        if current_price > self.first_five_high:
            self.SetHoldings(self.Symbol, 1)  # Entrar en posición larga
            self.Debug(f"Breakout! Entering long at price {current_price}")
            self.waiting_for_breakout = False

        # Stop Loss signal
        if self.Portfolio[self.Symbol].Invested:
            stop_price = self.first_five_low
            if current_price < stop_price:
                self.Liquidate(self.Symbol)
                self.Debug(f"Stop-loss triggered. Liquidating at {current_price}")

    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status == OrderStatus.Filled:
            self.Debug(f"Order filled for {orderEvent.Symbol} at price {orderEvent.FillPrice} at time {self.Time}")