| Overall Statistics |
|
Total Trades 19 Average Win 1.08% Average Loss -3.73% Compounding Annual Return 2.297% Drawdown 11.100% Expectancy 0.146 Net Profit 4.652% Sharpe Ratio 0.269 Probabilistic Sharpe Ratio 10.154% Loss Rate 11% Win Rate 89% Profit-Loss Ratio 0.29 Alpha -0.005 Beta 0.305 Annual Standard Deviation 0.067 Annual Variance 0.005 Information Ratio -0.576 Tracking Error 0.102 Treynor Ratio 0.059 Total Fees $47.50 Estimated Strategy Capacity $54000.00 Lowest Capacity Asset SPY 3174CDSVN3D5Y|SPY R735QTJ8XC9X |
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from AlgorithmImports import *
class TrailingStopRiskManagementModel(RiskManagementModel):
'''Provides an implementation of IRiskManagementModel that limits the maximum possible loss
measured from the highest unrealized profit'''
def __init__(self, maximumDrawdownPercent = 0.05):
'''Initializes a new instance of the TrailingStopRiskManagementModel class
Args:
maximumDrawdownPercent: The maximum percentage drawdown allowed for algorithm portfolio compared with the highest unrealized profit, defaults to 5% drawdown'''
self.maximumDrawdownPercent = abs(maximumDrawdownPercent)
self.trailing = dict()
def ManageRisk(self, algorithm, targets):
'''Manages the algorithm's risk at each time step
Args:
algorithm: The algorithm instance
targets: The current portfolio targets to be assessed for risk'''
riskAdjustedTargets = list()
for kvp in algorithm.Securities:
symbol = kvp.Key
security = kvp.Value
# Remove if not invested
if not security.Invested:
self.trailing.pop(symbol, None)
continue
profitPercent = security.Holdings.UnrealizedProfitPercent
# Add newly invested securities
value = self.trailing.get(symbol)
if value == None:
newValue = profitPercent if profitPercent > 0 else 0
self.trailing[symbol] = newValue
continue
# Check for new high and update
if value < profitPercent:
self.trailing[symbol] = profitPercent
continue
# If unrealized profit percent deviates from local max for more than affordable percentage
if profitPercent < value - self.maximumDrawdownPercent:
# liquidate
riskAdjustedTargets.append(PortfolioTarget(symbol, 0))
return riskAdjustedTargetsimport TrailingStopRiskManagementModel as mr
class UpgradedRedOrangeParrot(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2017, 10, 1) # Set Start Date
self.SetEndDate(2019, 10, 1) # Set Start Date
self.SetCash(100000) # Set Strategy Cash
self.equity = self.AddEquity("SPY", Resolution.Minute)
self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.symbol = self.equity.Symbol
self.vix = self.AddData(CBOE, "VIX").Symbol
self.rank = 0
self.contract = str()
self.contractsAdded = set()
self.LatestAskPrice=1
self.DaysBeforeExp = 2
self.DTE = 45
self.OTM = 0.10
self.lookbackIV = 252
self.IVlvl = 0.25
self.percentage=0.5
self.security = self.Securities["SPY"]
# self.SetRiskManagement(TrailingStopRiskManagementModel())
self.Schedule.On(self.DateRules.EveryDay(self.symbol), \
self.TimeRules.AfterMarketOpen(self.symbol, 30), \
self.Plotting)
self.Schedule.On(self.DateRules.EveryDay(self.symbol),\
self.TimeRules.AfterMarketOpen(self.symbol, 30), \
self.VIXRank)
def VIXRank(self):
history = self.History(CBOE, self.vix, self.lookbackIV, Resolution.Daily)
self.rank = ((self.Securities[self.vix].Price - min(history[:-1]["low"])) / (max(history[:-1]["high"]) - min(history[:-1]["low"])) )
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Arguments:
data: Slice object keyed by symbol containing the stock data
'''
if self.IsWarmingUp:
return
# if not self.Portfolio[self.symbol].invested:
# self.SetHoldings(self.symbol, self.percentage)
profitPercent = self.security.Holdings.UnrealizedProfitPercent
if self.rank > self.IVlvl:
self.SellPut(data)
#Only do this if profitable, management code needed
if self.contract:
if profitPercent >= 0.25 or profitPercent <= -2:
self.contract.Liquidate
if (self.contract.ID.Date - self.Time) <= timedelta(self.DaysBeforeExp):
self.Liquidate(self.contract)
self.Log("Closed: too close to expiration")
self.contract = str()
def SellPut(self, data):
if self.contract == str():
self.contract = self.OptionsFilter(data)
return
elif not self.Portfolio[self.contract].Invested and data.ContainsKey(self.contract):
# qty = self.Portfolio.TotalPortfolioValue / self.LatestAskPRice
# qty = int(self.percentage * quantity / 100)
bp = str(self.Portfolio.GetBuyingPower(self.symbol))
# self.Log("Starting BP: " + bp)
# self.Debug("Selling puts: " + str(10) + "@" + str(self.contract.ID.StrikePrice))
self.Sell(self.contract, 10)
bp = str(self.Portfolio.GetBuyingPower(self.symbol))
# self.Debug("Ending BP: " + bp)
def OptionsFilter(self, data):
contracts = self.OptionChainProvider.GetOptionContractList(self.symbol, data.Time)
self.underlyingPrice = self.Securities[self.symbol].Price
otm_puts = [i for i in contracts if i.ID.OptionRight== OptionRight.Put and
self.underlyingPrice - i.ID.StrikePrice > self.OTM * self.underlyingPrice and
self.DTE - 8 < (i.ID.Date - data.Time).days < self.DTE + 8]
if len(otm_puts) > 0:
contract = sorted(sorted(otm_puts, key = lambda x: abs((x.ID.Date - self.Time).days - self.DTE)),
key = lambda x: self.underlyingPrice - x.ID.StrikePrice)[0]
if contract not in self.contractsAdded:
self.contractsAdded.add(contract)
self.AddOptionContract(contract, Resolution.Minute)
return contract
else:
return str()
def Plotting(self):
self.Plot("Vol Chart", "Rank", self.rank)
self.Plot("Vol Chart", "lvl", self.IVlvl)
self.Plot("Data Chart", self.symbol, self.Securities[self.symbol].Close)
option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type == SecurityType.Option]
if option_invested:
self.Plot("Data Chart", "Strike", option_invested[0].ID.StrikePrice)