chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 QuantConnect.Interfaces;
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// An implementation of <see cref="IFutureChainProvider"/> that always returns an empty list of contracts
|
||||
/// </summary>
|
||||
public class EmptyFutureChainProvider : IFutureChainProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the list of future contracts for a given underlying symbol
|
||||
/// </summary>
|
||||
/// <param name="symbol">The underlying symbol</param>
|
||||
/// <param name="date">The date for which to request the future chain (only used in backtesting)</param>
|
||||
/// <returns>The list of future contracts</returns>
|
||||
public IEnumerable<Symbol> GetFutureContractList(Symbol symbol, DateTime date)
|
||||
{
|
||||
return Enumerable.Empty<Symbol>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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 QuantConnect.Orders.Fees;
|
||||
using QuantConnect.Orders.Fills;
|
||||
using QuantConnect.Orders.Slippage;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// Futures Security Object Implementation for Futures Assets
|
||||
/// </summary>
|
||||
/// <seealso cref="Security"/>
|
||||
public class Future : Security, IContinuousSecurity
|
||||
{
|
||||
private bool _isTradable;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether or not this security should be considered tradable
|
||||
/// </summary>
|
||||
/// <remarks>Canonical futures are not tradable</remarks>
|
||||
public override bool IsTradable
|
||||
{
|
||||
get
|
||||
{
|
||||
// once a future is removed it is no longer tradable
|
||||
return _isTradable && !Symbol.IsCanonical();
|
||||
}
|
||||
set
|
||||
{
|
||||
_isTradable = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default number of days required to settle a futures sale
|
||||
/// </summary>
|
||||
public const int DefaultSettlementDays = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The default time of day for settlement
|
||||
/// </summary>
|
||||
public static readonly TimeSpan DefaultSettlementTime = new TimeSpan(6, 0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the Future security
|
||||
/// </summary>
|
||||
/// <param name="exchangeHours">Defines the hours this exchange is open</param>
|
||||
/// <param name="quoteCurrency">The cash object that represent the quote currency</param>
|
||||
/// <param name="config">The subscription configuration for this security</param>
|
||||
/// <param name="symbolProperties">The symbol properties for this security</param>
|
||||
/// <param name="currencyConverter">Currency converter used to convert <see cref="CashAmount"/>
|
||||
/// instances into units of the account currency</param>
|
||||
/// <param name="registeredTypes">Provides all data types registered in the algorithm</param>
|
||||
public Future(SecurityExchangeHours exchangeHours,
|
||||
SubscriptionDataConfig config,
|
||||
Cash quoteCurrency,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes
|
||||
)
|
||||
: base(config,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new FutureExchange(exchangeHours),
|
||||
new FutureCache(),
|
||||
new SecurityPortfolioModel(),
|
||||
new FutureFillModel(),
|
||||
new InteractiveBrokersFeeModel(),
|
||||
NullSlippageModel.Instance,
|
||||
new FutureSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
null,
|
||||
new SecurityDataFilter(),
|
||||
new SecurityPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
BuyingPowerModel = new FutureMarginModel(0, this);
|
||||
// for now all futures are cash settled as we don't allow underlying (Live Cattle?) to be posted on the account
|
||||
SettlementType = SettlementType.Cash;
|
||||
Holdings = new FutureHolding(this, currencyConverter);
|
||||
ContractFilter = new EmptyContractFilter<FutureUniverse>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the Future security
|
||||
/// </summary>
|
||||
/// <param name="symbol">The subscription security symbol</param>
|
||||
/// <param name="exchangeHours">Defines the hours this exchange is open</param>
|
||||
/// <param name="quoteCurrency">The cash object that represent the quote currency</param>
|
||||
/// <param name="symbolProperties">The symbol properties for this security</param>
|
||||
/// <param name="currencyConverter">Currency converter used to convert <see cref="CashAmount"/>
|
||||
/// instances into units of the account currency</param>
|
||||
/// <param name="registeredTypes">Provides all data types registered in the algorithm</param>
|
||||
/// <param name="securityCache">Cache to store security information</param>
|
||||
public Future(Symbol symbol,
|
||||
SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes,
|
||||
SecurityCache securityCache)
|
||||
: base(symbol,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new FutureExchange(exchangeHours),
|
||||
securityCache,
|
||||
new SecurityPortfolioModel(),
|
||||
new FutureFillModel(),
|
||||
new InteractiveBrokersFeeModel(),
|
||||
NullSlippageModel.Instance,
|
||||
new FutureSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
null,
|
||||
new SecurityDataFilter(),
|
||||
new SecurityPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
BuyingPowerModel = new FutureMarginModel(0, this);
|
||||
// for now all futures are cash settled as we don't allow underlying (Live Cattle?) to be posted on the account
|
||||
SettlementType = SettlementType.Cash;
|
||||
Holdings = new FutureHolding(this, currencyConverter);
|
||||
ContractFilter = new EmptyContractFilter<FutureUniverse>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this is the future chain security, false if it is a specific future contract
|
||||
/// </summary>
|
||||
public bool IsFutureChain => Symbol.IsCanonical();
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this is a specific future contract security, false if it is the future chain security
|
||||
/// </summary>
|
||||
public bool IsFutureContract => !Symbol.IsCanonical();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the expiration date
|
||||
/// </summary>
|
||||
public DateTime Expiry
|
||||
{
|
||||
get { return Symbol.ID.Date; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies if futures contract has physical or cash settlement on settlement
|
||||
/// </summary>
|
||||
public SettlementType SettlementType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the currently mapped symbol for the security
|
||||
/// </summary>
|
||||
public Symbol Mapped
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the contract filter
|
||||
/// </summary>
|
||||
public IDerivativeSecurityFilter<FutureUniverse> ContractFilter
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="LocalTimeKeeper"/> to be used for this <see cref="Security"/>.
|
||||
/// This is the source of this instance's time.
|
||||
/// </summary>
|
||||
/// <param name="localTimeKeeper">The source of this <see cref="Security"/>'s time.</param>
|
||||
public override void SetLocalTimeKeeper(LocalTimeKeeper localTimeKeeper)
|
||||
{
|
||||
base.SetLocalTimeKeeper(localTimeKeeper);
|
||||
|
||||
var model = SettlementModel as FutureSettlementModel;
|
||||
if (model != null)
|
||||
{
|
||||
model.SetLocalDateTimeFrontier(LocalTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="ContractFilter"/> to a new instance of the filter
|
||||
/// using the specified expiration range values
|
||||
/// </summary>
|
||||
/// <param name="minExpiry">The minimum time until expiry to include, for example, TimeSpan.FromDays(10)
|
||||
/// would exclude contracts expiring in less than 10 days</param>
|
||||
/// <param name="maxExpiry">The maximum time until expiry to include, for example, TimeSpan.FromDays(10)
|
||||
/// would exclude contracts expiring in more than 10 days</param>
|
||||
public void SetFilter(TimeSpan minExpiry, TimeSpan maxExpiry)
|
||||
{
|
||||
SetFilterImp(universe => universe.Expiration(minExpiry, maxExpiry));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="ContractFilter"/> to a new instance of the filter
|
||||
/// using the specified expiration range values
|
||||
/// </summary>
|
||||
/// <param name="minExpiryDays">The minimum time, expressed in days, until expiry to include, for example, 10
|
||||
/// would exclude contracts expiring in less than 10 days</param>
|
||||
/// <param name="maxExpiryDays">The maximum time, expressed in days, until expiry to include, for example, 10
|
||||
/// would exclude contracts expiring in more than 10 days</param>
|
||||
public void SetFilter(int minExpiryDays, int maxExpiryDays)
|
||||
{
|
||||
SetFilterImp(universe => universe.Expiration(minExpiryDays, maxExpiryDays));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="ContractFilter"/> to a new universe selection function
|
||||
/// </summary>
|
||||
/// <param name="universeFunc">new universe selection function</param>
|
||||
public void SetFilter(Func<FutureFilterUniverse, FutureFilterUniverse> universeFunc)
|
||||
{
|
||||
SetFilterImp(universeFunc);
|
||||
ContractFilter.Asynchronous = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="ContractFilter"/> to a new universe selection function
|
||||
/// </summary>
|
||||
/// <param name="universeFunc">new universe selection function</param>
|
||||
public void SetFilter(PyObject universeFunc)
|
||||
{
|
||||
var pyUniverseFunc = PythonUtil.ToFunc<FutureFilterUniverse, FutureFilterUniverse>(universeFunc);
|
||||
SetFilter(pyUniverseFunc);
|
||||
}
|
||||
|
||||
private void SetFilterImp(Func<FutureFilterUniverse, FutureFilterUniverse> universeFunc)
|
||||
{
|
||||
Func<IDerivativeSecurityFilterUniverse<FutureUniverse>, IDerivativeSecurityFilterUniverse<FutureUniverse>> func = universe =>
|
||||
{
|
||||
var futureUniverse = universe as FutureFilterUniverse;
|
||||
var result = universeFunc(futureUniverse);
|
||||
return result.ApplyTypesFilter();
|
||||
};
|
||||
ContractFilter = new FuncSecurityDerivativeFilter<FutureUniverse>(func);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the securities symbol
|
||||
/// </summary>
|
||||
public static implicit operator Symbol(Future security) => security.Symbol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data;
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// Future specific caching support
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityCache"/>
|
||||
public class FutureCache : SecurityCache
|
||||
{
|
||||
/// <summary>
|
||||
/// The current settlement price
|
||||
/// </summary>
|
||||
public decimal SettlementPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Will consume the given data point updating the cache state and it's properties
|
||||
/// </summary>
|
||||
/// <param name="data">The data point to process</param>
|
||||
/// <param name="cacheByType">True if this data point should be cached by type</param>
|
||||
protected override void ProcessDataPoint(BaseData data, bool cacheByType)
|
||||
{
|
||||
base.ProcessDataPoint(data, cacheByType);
|
||||
|
||||
SettlementPrice = Price;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores the specified data list in the cache, updating the open interest from any chain universe data
|
||||
/// </summary>
|
||||
/// <param name="data">The collection of data to store in this cache</param>
|
||||
/// <param name="dataType">The data type</param>
|
||||
public override void StoreData(IReadOnlyList<BaseData> data, Type dataType)
|
||||
{
|
||||
UpdateOpenInterest(data);
|
||||
base.StoreData(data, dataType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// Future exchange class - information and helper tools for future exchange properties
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityExchange"/>
|
||||
public class FutureExchange : SecurityExchange
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of trading days per year for this security, 252.
|
||||
/// </summary>
|
||||
/// <remarks>Used for performance statistics to calculate sharpe ratio accurately</remarks>
|
||||
public override int TradingDaysPerYear
|
||||
{
|
||||
get { return 252; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FutureExchange"/> class using the specified
|
||||
/// exchange hours to determine open/close times
|
||||
/// </summary>
|
||||
/// <param name="exchangeHours">Contains the weekly exchange schedule plus holidays</param>
|
||||
public FutureExchange(SecurityExchangeHours exchangeHours)
|
||||
: base(exchangeHours)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class contains definitions of popular futures expiration cycles
|
||||
/// </summary>
|
||||
public static class FutureExpirationCycles
|
||||
{
|
||||
/// <summary>
|
||||
/// January Cycle: Expirations in January, April, July, October (the first month of each quarter)
|
||||
/// </summary>
|
||||
public static readonly int[] January = { 1, 4, 7, 10 };
|
||||
|
||||
/// <summary>
|
||||
/// February Cycle: Expirations in February, May, August, November (second month)
|
||||
/// </summary>
|
||||
public static readonly int[] February = { 2, 5, 8, 11 };
|
||||
|
||||
/// <summary>
|
||||
/// March Cycle: Expirations in March, June, September, December (third month)
|
||||
/// </summary>
|
||||
public static readonly int[] March = { 3, 6, 9, 12 };
|
||||
|
||||
/// <summary>
|
||||
/// December Cycle: Expirations in December
|
||||
/// </summary>
|
||||
public static readonly int[] December = { 12 };
|
||||
|
||||
/// <summary>
|
||||
/// All Year Cycle: Expirations in every month of the year
|
||||
/// </summary>
|
||||
public static readonly int[] AllYear = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
|
||||
|
||||
/// <summary>
|
||||
/// GJMQVZ Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] GJMQVZ = { 2, 4, 6, 8, 10, 12 };
|
||||
|
||||
/// <summary>
|
||||
/// GJKMNQVZ Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] GJKMNQVZ = { 2, 4, 5, 6, 7, 8, 10, 12 };
|
||||
|
||||
/// <summary>
|
||||
/// HMUZ Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] HMUZ = March;
|
||||
|
||||
/// <summary>
|
||||
/// HKNUZ Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] HKNUZ = { 3, 5, 7, 9, 12 };
|
||||
|
||||
/// <summary>
|
||||
/// HKNV Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] HKNV = { 3, 5, 7, 10 };
|
||||
|
||||
/// <summary>
|
||||
/// HKNVZ Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] HKNVZ = { 3, 5, 7, 10, 12 };
|
||||
|
||||
/// <summary>
|
||||
/// FHKNUX Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] FHKNUX = { 1, 3, 5, 7, 9, 11 };
|
||||
|
||||
/// <summary>
|
||||
/// FHJKQUVX Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] FHJKQUVX = { 1, 3, 4, 5, 8, 9, 10, 11 };
|
||||
|
||||
/// <summary>
|
||||
/// HKNUVZ Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] HKNUVZ = { 3, 5, 7, 9, 10, 12 };
|
||||
|
||||
/// <summary>
|
||||
/// FHKNQUVZ Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] FHKNUVZ = { 1, 3, 5, 7, 9, 10, 12 };
|
||||
|
||||
/// <summary>
|
||||
/// FHKMQUVZ Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] FHKNQUVZ = { 1, 3, 5, 7, 8, 9, 10, 12 };
|
||||
|
||||
/// <summary>
|
||||
/// FHKNQUX Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] FHKNQUX = { 1, 3, 5, 7, 8, 9, 11 };
|
||||
|
||||
/// <summary>
|
||||
/// FGHJKMNQUVXZ Cycle
|
||||
/// </summary>
|
||||
public static readonly int[] FGHJKMNQUVXZ = AllYear;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Securities.Future;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents futures symbols universe used in filtering.
|
||||
/// </summary>
|
||||
public class FutureFilterUniverse : ContractSecurityFilterUniverse<FutureFilterUniverse, FutureUniverse>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs FutureFilterUniverse
|
||||
/// </summary>
|
||||
public FutureFilterUniverse(IReadOnlyList<FutureUniverse> allData, DateTime localTime)
|
||||
: base(allData, localTime)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the given Future contract symbol is standard
|
||||
/// </summary>
|
||||
/// <returns>True if contract is standard</returns>
|
||||
protected override bool IsStandard(Symbol symbol)
|
||||
{
|
||||
return FutureSymbol.IsStandard(symbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the data type for the given symbol
|
||||
/// </summary>
|
||||
/// <returns>A data instance for the given symbol, which is just the symbol itself</returns>
|
||||
protected override FutureUniverse CreateDataInstance(Symbol symbol)
|
||||
{
|
||||
return new FutureUniverse()
|
||||
{
|
||||
Symbol = symbol,
|
||||
Time = LocalTime
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies filter selecting futures contracts based on expiration cycles. See <see cref="FutureExpirationCycles"/> for details
|
||||
/// </summary>
|
||||
/// <param name="months">Months to select contracts from</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public FutureFilterUniverse ExpirationCycle(int[] months)
|
||||
{
|
||||
var monthHashSet = months.ToHashSet();
|
||||
return this.Where(x => monthHashSet.Contains(x.ID.Date.Month));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extensions for Linq support
|
||||
/// </summary>
|
||||
public static class FutureFilterUniverseEx
|
||||
{
|
||||
/// <summary>
|
||||
/// Filters universe
|
||||
/// </summary>
|
||||
/// <param name="universe">Universe to apply the filter too</param>
|
||||
/// <param name="predicate">Bool function to determine which Symbol are filtered</param>
|
||||
/// <returns><see cref="FutureFilterUniverse"/> with filter applied</returns>
|
||||
public static FutureFilterUniverse Where(this FutureFilterUniverse universe, Func<FutureUniverse, bool> predicate)
|
||||
{
|
||||
universe.Data = universe.Data.Where(predicate).ToList();
|
||||
return universe;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps universe
|
||||
/// </summary>
|
||||
/// <param name="universe">Universe to apply the filter too</param>
|
||||
/// <param name="mapFunc">Symbol function to determine which Symbols are filtered</param>
|
||||
/// <returns><see cref="FutureFilterUniverse"/> with filter applied</returns>
|
||||
public static FutureFilterUniverse Select(this FutureFilterUniverse universe, Func<FutureUniverse, Symbol> mapFunc)
|
||||
{
|
||||
universe.AllSymbols = universe.Data.Select(mapFunc).ToList();
|
||||
return universe;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Binds universe
|
||||
/// </summary>
|
||||
/// <param name="universe">Universe to apply the filter too</param>
|
||||
/// <param name="mapFunc">Symbols function to determine which Symbols are filtered</param>
|
||||
/// <returns><see cref="FutureFilterUniverse"/> with filter applied</returns>
|
||||
public static FutureFilterUniverse SelectMany(this FutureFilterUniverse universe, Func<FutureUniverse, IEnumerable<Symbol>> mapFunc)
|
||||
{
|
||||
universe.AllSymbols = universe.Data.SelectMany(mapFunc).ToList();
|
||||
return universe;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// Future holdings implementation of the base securities class
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityHolding"/>
|
||||
public class FutureHolding : SecurityHolding
|
||||
{
|
||||
/// <summary>
|
||||
/// The cash settled profit for the current open position
|
||||
/// </summary>
|
||||
public virtual decimal SettledProfit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unsettled profit for the current open position <see cref="SettledProfit"/>
|
||||
/// </summary>
|
||||
public virtual decimal UnsettledProfit
|
||||
{
|
||||
get
|
||||
{
|
||||
return TotalCloseProfit() - SettledProfit;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Future Holding Class constructor
|
||||
/// </summary>
|
||||
/// <param name="security">The future security being held</param>
|
||||
/// <param name="currencyConverter">A currency converter instance</param>
|
||||
public FutureHolding(Security security, ICurrencyConverter currencyConverter)
|
||||
: base(security, currencyConverter)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* 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.IO;
|
||||
using System.Linq;
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Logging;
|
||||
using System.Threading.Tasks;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Orders.Fees;
|
||||
using QuantConnect.Configuration;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a simple margin model for margin futures. Margin file contains Initial and Maintenance margins
|
||||
/// </summary>
|
||||
public class FutureMarginModel : SecurityMarginModel
|
||||
{
|
||||
private static IDataProvider _dataProvider;
|
||||
private static readonly object _locker = new();
|
||||
private static Dictionary<string, MarginRequirementsEntry[]> _marginRequirementsCache = new();
|
||||
|
||||
// historical database of margin requirements
|
||||
private int _marginCurrentIndex;
|
||||
|
||||
private readonly Security _security;
|
||||
|
||||
/// <summary>
|
||||
/// True will enable usage of intraday margins.
|
||||
/// </summary>
|
||||
/// <remarks>Disabled by default. Note that intraday margins are less than overnight margins
|
||||
/// and could lead to margin calls</remarks>
|
||||
public bool EnableIntradayMargins { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initial Overnight margin requirement for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public virtual decimal InitialOvernightMarginRequirement => GetCurrentMarginRequirements(_security)?.InitialOvernight ?? 0m;
|
||||
|
||||
/// <summary>
|
||||
/// Maintenance Overnight margin requirement for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public virtual decimal MaintenanceOvernightMarginRequirement => GetCurrentMarginRequirements(_security)?.MaintenanceOvernight ?? 0m;
|
||||
|
||||
/// <summary>
|
||||
/// Initial Intraday margin for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public virtual decimal InitialIntradayMarginRequirement => GetCurrentMarginRequirements(_security)?.InitialIntraday ?? 0m;
|
||||
|
||||
/// <summary>
|
||||
/// Maintenance Intraday margin requirement for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public virtual decimal MaintenanceIntradayMarginRequirement => GetCurrentMarginRequirements(_security)?.MaintenanceIntraday ?? 0m;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FutureMarginModel"/>
|
||||
/// </summary>
|
||||
/// <param name="requiredFreeBuyingPowerPercent">The percentage used to determine the required unused buying power for the account.</param>
|
||||
/// <param name="security">The security that this model belongs to</param>
|
||||
public FutureMarginModel(decimal requiredFreeBuyingPowerPercent = 0, Security security = null)
|
||||
{
|
||||
RequiredFreeBuyingPowerPercent = requiredFreeBuyingPowerPercent;
|
||||
_security = security;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current leverage of the security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get leverage for</param>
|
||||
/// <returns>The current leverage in the security</returns>
|
||||
public override decimal GetLeverage(Security security)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the leverage for the applicable securities, i.e, futures
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is added to maintain backwards compatibility with the old margin/leverage system
|
||||
/// </remarks>
|
||||
/// <param name="security"></param>
|
||||
/// <param name="leverage">The new leverage</param>
|
||||
public override void SetLeverage(Security security, decimal leverage)
|
||||
{
|
||||
// Futures are leveraged products and different leverage cannot be set by user.
|
||||
throw new InvalidOperationException("Futures are leveraged products and different leverage cannot be set by user");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the maximum market order quantity to obtain a position with a given buying power percentage.
|
||||
/// Will not take into account free buying power.
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the portfolio, the security and the target signed buying power percentage</param>
|
||||
/// <returns>Returns the maximum allowed market order quantity and if zero, also the reason</returns>
|
||||
public override GetMaximumOrderQuantityResult GetMaximumOrderQuantityForTargetBuyingPower(
|
||||
GetMaximumOrderQuantityForTargetBuyingPowerParameters parameters)
|
||||
{
|
||||
if (Math.Abs(parameters.TargetBuyingPower) > 1)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Futures do not allow specifying a leveraged target, since they are traded using margin which already is leveraged. " +
|
||||
$"Possible target buying power goes from -1 to 1, target provided is: {parameters.TargetBuyingPower}");
|
||||
}
|
||||
return base.GetMaximumOrderQuantityForTargetBuyingPower(parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total margin required to execute the specified order in units of the account currency including fees
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the portfolio, the security and the order</param>
|
||||
/// <returns>The total margin in terms of the currency quoted in the order</returns>
|
||||
public override InitialMargin GetInitialMarginRequiredForOrder(
|
||||
InitialMarginRequiredForOrderParameters parameters
|
||||
)
|
||||
{
|
||||
//Get the order value from the non-abstract order classes (MarketOrder, LimitOrder, StopMarketOrder)
|
||||
//Market order is approximated from the current security price and set in the MarketOrder Method in QCAlgorithm.
|
||||
|
||||
var fees = parameters.Security.FeeModel.GetOrderFee(
|
||||
new OrderFeeParameters(parameters.Security,
|
||||
parameters.Order)).Value;
|
||||
var feesInAccountCurrency = parameters.CurrencyConverter.
|
||||
ConvertToAccountCurrency(fees).Amount;
|
||||
|
||||
var orderMargin = this.GetInitialMarginRequirement(parameters.Security, parameters.Order.Quantity);
|
||||
|
||||
return new InitialMargin(orderMargin + Math.Sign(orderMargin) * feesInAccountCurrency);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin currently allotted to the specified holding
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the security</param>
|
||||
/// <returns>The maintenance margin required for the </returns>
|
||||
public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters)
|
||||
{
|
||||
if (parameters.Quantity == 0m)
|
||||
{
|
||||
return 0m;
|
||||
}
|
||||
|
||||
var security = parameters.Security;
|
||||
var marginReq = GetCurrentMarginRequirements(security);
|
||||
if (marginReq == null)
|
||||
{
|
||||
return 0m;
|
||||
}
|
||||
|
||||
if (EnableIntradayMargins
|
||||
&& security.Exchange.ExchangeOpen
|
||||
&& !security.Exchange.ClosingSoon)
|
||||
{
|
||||
return marginReq.MaintenanceIntraday * parameters.AbsoluteQuantity * security.QuoteCurrency.ConversionRate;
|
||||
}
|
||||
|
||||
// margin is per contract
|
||||
return marginReq.MaintenanceOvernight * parameters.AbsoluteQuantity * security.QuoteCurrency.ConversionRate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The margin that must be held in order to increase the position by the provided quantity
|
||||
/// </summary>
|
||||
public override InitialMargin GetInitialMarginRequirement(InitialMarginParameters parameters)
|
||||
{
|
||||
var security = parameters.Security;
|
||||
var quantity = parameters.Quantity;
|
||||
if (quantity == 0m)
|
||||
{
|
||||
return InitialMargin.Zero;
|
||||
}
|
||||
|
||||
var marginReq = GetCurrentMarginRequirements(security);
|
||||
if (marginReq == null)
|
||||
{
|
||||
return InitialMargin.Zero;
|
||||
}
|
||||
|
||||
if (EnableIntradayMargins
|
||||
&& security.Exchange.ExchangeOpen
|
||||
&& !security.Exchange.ClosingSoon)
|
||||
{
|
||||
return new InitialMargin(marginReq.InitialIntraday * quantity * security.QuoteCurrency.ConversionRate);
|
||||
}
|
||||
|
||||
// margin is per contract
|
||||
return new InitialMargin(marginReq.InitialOvernight * quantity * security.QuoteCurrency.ConversionRate);
|
||||
}
|
||||
|
||||
private MarginRequirementsEntry GetCurrentMarginRequirements(Security security)
|
||||
{
|
||||
var lastData = security?.GetLastData();
|
||||
if (lastData == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var marginRequirementsHistory = LoadMarginRequirementsHistory(security.Symbol);
|
||||
var date = lastData.Time.Date;
|
||||
|
||||
while (_marginCurrentIndex + 1 < marginRequirementsHistory.Length &&
|
||||
marginRequirementsHistory[_marginCurrentIndex + 1].Date <= date)
|
||||
{
|
||||
_marginCurrentIndex++;
|
||||
}
|
||||
|
||||
return marginRequirementsHistory[_marginCurrentIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sorted list of historical margin changes produced by reading in the margin requirements
|
||||
/// data found in /Data/symbol-margin/
|
||||
/// </summary>
|
||||
/// <returns>Sorted list of historical margin changes</returns>
|
||||
private static MarginRequirementsEntry[] LoadMarginRequirementsHistory(Symbol symbol)
|
||||
{
|
||||
if (!_marginRequirementsCache.TryGetValue(symbol.ID.Symbol, out var marginRequirementsEntries))
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
if (!_marginRequirementsCache.TryGetValue(symbol.ID.Symbol, out marginRequirementsEntries))
|
||||
{
|
||||
Dictionary<string, MarginRequirementsEntry[]> marginRequirementsCache = new(_marginRequirementsCache)
|
||||
{
|
||||
[symbol.ID.Symbol] = marginRequirementsEntries = FromCsvFile(symbol)
|
||||
};
|
||||
// we change the reference so we can read without a lock
|
||||
_marginRequirementsCache = marginRequirementsCache;
|
||||
}
|
||||
}
|
||||
}
|
||||
return marginRequirementsEntries;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads margin requirements file and returns a sorted list of historical margin changes
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol to fetch margin requirements for</param>
|
||||
/// <returns>Sorted list of historical margin changes</returns>
|
||||
private static MarginRequirementsEntry[] FromCsvFile(Symbol symbol)
|
||||
{
|
||||
var file = Path.Combine(Globals.DataFolder,
|
||||
symbol.SecurityType.ToLower(),
|
||||
symbol.ID.Market.ToLowerInvariant(),
|
||||
"margins", symbol.ID.Symbol + ".csv");
|
||||
|
||||
if(_dataProvider == null)
|
||||
{
|
||||
ClearMarginCache();
|
||||
_dataProvider = Composer.Instance.GetPart<IDataProvider>();
|
||||
}
|
||||
|
||||
// skip the first header line, also skip #'s as these are comment lines
|
||||
var marginRequirementsEntries = _dataProvider.ReadLines(file)
|
||||
.Where(x => !x.StartsWith("#") && !string.IsNullOrWhiteSpace(x))
|
||||
.Skip(1)
|
||||
.Select(MarginRequirementsEntry.Create)
|
||||
.OrderBy(x => x.Date)
|
||||
.ToArray();
|
||||
|
||||
if (marginRequirementsEntries.Length == 0)
|
||||
{
|
||||
Log.Error($"FutureMarginModel.FromCsvFile(): Unable to locate future margin requirements file. Defaulting to zero margin for this symbol. File: {file}");
|
||||
|
||||
marginRequirementsEntries = new[] {
|
||||
new MarginRequirementsEntry
|
||||
{
|
||||
Date = DateTime.MinValue
|
||||
}
|
||||
};
|
||||
}
|
||||
return marginRequirementsEntries;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For live deployments we don't want to have stale margin requirements to we refresh them every day
|
||||
/// </summary>
|
||||
private static void ClearMarginCache()
|
||||
{
|
||||
Task.Delay(Time.OneDay).ContinueWith((_) =>
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
_marginRequirementsCache = new();
|
||||
}
|
||||
ClearMarginCache();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.Logging;
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// Settlement model which can handle daily profit and loss settlement
|
||||
/// </summary>
|
||||
public class FutureSettlementModel : ImmediateSettlementModel
|
||||
{
|
||||
private DateTime _lastSettlementDate;
|
||||
private decimal _settledFutureQuantity;
|
||||
private decimal _settlementPrice;
|
||||
|
||||
/// <summary>
|
||||
/// Applies unsettledContractsTodaysProfit settlement rules
|
||||
/// </summary>
|
||||
/// <param name="applyFundsParameters">The funds application parameters</param>
|
||||
public override void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsParameters)
|
||||
{
|
||||
if(_settledFutureQuantity != 0)
|
||||
{
|
||||
var fill = applyFundsParameters.Fill;
|
||||
var security = applyFundsParameters.Security;
|
||||
var futureHolding = (FutureHolding)security.Holdings;
|
||||
|
||||
var absoluteQuantityClosed = Math.Min(fill.AbsoluteFillQuantity, security.Holdings.AbsoluteQuantity);
|
||||
|
||||
var absoluteQuantityClosedSettled = Math.Min(absoluteQuantityClosed, Math.Abs(_settledFutureQuantity));
|
||||
var quantityClosedSettled = Math.Sign(-fill.FillQuantity) * absoluteQuantityClosedSettled;
|
||||
|
||||
// reduce our settled future quantity proportionally too
|
||||
var factor = quantityClosedSettled / _settledFutureQuantity;
|
||||
_settledFutureQuantity -= quantityClosedSettled;
|
||||
|
||||
// the passed in cash amount will hold the complete profit/loss of the trade, so we need to substract the settled profit we were given or taken from
|
||||
var removedSettledProfit = factor * futureHolding.SettledProfit;
|
||||
futureHolding.SettledProfit -= removedSettledProfit;
|
||||
|
||||
applyFundsParameters.CashAmount = new CashAmount(applyFundsParameters.CashAmount.Amount - removedSettledProfit, applyFundsParameters.CashAmount.Currency);
|
||||
}
|
||||
|
||||
base.ApplyFunds(applyFundsParameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan for pending settlements
|
||||
/// </summary>
|
||||
/// <param name="settlementParameters">The settlement parameters</param>
|
||||
public override void Scan(ScanSettlementModelParameters settlementParameters)
|
||||
{
|
||||
var security = settlementParameters.Security;
|
||||
|
||||
// In the futures markets, losers pay winners every day. So once a day after the settlement time has passed we will update the cash book to reflect this
|
||||
if (_lastSettlementDate.Date < security.LocalTime.Date)
|
||||
{
|
||||
if ((_lastSettlementDate != default) && security.Invested)
|
||||
{
|
||||
var futureHolding = (FutureHolding)security.Holdings;
|
||||
var futureCache = (FutureCache)security.Cache;
|
||||
_settlementPrice = futureCache.SettlementPrice;
|
||||
_settledFutureQuantity = security.Holdings.Quantity;
|
||||
|
||||
// We settled the daily P&L, losers pay winners
|
||||
var dailyProfitLoss = futureHolding.TotalCloseProfit(includeFees: false, exitPrice: _settlementPrice) - futureHolding.SettledProfit;
|
||||
if (dailyProfitLoss != 0)
|
||||
{
|
||||
futureHolding.SettledProfit += dailyProfitLoss;
|
||||
|
||||
settlementParameters.Portfolio.CashBook[security.QuoteCurrency.Symbol].AddAmount(dailyProfitLoss);
|
||||
Log.Trace($"FutureSettlementModel.Scan({security.Symbol}): {security.LocalTime} Daily P&L: {dailyProfitLoss} " +
|
||||
$"Quantity: {_settledFutureQuantity} Settlement: {_settlementPrice} UnrealizedProfit: {futureHolding.UnrealizedProfit}");
|
||||
}
|
||||
}
|
||||
_lastSettlementDate = security.LocalTime.Date;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the current datetime in terms of the exchange's local time zone
|
||||
/// </summary>
|
||||
/// <param name="newLocalTime">Current local time</param>
|
||||
public void SetLocalDateTimeFrontier(DateTime newLocalTime)
|
||||
{
|
||||
_lastSettlementDate = newLocalTime.Date;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.Logging;
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class contains common utility methods specific to symbols representing the future contracts
|
||||
/// </summary>
|
||||
public static class FutureSymbol
|
||||
{
|
||||
/// <summary>
|
||||
/// Determine if a given Futures contract is a standard contract.
|
||||
/// </summary>
|
||||
/// <param name="symbol">Future symbol</param>
|
||||
/// <returns>True if symbol expiration matches standard expiration</returns>
|
||||
public static bool IsStandard(Symbol symbol)
|
||||
{
|
||||
var contractExpirationDate = symbol.ID.Date.Date;
|
||||
|
||||
try
|
||||
{
|
||||
// Use our FutureExpiryFunctions to determine standard contracts dates.
|
||||
var expiryFunction = FuturesExpiryFunctions.FuturesExpiryFunction(symbol);
|
||||
var contractMonth = FuturesExpiryUtilityFunctions.GetFutureContractMonth(symbol);
|
||||
|
||||
var standardExpirationDate = expiryFunction(contractMonth);
|
||||
|
||||
// Return true if the dates match
|
||||
return contractExpirationDate == standardExpirationDate.Date;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Log.Error($"FutureSymbol.IsStandard(): Could not find standard date for {symbol}, will be classified as standard");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the future contract is a weekly contract
|
||||
/// </summary>
|
||||
/// <param name="symbol">Future symbol</param>
|
||||
/// <returns>True if symbol is non-standard contract</returns>
|
||||
public static bool IsWeekly(Symbol symbol)
|
||||
{
|
||||
return !IsStandard(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* 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 static QuantConnect.StringExtensions;
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to implement common functions used in FuturesExpiryFunctions
|
||||
/// </summary>
|
||||
public static class FuturesExpiryUtilityFunctions
|
||||
{
|
||||
private static readonly MarketHoursDatabase MarketHoursDatabase = MarketHoursDatabase.FromDataFolder();
|
||||
|
||||
/// <summary>
|
||||
/// Get holiday list from the MHDB given the market and the symbol of the security
|
||||
/// </summary>
|
||||
/// <param name="market">The market the exchange resides in, i.e, 'usa', 'fxcm', ect...</param>
|
||||
/// <param name="symbol">The particular symbol being traded</param>s
|
||||
internal static HashSet<DateTime> GetExpirationHolidays(string market, string symbol)
|
||||
{
|
||||
var exchangeHours = MarketHoursDatabase.FromDataFolder()
|
||||
.GetEntry(market, symbol, SecurityType.Future)
|
||||
.ExchangeHours;
|
||||
return exchangeHours.Holidays.Concat(exchangeHours.BankHolidays).ToHashSet();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve n^th succeeding/preceding business day for a given day
|
||||
/// </summary>
|
||||
/// <param name="time">The current Time</param>
|
||||
/// <param name="n">Number of business days succeeding current time. Use negative value for preceding business days</param>
|
||||
/// <param name="holidays">Set of holidays to exclude. These should be sourced from the <see cref="MarketHoursDatabase"/></param>
|
||||
/// <returns>The date-time after adding n business days</returns>
|
||||
public static DateTime AddBusinessDays(DateTime time, int n, HashSet<DateTime> holidays)
|
||||
{
|
||||
if (n < 0)
|
||||
{
|
||||
var businessDays = -n;
|
||||
var totalDays = 1;
|
||||
do
|
||||
{
|
||||
var previousDay = time.AddDays(-totalDays);
|
||||
if (!holidays.Contains(previousDay.Date) && previousDay.IsCommonBusinessDay())
|
||||
{
|
||||
businessDays--;
|
||||
}
|
||||
|
||||
if (businessDays > 0) totalDays++;
|
||||
} while (businessDays > 0);
|
||||
|
||||
return time.AddDays(-totalDays);
|
||||
}
|
||||
else
|
||||
{
|
||||
var businessDays = n;
|
||||
var totalDays = 1;
|
||||
do
|
||||
{
|
||||
var previousDay = time.AddDays(totalDays);
|
||||
if (!holidays.Contains(previousDay.Date) && previousDay.IsCommonBusinessDay())
|
||||
{
|
||||
businessDays--;
|
||||
}
|
||||
|
||||
if (businessDays > 0) totalDays++;
|
||||
} while (businessDays > 0);
|
||||
|
||||
return time.AddDays(totalDays);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve n^th succeeding/preceding business day for a given day if there was a holiday on that day
|
||||
/// </summary>
|
||||
/// <param name="time">The current Time</param>
|
||||
/// <param name="n">Number of business days succeeding current time. Use negative value for preceding business days</param>
|
||||
/// <param name="holidayList">Enumerable of holidays to exclude. These should be sourced from the <see cref="MarketHoursDatabase"/></param>
|
||||
/// <returns>The date-time after adding n business days</returns>
|
||||
public static DateTime AddBusinessDaysIfHoliday(DateTime time, int n, HashSet<DateTime> holidayList)
|
||||
{
|
||||
if (holidayList.Contains(time))
|
||||
{
|
||||
return AddBusinessDays(time, n, holidayList);
|
||||
}
|
||||
else
|
||||
{
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve the n^th last business day of the delivery month.
|
||||
/// </summary>
|
||||
/// <param name="time">DateTime for delivery month</param>
|
||||
/// <param name="n">Number of days</param>
|
||||
/// <param name="holidayList">Holidays to use while calculating n^th business day. Useful for MHDB entries</param>
|
||||
/// <returns>Nth Last Business day of the month</returns>
|
||||
public static DateTime NthLastBusinessDay(DateTime time, int n, IEnumerable<DateTime> holidayList)
|
||||
{
|
||||
var daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
|
||||
var lastDayOfMonth = new DateTime(time.Year, time.Month, daysInMonth);
|
||||
var holidays = holidayList.Select(x => x.Date);
|
||||
|
||||
if (n > daysInMonth)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(n), Invariant(
|
||||
$"Number of days ({n}) is larger than the size of month({daysInMonth})"
|
||||
));
|
||||
}
|
||||
// Count the number of days in the month after the third to last business day
|
||||
var businessDays = n;
|
||||
var totalDays = 0;
|
||||
do
|
||||
{
|
||||
var previousDay = lastDayOfMonth.AddDays(-totalDays);
|
||||
if (NotHoliday(previousDay, holidays) && !holidays.Contains(previousDay))
|
||||
{
|
||||
businessDays--;
|
||||
}
|
||||
if (businessDays > 0) totalDays++;
|
||||
} while (businessDays > 0);
|
||||
|
||||
return lastDayOfMonth.AddDays(-totalDays);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the n^th business day of the month (includes checking for holidays)
|
||||
/// </summary>
|
||||
/// <param name="time">Month to calculate business day for</param>
|
||||
/// <param name="nthBusinessDay">n^th business day to get</param>
|
||||
/// <param name="holidayList"> Holidays to not count as business days</param>
|
||||
/// <returns>Nth business day of the month</returns>
|
||||
public static DateTime NthBusinessDay(DateTime time, int nthBusinessDay, IEnumerable<DateTime> holidayList)
|
||||
{
|
||||
var daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
|
||||
var holidays = holidayList.Select(x => x.Date);
|
||||
if (nthBusinessDay > daysInMonth)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(Invariant(
|
||||
$"Argument nthBusinessDay (${nthBusinessDay}) is larger than the amount of days in the current month (${daysInMonth})"
|
||||
));
|
||||
}
|
||||
if (nthBusinessDay < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(Invariant(
|
||||
$"Argument nthBusinessDay (${nthBusinessDay}) is less than one. Provide a number greater than one and less than the days in month"
|
||||
));
|
||||
}
|
||||
|
||||
var calculatedTime = new DateTime(time.Year, time.Month, 1);
|
||||
|
||||
var daysCounted = calculatedTime.IsCommonBusinessDay() ? 1 : 0;
|
||||
var i = 0;
|
||||
|
||||
// Check for holiday up here in case we want the first business day and it is a holiday so that we don't skip over it.
|
||||
// We also want to make sure that we don't stop on a weekend.
|
||||
while (daysCounted < nthBusinessDay || holidays.Contains(calculatedTime) || !calculatedTime.IsCommonBusinessDay())
|
||||
{
|
||||
// The asset continues trading on days contained within `USHoliday.Dates`, but
|
||||
// the last trade date is affected by those holidays. We check for
|
||||
// both MHDB entries and holidays to get accurate business days
|
||||
if (holidays.Contains(calculatedTime))
|
||||
{
|
||||
// Catches edge case where first day is on a friday
|
||||
if (i == 0 && calculatedTime.DayOfWeek == DayOfWeek.Friday)
|
||||
{
|
||||
daysCounted = 0;
|
||||
}
|
||||
|
||||
calculatedTime = calculatedTime.AddDays(1);
|
||||
|
||||
if (i != 0 && calculatedTime.IsCommonBusinessDay())
|
||||
{
|
||||
daysCounted++;
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
calculatedTime = calculatedTime.AddDays(1);
|
||||
|
||||
if (!holidays.Contains(calculatedTime) && NotHoliday(calculatedTime, holidays))
|
||||
{
|
||||
daysCounted++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return calculatedTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve the 2nd Friday of the given month
|
||||
/// </summary>
|
||||
/// <param name="time">Date from the given month</param>
|
||||
/// <returns>2nd Friday of given month</returns>
|
||||
public static DateTime SecondFriday(DateTime time) => NthFriday(time, 2);
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve the 3rd Friday of the given month
|
||||
/// </summary>
|
||||
/// <param name="time">Date from the given month</param>
|
||||
/// <returns>3rd Friday of given month</returns>
|
||||
public static DateTime ThirdFriday(DateTime time) => NthFriday(time, 3);
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve the Nth Friday of the given month
|
||||
/// </summary>
|
||||
/// <param name="time">Date from the given month</param>
|
||||
/// <param name="n">The order of the Friday in the period</param>
|
||||
/// <returns>Nth Friday of given month</returns>
|
||||
public static DateTime NthFriday(DateTime time, int n) => NthWeekday(time, n, DayOfWeek.Friday);
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve third Wednesday of the given month (usually Monday).
|
||||
/// </summary>
|
||||
/// <param name="time">Date from the given month</param>
|
||||
/// <returns>Third Wednesday of the given month</returns>
|
||||
public static DateTime ThirdWednesday(DateTime time) => NthWeekday(time, 3, DayOfWeek.Wednesday);
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve the Nth Weekday of the given month
|
||||
/// </summary>
|
||||
/// <param name="time">Date from the given month</param>
|
||||
/// <param name="n">The order of the Weekday in the period</param>
|
||||
/// <param name="dayOfWeek">The day of the week</param>
|
||||
/// <returns>Nth Weekday of given month</returns>
|
||||
public static DateTime NthWeekday(DateTime time, int n, DayOfWeek dayOfWeek)
|
||||
{
|
||||
if (n < 1 || n > 5)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(n), "'n' lower than 1 or greater than 5");
|
||||
}
|
||||
|
||||
var daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
|
||||
return (from day in Enumerable.Range(1, daysInMonth)
|
||||
where new DateTime(time.Year, time.Month, day).DayOfWeek == dayOfWeek
|
||||
select new DateTime(time.Year, time.Month, day)).ElementAt(n - 1);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve the last weekday of any month
|
||||
/// </summary>
|
||||
/// <param name="time">Date from the given month</param>
|
||||
/// <param name="dayOfWeek">the last weekday to be found</param>
|
||||
/// <returns>Last day of the we</returns>
|
||||
public static DateTime LastWeekday(DateTime time, DayOfWeek dayOfWeek)
|
||||
{
|
||||
|
||||
var daysInMonth = DateTime.DaysInMonth(time.Year, time.Month);
|
||||
return (from day in Enumerable.Range(1, daysInMonth).Reverse()
|
||||
where new DateTime(time.Year, time.Month, day).DayOfWeek == dayOfWeek
|
||||
select new DateTime(time.Year, time.Month, day)).First();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve the last Thursday of any month
|
||||
/// </summary>
|
||||
/// <param name="time">Date from the given month</param>
|
||||
/// <returns>Last Thursday of the given month</returns>
|
||||
public static DateTime LastThursday(DateTime time) => LastWeekday(time, DayOfWeek.Thursday);
|
||||
|
||||
/// <summary>
|
||||
/// Method to retrieve the last Friday of any month
|
||||
/// </summary>
|
||||
/// <param name="time">Date from the given month</param>
|
||||
/// <returns>Last Friday of the given month</returns>
|
||||
public static DateTime LastFriday(DateTime time) => LastWeekday(time, DayOfWeek.Friday);
|
||||
|
||||
/// <summary>
|
||||
/// Method to check whether a given time is holiday or not
|
||||
/// </summary>
|
||||
/// <param name="time">The DateTime for consideration</param>
|
||||
/// <param name="holidayList">Enumerable of holidays to exclude. These should be sourced from the <see cref="MarketHoursDatabase"/></param>
|
||||
/// <returns>True if the time is not a holidays, otherwise returns false</returns>
|
||||
public static bool NotHoliday(DateTime time, IEnumerable<DateTime> holidayList)
|
||||
{
|
||||
return time.IsCommonBusinessDay() && !holidayList.Contains(time.Date);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function takes Thursday as input and returns true if four weekdays preceding it are not Holidays
|
||||
/// </summary>
|
||||
/// <param name="thursday">DateTime of a given Thursday</param>
|
||||
/// <param name="holidayList">Enumerable of holidays to exclude. These should be sourced from the <see cref="MarketHoursDatabase"/></param>
|
||||
/// <returns>False if DayOfWeek is not Thursday or is not preceded by four weekdays,Otherwise returns True</returns>
|
||||
public static bool NotPrecededByHoliday(DateTime thursday, IEnumerable<DateTime> holidayList)
|
||||
{
|
||||
if (thursday.DayOfWeek != DayOfWeek.Thursday)
|
||||
{
|
||||
throw new ArgumentException("Input to NotPrecededByHolidays must be a Thursday");
|
||||
}
|
||||
var result = true;
|
||||
// for Monday, Tuesday and Wednesday
|
||||
for (var i = 1; i <= 3; i++)
|
||||
{
|
||||
if (!NotHoliday(thursday.AddDays(-i), holidayList))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
// for Friday
|
||||
if (!NotHoliday(thursday.AddDays(-6), holidayList))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of months between the contract month and the expiry date.
|
||||
/// </summary>
|
||||
/// <param name="underlying">The future symbol ticker</param>
|
||||
/// <param name="futureExpiryDate">Expiry date to use to look up contract month delta. Only used for dairy, since we need to lookup its contract month in a pre-defined table.</param>
|
||||
/// <returns>The number of months between the contract month and the contract expiry</returns>
|
||||
public static int GetDeltaBetweenContractMonthAndContractExpiry(string underlying, DateTime? futureExpiryDate = null)
|
||||
{
|
||||
return ExpiriesPriorMonth.TryGetValue(underlying, out int value) ? value : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to retrieve the futures contract month
|
||||
/// </summary>
|
||||
public static DateTime GetFutureContractMonth(Symbol symbol)
|
||||
{
|
||||
if (symbol.SecurityType == SecurityType.FutureOption)
|
||||
{
|
||||
symbol = symbol.Underlying;
|
||||
}
|
||||
|
||||
var contractExpirationDate = symbol.ID.Date.Date;
|
||||
var monthsToAdd = GetDeltaBetweenContractMonthAndContractExpiry(symbol.ID.Symbol, contractExpirationDate);
|
||||
var contractMonth = contractExpirationDate.AddDays(-(contractExpirationDate.Day - 1))
|
||||
.AddMonths(monthsToAdd);
|
||||
return contractMonth;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to resolve a future expiration from it's contract month
|
||||
/// </summary>
|
||||
public static DateTime GetFutureExpirationFromContractMonth(string symbol, string market, DateTime contractMonth)
|
||||
{
|
||||
return GetFutureExpirationFromContractMonth(Symbol.CreateFuture(symbol, market, SecurityIdentifier.DefaultDate), contractMonth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to resolve a future expiration from it's contract month
|
||||
/// </summary>
|
||||
public static DateTime GetFutureExpirationFromContractMonth(Symbol future, DateTime contractMonth)
|
||||
{
|
||||
var futureExpiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(future.Canonical);
|
||||
var futureExpiry = futureExpiryFunc(contractMonth);
|
||||
return futureExpiry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function returns the third Friday of the month, adjusted for holidays and weekends.
|
||||
/// </summary>
|
||||
public static DateTime ThirdFriday(DateTime time, Symbol contract)
|
||||
{
|
||||
if (contract.ID.SecurityType.IsOption())
|
||||
{
|
||||
return ThirdFriday(time, contract.Underlying);
|
||||
}
|
||||
var thirdFriday = ThirdFriday(time);
|
||||
var holidays = GetExpirationHolidays(contract.ID.Market, contract.ID.Symbol);
|
||||
return AddBusinessDaysIfHoliday(thirdFriday, -1, holidays);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the future contract is expired.
|
||||
/// </summary>
|
||||
public static bool IsFutureContractExpired(Symbol symbol, DateTime currentUtcTime, MarketHoursDatabase marketHoursDatabase = null)
|
||||
{
|
||||
var exchangeHours = (marketHoursDatabase ?? MarketHoursDatabase).GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType);
|
||||
var currentTimeInExchangeTz = currentUtcTime.ConvertFromUtc(exchangeHours.TimeZone);
|
||||
if (currentTimeInExchangeTz >= symbol.ID.Date)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, int> ExpiriesPriorMonth = new Dictionary<string, int>
|
||||
{
|
||||
{ Futures.Energy.ArgusLLSvsWTIArgusTradeMonth, 1 },
|
||||
{ Futures.Energy.ArgusPropaneSaudiAramco, 1 },
|
||||
{ Futures.Energy.BrentCrude, 2 },
|
||||
{ Futures.Energy.BrentLastDayFinancial, 2 },
|
||||
{ Futures.Energy.CrudeOilWTI, 1 },
|
||||
{ Futures.Energy.MicroCrudeOilWTI, 1 },
|
||||
{ Futures.Energy.Gasoline, 1 },
|
||||
{ Futures.Energy.HeatingOil, 1 },
|
||||
{ Futures.Energy.MarsArgusVsWTITradeMonth, 1 },
|
||||
{ Futures.Energy.NaturalGas, 1 },
|
||||
{ Futures.Energy.NaturalGasHenryHubLastDayFinancial, 1 },
|
||||
{ Futures.Energy.NaturalGasHenryHubPenultimateFinancial, 1 },
|
||||
{ Futures.Energy.WTIHoustonArgusVsWTITradeMonth, 1 },
|
||||
{ Futures.Energy.WTIHoustonCrudeOil, 1 },
|
||||
{ Futures.Softs.Sugar11, 1 },
|
||||
{ Futures.Softs.Sugar11CME, 1 }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// Helpers for getting the futures contracts that are trading on a given date.
|
||||
/// This is a substitute for the BacktestingFutureChainProvider, but
|
||||
/// does not outright replace it because of missing entries. This will resolve
|
||||
/// the listed contracts without having any data in place. We follow the listing rules
|
||||
/// set forth by the exchange to get the <see cref="Symbol"/>s that are listed at a given date.
|
||||
/// </summary>
|
||||
public static class FuturesListings
|
||||
{
|
||||
private static readonly Symbol _zb = Symbol.Create("ZB", SecurityType.Future, Market.CBOT);
|
||||
private static readonly Symbol _zc = Symbol.Create("ZC", SecurityType.Future, Market.CBOT);
|
||||
private static readonly Symbol _zs = Symbol.Create("ZS", SecurityType.Future, Market.CBOT);
|
||||
private static readonly Symbol _zm = Symbol.Create("ZM", SecurityType.Future, Market.CBOT);
|
||||
private static readonly Symbol _zt = Symbol.Create("ZT", SecurityType.Future, Market.CBOT);
|
||||
private static readonly Symbol _zl = Symbol.Create("ZL", SecurityType.Future, Market.CBOT);
|
||||
private static readonly Symbol _zw = Symbol.Create("ZW", SecurityType.Future, Market.CBOT);
|
||||
private static readonly Symbol _tn = Symbol.Create("TN", SecurityType.Future, Market.CBOT);
|
||||
private static readonly Symbol _aud = Symbol.Create("6A", SecurityType.Future, Market.CME);
|
||||
private static readonly Symbol _gbp = Symbol.Create("6B", SecurityType.Future, Market.CME);
|
||||
private static readonly Symbol _mxn = Symbol.Create("6M", SecurityType.Future, Market.CME);
|
||||
private static readonly Symbol _jpy = Symbol.Create("6J", SecurityType.Future, Market.CME);
|
||||
private static readonly Symbol _eur = Symbol.Create("6E", SecurityType.Future, Market.CME);
|
||||
private static readonly Symbol _cad = Symbol.Create("6C", SecurityType.Future, Market.CME);
|
||||
|
||||
private static Dictionary<string, Func<DateTime, List<Symbol>>> _futuresListingRules = new Dictionary<string, Func<DateTime, List<Symbol>>>
|
||||
{
|
||||
{ "ZB", t => QuarterlyContracts(_zb, t, 3) },
|
||||
{ "ZC", t => MonthlyContractListings(
|
||||
_zc,
|
||||
t,
|
||||
12,
|
||||
new FuturesListingCycles(new[] { 3, 5, 9 }, 9),
|
||||
new FuturesListingCycles(new[] { 7, 12 }, 8)) },
|
||||
{ "ZN", t => QuarterlyContracts(_zt, t, 3) },
|
||||
{ "TN", t => QuarterlyContracts(_tn, t, 3) },
|
||||
{ "ZS", t => MonthlyContractListings(
|
||||
_zs,
|
||||
t,
|
||||
11,
|
||||
new FuturesListingCycles(new[] { 1, 3, 5, 8, 9 }, 15),
|
||||
new FuturesListingCycles(new[] { 7, 11 }, 8)) },
|
||||
{ "ZM", t => MonthlyContractListings(
|
||||
_zm,
|
||||
t,
|
||||
12,
|
||||
new FuturesListingCycles(new[] { 1, 3, 5, 8, 9 }, 15),
|
||||
new FuturesListingCycles(new[] { 7, 10, 12 }, 12)) },
|
||||
{ "ZL", t => MonthlyContractListings(
|
||||
_zl,
|
||||
t,
|
||||
12,
|
||||
new FuturesListingCycles(new[] { 1, 3, 5, 8, 9 }, 15),
|
||||
new FuturesListingCycles(new[] { 7, 10, 12 }, 12)) },
|
||||
{ "ZT", t => QuarterlyContracts(_zt, t, 3) },
|
||||
{ "ZW", t => MonthlyContractListings(
|
||||
_zw,
|
||||
t,
|
||||
7,
|
||||
new FuturesListingCycles(new[] { 3, 5, 7, 9, 12 }, 15)) },
|
||||
{ "6A", t => QuarterlyContracts(_aud, t, 8) },
|
||||
{ "6B", t => QuarterlyContracts(_gbp, t, 8) },
|
||||
{ "6M", t => QuarterlyContracts(_mxn, t, 8) },
|
||||
{ "6J", t => QuarterlyContracts(_jpy, t, 8) },
|
||||
{ "6E", t => QuarterlyContracts(_eur, t, 8) },
|
||||
{ "6C", t => QuarterlyContracts(_cad, t, 8) },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the listed futures contracts on a given date
|
||||
/// </summary>
|
||||
/// <param name="futureTicker">Ticker of the future contract</param>
|
||||
/// <param name="time">Contracts to look up that are listed at that time</param>
|
||||
/// <returns>The currently trading contracts on the exchange</returns>
|
||||
public static List<Symbol> ListedContracts(string futureTicker, DateTime time)
|
||||
{
|
||||
if (!_futuresListingRules.ContainsKey(futureTicker))
|
||||
{
|
||||
// No entries found. This differs from entries being returned as an empty array, where
|
||||
// that would mean that no listings were found.
|
||||
return null;
|
||||
}
|
||||
|
||||
return _futuresListingRules[futureTicker](time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets contracts following a quarterly listing procedure, with a limit of
|
||||
/// how many contracts are listed at once.
|
||||
/// </summary>
|
||||
/// <param name="canonicalFuture">Canonical Futures Symbol</param>
|
||||
/// <param name="time">Contracts to look up that are listed at that time</param>
|
||||
/// <param name="limit">Number of Symbols we get back/are listed at a given time</param>
|
||||
/// <returns>Symbols that are listed at the given time</returns>
|
||||
private static List<Symbol> QuarterlyContracts(Symbol canonicalFuture, DateTime time, int limit)
|
||||
{
|
||||
var contractMonth = new DateTime(time.Year, time.Month, 1);
|
||||
var futureExpiry = DateTime.MinValue;
|
||||
var expiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFuture);
|
||||
|
||||
// Skip any contracts that have already expired.
|
||||
while (futureExpiry < time)
|
||||
{
|
||||
futureExpiry = expiryFunc(contractMonth);
|
||||
contractMonth = contractMonth.AddMonths(1);
|
||||
}
|
||||
|
||||
// Negate the last incrementation from the while loop to get the actual contract month of the future.
|
||||
var firstFutureContractMonth = contractMonth.AddMonths(-1);
|
||||
|
||||
var quarterlyContracts = new List<Symbol>();
|
||||
// Gets the next closest month from the current month in multiples of 3
|
||||
var quarterlyContractMonth = (int)Math.Ceiling((double)firstFutureContractMonth.Month / 3) * 3;
|
||||
|
||||
for (var i = 0; i < limit; i++)
|
||||
{
|
||||
// We're past the expiration frontier due to the while loop above, which means
|
||||
// that any contracts from here on out will be greater than the current time.
|
||||
var currentContractMonth = firstFutureContractMonth.AddMonths(-firstFutureContractMonth.Month + quarterlyContractMonth);
|
||||
var currentFutureExpiry = expiryFunc(currentContractMonth);
|
||||
|
||||
quarterlyContracts.Add(Symbol.CreateFuture(canonicalFuture.ID.Symbol, canonicalFuture.ID.Market, currentFutureExpiry));
|
||||
quarterlyContractMonth += 3;
|
||||
}
|
||||
|
||||
return quarterlyContracts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets Futures contracts that follow a limited cyclical pattern
|
||||
/// </summary>
|
||||
/// <param name="canonicalFuture">Canonical Futures Symbol</param>
|
||||
/// <param name="time">Contracts to look up that are listed at that time</param>
|
||||
/// <param name="contractMonthForNewListings">Contract month that results in new listings after this contract's expiry</param>
|
||||
/// <param name="futureListingCycles">
|
||||
/// Cycles that define the number of contracts and the months the contracts are listed on, including
|
||||
/// the limit of how many contracts will be listed.
|
||||
/// </param>
|
||||
/// <returns>Symbols that are listed at the given time</returns>
|
||||
private static List<Symbol> MonthlyContractListings(
|
||||
Symbol canonicalFuture,
|
||||
DateTime time,
|
||||
int contractMonthForNewListings,
|
||||
params FuturesListingCycles[] futureListingCycles)
|
||||
{
|
||||
var listings = new List<Symbol>();
|
||||
var expiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFuture);
|
||||
var yearDelta = 0;
|
||||
|
||||
var contractMonthForNewListingCycle = new DateTime(time.Year, contractMonthForNewListings, 1);
|
||||
var contractMonthForNewListingCycleExpiry = expiryFunc(contractMonthForNewListingCycle);
|
||||
|
||||
if (time <= contractMonthForNewListingCycleExpiry)
|
||||
{
|
||||
// Go back a year if we haven't yet crossed this year's contract renewal expiration date.
|
||||
contractMonthForNewListingCycleExpiry = expiryFunc(contractMonthForNewListingCycle.AddYears(-1));
|
||||
yearDelta = -1;
|
||||
}
|
||||
|
||||
foreach (var listingCycle in futureListingCycles)
|
||||
{
|
||||
var year = yearDelta;
|
||||
var count = 0;
|
||||
var initialListings = true;
|
||||
|
||||
while (count != listingCycle.Limit)
|
||||
{
|
||||
var monthStartIndex = 0;
|
||||
if (initialListings)
|
||||
{
|
||||
// For the initial listing, we want to start counting at some month that might not be the first
|
||||
// index of the collection. The index is discovered here and used as the starting point for listed contracts.
|
||||
monthStartIndex = listingCycle.Cycle.Length - listingCycle.Cycle.Count(c => c > contractMonthForNewListingCycleExpiry.Month);
|
||||
initialListings = false;
|
||||
}
|
||||
|
||||
for (var m = monthStartIndex; m < listingCycle.Cycle.Length; m++)
|
||||
{
|
||||
// Add the future's expiration to the listings
|
||||
var currentContractMonth = new DateTime(time.Year + year, listingCycle.Cycle[m], 1);
|
||||
var currentFutureExpiry = expiryFunc(currentContractMonth);
|
||||
if (currentFutureExpiry >= time)
|
||||
{
|
||||
listings.Add(Symbol.CreateFuture(canonicalFuture.ID.Symbol, canonicalFuture.ID.Market, currentFutureExpiry));
|
||||
}
|
||||
|
||||
if (++count == listingCycle.Limit)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
year++;
|
||||
}
|
||||
}
|
||||
|
||||
return listings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Listing Cycles, i.e. the months and number of contracts that are renewed whenever
|
||||
/// the specified renewal expiration contract expires.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example:
|
||||
///
|
||||
/// (from: https://www.cmegroup.com/trading/agricultural/grain-and-oilseed/wheat_contract_specifications.html)
|
||||
/// "15 monthly contracts of Mar, May, Jul, Sep, Dec listed annually following the termination of trading in the July contract of the current year."
|
||||
///
|
||||
/// This would equate to a cycle of [3, 5, 7, 9, 12], a limit of 15, and the contract month == 7.
|
||||
/// </remarks>
|
||||
private class FuturesListingCycles
|
||||
{
|
||||
/// <summary>
|
||||
/// Monthly cycles that the futures listings rule follows
|
||||
/// </summary>
|
||||
public int[] Cycle { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Max number of contracts returned by this rule
|
||||
/// </summary>
|
||||
public int Limit { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a listing cycle rule
|
||||
/// </summary>
|
||||
/// <param name="cycle">New contract listing cycles</param>
|
||||
/// <param name="limit">Max number of contracts to return in this rule</param>
|
||||
public FuturesListingCycles(int[] cycle, int limit)
|
||||
{
|
||||
Cycle = cycle;
|
||||
Limit = limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.Globalization;
|
||||
using QuantConnect.Logging;
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// POCO class for modeling margin requirements at given date
|
||||
/// </summary>
|
||||
public class MarginRequirementsEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Date of margin requirements change
|
||||
/// </summary>
|
||||
public DateTime Date { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Initial overnight margin for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public decimal InitialOvernight { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Maintenance overnight margin for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public decimal MaintenanceOvernight { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Initial intraday margin for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public decimal InitialIntraday { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Maintenance intraday margin for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public decimal MaintenanceIntraday { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="MarginRequirementsEntry"/> from the specified csv line
|
||||
/// </summary>
|
||||
/// <param name="csvLine">The csv line to be parsed</param>
|
||||
/// <returns>A new <see cref="MarginRequirementsEntry"/> for the specified csv line</returns>
|
||||
public static MarginRequirementsEntry Create(string csvLine)
|
||||
{
|
||||
var line = csvLine.Split(',');
|
||||
|
||||
DateTime date;
|
||||
if (!DateTime.TryParseExact(line[0], DateFormat.EightCharacter, CultureInfo.InvariantCulture, DateTimeStyles.None, out date))
|
||||
{
|
||||
Log.Trace($"Couldn't parse date/time while reading future margin requirement file. Line: {csvLine}");
|
||||
}
|
||||
|
||||
decimal initialOvernight;
|
||||
if (!decimal.TryParse(line[1], out initialOvernight))
|
||||
{
|
||||
Log.Trace($"Couldn't parse Initial Overnight margin requirements while reading future margin requirement file. Line: {csvLine}");
|
||||
}
|
||||
|
||||
decimal maintenanceOvernight;
|
||||
if (!decimal.TryParse(line[2], out maintenanceOvernight))
|
||||
{
|
||||
Log.Trace($"Couldn't parse Maintenance Overnight margin requirements while reading future margin requirement file. Line: {csvLine}");
|
||||
}
|
||||
|
||||
// default value, if present in file we try to parse
|
||||
decimal initialIntraday = initialOvernight * 0.4m;
|
||||
if (line.Length >= 4
|
||||
&& !decimal.TryParse(line[3], out initialIntraday))
|
||||
{
|
||||
Log.Trace($"Couldn't parse Initial Intraday margin requirements while reading future margin requirement file. Line: {csvLine}");
|
||||
}
|
||||
|
||||
// default value, if present in file we try to parse
|
||||
decimal maintenanceIntraday = maintenanceOvernight * 0.4m;
|
||||
if (line.Length >= 5
|
||||
&& !decimal.TryParse(line[4], out maintenanceIntraday))
|
||||
{
|
||||
Log.Trace($"Couldn't parse Maintenance Intraday margin requirements while reading future margin requirement file. Line: {csvLine}");
|
||||
}
|
||||
|
||||
return new MarginRequirementsEntry
|
||||
{
|
||||
Date = date,
|
||||
InitialOvernight = initialOvernight,
|
||||
MaintenanceOvernight = maintenanceOvernight,
|
||||
InitialIntraday = initialIntraday,
|
||||
MaintenanceIntraday = maintenanceIntraday
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user