/*
* 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 System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using QuantConnect.Interfaces;
using QuantConnect.Logging;
namespace QuantConnect.Lean.Engine.DataFeeds
{
///
/// An implementation of that fetches the list of contracts
/// from the Options Clearing Corporation (OCC) website
///
public class LiveOptionChainProvider : IOptionChainProvider
{
private const int MaxDownloadAttempts = 5;
///
/// Static constructor for the class
///
static LiveOptionChainProvider()
{
// The OCC website now requires at least TLS 1.1 for API requests.
// NET 4.5.2 and below does not enable these more secure protocols by default, so we add them in here
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
}
///
/// Gets the list of option contracts for a given underlying symbol
///
/// The underlying symbol
/// The date for which to request the option chain (only used in backtesting)
/// The list of option contracts
public IEnumerable GetOptionContractList(Symbol symbol, DateTime date)
{
if (symbol.SecurityType != SecurityType.Equity)
{
throw new NotSupportedException($"LiveOptionChainProvider.GetOptionContractList(): SecurityType.Equity is expected but was {symbol.SecurityType}");
}
var attempt = 1;
IEnumerable contracts;
while (true)
{
try
{
Log.Trace($"LiveOptionChainProvider.GetOptionContractList(): Fetching option chain for {symbol.Value} [Attempt {attempt}]");
contracts = FindOptionContracts(symbol.Value);
break;
}
catch (WebException exception)
{
Log.Error(exception);
if (++attempt > MaxDownloadAttempts)
{
throw;
}
Thread.Sleep(1000);
}
}
return contracts;
}
///
/// Retrieve the list of option contracts for an underlying symbol from the OCC website
///
private static IEnumerable FindOptionContracts(string underlyingSymbol)
{
var symbols = new List();
using (var client = new WebClient())
{
// use QC url to bypass TLS issues with Mono pre-4.8 version
var url = "https://www.quantconnect.com/api/v2/theocc/series-search?symbolType=U&symbol=" + underlyingSymbol;
// download the text file
var fileContent = client.DownloadString(url);
// read the lines, skipping the headers
var lines = fileContent.Split(new[] { "\r\n" }, StringSplitOptions.None).Skip(7);
// parse the lines, creating the Lean option symbols
foreach (var line in lines)
{
var fields = line.Split('\t');
var ticker = fields[0].Trim();
if (ticker != underlyingSymbol)
continue;
var expiryDate = new DateTime(fields[2].ToInt32(), fields[3].ToInt32(), fields[4].ToInt32());
var strike = (fields[5] + "." + fields[6]).ToDecimal();
if (fields[7].Contains("C"))
{
symbols.Add(Symbol.CreateOption(underlyingSymbol, Market.USA, OptionStyle.American, OptionRight.Call, strike, expiryDate));
}
if (fields[7].Contains("P"))
{
symbols.Add(Symbol.CreateOption(underlyingSymbol, Market.USA, OptionStyle.American, OptionRight.Put, strike, expiryDate));
}
}
}
return symbols;
}
}
}