Overall Statistics
Total Trades
79
Average Win
11.47%
Average Loss
-15.00%
Compounding Annual Return
0%
Drawdown
100.000%
Expectancy
-0.412
Net Profit
-100.012%
Sharpe Ratio
-0.23
Probabilistic Sharpe Ratio
0.000%
Loss Rate
67%
Win Rate
33%
Profit-Loss Ratio
0.76
Alpha
-3.5
Beta
11.302
Annual Standard Deviation
4.547
Annual Variance
20.68
Information Ratio
-0.28
Tracking Error
4.503
Treynor Ratio
-0.092
Total Fees
$2063.75
Estimated Strategy Capacity
$720000.00
Lowest Capacity Asset
SPY Y5BMQ8ZJJZ3A|SPY R735QTJ8XC9X
Portfolio Turnover
-10010.61%
from AlgorithmImports import *
class MorningStarDataAlgorithm(QCAlgorithm):
    UnderlyingTicker = "SPY"

    def Initialize(self):
        self.SetStartDate(2023, 1, 1) # Cambiar fechas en las que quieres que corra
        self.SetEndDate(2023, 11, 1)
        self.SetCash(100000) 

        self.UniverseSettings.Resolution = Resolution.Daily
        
        equity = self.AddEquity(self.UnderlyingTicker, Resolution.Daily)
        option = self.AddOption(self.UnderlyingTicker)
        self.option_symbol = option.Symbol
        symbols = [self.option_symbol]
        #self.AddUniverseSelection(ManualUniverseSelectionModel(symbols))

        option.SetFilter(lambda u: (u.Strikes(-2, +2).Expiration(0, 90)))
        self.SetBenchmark(equity.Symbol)
        self.last_month = None
        self.ticket = None
        # Use the following method for a Framework Algorithm
        self.etf_constituents = []
        self.universe_etf = self.Universe.ETF("SPY", Market.USA,
            self.UniverseSettings, self.ETFConstituentsFilter)

        self.num_symbols = 2 # Número de acciones en el portafolio
        #self.AddUniverse(self.universe_etf)
        
        self.securities = []
        self.lastTradeDay = self.Time.date()
        #self.AddRiskManagement(MaximumDrawdownPercentPerSecurity())
        #self.AddRiskManagement(MaximumDrawdownPercentPortfolio(0.10, True))
        #self.AddRiskManagement(TrailingStopRiskManagementModel(0.40))

        #self.Schedule.On(self.DateRules.On(self.EndDate), 
        #         self.TimeRules.At(15, 55), 
        #         self.Liquidate)

        self.changes = None

    def ETFConstituentsFilter(self, constituents: List[ETFConstituentData]) -> List[Symbol]:
        selected = sorted([c for c in constituents if c.Weight],
            key=lambda c: c.Weight, reverse=True)
        if not selected:
            # keep the current universe if all weights are None
            return Universe.Unchanged

        self.etf_constituents = []
        for i in range(len(selected)):
            symbol = selected[i].Symbol
            if symbol in self.etf_constituents:
                continue
            self.etf_constituents.append(symbol)
            if len(self.etf_constituents) == self.num_symbols:
                return self.etf_constituents

        return Universe.Unchanged

    def OnData(self, data):
        ##### Options #####
        if self.IsMarketOpen(self.option_symbol):

            current_month = self.Time.month

            if current_month != self.last_month:
                if not self.ticket is None:
                    self.MarketOrder(self.ticket.Symbol, -1)
                chain = data.OptionChains.GetValue(self.option_symbol)
                if chain is None:
                    self.Debug('Chain is none')
                    return
                underlying_price = self.Securities[self.option_symbol.Underlying].Price
                expiry = max([x.Expiry for x in chain])
                # we sort the contracts to find OTM contract with farthest expiration
                contracts = sorted([x for x in chain if  x.Right == OptionRight.Put and x.Expiry == expiry], key=lambda x: x.Expiry, reverse=True)
                # Select contracts with a strike price 30% below the current market price
                contracts = [i for i in chain if i.Strike <= underlying_price * 0.71 and i.Strike >= underlying_price * 0.69]

                # if found, trade it
                if len(contracts) == 0: 
                    self.Debug('No contracts found..')
                    return

                self.Debug('Strike [-1]: '+str(contracts[-1].Strike))
                self.Debug('Expiry [-1]: '+str(contracts[-1].Expiry))

                symbol = contracts[-1].Symbol
                self.ticket = self.MarketOrder(symbol, 1)
                self.last_month = current_month

        ##### SPY Constituents #####

        if not self.changes is None: 
            if self.Time.date() != self.lastTradeDay:
                # liquidate removed securities
                for security in self.changes.RemovedSecurities:
                    if security.Invested:
                        self.Liquidate(security.Symbol)
                        self.Debug("Liquidated Stock: " + str(security.Symbol.Value))

                # we want 50% allocation in each security in our universe
                for security in self.changes.AddedSecurities:
                    self.SetHoldings(security.Symbol, 1/self.num_symbols)
                    self.Debug("Bought Stock: " + str(security.Symbol.Value))

            self.changes = None
            self.lastTradeDay = self.Time.date()
        
    def OnSecuritiesChanged(self, changes):
        self.changes = changes
        self.Log(str(changes))

    def OnOrderEvent(self, orderEvent):
        self.Log(str(orderEvent))