Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.Market;


namespace QuantConnect.Algorithm.CSharp.MyStuff.OptionsDataCheck
{
    /// <summary>
    /// This is a crude (non-foolproof) algorithm to check for bulk missing options data files.
    /// 
    /// For the specified options underlying, every day (at 2 hours after open) it checks to see if there is at least 1 ATM call
    /// and 1 ATM put for each of the expiry dates it's seen before.  If none are found, it logs a debug message.
    /// 
    /// It only checks monthly options with 65 or less days to expiration, but could be set to whatever in Initialize().
    /// Also, there's a flag to invert the logging, to only log when there IS data available.
    /// </summary>
    public class ÒptionsDataCheckAlgo : QCAlgorithm
    {
        private Symbol _optionSymbol;
        private bool _checkNextSlice = false;
        List<DateTime> _existingExpiries = new List<DateTime>();
        private bool _onlyLogWhenThereIsData = false;

        /// <summary>
        /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
        /// </summary>
        public override void Initialize()
        {
            //SetStartDate(2012, 1, 1);
            //SetEndDate(2018, 9, 1);

            SetStartDate(2018, 10, 1);
            SetEndDate(  2019, 2, 13);

            var option = AddOption("AAPL", Resolution.Minute);
            option.SetFilter(-1, 1, TimeSpan.FromDays(0), TimeSpan.FromDays(65));
            _optionSymbol = option.Symbol;

            // Flag to invert the logging.
            _onlyLogWhenThereIsData = false; //true;

            // Flag to check next data slice every day 2 hours after market open.
            Schedule.On(DateRules.EveryDay(_optionSymbol), TimeRules.AfterMarketOpen(_optionSymbol, 120), () => _checkNextSlice = true);
        }

        /// <summary>
        /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
        /// </summary>
        /// <param name="data">Slice object keyed by symbol containing the stock data</param>
        public override void OnData(Slice data)
        {
            if (!_checkNextSlice)
                return;

            _checkNextSlice = false;

            if (!IsMarketOpen(_optionSymbol))
            {
                if (!_onlyLogWhenThereIsData)
                    Debug("On " + Time.ToString("yyyy-MM-dd") + " market closed for " + _optionSymbol.ToString());
                return;
            }

            OptionChain chain;
            if (data.OptionChains.TryGetValue(_optionSymbol, out chain))
            {
                // Remove expired expiries.
                var expiredExpiries = _existingExpiries.Where(e => e.Date < Time.Date).ToList();
                foreach (var expiry in expiredExpiries)
                {
                    //Debug("Removing old expiry " + expiry.ToString("yyyy-MM-dd"));
                    _existingExpiries.Remove(expiry);
                }

                // Add new expiries.
                var newExpiries = chain.Where(oc => !_existingExpiries.Contains(oc.Expiry)).Select(oc => oc.Expiry).Distinct();
                foreach (var expiry in newExpiries)
                {
                    //Debug("Adding new expiry " + expiry.ToString("yyyy-MM-dd"));
                    _existingExpiries.Add(expiry);
                }

                // Check there is at least 1 expiry to check.
                if (!_onlyLogWhenThereIsData)
                {
                    if (_existingExpiries.Count == 0)
                    {
                        Debug("On " + Time.ToString("yyyy-MM-dd") + " " + chain.Underlying.Symbol.ToString() + " there are no options expiries to check (i.e. missing all options)");
                    }
                }

                // Check if there's any calls & puts for each expiry.
                foreach (var expiry in _existingExpiries)
                {
                    var calls = chain.Where(oc => oc.Expiry == expiry && oc.Right == OptionRight.Call).Count();
                    var puts = chain.Where(oc => oc.Expiry == expiry && oc.Right == OptionRight.Put).Count();

                    // Check for missing data.
                    if (!_onlyLogWhenThereIsData)
                    {
                        if (calls == 0 || puts == 0)
                        {
                            Debug("On " + Time.ToString("yyyy-MM-dd") + " " + chain.Underlying.Symbol.ToString() + " options for expiry=" + expiry.ToString("yyyy-MM-dd") + " is missing: " +
                                (calls == 0 ? "calls " : "") +
                                (puts == 0 ? "puts " : ""));
                        }
                    }

                    // Check for data.
                    if (_onlyLogWhenThereIsData)
                    {
                        if (calls > 0 || puts > 0)
                        {
                            Debug("On " + Time.ToString("yyyy-MM-dd") + " " + chain.Underlying.Symbol.ToString() + " options for expiry=" + expiry.ToString("yyyy-MM-dd") + " exists for: " +
                                (calls > 0 ? "calls " : "") +
                                (puts > 0 ? "puts " : ""));
                        }
                    }
                }
            }
            else
            {
                if (!_onlyLogWhenThereIsData)
                    Debug("On " + Time.ToString("yyyy-MM-dd") + " no options chain for " + _optionSymbol.ToString());
            }
        }

    }
}