/*
* 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);
}
}
}