chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Securities.FutureOption.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// CME Option Chain Quotes API call root response
|
||||
/// </summary>
|
||||
public class CMEOptionChainQuotes
|
||||
{
|
||||
/// <summary>
|
||||
/// The future options contracts with/without settlements
|
||||
/// </summary>
|
||||
[JsonProperty("optionContractQuotes")]
|
||||
public List<CMEOptionChainQuoteEntry> Quotes { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Option chain entry quotes, containing strike price
|
||||
/// </summary>
|
||||
public class CMEOptionChainQuoteEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Strike price of the future option quote entry
|
||||
/// </summary>
|
||||
[JsonProperty("strikePrice"), JsonConverter(typeof(StringDecimalJsonConverter), true)]
|
||||
public decimal StrikePrice { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* 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 Newtonsoft.Json;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Securities.FutureOption.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// CME options trades, dates, and expiration list API call root response
|
||||
/// </summary>
|
||||
/// <remarks>Returned as a List of this class</remarks>
|
||||
public class CMEOptionsTradeDatesAndExpiration
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the type of future option this entry is
|
||||
/// </summary>
|
||||
[JsonProperty("label")]
|
||||
public string Label { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the product
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Option type. "AME" for American, "EUR" for European.
|
||||
/// Note that there are other types such as weekly, but we
|
||||
/// only support American options for now.
|
||||
/// </summary>
|
||||
[JsonProperty("optionType")]
|
||||
public string OptionType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Product ID of the option
|
||||
/// </summary>
|
||||
[JsonProperty("productId")]
|
||||
public int ProductId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is Daily option
|
||||
/// </summary>
|
||||
[JsonProperty("daily")]
|
||||
public bool Daily { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// ???
|
||||
/// </summary>
|
||||
[JsonProperty("sto")]
|
||||
public bool Sto { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is weekly option
|
||||
/// </summary>
|
||||
[JsonProperty("weekly")]
|
||||
public bool Weekly { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Expirations of the future option
|
||||
/// </summary>
|
||||
[JsonProperty("expirations")]
|
||||
public List<CMEOptionsExpiration> Expirations { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Future options Expiration entries. These are useful because we can derive the
|
||||
/// future chain from this data, since FOP and FUT share a 1-1 expiry code.
|
||||
/// </summary>
|
||||
public class CMEOptionsExpiration
|
||||
{
|
||||
/// <summary>
|
||||
/// Date of expiry
|
||||
/// </summary>
|
||||
[JsonProperty("label")]
|
||||
public string Label { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Product ID of the expiring asset (usually future option)
|
||||
/// </summary>
|
||||
[JsonProperty("productId")]
|
||||
public int ProductId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contract ID of the asset
|
||||
/// </summary>
|
||||
/// <remarks>Used to search settlements for the option chain</remarks>
|
||||
[JsonProperty("contractId")]
|
||||
public string ContractId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Contract month code formatted as [FUTURE_MONTH_LETTER(1)][YEAR(1)]
|
||||
/// </summary>
|
||||
[JsonProperty("expiration")]
|
||||
public CMEOptionExpirationEntry Expiration { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chicago Mercantile Exchange Option Expiration Entry
|
||||
/// </summary>
|
||||
public class CMEOptionExpirationEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Month of expiry
|
||||
/// </summary>
|
||||
[JsonProperty("month")]
|
||||
public int Month { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Year of expiry
|
||||
/// </summary>
|
||||
[JsonProperty("year")]
|
||||
public int Year { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Expiration code (two letter)
|
||||
/// </summary>
|
||||
[JsonProperty("code")]
|
||||
public string Code { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Expiration code (three letter)
|
||||
/// </summary>
|
||||
[JsonProperty("twoDigitsCode")]
|
||||
public string TwoDigitsCode { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace QuantConnect.Securities.FutureOption.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// Product slate API call root response
|
||||
/// </summary>
|
||||
public class CMEProductSlateV2ListResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Products matching the search criteria
|
||||
/// </summary>
|
||||
[JsonProperty("products")]
|
||||
public List<CMEProductSlateV2ListEntry> Products { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Product entry describing the asset matching the search criteria
|
||||
/// </summary>
|
||||
public class CMEProductSlateV2ListEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// CME ID for the asset
|
||||
/// </summary>
|
||||
[JsonProperty("id")]
|
||||
public int Id { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the product (e.g. E-mini NASDAQ futures)
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Clearing code
|
||||
/// </summary>
|
||||
[JsonProperty("clearing")]
|
||||
public string Clearing { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// GLOBEX ticker
|
||||
/// </summary>
|
||||
[JsonProperty("globex")]
|
||||
public string Globex { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Is traded in the GLOBEX venue
|
||||
/// </summary>
|
||||
[JsonProperty("globexTraded")]
|
||||
public bool GlobexTraded { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Venues this asset trades on
|
||||
/// </summary>
|
||||
[JsonProperty("venues")]
|
||||
public string Venues { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Asset type this product is cleared as (i.e. "Futures", "Options")
|
||||
/// </summary>
|
||||
[JsonProperty("cleared")]
|
||||
public string Cleared { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Exchange the asset trades on (i.e. CME, NYMEX, COMEX, CBOT)
|
||||
/// </summary>
|
||||
[JsonProperty("exch")]
|
||||
public string Exchange { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Asset class group ID - describes group of asset class (e.g. equities, agriculture, etc.)
|
||||
/// </summary>
|
||||
[JsonProperty("groupId")]
|
||||
public int GroupId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// More specific ID describing product
|
||||
/// </summary>
|
||||
[JsonProperty("subGroupId")]
|
||||
public int subGroupId { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Securities.FutureOption
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a means to get the scaling factor for CME's quotes API
|
||||
/// </summary>
|
||||
public class CMEStrikePriceScalingFactors
|
||||
{
|
||||
/// <summary>
|
||||
/// CME's option chain quotes strike price scaling factor
|
||||
/// </summary>
|
||||
private static readonly IReadOnlyDictionary<string, decimal> _scalingFactors = new Dictionary<string, decimal>
|
||||
{
|
||||
{ "SI", 0.1m },
|
||||
{ "NG", 5m }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the option chain strike price scaling factor for the quote response from CME
|
||||
/// </summary>
|
||||
/// <param name="underlyingFuture">Underlying future Symbol to normalize</param>
|
||||
/// <returns>Scaling factor for the strike price</returns>
|
||||
public static decimal GetScaleFactor(Symbol underlyingFuture)
|
||||
{
|
||||
return _scalingFactors.ContainsKey(underlyingFuture.ID.Symbol)
|
||||
? _scalingFactors[underlyingFuture.ID.Symbol]
|
||||
: 1m;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.Orders.Fees;
|
||||
using QuantConnect.Orders.Fills;
|
||||
using QuantConnect.Orders.Slippage;
|
||||
using QuantConnect.Securities.Option;
|
||||
|
||||
namespace QuantConnect.Securities.FutureOption
|
||||
{
|
||||
/// <summary>
|
||||
/// Futures Options security
|
||||
/// </summary>
|
||||
public class FutureOption : Option.Option
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor for the future option security
|
||||
/// </summary>
|
||||
/// <param name="symbol">Symbol of the future option</param>
|
||||
/// <param name="exchangeHours">Exchange hours of the future option</param>
|
||||
/// <param name="quoteCurrency">Quoted currency of the future option</param>
|
||||
/// <param name="symbolProperties">Symbol properties of the future option</param>
|
||||
/// <param name="currencyConverter">Currency converter</param>
|
||||
/// <param name="registeredTypes">Provides all data types registered to the algorithm</param>
|
||||
/// <param name="securityCache">Cache of security objects</param>
|
||||
/// <param name="underlying">Future underlying security</param>
|
||||
public FutureOption(Symbol symbol,
|
||||
SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
OptionSymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes,
|
||||
SecurityCache securityCache,
|
||||
Security underlying)
|
||||
: base(symbol,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new OptionExchange(exchangeHours),
|
||||
securityCache,
|
||||
new OptionPortfolioModel(),
|
||||
new FutureOptionFillModel(),
|
||||
new InteractiveBrokersFeeModel(),
|
||||
NullSlippageModel.Instance,
|
||||
new ImmediateSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
null,
|
||||
new OptionDataFilter(),
|
||||
new SecurityPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
underlying,
|
||||
null
|
||||
)
|
||||
{
|
||||
BuyingPowerModel = new FuturesOptionsMarginModel(0, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the securities symbol
|
||||
/// </summary>
|
||||
public static implicit operator Symbol(FutureOption security) => security.Symbol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.FutureOption
|
||||
{
|
||||
/// <summary>
|
||||
/// Future option specific caching support
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityCache"/>
|
||||
public class FutureOptionCache : Option.OptionCache
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Securities.FutureOption
|
||||
{
|
||||
/// <summary>
|
||||
/// Static helper methods to resolve Futures Options Symbol-related tasks.
|
||||
/// </summary>
|
||||
public static class FutureOptionSymbol
|
||||
{
|
||||
/// <summary>
|
||||
/// Detects if the future option contract is standard, i.e. not weekly, not short-term, not mid-sized, etc.
|
||||
/// </summary>
|
||||
/// <param name="_">Symbol</param>
|
||||
/// <returns>true</returns>
|
||||
/// <remarks>
|
||||
/// We have no way of identifying the type of FOP contract based on the properties contained within the Symbol.
|
||||
/// </remarks>
|
||||
public static bool IsStandard(Symbol _) => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last day of trading, aliased to be the Futures options' expiry
|
||||
/// </summary>
|
||||
/// <param name="symbol">Futures Options Symbol</param>
|
||||
/// <returns>Last day of trading date</returns>
|
||||
public static DateTime GetLastDayOfTrading(Symbol symbol) => symbol.ID.Date.Date;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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.Securities.Future;
|
||||
|
||||
namespace QuantConnect.Securities.FutureOption
|
||||
{
|
||||
/// <summary>
|
||||
/// Futures options expiry lookup utility class
|
||||
/// </summary>
|
||||
public static class FuturesOptionsExpiryFunctions
|
||||
{
|
||||
private static readonly Symbol _lo = Symbol.CreateCanonicalOption(Symbol.Create("CL", SecurityType.Future, Market.NYMEX));
|
||||
private static readonly Symbol _on = Symbol.CreateCanonicalOption(Symbol.Create("NG", SecurityType.Future, Market.NYMEX));
|
||||
private static readonly Symbol _ozm = Symbol.CreateCanonicalOption(Symbol.Create("ZM", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _ozb = Symbol.CreateCanonicalOption(Symbol.Create("ZB", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _ozc = Symbol.CreateCanonicalOption(Symbol.Create("ZC", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _ozn = Symbol.CreateCanonicalOption(Symbol.Create("ZN", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _otn = Symbol.CreateCanonicalOption(Symbol.Create("TN", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _oub = Symbol.CreateCanonicalOption(Symbol.Create("UB", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _ozo = Symbol.CreateCanonicalOption(Symbol.Create("ZO", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _oke = Symbol.CreateCanonicalOption(Symbol.Create("KE", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _ozf = Symbol.CreateCanonicalOption(Symbol.Create("ZF", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _ozs = Symbol.CreateCanonicalOption(Symbol.Create("ZS", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _ozt = Symbol.CreateCanonicalOption(Symbol.Create("ZT", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _ozl = Symbol.CreateCanonicalOption(Symbol.Create("ZL", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _ozw = Symbol.CreateCanonicalOption(Symbol.Create("ZW", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _oym = Symbol.CreateCanonicalOption(Symbol.Create("YM", SecurityType.Future, Market.CBOT));
|
||||
private static readonly Symbol _hxe = Symbol.CreateCanonicalOption(Symbol.Create("HG", SecurityType.Future, Market.COMEX));
|
||||
private static readonly Symbol _og = Symbol.CreateCanonicalOption(Symbol.Create("GC", SecurityType.Future, Market.COMEX));
|
||||
private static readonly Symbol _so = Symbol.CreateCanonicalOption(Symbol.Create("SI", SecurityType.Future, Market.COMEX));
|
||||
private static readonly Symbol _aud = Symbol.CreateCanonicalOption(Symbol.Create("6A", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _gbu = Symbol.CreateCanonicalOption(Symbol.Create("6B", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _cau = Symbol.CreateCanonicalOption(Symbol.Create("6C", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _euu = Symbol.CreateCanonicalOption(Symbol.Create("6E", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _jpu = Symbol.CreateCanonicalOption(Symbol.Create("6J", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _chu = Symbol.CreateCanonicalOption(Symbol.Create("6S", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _nzd = Symbol.CreateCanonicalOption(Symbol.Create("6N", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _mxn = Symbol.CreateCanonicalOption(Symbol.Create("6M", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _ead = Symbol.CreateCanonicalOption(Symbol.Create("EAD", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _ajy = Symbol.CreateCanonicalOption(Symbol.Create("AJY", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _ane = Symbol.CreateCanonicalOption(Symbol.Create("ANE", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _ecd = Symbol.CreateCanonicalOption(Symbol.Create("ECD", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _le = Symbol.CreateCanonicalOption(Symbol.Create("LE", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _he = Symbol.CreateCanonicalOption(Symbol.Create("HE", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _lbr = Symbol.CreateCanonicalOption(Symbol.Create("LBR", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _lbs = Symbol.CreateCanonicalOption(Symbol.Create("LBS", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _es = Symbol.CreateCanonicalOption(Symbol.Create("ES", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _emd = Symbol.CreateCanonicalOption(Symbol.Create("EMD", SecurityType.Future, Market.CME));
|
||||
private static readonly Symbol _nq = Symbol.CreateCanonicalOption(Symbol.Create("NQ", SecurityType.Future, Market.CME));
|
||||
|
||||
/// <summary>
|
||||
/// Futures options expiry functions lookup table, keyed by canonical future option Symbol
|
||||
/// </summary>
|
||||
private static readonly IReadOnlyDictionary<Symbol, Func<DateTime, DateTime>> _futuresOptionExpiryFunctions = new Dictionary<Symbol, Func<DateTime,DateTime>>
|
||||
{
|
||||
// Trading terminates 7 business days before the 26th calendar of the month prior to the contract month. https://www.cmegroup.com/trading/energy/crude-oil/light-sweet-crude_contractSpecs_options.html#optionProductId=190
|
||||
{_lo, expiryMonth => {
|
||||
var twentySixthDayOfPreviousMonthFromContractMonth = expiryMonth.AddMonths(-1).AddDays(-(expiryMonth.Day - 1)).AddDays(25);
|
||||
var holidays = FuturesExpiryUtilityFunctions.GetExpirationHolidays(_lo.ID.Market, _lo.Underlying.ID.Symbol);
|
||||
|
||||
return FuturesExpiryUtilityFunctions.AddBusinessDays(twentySixthDayOfPreviousMonthFromContractMonth, -7, holidays);
|
||||
}},
|
||||
// Trading terminates on the 4th last business day of the month prior to the contract month (1 business day prior to the expiration of the underlying futures corresponding contract month).
|
||||
// https://www.cmegroup.com/trading/energy/natural-gas/natural-gas_contractSpecs_options.html
|
||||
// Although not stated, this follows the same rules as seen in the COMEX markets, but without Fridays. Case: Dec 2020 expiry, Last Trade Date: 24 Nov 2020
|
||||
{ _on, expiryMonth => FourthLastBusinessDayInPrecedingMonthFromContractMonth(_on.Underlying, expiryMonth, 0, 0, noFridays: false) },
|
||||
{ _ozb, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_ozb.Underlying, expiryMonth) },
|
||||
{ _ozc, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_ozc.Underlying, expiryMonth) },
|
||||
{ _ozn, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_ozn.Underlying, expiryMonth) },
|
||||
{ _otn, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_otn.Underlying, expiryMonth) },
|
||||
{ _oub, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_oub.Underlying, expiryMonth) },
|
||||
{ _ozo, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_ozo.Underlying, expiryMonth) },
|
||||
{ _oke, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_oke.Underlying, expiryMonth) },
|
||||
{ _ozf, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_ozf.Underlying, expiryMonth) },
|
||||
{ _ozs, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_ozs.Underlying, expiryMonth) },
|
||||
{ _ozt, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_ozt.Underlying, expiryMonth) },
|
||||
{ _ozw, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_ozw.Underlying, expiryMonth) },
|
||||
{ _ozl, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_ozl.Underlying, expiryMonth) },
|
||||
{ _ozm, expiryMonth => FridayBeforeTwoBusinessDaysBeforeEndOfMonth(_ozm.Underlying, expiryMonth) },
|
||||
{ _hxe, expiryMonth => FourthLastBusinessDayInPrecedingMonthFromContractMonth(_hxe.Underlying, expiryMonth, 12, 0) },
|
||||
{ _og, expiryMonth => FourthLastBusinessDayInPrecedingMonthFromContractMonth(_og.Underlying, expiryMonth, 12, 30) },
|
||||
{ _so, expiryMonth => FourthLastBusinessDayInPrecedingMonthFromContractMonth(_so.Underlying, expiryMonth, 12, 25) },
|
||||
{ _aud, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_aud.Underlying, expiryMonth) },
|
||||
{ _gbu, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_gbu.Underlying, expiryMonth) },
|
||||
{ _cau, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_cau.Underlying, expiryMonth) },
|
||||
{ _euu, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_euu.Underlying, expiryMonth) },
|
||||
{ _jpu, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_jpu.Underlying, expiryMonth) },
|
||||
{ _chu, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_chu.Underlying, expiryMonth) },
|
||||
{ _nzd, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_nzd.Underlying, expiryMonth) },
|
||||
{ _mxn, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_mxn.Underlying, expiryMonth) },
|
||||
{ _ead, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_ead.Underlying, expiryMonth) },
|
||||
{ _ajy, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_ajy.Underlying, expiryMonth) },
|
||||
{ _ane, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_ane.Underlying, expiryMonth) },
|
||||
{ _ecd, expiryMonth => SecondFridayBeforeThirdWednesdayOfContractMonth(_ecd.Underlying, expiryMonth) },
|
||||
{ _le, expiryMonth => FirstFridayOfContractMonth(_le.Underlying, expiryMonth) },
|
||||
{ _he, expiryMonth => TenthBusinessDayOfContractMonth(_he.Underlying, expiryMonth) },
|
||||
{ _lbr, expiryMonth => LastBusinessDayInPrecedingMonthFromContractMonth(_lbr.Underlying, expiryMonth) },
|
||||
{ _lbs, expiryMonth => LastBusinessDayInPrecedingMonthFromContractMonth(_lbs.Underlying, expiryMonth) },
|
||||
// even though these FOPs are currently quarterly (as underlying), they had until some serial months. Expiration is the same rule for all
|
||||
{ _es, expiryMonth => FuturesExpiryUtilityFunctions.ThirdFriday(expiryMonth, _es) },
|
||||
{ _emd, expiryMonth => FuturesExpiryUtilityFunctions.ThirdFriday(expiryMonth, _emd) },
|
||||
{ _oym, expiryMonth => FuturesExpiryUtilityFunctions.ThirdFriday(expiryMonth, _oym) },
|
||||
{ _nq, expiryMonth => FuturesExpiryUtilityFunctions.ThirdFriday(expiryMonth, _nq) },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Futures Options' expiry for the given contract month.
|
||||
/// </summary>
|
||||
/// <param name="canonicalFutureOptionSymbol">Canonical Futures Options Symbol. Will be made canonical if not provided a canonical</param>
|
||||
/// <param name="futureContractMonth">Contract month of the underlying Future</param>
|
||||
/// <returns>Expiry date/time</returns>
|
||||
public static DateTime FuturesOptionExpiry(Symbol canonicalFutureOptionSymbol, DateTime futureContractMonth)
|
||||
{
|
||||
if (!canonicalFutureOptionSymbol.IsCanonical() || !canonicalFutureOptionSymbol.Underlying.IsCanonical())
|
||||
{
|
||||
canonicalFutureOptionSymbol = Symbol.CreateCanonicalOption(
|
||||
Symbol.Create(canonicalFutureOptionSymbol.Underlying.ID.Symbol,
|
||||
SecurityType.Future,
|
||||
canonicalFutureOptionSymbol.Underlying.ID.Market));
|
||||
}
|
||||
|
||||
if (!_futuresOptionExpiryFunctions.TryGetValue(canonicalFutureOptionSymbol, out var expiryFunction))
|
||||
{
|
||||
// No definition exists for this FOP. Let's default to futures expiry.
|
||||
return FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFutureOptionSymbol.Underlying)(futureContractMonth);
|
||||
}
|
||||
|
||||
return expiryFunction(futureContractMonth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Future Option's expiry from the Future Symbol provided
|
||||
/// </summary>
|
||||
/// <param name="futureSymbol">Future (non-canonical) Symbol</param>
|
||||
/// <param name="canonicalFutureOption">The canonical Future Option Symbol</param>
|
||||
/// <returns>Future Option Expiry for the Future with the same contract month</returns>
|
||||
public static DateTime GetFutureOptionExpiryFromFutureExpiry(Symbol futureSymbol, Symbol canonicalFutureOption = null)
|
||||
{
|
||||
var futureContractMonth = FuturesExpiryUtilityFunctions.GetFutureContractMonth(futureSymbol);
|
||||
|
||||
if (canonicalFutureOption == null)
|
||||
{
|
||||
canonicalFutureOption = Symbol.CreateCanonicalOption(
|
||||
Symbol.Create(futureSymbol.ID.Symbol, SecurityType.Future, futureSymbol.ID.Market));
|
||||
}
|
||||
|
||||
return FuturesOptionExpiry(canonicalFutureOption, futureContractMonth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expiry function for CBOT Futures Options entries.
|
||||
/// Returns the Friday before the 2nd last business day of the month preceding the future contract expiry month.
|
||||
/// </summary>
|
||||
/// <param name="underlyingFuture">Underlying future symbol</param>
|
||||
/// <param name="expiryMonth">Expiry month date</param>
|
||||
/// <returns>Expiry DateTime of the Future Option</returns>
|
||||
private static DateTime FridayBeforeTwoBusinessDaysBeforeEndOfMonth(Symbol underlyingFuture, DateTime expiryMonth)
|
||||
{
|
||||
var holidays = FuturesExpiryUtilityFunctions.GetExpirationHolidays(underlyingFuture.ID.Market, underlyingFuture.ID.Symbol);
|
||||
|
||||
var expiryMonthPreceding = expiryMonth.AddMonths(-1).AddDays(-(expiryMonth.Day - 1));
|
||||
var fridayBeforeSecondLastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(
|
||||
expiryMonthPreceding,
|
||||
2,
|
||||
holidays).AddDays(-1);
|
||||
|
||||
while (fridayBeforeSecondLastBusinessDay.DayOfWeek != DayOfWeek.Friday)
|
||||
{
|
||||
fridayBeforeSecondLastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(fridayBeforeSecondLastBusinessDay, -1, holidays);
|
||||
}
|
||||
|
||||
return fridayBeforeSecondLastBusinessDay;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For Trading that terminates on the 4th last business day of the month prior to the contract month.
|
||||
/// If the 4th last business day occurs on a Friday or the day before a holiday, trading terminates on the
|
||||
/// prior business day. This applies to some NYMEX (with fridays), all COMEX.
|
||||
/// </summary>
|
||||
/// <param name="underlyingFuture">Underlying Future Symbol</param>
|
||||
/// <param name="expiryMonth">Contract expiry month</param>
|
||||
/// <param name="hour">Hour the contract expires at</param>
|
||||
/// <param name="minutes">Minute the contract expires at</param>
|
||||
/// <param name="noFridays">Exclude Friday expiration dates from consideration</param>
|
||||
/// <returns>Expiry DateTime of the Future Option</returns>
|
||||
private static DateTime FourthLastBusinessDayInPrecedingMonthFromContractMonth(Symbol underlyingFuture, DateTime expiryMonth, int hour, int minutes, bool noFridays = true)
|
||||
{
|
||||
var holidays = FuturesExpiryUtilityFunctions.GetExpirationHolidays(underlyingFuture.ID.Market, underlyingFuture.ID.Symbol);
|
||||
|
||||
var expiryMonthPreceding = expiryMonth.AddMonths(-1);
|
||||
var fourthLastBusinessDay = FuturesExpiryUtilityFunctions.NthLastBusinessDay(expiryMonthPreceding, 4, holidays);
|
||||
|
||||
if (noFridays)
|
||||
{
|
||||
while (fourthLastBusinessDay.DayOfWeek == DayOfWeek.Friday || holidays.Contains(fourthLastBusinessDay.AddDays(1)))
|
||||
{
|
||||
fourthLastBusinessDay = FuturesExpiryUtilityFunctions.AddBusinessDays(fourthLastBusinessDay, -1, holidays);
|
||||
}
|
||||
}
|
||||
|
||||
return fourthLastBusinessDay.AddHours(hour).AddMinutes(minutes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expiry function for AUD Future Options expiry.
|
||||
/// Returns the second Friday before the 3rd Wednesday of contract expiry month, 9am.
|
||||
/// </summary>
|
||||
/// <param name="underlyingFuture">Underlying future symbol</param>
|
||||
/// <param name="expiryMonth">Expiry month date</param>
|
||||
/// <returns>Expiry DateTime of the Future Option</returns>
|
||||
private static DateTime SecondFridayBeforeThirdWednesdayOfContractMonth(Symbol underlyingFuture, DateTime expiryMonth)
|
||||
{
|
||||
var holidays = FuturesExpiryUtilityFunctions.GetExpirationHolidays(underlyingFuture.ID.Market, underlyingFuture.ID.Symbol);
|
||||
var thirdWednesday = FuturesExpiryUtilityFunctions.ThirdWednesday(expiryMonth);
|
||||
var secondFridayBeforeThirdWednesday = thirdWednesday.AddDays(-12);
|
||||
|
||||
if (holidays.Contains(secondFridayBeforeThirdWednesday))
|
||||
{
|
||||
secondFridayBeforeThirdWednesday = FuturesExpiryUtilityFunctions.AddBusinessDays(secondFridayBeforeThirdWednesday, -1, holidays);
|
||||
}
|
||||
|
||||
return secondFridayBeforeThirdWednesday.AddHours(9);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// First friday of the contract month
|
||||
/// </summary>
|
||||
public static DateTime FirstFridayOfContractMonth(Symbol underlyingFuture, DateTime expiryMonth)
|
||||
{
|
||||
var holidays = FuturesExpiryUtilityFunctions.GetExpirationHolidays(underlyingFuture.ID.Market, underlyingFuture.ID.Symbol);
|
||||
var firstFriday = FuturesExpiryUtilityFunctions.NthFriday(expiryMonth, 1);
|
||||
if (holidays.Contains(firstFriday))
|
||||
{
|
||||
firstFriday = FuturesExpiryUtilityFunctions.AddBusinessDays(firstFriday, -1, holidays);
|
||||
}
|
||||
return firstFriday.AddHours(13);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tenth business day of the month
|
||||
/// </summary>
|
||||
public static DateTime TenthBusinessDayOfContractMonth(Symbol underlyingFuture, DateTime expiryMonth)
|
||||
{
|
||||
var holidays = FuturesExpiryUtilityFunctions.GetExpirationHolidays(underlyingFuture.ID.Market, underlyingFuture.ID.Symbol);
|
||||
return FuturesExpiryUtilityFunctions.NthBusinessDay(expiryMonth, 10, holidays);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Last business day of the month preceding the contract month
|
||||
/// </summary>
|
||||
private static DateTime LastBusinessDayInPrecedingMonthFromContractMonth(Symbol underlying, DateTime expiryMonth)
|
||||
{
|
||||
var holidays = FuturesExpiryUtilityFunctions.GetExpirationHolidays(underlying.ID.Market, underlying.ID.Symbol);
|
||||
return FuturesExpiryUtilityFunctions.NthLastBusinessDay(expiryMonth.AddMonths(-1), 1, holidays);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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.Securities.Future;
|
||||
|
||||
namespace QuantConnect.Securities.Option
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a margin model for future options (an option with a future as its underlying).
|
||||
/// We re-use the <see cref="FutureMarginModel"/> implementation and multiply its results
|
||||
/// by 1.5x to simulate the increased margins seen for future options.
|
||||
/// </summary>
|
||||
public class FuturesOptionsMarginModel : FutureMarginModel
|
||||
{
|
||||
private readonly Option _futureOption;
|
||||
|
||||
/// <summary>
|
||||
/// Initial Overnight margin requirement for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public override decimal InitialOvernightMarginRequirement => GetMarginRequirement(_futureOption, base.InitialOvernightMarginRequirement);
|
||||
|
||||
/// <summary>
|
||||
/// Maintenance Overnight margin requirement for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public override decimal MaintenanceOvernightMarginRequirement => GetMarginRequirement(_futureOption, base.MaintenanceOvernightMarginRequirement);
|
||||
|
||||
/// <summary>
|
||||
/// Initial Intraday margin for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public override decimal InitialIntradayMarginRequirement => GetMarginRequirement(_futureOption, base.InitialIntradayMarginRequirement);
|
||||
|
||||
/// <summary>
|
||||
/// Maintenance Intraday margin requirement for the contract effective from the date of change
|
||||
/// </summary>
|
||||
public override decimal MaintenanceIntradayMarginRequirement => GetMarginRequirement(_futureOption, base.MaintenanceIntradayMarginRequirement);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of FutureOptionMarginModel
|
||||
/// </summary>
|
||||
/// <param name="requiredFreeBuyingPowerPercent">The percentage used to determine the required unused buying power for the account.</param>
|
||||
/// <param name="futureOption">Option Security containing a Future security as the underlying</param>
|
||||
public FuturesOptionsMarginModel(decimal requiredFreeBuyingPowerPercent = 0, Option futureOption = null) : base(requiredFreeBuyingPowerPercent, futureOption?.Underlying)
|
||||
{
|
||||
_futureOption = futureOption;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin currently alloted to the specified holding.
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the security</param>
|
||||
/// <returns>The maintenance margin required for the option</returns>
|
||||
/// <remarks>
|
||||
/// We fix the option to 1.5x the maintenance because of its close coupling with the underlying.
|
||||
/// The option's contract multiplier is 1x, but might be more sensitive to volatility shocks in the long
|
||||
/// run when it comes to calculating the different market scenarios attempting to simulate VaR, resulting
|
||||
/// in a margin greater than the underlying's margin.
|
||||
/// </remarks>
|
||||
public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters)
|
||||
{
|
||||
var underlyingRequirement = base.GetMaintenanceMargin(parameters.ForUnderlying(parameters.Quantity));
|
||||
var positionSide = parameters.Quantity > 0 ? PositionSide.Long : PositionSide.Short;
|
||||
return GetMarginRequirement(_futureOption, underlyingRequirement, positionSide);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The margin that must be held in order to increase the position by the provided quantity
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the security and quantity of shares</param>
|
||||
/// <returns>The initial margin required for the option (i.e. the equity required to enter a position for this option)</returns>
|
||||
/// <remarks>
|
||||
/// We fix the option to 1.5x the initial because of its close coupling with the underlying.
|
||||
/// The option's contract multiplier is 1x, but might be more sensitive to volatility shocks in the long
|
||||
/// run when it comes to calculating the different market scenarios attempting to simulate VaR, resulting
|
||||
/// in a margin greater than the underlying's margin.
|
||||
/// </remarks>
|
||||
public override InitialMargin GetInitialMarginRequirement(InitialMarginParameters parameters)
|
||||
{
|
||||
var underlyingRequirement = base.GetInitialMarginRequirement(parameters.ForUnderlying()).Value;
|
||||
var positionSide = parameters.Quantity > 0 ? PositionSide.Long : PositionSide.Short;
|
||||
|
||||
return new InitialMargin(GetMarginRequirement(_futureOption, underlyingRequirement, positionSide));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get's the margin requirement for a future option based on the underlying future margin requirement and the position side to trade.
|
||||
/// FOPs margin requirement is an 'S' curve based on the underlying requirement around it's current price, see https://en.wikipedia.org/wiki/Logistic_function
|
||||
/// </summary>
|
||||
/// <param name="option">The future option contract to trade</param>
|
||||
/// <param name="underlyingRequirement">The underlying future associated margin requirement</param>
|
||||
/// <param name="positionSide">The position side to trade, long by default. This is because short positions require higher margin requirements</param>
|
||||
public static int GetMarginRequirement(Option option, decimal underlyingRequirement, PositionSide positionSide = PositionSide.Long)
|
||||
{
|
||||
var maximumValue = underlyingRequirement;
|
||||
var curveGrowthRate = -7.8m;
|
||||
var underlyingPrice = option.Underlying.Price;
|
||||
|
||||
// If the underlying price is 0, we can't calculate a margin requirement, so return the underlying requirement.
|
||||
// This could be removed after GH issue #6523 is resolved.
|
||||
if (option.Underlying == null || option.Underlying.Price == 0m)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (positionSide == PositionSide.Short)
|
||||
{
|
||||
if (option.Right == OptionRight.Call)
|
||||
{
|
||||
// going short the curve growth rate is slower
|
||||
curveGrowthRate = -4m;
|
||||
// curve shifted to the right -> causes a margin requirement increase
|
||||
underlyingPrice *= 1.5m;
|
||||
}
|
||||
else
|
||||
{
|
||||
// higher max requirements
|
||||
maximumValue *= 1.25m;
|
||||
// puts are inverter from calls
|
||||
curveGrowthRate = 2.4m;
|
||||
// curve shifted to the left -> causes a margin requirement increase
|
||||
underlyingPrice *= 0.30m;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (option.Right == OptionRight.Put)
|
||||
{
|
||||
// fastest change rate
|
||||
curveGrowthRate = 9m;
|
||||
}
|
||||
else
|
||||
{
|
||||
maximumValue *= 1.20m;
|
||||
}
|
||||
}
|
||||
|
||||
// we normalize the curve growth rate by dividing by the underlyings price
|
||||
// this way, contracts with different order of magnitude price and strike (like CL & ES) share this logic
|
||||
var denominator = Math.Pow(Math.E, (double) (-curveGrowthRate * (option.ScaledStrikePrice - underlyingPrice) / underlyingPrice));
|
||||
|
||||
if (double.IsInfinity(denominator))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (denominator.IsNaNOrZero())
|
||||
{
|
||||
return (int) maximumValue;
|
||||
}
|
||||
|
||||
return (int) (maximumValue / (1 + denominator).SafeDecimalCast());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace QuantConnect.Securities.Future
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides conversions from a GLOBEX Futures ticker to a GLOBEX Futures Options ticker
|
||||
/// </summary>
|
||||
public static class FuturesOptionsSymbolMappings
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines Futures GLOBEX Ticker -> Futures Options GLOBEX Ticker
|
||||
/// </summary>
|
||||
private static Dictionary<string, string> _futureToFutureOptionsGLOBEX = new Dictionary<string, string>
|
||||
{
|
||||
{ "EH", "OEH" },
|
||||
{ "KE", "OKE" },
|
||||
{ "TN", "OTN" },
|
||||
{ "UB", "OUB" },
|
||||
{ "YM", "OYM" },
|
||||
{ "ZB", "OZB" },
|
||||
{ "ZC", "OZC" },
|
||||
{ "ZF", "OZF" },
|
||||
{ "ZL", "OZL" },
|
||||
{ "ZM", "OZM" },
|
||||
{ "ZN", "OZN" },
|
||||
{ "ZO", "OZO" },
|
||||
{ "ZS", "OZS" },
|
||||
{ "ZT", "OZT" },
|
||||
{ "ZW", "OZW" },
|
||||
{ "RTY", "RTO" },
|
||||
{ "GC", "OG" },
|
||||
{ "HG", "HXE" },
|
||||
{ "SI", "SO" },
|
||||
{ "CL", "LO" },
|
||||
{ "HCL", "HCO" },
|
||||
{ "HO", "OH" },
|
||||
{ "NG", "ON" },
|
||||
{ "PA", "PAO" },
|
||||
{ "PL", "PO" },
|
||||
{ "RB", "OB" },
|
||||
{ "YG", "OYG" },
|
||||
{ "ZG", "OZG" },
|
||||
{ "ZI", "OZI" },
|
||||
{ "6A", "ADU" },
|
||||
{ "6B", "GBU" },
|
||||
{ "6C", "CAU" },
|
||||
{ "6E", "EUU" },
|
||||
{ "6J", "JPU" },
|
||||
{ "6S", "CHU" }
|
||||
};
|
||||
|
||||
private static Dictionary<string, string> _futureOptionsToFutureGLOBEX = _futureToFutureOptionsGLOBEX
|
||||
.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the futures options ticker for the given futures ticker.
|
||||
/// </summary>
|
||||
/// <param name="futureTicker">Future GLOBEX ticker to get Future Option GLOBEX ticker for</param>
|
||||
/// <returns>Future option ticker. Defaults to future ticker provided if no entry is found</returns>
|
||||
public static string Map(string futureTicker)
|
||||
{
|
||||
futureTicker = futureTicker.ToUpperInvariant();
|
||||
|
||||
string result;
|
||||
if (!_futureToFutureOptionsGLOBEX.TryGetValue(futureTicker, out result))
|
||||
{
|
||||
return futureTicker;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a futures options ticker to its underlying future's ticker
|
||||
/// </summary>
|
||||
/// <param name="futureOptionTicker">Future option ticker to map to the underlying</param>
|
||||
/// <returns>Future ticker</returns>
|
||||
public static string MapFromOption(string futureOptionTicker)
|
||||
{
|
||||
futureOptionTicker = futureOptionTicker.ToUpperInvariant();
|
||||
|
||||
string result;
|
||||
if (!_futureOptionsToFutureGLOBEX.TryGetValue(futureOptionTicker, out result))
|
||||
{
|
||||
return futureOptionTicker;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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.Securities.Future;
|
||||
|
||||
namespace QuantConnect.Securities.FutureOption
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates the underlying Symbol that corresponds to a futures options contract
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Because there can exist futures options (FOP) contracts that have an underlying Future
|
||||
/// that does not have the same contract month as FOPs contract month, we need a way to resolve
|
||||
/// the underlying Symbol of the FOP to the specific future contract it belongs to.
|
||||
///
|
||||
/// Luckily, these FOPs all follow a pattern as to how the underlying is determined. The
|
||||
/// method <see cref="GetUnderlyingFutureFromFutureOption"/> will automatically resolve the FOP contract's
|
||||
/// underlying Future, and will ensure that the rules of the underlying are being followed.
|
||||
///
|
||||
/// An example of a contract that this happens to is Gold Futures (FUT=GC, FOP=OG). OG FOPs
|
||||
/// underlying Symbols are not determined by the contract month of the FOP itself, but rather
|
||||
/// by the closest contract to it in an even month.
|
||||
///
|
||||
/// Examples:
|
||||
/// OGH21 would have an underlying of GCJ21
|
||||
/// OGJ21 would have an underlying of GCJ21
|
||||
/// OGK21 would have an underlying of GCM21
|
||||
/// OGM21 would have an underlying of GCM21...
|
||||
/// </remarks>
|
||||
public static class FuturesOptionsUnderlyingMapper
|
||||
{
|
||||
private static readonly Dictionary<string, Func<DateTime, DateTime?, DateTime?>> _underlyingFuturesOptionsRules = new Dictionary<string, Func<DateTime, DateTime?, DateTime?>>
|
||||
{
|
||||
// CBOT
|
||||
{ "ZB", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("ZB", SecurityType.Future, Market.CBOT), d, ld.Value) },
|
||||
{ "ZC", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("ZC", SecurityType.Future, Market.CBOT), d, ld.Value) },
|
||||
{ "ZN", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("ZN", SecurityType.Future, Market.CBOT), d, ld.Value) },
|
||||
{ "ZS", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("ZS", SecurityType.Future, Market.CBOT), d, ld.Value) },
|
||||
{ "ZM", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("ZM", SecurityType.Future, Market.CBOT), d, ld.Value) },
|
||||
{ "ZT", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("ZT", SecurityType.Future, Market.CBOT), d, ld.Value) },
|
||||
{ "ZW", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("ZW", SecurityType.Future, Market.CBOT), d, ld.Value) },
|
||||
{ "ZL", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("ZL", SecurityType.Future, Market.CBOT), d, ld.Value) },
|
||||
{ "TN", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("TN", SecurityType.Future, Market.CBOT), d, ld.Value) },
|
||||
|
||||
// COMEX
|
||||
{ "HG", (d, _) => ContractMonthYearStartThreeMonthsThenEvenOddMonthsSkipRule(d, true) },
|
||||
{ "SI", (d, _) => ContractMonthYearStartThreeMonthsThenEvenOddMonthsSkipRule(d, true) },
|
||||
{ "GC", (d, _) => ContractMonthEvenOddMonth(d, false) },
|
||||
|
||||
// CME
|
||||
{ "6A", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6A", SecurityType.Future, Market.CME), d, ld.Value) },
|
||||
{ "6B", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6B", SecurityType.Future, Market.CME), d, ld.Value) },
|
||||
{ "6M", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6M", SecurityType.Future, Market.CME), d, ld.Value) },
|
||||
{ "6J", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6J", SecurityType.Future, Market.CME), d, ld.Value) },
|
||||
{ "6E", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6E", SecurityType.Future, Market.CME), d, ld.Value) },
|
||||
{ "6C", (d, ld) => ContractMonthSerialLookupRule(Symbol.Create("6C", SecurityType.Future, Market.CME), d, ld.Value) },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The difference in months for the Futures expiry month minus the Futures Options expiry month. This assumes
|
||||
/// that the underlying Future follows a 1-1 mapping between the FOP and future, i.e. this will result in incorrect
|
||||
/// results, but is needed as an intermediate step to resolve the actual expiry.
|
||||
/// </summary>
|
||||
private static readonly IReadOnlyDictionary<string, int> _futuresOptionsExpiryDelta = new Dictionary<string, int>
|
||||
{
|
||||
{ "ZB", 1 },
|
||||
{ "ZC", 1 },
|
||||
{ "ZM", 1 },
|
||||
{ "ZN", 1 },
|
||||
{ "TN", 1 },
|
||||
{ "ZS", 1 },
|
||||
{ "ZT", 1 },
|
||||
{ "ZW", 1 },
|
||||
{ "ZL", 1 },
|
||||
{ "HG", 1 },
|
||||
{ "GC", 1 },
|
||||
{ "SI", 1 },
|
||||
{ "UB", 1 },
|
||||
{ "ZO", 1 },
|
||||
{ "KE", 1 },
|
||||
{ "ZF", 1 },
|
||||
{ "LBR", 1 },
|
||||
{ "LBS", 1 }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the FOP's underlying Future. The underlying Future's contract month might not match
|
||||
/// the contract month of the Future Option when providing CBOT or COMEX based FOPs contracts to this method.
|
||||
/// </summary>
|
||||
/// <param name="futureOptionTicker">Future option ticker</param>
|
||||
/// <param name="market">Market of the Future Option</param>
|
||||
/// <param name="futureOptionExpiration">Expiration date of the future option</param>
|
||||
/// <param name="date">Date to search the future chain provider with. Optional, but required for CBOT based contracts</param>
|
||||
/// <returns>Symbol if there is an underlying for the FOP, null if there's no underlying found for the Future Option</returns>
|
||||
public static Symbol GetUnderlyingFutureFromFutureOption(string futureOptionTicker, string market, DateTime futureOptionExpiration, DateTime? date = null)
|
||||
{
|
||||
var futureTicker = FuturesOptionsSymbolMappings.MapFromOption(futureOptionTicker);
|
||||
var canonicalFuture = Symbol.Create(futureTicker, SecurityType.Future, market);
|
||||
// Get the contract month of the FOP to use when searching for the underlying.
|
||||
// If the FOP and Future share the same contract month, this is reused as the future's
|
||||
// contract month so that we can resolve the Future's expiry.
|
||||
var contractMonth = GetFutureContractMonthNoRulesApplied(canonicalFuture, futureOptionExpiration);
|
||||
|
||||
if (_underlyingFuturesOptionsRules.ContainsKey(futureTicker))
|
||||
{
|
||||
// The provided ticker follows some sort of rule. Let's figure out the underlying's contract month.
|
||||
var newFutureContractMonth = _underlyingFuturesOptionsRules[futureTicker](contractMonth, date);
|
||||
if (newFutureContractMonth == null)
|
||||
{
|
||||
// This will only happen when we search the Futures chain for a given contract and no
|
||||
// closest match could be made, i.e. there are no futures in the chain that come after the FOP's
|
||||
// contract month.
|
||||
return null;
|
||||
}
|
||||
|
||||
contractMonth = newFutureContractMonth.Value;
|
||||
}
|
||||
|
||||
var futureExpiry = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFuture)(contractMonth);
|
||||
return Symbol.CreateFuture(futureTicker, market, futureExpiry);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the futures chain for the next matching futures contract, and resolves the underlying
|
||||
/// as the closest future we can find during or after the contract month.
|
||||
/// </summary>
|
||||
/// <param name="canonicalFutureSymbol">Canonical future Symbol</param>
|
||||
/// <param name="futureOptionContractMonth">Future option contract month. Note that this is not the expiry of the Future Option.</param>
|
||||
/// <param name="lookupDate">The date that we'll be using to look at the Future chain</param>
|
||||
/// <returns>The underlying future's contract month, or null if no closest contract was found</returns>
|
||||
private static DateTime? ContractMonthSerialLookupRule(Symbol canonicalFutureSymbol, DateTime futureOptionContractMonth, DateTime lookupDate)
|
||||
{
|
||||
var futureChain = FuturesListings.ListedContracts(canonicalFutureSymbol.ID.Symbol, lookupDate);
|
||||
if (futureChain == null)
|
||||
{
|
||||
// No matching contract listing rules entry was found
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (var future in futureChain.OrderBy(s => s.ID.Date))
|
||||
{
|
||||
// Normalize by date first, normalize to a contract month date, then we want to get the contract
|
||||
// month of the Future contract so we normalize by getting the delta between the expiration
|
||||
// and the contract month.
|
||||
var futureContractMonth = FuturesExpiryUtilityFunctions.GetFutureContractMonth(future);
|
||||
|
||||
// We want a contract that is either the same as the contract month or greater
|
||||
if (futureContractMonth < futureOptionContractMonth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return futureContractMonth;
|
||||
}
|
||||
|
||||
// No matching/closest contract was found in the futures chain.
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for the closest future's contract month depending on whether the Future Option's contract month is
|
||||
/// on an even or odd month.
|
||||
/// </summary>
|
||||
/// <param name="futureOptionContractMonth">Future option contract month. Note that this is not the expiry of the Future Option.</param>
|
||||
/// <param name="oddMonths">True if the Future Option's underlying future contract month is on odd months, false if on even months</param>
|
||||
/// <returns>The underlying Future's contract month</returns>
|
||||
private static DateTime ContractMonthEvenOddMonth(DateTime futureOptionContractMonth, bool oddMonths)
|
||||
{
|
||||
var monthEven = futureOptionContractMonth.Month % 2 == 0;
|
||||
if (oddMonths && monthEven)
|
||||
{
|
||||
return futureOptionContractMonth.AddMonths(1);
|
||||
}
|
||||
if (!oddMonths && !monthEven)
|
||||
{
|
||||
return futureOptionContractMonth.AddMonths(1);
|
||||
}
|
||||
|
||||
return futureOptionContractMonth;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the contract month to the third month for the first 3 months, then begins using the <see cref="ContractMonthEvenOddMonth"/> rule.
|
||||
/// </summary>
|
||||
/// <param name="futureOptionContractMonth">Future option contract month. Note that this is not the expiry of the Future Option.</param>
|
||||
/// <param name="oddMonths">True if the Future Option's underlying future contract month is on odd months, false if on even months. Only used for months greater than 3 months</param>
|
||||
/// <returns></returns>
|
||||
private static DateTime ContractMonthYearStartThreeMonthsThenEvenOddMonthsSkipRule(DateTime futureOptionContractMonth, bool oddMonths)
|
||||
{
|
||||
if (futureOptionContractMonth.Month <= 3)
|
||||
{
|
||||
return new DateTime(futureOptionContractMonth.Year, 3, 1);
|
||||
}
|
||||
|
||||
return ContractMonthEvenOddMonth(futureOptionContractMonth, oddMonths);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the theoretical (i.e. intermediate/naive) future contract month if we assumed a 1-1 mapping
|
||||
/// between FOPs contract months and Futures contract months, i.e. they share the same contract month.
|
||||
/// </summary>
|
||||
/// <param name="canonicalFutureSymbol">Canonical future Symbol</param>
|
||||
/// <param name="futureOptionExpirationDate">Future Option Expiration Date</param>
|
||||
/// <returns>Contract month assuming that the Future Option and Future share the same contract month</returns>
|
||||
public static DateTime GetFutureContractMonthNoRulesApplied(Symbol canonicalFutureSymbol, DateTime futureOptionExpirationDate)
|
||||
{
|
||||
var baseOptionExpiryMonthDate = new DateTime(futureOptionExpirationDate.Year, futureOptionExpirationDate.Month, 1);
|
||||
if (!_futuresOptionsExpiryDelta.ContainsKey(canonicalFutureSymbol.ID.Symbol))
|
||||
{
|
||||
// For contracts like CL, they have no expiry delta between the Futures and FOPs, so we hit this path.
|
||||
// However, it does have a delta between its expiry and contract month, which we adjust here before
|
||||
// claiming that `baseOptionExpiryMonthDate` is the future's contract month.
|
||||
var futuresExpiry = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFutureSymbol)(baseOptionExpiryMonthDate);
|
||||
var futuresDelta = FuturesExpiryUtilityFunctions.GetDeltaBetweenContractMonthAndContractExpiry(canonicalFutureSymbol.ID.Symbol, futuresExpiry);
|
||||
|
||||
return baseOptionExpiryMonthDate.AddMonths(futuresDelta);
|
||||
}
|
||||
|
||||
return baseOptionExpiryMonthDate.AddMonths(_futuresOptionsExpiryDelta[canonicalFutureSymbol.ID.Symbol]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user