Overall Statistics |
Total Trades 4 Average Win 0.16% Average Loss -0.16% Compounding Annual Return 1.920% Drawdown 0.500% Expectancy -0.012 Net Profit 0.150% Sharpe Ratio 1.04 Probabilistic Sharpe Ratio 50.428% Loss Rate 50% Win Rate 50% Profit-Loss Ratio 0.98 Alpha 0.038 Beta 0.097 Annual Standard Deviation 0.015 Annual Variance 0 Information Ratio 1.881 Tracking Error 0.128 Treynor Ratio 0.166 Total Fees $3.00 Estimated Strategy Capacity $5600000.00 Lowest Capacity Asset SPY 2ZWFKA76R7RAE|SPY R735QTJ8XC9X |
//########################################################################################## //# Greeks Demo //# ----------- //# Simple algo illustrating how to inspect the option chain greeks //# The below sells a 30 delta put expiring in 10 days and rolls it at expiration //# This is not a tradable strategy. //################### //## Quantish.io ## //########################################################################################## namespace QuantConnect.Algorithm.CSharp { public class NonTradableGreeksDemo : QCAlgorithm { public Equity equity; public float putDelta; public int putDTE; public OptionsUtil _OptionsUtil; public void InitOptions(Equity theEquity) { _OptionsUtil = new OptionsUtil(theEquity, this); _OptionsUtil.InitOptions(); } public override void Initialize() { SetStartDate(2015, 1, 1); //Set Start Date SetEndDate(2015, 1, 30); SetCash(100000); //Set Strategy Cash equity = AddEquity("SPY", Resolution.Minute); putDelta = float.Parse((GetParameter("putDelta")))/100; putDTE = int.Parse(GetParameter("putDTE")); InitOptions(equity); } /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// Slice object keyed by symbol containing the stock data public override void OnData(Slice data) { // If we're done warming up, and not invested, Sell a put. if ((!IsWarmingUp) && (!Portfolio.Invested) && (data.ContainsKey(equity.Symbol))){ _OptionsUtil.SellAnOTMPut(putDelta, putDTE); } else if ((Portfolio.Invested) && (_OptionsUtil.PortfolioHasOptions() == false)) { Liquidate(); } } } }
namespace QuantConnect.Algorithm.CSharp { public class OptionsUtil { public Equity equity; public NonTradableGreeksDemo _this; // CandlestickPatternspublic Option opt; public OptionsUtil(Equity symbol, NonTradableGreeksDemo mainObject) { equity = symbol; _this = mainObject; } // Initialize Options settings, chain filters, pricing models, etc // ==================================================================== public void InitOptions() { // 1. Specify the data normalization mode (must be 'Raw' for options) equity.SetDataNormalizationMode(DataNormalizationMode.Raw); // 2. Set Warmup period of at leasr 30 days _this.SetWarmup(30, Resolution.Daily); // 3. Set the security initializer to call SetMarketPrice _this.SetSecurityInitializer(x => x.SetMarketPrice(_this.GetLastKnownPrice(x))); // 4. Subscribe to the option feed for the symbol var theOptionSubscription = _this.AddOption(equity.Symbol); // 5. set the pricing model, to calculate Greeks and volatility theOptionSubscription.PriceModel = OptionPriceModels.CrankNicolsonFD(); // both European & American, automatically // 6. Set the function to filter out strikes and expiry dates from the option chain // It was easier and more time efficient to not create a new method for this part var strikeCount = 20; // no of strikes around underyling price => for universe selection var minExpiryDTE = 10; // min num of days to expiration => for uni selection var maxExpiryDTE = 40; // max num of days to expiration => for uni selection theOptionSubscription.SetFilter(u => u.IncludeWeeklys() .Strikes(-strikeCount, strikeCount) .Expiration(TimeSpan.FromDays(minExpiryDTE), TimeSpan.FromDays(maxExpiryDTE))); } // Sell an OTM Put Option. // Use Delta to select a put contract to sell // ================================================================== public void SellAnOTMPut(float putDelta, int putDTE) { // Sell a Put expiring in 2 weeks (14 days) // putDelta = float(self.algo.GetParameter("putDelta"))/100 // putDTE = int(self.algo.GetParameter("putDTE")) var putContract = SelectContractByDelta(equity.Symbol, putDelta, putDTE, OptionRight.Put); // construct an order message -- good for debugging and order rrecords string orderMessage = $"Stock @ ${_this.CurrentSlice[equity.Symbol].Close} | Sell {putContract.Symbol} | ({(putContract.Greeks.Delta,2)} Delta)"; _this.Debug($"{_this.Time} {orderMessage}"); _this.Order(putContract.Symbol, -1, false, orderMessage); } public bool PortfolioHasOptions(){ List<Symbol> allHoldings = new List<Symbol>(); foreach(KeyValuePair<Symbol, SecurityHolding> pair in _this.Portfolio) { if((pair.Value.Invested == true) && (((pair.Value).GetType()).Equals(typeof(OptionHolding)))){ allHoldings.Add(pair.Key); } } var numOptHoldings = allHoldings.Count(); if (numOptHoldings == 0){ return false; } return true; } // Get an options contract that matches the specified criteria: // Underlying symbol, delta, days till expiration, Option right (put or call) // ============================================================================ public OptionContract SelectContractByDelta(Symbol symbolArg, float strikeDeltaArg, int expiryDTE, OptionRight optionRightArg=OptionRight.Call) { var canonicalSymbol = _this.AddOption(symbolArg); var theOptionChain = _this.CurrentSlice.OptionChains[canonicalSymbol.Symbol]; var theExpiryDate = _this.Time.AddDays(expiryDTE); // Filter the Call/Put options contracts List<OptionContract> filteredContracts = new List<OptionContract>(); foreach(var x in theOptionChain) { if(x.Right == optionRightArg) { filteredContracts.Add(x); } } // Sort the contracts according to their closeness to our desired expiry filteredContracts.Sort((x,y)=>(Math.Abs((x.Expiry.ToOADate()-theExpiryDate.ToOADate()))).CompareTo(Math.Abs((y.Expiry.ToOADate()-theExpiryDate.ToOADate())))); var contractsSortedByExpiration = filteredContracts; var closestExpirationDate = contractsSortedByExpiration[0].Expiry; // Get all contracts for selected expiration List<OptionContract> contractsMatchingExpiryDTE = new List<OptionContract>(); foreach(var contract in contractsSortedByExpiration) { if (contract.Expiry == closestExpirationDate) { contractsMatchingExpiryDTE.Add(contract); } } // Get the contract with the contract with the closest delta var closestContract = contractsMatchingExpiryDTE.First(x => Math.Abs(Math.Abs(x.Greeks.Delta)-(decimal)strikeDeltaArg) == contractsMatchingExpiryDTE.Min(x => Math.Abs(Math.Abs(x.Greeks.Delta)-(decimal)strikeDeltaArg))); return closestContract; } } }