| Overall Statistics |
|
Total Trades 155 Average Win 2.37% Average Loss -1.48% Compounding Annual Return -100.000% Drawdown 36.800% Expectancy -0.189 Net Profit -20.462% Sharpe Ratio -1.045 Probabilistic Sharpe Ratio 0% Loss Rate 69% Win Rate 31% Profit-Loss Ratio 1.60 Alpha 27.105 Beta -3.185 Annual Standard Deviation 0.957 Annual Variance 0.916 Information Ratio -9.154 Tracking Error 1.073 Treynor Ratio 0.314 Total Fees $387.50 |
from clr import AddReference
AddReference("System")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Common")
from System import *
from QuantConnect import *
from QuantConnect.Data import *
from QuantConnect.Algorithm import *
from QuantConnect.Securities.Option import OptionPriceModels
import numpy as np
from datetime import timedelta
### <summary>
### Demonstration of the Option Chain Provider -- a much faster mechanism for manually specifying the option contracts you'd like to recieve
### data for and manually subscribing to them.
### </summary>
### <meta name="tag" content="strategy example" />
### <meta name="tag" content="options" />
### <meta name="tag" content="using data" />
### <meta name="tag" content="selecting options" />
### <meta name="tag" content="manual selection" />
class OptionChainProviderAlgorithm(QCAlgorithm):
trailing_stop_pct = .93
highestPrice_call = 0
highestPrice_put = 0
trailing_stop_price_call = 0
trailing_stop_price_put = 0
def Initialize(self):
self.SetStartDate(2020, 4, 21)
self.SetEndDate(2020, 4, 25)
self.SetCash(20000)
# add the underlying asset
self.equity = self.AddEquity("SPY R735QTJ8XC9X", Resolution.Minute)
self.syl = "SPY"
self.spy = "SPY"
self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
# create a XX-period exponential moving average
self.fast = self.EMA("SPY", 30, Resolution.Minute)
# create a XX-period exponential moving average since this is minute, may have to multiply by 2 if want 2 min chart
#self.slow = self.EMA("SPY", 50, Resolution.Minute)
slow_ema_lookback = 100
self.slow = self.EMA("SPY", slow_ema_lookback, Resolution.Minute);
self.SetWarmUp(slow_ema_lookback)
# initialize the option contract with empty string
self.contract_put = str()
self.contract_call = str ()
self.contractsAdded = set()
self.underlyingsymbol = self.AddEquity(self.syl, Resolution.Minute).Symbol
def OnData(self, data):
if self.IsWarmingUp:
return
if data.Time.hour < 10 or (data.Time.hour == 15 and data.Time.minute >= 30) or data.Time.hour > 15:
return
if not self.Portfolio.Invested:
fast = self.fast.Current.Value
slow = self.slow.Current.Value
call_entry = (fast >= slow)
put_entry = (fast <= slow)
if call_entry:
self.contract_call = self.OptionsFilter(data, OptionRight.Call)
if self.contract_call in data:
self.MarketOrder(self.contract_call, +10)
price = self.Securities[self.contract_call].Close
self.trailing_stop_price_call = self.trailing_stop_pct * price
self.highestPrice_call = price
if put_entry:
self.contract_put = self.OptionsFilter(data, OptionRight.Put)
if self.contract_put in data:
self.MarketOrder(self.contract_put, +10)
price = self.Securities[self.contract_put].Close
self.trailing_stop_price_put = self.trailing_stop_pct * price
self.highestPrice_put = price
#exit
if self.Portfolio.Invested:
if self.contract_call in self.Securities and self.Portfolio[self.contract_call].Invested:
contract_price_call = self.Securities[self.contract_call].Close
take_profit = contract_price_call >= self.trailing_stop_price_call * 1.3
stop_loss_hit = contract_price_call < self.trailing_stop_price_call
if take_profit or stop_loss_hit:
self.MarketOrder(self.contract_call, -10)
self.trailing_stop_price_call = 0
self.highestPrice_call = 0
# Updating trailing stop loss level
elif contract_price_call > self.highestPrice_call:
self.highestPrice_call = contract_price_call
self.trailing_stop_price_call = self.highestPrice_call * self.trailing_stop_pct
if self.contract_put in self.Securities and self.Portfolio[self.contract_put].Invested:
contract_price_put = self.Securities[self.contract_put].Close
take_profit = contract_price_put >= self.trailing_stop_price_put * 1.3
stop_loss_hit = contract_price_put < self.trailing_stop_price_put
if take_profit or stop_loss_hit:
self.MarketOrder(self.contract_put, -10)
self.trailing_stop_price_put = 0
self.highestPrice_put = 0
# Updating trailing stop loss level
elif contract_price_put > self.highestPrice_put:
self.highestPrice_put = contract_price_put
self.trailing_stop_price_put = self.highestPrice_put * self.trailing_stop_pct
def OptionsFilter(self, data, optionRight):
''' OptionChainProvider gets a list of option contracts for an underlying symbol at requested date.
Then you can manually filter the contract list returned by GetOptionContractList.
The manual filtering will be limited to the information included in the Symbol
(strike, expiration, type, style) and/or prices from a History call '''
contracts = self.OptionChainProvider.GetOptionContractList(self.equity.Symbol, data.Time)
self.underlyingPrice = self.Securities[self.equity.Symbol].Price
otm_contracts = [i for i in contracts if i.ID.OptionRight == optionRight and i.ID.Date > data.Time]
if len(otm_contracts) == 0:
return str()
contract = sorted(sorted(otm_contracts, key=lambda x: abs(self.underlyingPrice - x.ID.StrikePrice)),
key=lambda x: x.ID.Date)[0]
if contract not in self.contractsAdded:
self.contractsAdded.add(contract)
# use AddOptionContract() to subscribe the data for specified contract
self.AddOptionContract(contract, Resolution.Minute)
return contract