Overall Statistics
Total Trades
9
Average Win
0%
Average Loss
0%
Compounding Annual Return
1130.493%
Drawdown
26.300%
Expectancy
0
Net Profit
24.614%
Sharpe Ratio
10.83
Probabilistic Sharpe Ratio
69.521%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
10.755
Beta
1.393
Annual Standard Deviation
1.029
Annual Variance
1.06
Information Ratio
10.708
Tracking Error
1.015
Treynor Ratio
8.001
Total Fees
$9.00
Estimated Strategy Capacity
$200000.00
Lowest Capacity Asset
CEY XM6DSR8J2TQE|CEY S67FQV7Z62CL
#region imports
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Globalization;
    using System.Drawing;
    using QuantConnect;
    using QuantConnect.Algorithm.Framework;
    using QuantConnect.Algorithm.Framework.Selection;
    using QuantConnect.Algorithm.Framework.Alphas;
    using QuantConnect.Algorithm.Framework.Portfolio;
    using QuantConnect.Algorithm.Framework.Execution;
    using QuantConnect.Algorithm.Framework.Risk;
    using QuantConnect.Parameters;
    using QuantConnect.Benchmarks;
    using QuantConnect.Brokerages;
    using QuantConnect.Util;
    using QuantConnect.Interfaces;
    using QuantConnect.Algorithm;
    using QuantConnect.Indicators;
    using QuantConnect.Data;
    using QuantConnect.Data.Consolidators;
    using QuantConnect.Data.Custom;
    using QuantConnect.DataSource;
    using QuantConnect.Data.Fundamental;
    using QuantConnect.Data.Market;
    using QuantConnect.Data.UniverseSelection;
    using QuantConnect.Notifications;
    using QuantConnect.Orders;
    using QuantConnect.Orders.Fees;
    using QuantConnect.Orders.Fills;
    using QuantConnect.Orders.Slippage;
    using QuantConnect.Scheduling;
    using QuantConnect.Securities;
    using QuantConnect.Securities.Equity;
    using QuantConnect.Securities.Future;
    using QuantConnect.Securities.Option;
    using QuantConnect.Securities.Forex;
    using QuantConnect.Securities.Crypto;   
    using QuantConnect.Securities.Interfaces;
    using QuantConnect.Storage;
    using QuantConnect.Data.Custom.AlphaStreams;
    using QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
    using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
#endregion
namespace QuantConnect.Algorithm.CSharp
{
    public class DeterminedMagentaGoat : QCAlgorithm
    {

        public override void Initialize()
        {
            SetStartDate(2021, 1, 19);  //Set Start Date
            SetEndDate(2021, 2, 19);    //Set End Date
            SetCash(100000);            //Set Strategy Cash
            
            AddUniverseSelection(
                new OptionsUniverseSelectionModel(
                    new CoarseFundamentalUniverseSelectionModel(SelectCoarse),
                    OptionFilterFunction
                )
            );
        }

        /// 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)
        {
            // We can use data.OptionChains, based on the Fundamental universe from Initialize

            if (!Portfolio.Invested)
            {
                foreach (var kpv in data.OptionChains)
                {
                    var optionChain = kpv.Value;
                    
                    // Buy closest Call Option
                    var closestCall = optionChain.Where(c => c.Right==OptionRight.Call && c.Strike>c.UnderlyingLastPrice)
                                        .OrderBy(c => c.Strike)
                                        .Select(c => c.Symbol)
                                        .First();
                    
                    Buy(closestCall, 1);
                }
            }
        }

        private IEnumerable<Symbol> SelectCoarse(IEnumerable<CoarseFundamental> coarse)
        {
            // Return most liquid assets w/ fundamentals
            return coarse.Where(c => c.HasFundamentalData)
                        .OrderByDescending(c => c.DollarVolume)
                        .Take(100)
                        .Select(c => c.Symbol);
        }

        private OptionFilterUniverse OptionFilterFunction(OptionFilterUniverse optionFilterUniverse)
        {
            return optionFilterUniverse.Strikes(-2, +2).FrontMonth().CallsOnly();
        }
    }
}
#region imports
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Globalization;
    using System.Drawing;
    using QuantConnect;
    using QuantConnect.Algorithm.Framework;
    using QuantConnect.Algorithm.Framework.Selection;
    using QuantConnect.Algorithm.Framework.Alphas;
    using QuantConnect.Algorithm.Framework.Portfolio;
    using QuantConnect.Algorithm.Framework.Execution;
    using QuantConnect.Algorithm.Framework.Risk;
    using QuantConnect.Parameters;
    using QuantConnect.Benchmarks;
    using QuantConnect.Brokerages;
    using QuantConnect.Util;
    using QuantConnect.Interfaces;
    using QuantConnect.Algorithm;
    using QuantConnect.Indicators;
    using QuantConnect.Data;
    using QuantConnect.Data.Consolidators;
    using QuantConnect.Data.Custom;
    using QuantConnect.DataSource;
    using QuantConnect.Data.Fundamental;
    using QuantConnect.Data.Market;
    using QuantConnect.Data.UniverseSelection;
    using QuantConnect.Notifications;
    using QuantConnect.Orders;
    using QuantConnect.Orders.Fees;
    using QuantConnect.Orders.Fills;
    using QuantConnect.Orders.Slippage;
    using QuantConnect.Scheduling;
    using QuantConnect.Securities;
    using QuantConnect.Securities.Equity;
    using QuantConnect.Securities.Future;
    using QuantConnect.Securities.Option;
    using QuantConnect.Securities.Forex;
    using QuantConnect.Securities.Crypto;
    using QuantConnect.Securities.Interfaces;
    using QuantConnect.Storage;
    using QuantConnect.Data.Custom.AlphaStreams;
    using QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
    using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
#endregion


namespace QuantConnect {
    /// <summary>
    /// This universe selection model will chain to the security changes of a given <see cref="UniverseSelectionModel"/> selection
    /// output and create a new <see cref="OptionChainUniverse"/> for each of them
    /// 
    /// This class is based on https://www.quantconnect.com/docs/v2/writing-algorithms/algorithm-framework/universe-selection/options-universes#61-Option-Chained-Universe-Selection
    /// instead of attaching to a Universe, it attaches to a UniverseSelectionModel
    /// </summary>
    public class OptionsUniverseSelectionModel : UniverseSelectionModel
    {
        private DateTime _nextRefreshTimeUtc;
        private readonly UniverseSelectionModel _universeSelectionModel;
        private readonly Func<OptionFilterUniverse, OptionFilterUniverse> _optionFilter;
        private readonly Dictionary<Universe, IEnumerable<Symbol>> _fundamentalUniverses;
        
        /// <summary>
        /// Gets the next time the framework should invoke the `CreateUniverses` method to refresh the set of universes.
        /// </summary>
        public override DateTime GetNextRefreshTimeUtc()
        {
            var parentRefreshTime = _universeSelectionModel.GetNextRefreshTimeUtc();
            if (parentRefreshTime <= _nextRefreshTimeUtc)
            {
                _fundamentalUniverses.Clear();
                _nextRefreshTimeUtc = parentRefreshTime;
            }
            return _nextRefreshTimeUtc;
        }

        /// <summary>
        /// Creates a new instance of <see cref="OptionsUniverseSelectionModel"/>
        /// </summary>
        /// <param name="universeSelectionModel">The universe selection model we want to chain to</param>
        /// <param name="optionFilter">The option filter universe to use</param>
        public OptionsUniverseSelectionModel(UniverseSelectionModel universeSelectionModel, Func<OptionFilterUniverse, OptionFilterUniverse> optionFilter = null) {
            _nextRefreshTimeUtc = DateTime.MaxValue;
            _universeSelectionModel = universeSelectionModel;
            _optionFilter = optionFilter;
            _fundamentalUniverses = new Dictionary<Universe, IEnumerable<Symbol>>();
        }
        
        /// <summary>
        /// Creates the universes for this algorithm. Called when the original universeSelectionModel
        /// or when the symbols it contains change
        /// </summary>
        /// <param name="algorithm">The algorithm instance to create universes for</param>
        /// <returns>The universes to be used by the algorithm</returns>
        public override IEnumerable<Universe> CreateUniverses(QCAlgorithm algorithm)
        {
            _nextRefreshTimeUtc = DateTime.MaxValue;

            if (_fundamentalUniverses.Count <= 0)
            {
                var universes = _universeSelectionModel.CreateUniverses(algorithm);

                foreach (var universe in universes)
                {
                    _fundamentalUniverses.Add(universe, Enumerable.Empty<Symbol>());
                    universe.SelectionChanged += (sender, args) =>
                    {
                        // We must create the new option Symbol using the CreateOption(Symbol, ...) overload.
                        // Otherwise, we'll end up loading equity data for the selected Symbol, which won't
                        // work whenever we're loading options data for any non-equity underlying asset class.
                        _fundamentalUniverses[universe] = ((Universe.SelectionEventArgs)args).CurrentSelection
                            .Select(symbol => Symbol.CreateOption(
                                symbol,
                                symbol.ID.Market,
                                symbol.SecurityType.DefaultOptionStyle(),
                                default(OptionRight),
                                0m,
                                SecurityIdentifier.DefaultDate))
                            .ToList();
                        
                        // the universe we were watching changed, this will trigger a call to CreateUniverses
                        _nextRefreshTimeUtc = DateTime.MinValue;
                    };
                }
            }

            foreach (var kpv in _fundamentalUniverses)
            {
                yield return kpv.Key;

                foreach (var optionSymbol in kpv.Value)
                {
                    yield return algorithm.CreateOptionChain(optionSymbol, _optionFilter, kpv.Key.UniverseSettings);
                }
            }
        }
    }
}