Overall Statistics |
Total Orders 5 Average Win 1627.50% Average Loss -45.61% Compounding Annual Return 73.108% Drawdown 86.000% Expectancy 23.453 Start Equity 100000 End Equity 519521.87 Net Profit 419.522% Sharpe Ratio 1.209 Sortino Ratio 1.171 Probabilistic Sharpe Ratio 42.852% Loss Rate 33% Win Rate 67% Profit-Loss Ratio 35.68 Alpha 0.578 Beta 1.98 Annual Standard Deviation 0.634 Annual Variance 0.402 Information Ratio 1.234 Tracking Error 0.544 Treynor Ratio 0.387 Total Fees $202.13 Estimated Strategy Capacity $58000000.00 Lowest Capacity Asset QQQ RIWIV7K5Z9LX Portfolio Turnover 2.67% |
from AlgorithmImports import * import datetime class TrailingStopLossOptions(QCAlgorithm): def Initialize(self): self.SetStartDate(2018, 1, 1) self.SetEndDate(2021, 1, 1) self.SetCash(100000) self.underlying = self.AddEquity("QQQ", Resolution.Hour).Symbol self.options = self.AddOption("QQQ", Resolution.Hour) self.options.SetFilter(-2, 2, timedelta(days=30), timedelta(days=90)) self.contract = None self.expiration_threshold = timedelta(days=30) self.entryTicket = None self.stopMarketTicket = None self.entryTime = datetime.datetime.min self.stopMarketOrderFillTime = datetime.datetime.min self.highestPrice = 0 def OnData(self, slice): if not slice.OptionChains.ContainsKey(self.options.Symbol): return chain = slice.OptionChains[self.options.Symbol] if not chain: return if (self.Time - self.stopMarketOrderFillTime).days < 30: return if not self.contract or self.contract.Expiry - self.Time < self.expiration_threshold: self.contract = self.SelectOptionContract(chain) if not self.contract: return option_contract = chain.Contracts.get(self.contract.Symbol) if not option_contract: return option_price = option_contract.LastPrice self.Debug(f"Option Price: {option_price}") if not self.Portfolio.Invested and not self.Transactions.GetOpenOrders(self.contract.Symbol): quantity = self.CalculateOrderQuantity(self.contract.Symbol, 0.9) self.entryTicket = self.MarketOrder(self.contract.Symbol, quantity) self.entryTime = self.Time self.Debug(f"Entered position: {self.contract.Symbol}, Quantity: {quantity}") if self.stopMarketTicket is not None and self.Portfolio.Invested: if option_price > self.highestPrice: self.highestPrice = option_price updateFields = UpdateOrderFields() updateFields.StopPrice = option_price * 0.95 self.stopMarketTicket.Update(updateFields) self.Debug(f"Updated Stop Price to: {updateFields.StopPrice}") def SelectOptionContract(self, chain): contracts = [ contract for contract in chain if contract.Right == OptionRight.Call and 0.5 <= contract.Greeks.Delta <= 0.8 and contract.Expiry > self.Time + timedelta(days=30) and contract.Expiry < self.Time + timedelta(days=90) ] if not contracts: return None return min(contracts, key=lambda x: abs(x.Greeks.Delta - 0.7)) def OnOrderEvent(self, orderEvent): self.Debug(f"Order Event: {orderEvent}") if orderEvent.Status != OrderStatus.Filled: return if self.entryTicket is not None and self.entryTicket.OrderId == orderEvent.OrderId: self.highestPrice = orderEvent.FillPrice self.stopMarketTicket = self.StopMarketOrder(self.contract.Symbol, -self.entryTicket.Quantity, 0.95 * self.highestPrice) self.Debug(f"Placed Stop Market Order for: {self.contract.Symbol}") if self.stopMarketTicket is not None and self.stopMarketTicket.OrderId == orderEvent.OrderId: self.stopMarketOrderFillTime = self.Time self.highestPrice = 0 self.Debug("Stop market order filled.")