Overall Statistics
Total Orders
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Start Equity
100000
End Equity
100000
Net Profit
0%
Sharpe Ratio
0
Sortino Ratio
0
Probabilistic 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
-5.908
Tracking Error
0.136
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
Portfolio Turnover
0%
#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.Algorithm.Selection;
    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 QCAlgorithmFramework = QuantConnect.Algorithm.QCAlgorithm;
    using QCAlgorithmFrameworkBridge = QuantConnect.Algorithm.QCAlgorithm;
#endregion

using MathNet.Numerics.Statistics;

namespace QuantConnect.Algorithm.CSharp
{
    public class FormalYellowGreenBison : QCAlgorithm
    {
        public override void Initialize()
        {
            SetStartDate(2023, 1, 1);
            SetEndDate(2023, 2, 1);
            
            var underlyingSymbol = AddEquity("SPY").Symbol;
            var option = AddOption(underlyingSymbol);

            var version = int.Parse(Globals.Version.Split(".")[^1]);
            
            // Branch
            if (version == 16598)
            {
                option.SetFilter(universe => 
                {
                    // var minIv = universe.Select(x => x.ImpliedVolatility).Min();
                    // var maxIv = universe.Select(x => x.ImpliedVolatility).Max();
                    // Log($"[{Time}] :: Min IV: {minIv}. Max IV: {maxIv}");
                    // return universe.Contracts(Enumerable.Empty<Symbol>());
                    
                    var ivMedian = universe.Select(x => x.ImpliedVolatility).Median();
                    var minIv = ivMedian * 0.50m;
                    var maxIv = ivMedian * 1.50m;

                    return universe.IV(minIv, maxIv).Contracts(Enumerable.Empty<Symbol>());;
                });
            }
            // Master
            else 
            {
                /*
                option.SetFilter(universe => 
                {
                    return universe.Contracts(contracts => 
                    {
                        var contractsList = contracts.ToList();
                        var ivValues = contractsList.Select(x => 
                        {
                            var mirror = QuantConnect.Symbol.CreateOption(x.Underlying, 
                                x.ID.Market, 
                                x.ID.OptionStyle, 
                                x.ID.OptionRight == OptionRight.Call ? OptionRight.Put : OptionRight.Call, 
                                x.ID.StrikePrice, 
                                x.ID.Date);
                            var iv = new ImpliedVolatility(x, 
                                new InterestRateProvider(), 
                                new DividendYieldProvider(x.Underlying),
                                mirror);

                            // We know SPY equity and option exchange and data TZ are de same but in real cases we would need to get the config for both the option and the underlying
                            var config = SubscriptionManager.Subscriptions.First(x => x.Symbol == option.Symbol);
                            var end = Time.ConvertTo(TimeZone, option.Exchange.TimeZone).Date.AddDays(1);
                            var start = QuantConnect.Time.GetStartTimeForTradeBars(option.Exchange.Hours, end, Resolution.Daily.ToTimeSpan(),
                                1, false, config.DataTimeZone);
                            var endUtc = end.ConvertToUtc(option.Exchange.TimeZone);
                            var startUtc = start.ConvertToUtc(option.Exchange.TimeZone);

                            var underlyingHistoryRequest = new HistoryRequest(
                                startUtc,
                                endUtc,
                                typeof(TradeBar),
                                underlyingSymbol,
                                Resolution.Daily,
                                option.Exchange.Hours,
                                config.DataTimeZone,
                                Resolution.Daily,
                                includeExtendedMarketHours: false,
                                isCustomData: false,
                                DataNormalizationMode.ScaledRaw,
                                LeanData.GetCommonTickTypeForCommonDataTypes(typeof(TradeBar), SecurityType.Equity));
                            var optionHistoryRequest = new HistoryRequest(
                                startUtc,
                                endUtc,
                                typeof(QuoteBar),
                                option.Symbol,
                                Resolution.Daily,
                                option.Exchange.Hours,
                                config.DataTimeZone,
                                Resolution.Daily,
                                includeExtendedMarketHours: false,
                                isCustomData: false,
                                DataNormalizationMode.ScaledRaw,
                                LeanData.GetCommonTickTypeForCommonDataTypes(typeof(QuoteBar), SecurityType.Equity));
                            var mirrorHistoryRequest = new HistoryRequest(
                                startUtc,
                                endUtc,
                                typeof(QuoteBar),
                                mirror,
                                Resolution.Daily,
                                option.Exchange.Hours,
                                config.DataTimeZone,
                                Resolution.Daily,
                                includeExtendedMarketHours: false,
                                isCustomData: false,
                                DataNormalizationMode.ScaledRaw,
                                LeanData.GetCommonTickTypeForCommonDataTypes(typeof(QuoteBar), SecurityType.Equity));

                            var history = HistoryProvider.GetHistory(new [] { underlyingHistoryRequest, optionHistoryRequest, mirrorHistoryRequest }, TimeZone);
                            foreach (var slice in history)
                            {
                                if (slice.Bars.TryGetValue(underlyingSymbol, out var underlyingTrade))
                                {
                                    var point = new IndicatorDataPoint(underlyingTrade.Symbol, underlyingTrade.EndTime, underlyingTrade.Close);
                                    iv.Update(point);
                                }

                                foreach (var quote in slice.QuoteBars.Values)
                                {
                                    var point = new IndicatorDataPoint(quote.Symbol, quote.EndTime, quote.Close);
                                    iv.Update(point);
                                }
                            }

                            return iv.Current.Value;
                        }).ToList();

                        var ivMedian = ivValues.Median();
                        var minIv = ivMedian * 0.50m;
                        var maxIv = ivMedian * 1.50m;

                        var result = new List<Symbol>();

                        for (var i = 0; i < contractsList.Count; i++)
                        {
                            if (ivValues[i] >= minIv && ivValues[i] <= maxIv) 
                            {
                                result.Add(contractsList[i]);
                            }
                        }

                        // return result;
                        return universe.Contracts(Enumerable.Empty<Symbol>());
                    });
                });
            */
            }
        }

        public override void OnSecuritiesChanged(SecurityChanges changes)
        {
            Log($"[{Time}] :: Added {changes.AddedSecurities.Where(x => x.Symbol.SecurityType == SecurityType.Option && !x.Symbol.IsCanonical()).Count()} options.");
        }
    }
}