Overall Statistics
/*
 * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
 * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

using System;
using QuantConnect.Data;
using System.Collections.Generic;
using QuantConnect.Indicators;
using QuantConnect.Interfaces;

namespace QuantConnect.Algorithm.CSharp
{
    /// <summary>
    /// This example demonstrates how to add index asset types and trade index options on SPX.
    /// </summary>
    public class BasicTemplateIndexOptionsAlgorithm : QCAlgorithm
    {
        private Symbol _spx;
        private ExponentialMovingAverage _emaSlow;
        private ExponentialMovingAverage _emaFast;

        /// <summary>
        /// Initialize your algorithm and add desired assets.
        /// </summary>
        public override void Initialize()
        {
            SetStartDate(2021, 1, 4);
            SetEndDate(2021, 2, 1);
            SetCash(1000000);

            // Use indicator for signal; but it cannot be traded.
            // We will instead trade on SPX options
            _spx = AddIndex("SPX", Resolution.Minute).Symbol;
            var spxOptions = AddIndexOption(_spx, Resolution.Minute);
            spxOptions.SetFilter(filterFunc => filterFunc.CallsOnly());

            _emaSlow = EMA(_spx, 80);
            _emaFast = EMA(_spx, 200);
        }

        /// <summary>
        /// Index EMA Cross trading index options of the index.
        /// </summary>
        public override void OnData(Slice slice)
        {
            if (!slice.Bars.ContainsKey(_spx))
            {
                Debug($"No SPX on {Time}");
                return;
            }

            // Warm up indicators
            if (!_emaSlow.IsReady)
            {
                Debug($"EMA slow not ready on {Time}");
                return;
            }

            foreach (var chain in slice.OptionChains.Values)
            {
                foreach (var contract in chain.Contracts.Values)
                {
                    if (contract.Expiry.Month == 3 && contract.Symbol.ID.StrikePrice == 3700m && contract.Right == OptionRight.Call && slice.QuoteBars.ContainsKey(contract.Symbol))
                    {
                        Log($"{Time} {contract.Strike}{(contract.Right == OptionRight.Call ? 'C' : 'P')} -- {slice.QuoteBars[contract.Symbol]}");
                    }

                    if (Portfolio.Invested)
                    {
                        continue;
                    }

                    if (_emaFast > _emaSlow && contract.Right == OptionRight.Call)
                    {
                        Liquidate(InvertOption(contract.Symbol));
                        MarketOrder(contract.Symbol, 1);
                    }
                    else if (_emaFast < _emaSlow && contract.Right == OptionRight.Put)
                    {
                        Liquidate(InvertOption(contract.Symbol));
                        MarketOrder(contract.Symbol, 1);
                    }
                }
            }
        }

        public override void OnEndOfAlgorithm()
        {
            if (Portfolio[_spx].TotalSaleVolume > 0)
            {
                throw new Exception("Index is not tradable.");
            }
            if (Portfolio.TotalSaleVolume == 0)
            {
                throw new Exception("Trade volume should be greater than zero by the end of this algorithm");
            }
        }

        public Symbol InvertOption(Symbol symbol)
        {
            return QuantConnect.Symbol.CreateOption(
                symbol.Underlying,
                symbol.ID.Market,
                symbol.ID.OptionStyle,
                symbol.ID.OptionRight == OptionRight.Call ? OptionRight.Put : OptionRight.Call,
                symbol.ID.StrikePrice,
                symbol.ID.Date);
        }

        
    }
}