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;

		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;
		}
		
	}
}