Overall Statistics |
Total Trades 4 Average Win 0.68% Average Loss -0.36% Compounding Annual Return -37.556% Drawdown 2.100% Expectancy -0.047 Net Profit -1.489% Sharpe Ratio -2.717 Probabilistic Sharpe Ratio 17.037% Loss Rate 67% Win Rate 33% Profit-Loss Ratio 1.86 Alpha 0.136 Beta 0.939 Annual Standard Deviation 0.104 Annual Variance 0.011 Information Ratio 6.793 Tracking Error 0.024 Treynor Ratio -0.3 Total Fees $9.20 Estimated Strategy Capacity $11000.00 Lowest Capacity Asset SPY 2ZXQTQXDXTEPY|SPY R735QTJ8XC9X Portfolio Turnover 45.24% |
#region imports from AlgorithmImports import * #endregion import numpy as np import math from position import * import datetime as dt class HipsterVioletCat(QCAlgorithm): def Initialize(self): self.SetStartDate(2015, 2, 27) # Set Start Date self.SetEndDate(2015, 3, 10) # Set Start Date self.SetCash(100000) # Set Strategy Cash # ------------------------------------ # Perameters # ------------------------------------ self.equity = self.AddEquity("SPY", Resolution.Minute) self.option= self.AddOption("SPY", Resolution.Minute) self.option.SetFilter(self.ContractUniverse) self.option.PriceModel = OptionPriceModels.CrankNicolsonFD() # both European & American, automatically # record data on each incoming data self.data = None # record contract subscribed self.contractsAdded = set() self.optionHoldings = dict() # instantiate trade manager self.trade_manager = TradeManager(self) self.Schedule.On(self.DateRules.EveryDay(self.equity.Symbol), self.TimeRules.AfterMarketOpen("SPY", 30), Action(self.TradeOption)) def OnData(self, data): if self.Time.time()>dt.time(10,1): return self.data = data self.chain =self.data.OptionChains.get(self.option.Symbol) def TradeOption(self): if self.chain is None: return if not self.Portfolio.Invested: self.trade_manager.TradeOption(self.getContractByDelta(-0.4, OptionRight.Put),-15) def ContractUniverse(self, universe): return universe.IncludeWeeklys().Expiration(TimeSpan.FromDays(1), TimeSpan.FromDays(45)).Strikes(-5,-5) def getContractByDelta(self,targetDelta, right= OptionRight.Call): ## Filter the Call/Put options contracts filteredContracts = [x for x in self.chain if x.Right == right] ## Sort the contracts according to their closeness to our desired expiry contractsSortedByExpiration = sorted(filteredContracts, key=lambda p: p.Expiry, reverse=False) closestExpirationDate = contractsSortedByExpiration[0].Expiry ## Get all contracts for selected expiration contractsMatchingExpiryDTE = [contract for contract in contractsSortedByExpiration if contract.Expiry == closestExpirationDate] ## Get the contract with the contract with the closest delta closestContract = min(contractsMatchingExpiryDTE, key=lambda x: abs(abs(x.Greeks.Delta)-targetDelta)) return closestContract
#region imports from AlgorithmImports import * #endregion class TradeManager: def __init__(self, algorithm): self.Positions = {} self.Algorithm = algorithm self.nextTradeId = 0 def OpenPosition(self): return [t for t in self.Positions.values() if t.IsOpen()] def OpenOptionPosition(self): return [t for t in self.Positions.values() if t.IsOpen() and (t.AssetType()==SecurityType.Option or t.AssetType()==SecurityType.IndexOption)] def GetPositionByDelta(self, delta): if len(self.OpenOptionPosition()) ==0: return None return sorted(self.OpenOptionPosition(), key=lambda x: abs(x.Delta() - delta))[0] def GetPositionByUnitDelta(self, delta): if len(self.OpenOptionPosition()) ==0: return None return sorted(self.OpenOptionPosition(), key=lambda x: abs(x.UnitDelta() - delta))[0] def PortfolioDelta(self): return sum([t.Delta() for t in self.Positions.values() if t.IsOpen()]) # Place a trade in the direction signalled def TradeOption(self, contract, qty): symbol = contract.Symbol price = self.Algorithm.Securities[symbol].Price asset = self.Algorithm.Securities[contract.UnderlyingSymbol].Price tag = f"Underlying Price: {asset} | Opened at ${price}" ticket = self.Algorithm.MarketOrder(symbol, qty, False, tag) if not contract.Symbol in self.Positions: self.Positions[contract.Symbol]=OptionPosition(contract, self.Algorithm) return ticket def SetHoldings(self, symbol, proportion): qty = self.Algorithm.CalculateOrderQuantity(symbol, proportion) return self.TradeEquity(symbol, qty) def TradeEquity(self, symbol, qty): price = self.Algorithm.Securities[symbol].Price tag = f"{symbol}#{qty}|Opened at ${price}" ticket = self.Algorithm.MarketOrder(symbol, qty, False, tag) if not symbol in self.Positions: self.Positions[symbol]=Position(symbol, self.Algorithm) return ticket def Close(self, symbol, qty=None, reason=None): self.Positions[symbol].Close(qty, reason) if not self.Positions[symbol].IsOpen(): del self.Positions[symbol] #TODO: add a position base class class Position: def __init__(self, symbol, algorithm): self.Symbol = symbol self.Algorithm = algorithm self.Security = self.Algorithm.Securities[self.Symbol] self.position = self.Algorithm.Portfolio[self.Symbol] #TODO: add check for order status, see if fully executed def AssetType(self): return self.position.Type def AveragePrice(self): return self.position.AveragePrice def Quantity(self): return self.position.Quantity def MarketPrice(self): return self.Security.Holdings.Price def UnrealizedProfitPercent(self): return self.position.UnrealizedProfitPercent def UnrealizedProfit(self): return self.position.UnrealizedProfit def IsOpen(self): return self.position.Invested def Close(self, qty=None, reason=None): tag = f"Close | {reason} | {self.UnrealizedProfit()} Net" if not qty: self.Algorithm.Liquidate(self.Symbol, tag) if self.Quantity()*qty > 0: qty = -1*qty self.Algorithm.MarketOrder(self.Symbol, qty, False, tag) def Delta(self): return self.Security.SymbolProperties.ContractMultiplier* self.Quantity() #TODO: add Greeks interface, e.g. delta, gamma extra #TODO: rename class objects class OptionPosition(Position): def __init__(self, contract, algorithm): super().__init__(contract.Symbol, algorithm) self.Algorithm = algorithm self.Contract = contract def ExpiringWithIn(self, time_to_eixpiry = timedelta(minutes=10)): expiry = self.Symbol.ID.Date + timedelta(hours=16) return True if ((expiry - self.Algorithm.Time) < time_to_eixpiry) else False def _Greeks(self): return self.Security.EvaluatePriceModel(self.Algorithm.CurrentSlice, self.Contract).Greeks def UnitDelta(self): return self._Greeks().Delta def Delta(self): return self.UnitDelta()*self.Security.SymbolProperties.ContractMultiplier* self.Quantity() #TODO: add new underlying position #TODO: add spread position