/*
* 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 QuantConnect.Util;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
namespace QuantConnect.Data.UniverseSelection
{
///
/// Represents a universe of futures data
///
public class FutureUniverse : BaseChainUniverseData
{
///
/// Cache for the symbols to avoid creating them multiple times
///
/// Key: securityType, market, ticker, expiry
private static readonly Dictionary<(SecurityType, string, string, DateTime), Symbol> _symbolsCache = new();
///
/// Creates a new instance of the class
///
public FutureUniverse()
{
}
///
/// Creates a new instance of the class
///
public FutureUniverse(DateTime date, Symbol symbol, string csv)
: base(date, symbol, csv)
{
}
///
/// Creates a new instance of the class as a copy of the given instance
///
public FutureUniverse(FutureUniverse other)
: base(other)
{
}
///
/// Reader converts each line of the data source into BaseData objects. Each data type creates its own factory method, and returns a new instance of the object
/// each time it is called.
///
/// Subscription data config setup object
/// Stream reader of the source document
/// Date of the requested data
/// true if we're in live mode, false for backtesting mode
/// Instance of the T:BaseData object generated by this line of the CSV
[StubsIgnore]
public override BaseData Reader(SubscriptionDataConfig config, StreamReader stream, DateTime date, bool isLiveMode)
{
if (stream == null || stream.EndOfStream)
{
return null;
}
if (stream.Peek() == '#')
{
// Skip header
stream.ReadLine();
return null;
}
var expiry = stream.GetDateTime("yyyyMMdd");
var cacheKey = (config.SecurityType, config.Market, config.Symbol.ID.Symbol, expiry);
if (!TryGetCachedSymbol(cacheKey, out var symbol))
{
symbol = Symbol.CreateFuture(config.Symbol.ID.Symbol, config.Symbol.ID.Market, expiry);
CacheSymbol(cacheKey, symbol);
}
return new FutureUniverse(date, symbol, stream.ReadLine());
}
///
/// Creates a copy of the instance
///
/// Clone of the instance
public override BaseData Clone()
{
return new FutureUniverse(this);
}
///
/// Gets the default resolution for this data and security type
///
/// This is a method and not a property so that python
/// custom data types can override it
public override Resolution DefaultResolution()
{
return Resolution.Daily;
}
///
/// Implicit conversion into
///
/// The option universe data to be converted
#pragma warning disable CA2225 // Operator overloads have named alternates
public static implicit operator Symbol(FutureUniverse data)
#pragma warning restore CA2225 // Operator overloads have named alternates
{
return data.Symbol;
}
///
/// Gets the CSV string representation of this universe entry
///
public static string ToCsv(Symbol symbol, decimal open, decimal high, decimal low, decimal close, decimal volume, decimal? openInterest)
{
return $"{symbol.ID.Date:yyyyMMdd},{open},{high},{low},{close},{volume},{openInterest}";
}
///
/// Gets the CSV header string for this universe entry
///
public static string CsvHeader => "expiry,open,high,low,close,volume,open_interest";
///
/// Tries to get a symbol from the cache
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static bool TryGetCachedSymbol((SecurityType, string, string, DateTime) key, out Symbol symbol)
{
lock (_symbolsCache)
{
return _symbolsCache.TryGetValue(key, out symbol);
}
}
///
/// Caches a symbol
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static void CacheSymbol((SecurityType, string, string, DateTime) key, Symbol symbol)
{
lock (_symbolsCache)
{
// limit the cache size to help with memory usage
if (_symbolsCache.Count >= 100000)
{
_symbolsCache.Clear();
}
_symbolsCache.TryAdd(key, symbol);
}
}
}
}