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