| 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