chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Represents the model responsible for applying cash settlement rules
|
||||
/// </summary>
|
||||
/// <remarks>This model converts the amount to the account currency and applies cash settlement immediately</remarks>
|
||||
public class AccountCurrencyImmediateSettlementModel : ImmediateSettlementModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies cash settlement rules
|
||||
/// </summary>
|
||||
/// <param name="applyFundsParameters">The funds application parameters</param>
|
||||
public override void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsParameters)
|
||||
{
|
||||
var currency = applyFundsParameters.CashAmount.Currency;
|
||||
var amount = applyFundsParameters.CashAmount.Amount;
|
||||
var portfolio = applyFundsParameters.Portfolio;
|
||||
var amountInAccountCurrency = portfolio.CashBook.ConvertToAccountCurrency(amount, currency);
|
||||
|
||||
portfolio.CashBook[portfolio.CashBook.AccountCurrency].AddAmount(amountInAccountCurrency);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Messaging class signifying a change in a user's account
|
||||
/// </summary>
|
||||
public class AccountEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the total cash balance of the account in units of <see cref="CurrencySymbol"/>
|
||||
/// </summary>
|
||||
public decimal CashBalance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the currency symbol
|
||||
/// </summary>
|
||||
public string CurrencySymbol { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates an AccountEvent
|
||||
/// </summary>
|
||||
/// <param name="currencySymbol">The currency's symbol</param>
|
||||
/// <param name="cashBalance">The total cash balance of the account</param>
|
||||
public AccountEvent(string currencySymbol, decimal cashBalance)
|
||||
{
|
||||
CashBalance = cashBalance;
|
||||
CurrencySymbol = currencySymbol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string that represents the current object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A string that represents the current object.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public override string ToString()
|
||||
{
|
||||
return Messages.AccountEvent.ToString(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Provides an implementation of <see cref="IPriceVariationModel"/>
|
||||
/// for use when data is <see cref="DataNormalizationMode.Adjusted"/>.
|
||||
/// </summary>
|
||||
public class AdjustedPriceVariationModel : IPriceVariationModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the minimum price variation from a security
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the method parameters</param>
|
||||
/// <returns>Zero</returns>
|
||||
public virtual decimal GetMinimumPriceVariation(GetMinimumPriceVariationParameters parameters)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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;
|
||||
using System;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper parameters class for <see cref="ISettlementModel.ApplyFunds(ApplyFundsSettlementModelParameters)"/>
|
||||
/// </summary>
|
||||
public class ApplyFundsSettlementModelParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// The algorithm portfolio instance
|
||||
/// </summary>
|
||||
public SecurityPortfolioManager Portfolio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The associated security type
|
||||
/// </summary>
|
||||
public Security Security { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The current Utc time
|
||||
/// </summary>
|
||||
public DateTime UtcTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The funds to apply
|
||||
/// </summary>
|
||||
public CashAmount CashAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The associated fill event
|
||||
/// </summary>
|
||||
public OrderEvent Fill { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The fill's security</param>
|
||||
/// <param name="applicationTimeUtc">The fill time (in UTC)</param>
|
||||
/// <param name="cashAmount">The amount to settle</param>
|
||||
/// <param name="fill">The associated fill</param>
|
||||
public ApplyFundsSettlementModelParameters(SecurityPortfolioManager portfolio, Security security, DateTime applicationTimeUtc, CashAmount cashAmount, OrderEvent fill)
|
||||
{
|
||||
Portfolio = portfolio;
|
||||
Security = security;
|
||||
UtcTime = applicationTimeUtc;
|
||||
CashAmount = cashAmount;
|
||||
Fill = fill;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* 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.Util;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for security databases, including market hours and symbol properties.
|
||||
/// </summary>
|
||||
public abstract class BaseSecurityDatabase<T, TEntry>
|
||||
where T : BaseSecurityDatabase<T, TEntry>
|
||||
{
|
||||
/// <summary>
|
||||
/// The database instance loaded from the data folder
|
||||
/// </summary>
|
||||
protected static T DataFolderDatabase { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Lock object for the data folder database
|
||||
/// </summary>
|
||||
protected static readonly object DataFolderDatabaseLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// The database entries
|
||||
/// </summary>
|
||||
protected Dictionary<SecurityDatabaseKey, TEntry> Entries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Custom entries set by the user.
|
||||
/// </summary>
|
||||
protected HashSet<SecurityDatabaseKey> CustomEntries { get; }
|
||||
|
||||
// _loadFromFromDataFolder and _updateEntry are used to load the database from
|
||||
// the data folder and update an entry respectively.
|
||||
// These are not abstract or virtual methods because they might be static methods.
|
||||
private readonly Func<T> _loadFromFromDataFolder;
|
||||
private readonly Action<TEntry, TEntry> _updateEntry;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseSecurityDatabase{T, TEntry}"/> class
|
||||
/// </summary>
|
||||
/// <param name="entries">The full listing of exchange hours by key</param>
|
||||
/// <param name="fromDataFolder">Method to load the database form the data folder</param>
|
||||
/// <param name="updateEntry">Method to update a database entry</param>
|
||||
protected BaseSecurityDatabase(Dictionary<SecurityDatabaseKey, TEntry> entries,
|
||||
Func<T> fromDataFolder, Action<TEntry, TEntry> updateEntry)
|
||||
{
|
||||
Entries = entries;
|
||||
CustomEntries = new();
|
||||
_loadFromFromDataFolder = fromDataFolder;
|
||||
_updateEntry = updateEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the database, forcing a reload when reused.
|
||||
/// Called in tests where multiple algorithms are run sequentially,
|
||||
/// and we need to guarantee that every test starts with the same environment.
|
||||
/// </summary>
|
||||
#pragma warning disable CA1000 // Do not declare static members on generic types
|
||||
public static void Reset()
|
||||
#pragma warning restore CA1000 // Do not declare static members on generic types
|
||||
{
|
||||
lock (DataFolderDatabaseLock)
|
||||
{
|
||||
DataFolderDatabase = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reload entries dictionary from file and merge them with previous custom ones
|
||||
/// </summary>
|
||||
internal void UpdateDataFolderDatabase()
|
||||
{
|
||||
lock (DataFolderDatabaseLock)
|
||||
{
|
||||
Reset();
|
||||
var newDatabase = _loadFromFromDataFolder();
|
||||
Merge(newDatabase, resetCustomEntries: false);
|
||||
// Make sure we keep this as the data folder database
|
||||
DataFolderDatabase = (T)this;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the entries dictionary with the new entries from the specified database
|
||||
/// </summary>
|
||||
internal virtual void Merge(T newDatabase, bool resetCustomEntries)
|
||||
{
|
||||
var newEntries = new List<KeyValuePair<SecurityDatabaseKey, TEntry>>();
|
||||
|
||||
foreach (var newEntry in newDatabase.Entries)
|
||||
{
|
||||
if (Entries.TryGetValue(newEntry.Key, out var entry))
|
||||
{
|
||||
if (resetCustomEntries || !CustomEntries.Contains(newEntry.Key))
|
||||
{
|
||||
_updateEntry(entry, newEntry.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newEntries.Add(KeyValuePair.Create(newEntry.Key, newEntry.Value));
|
||||
}
|
||||
}
|
||||
|
||||
Entries = Entries
|
||||
.Where(kvp => (!resetCustomEntries && CustomEntries.Contains(kvp.Key)) || newDatabase.Entries.ContainsKey(kvp.Key))
|
||||
.Concat(newEntries)
|
||||
.ToDictionary();
|
||||
|
||||
if (resetCustomEntries)
|
||||
{
|
||||
CustomEntries.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the database contains the specified key
|
||||
/// </summary>
|
||||
/// <param name="key">The key to search for</param>
|
||||
/// <returns>True if an entry is found, otherwise false</returns>
|
||||
protected bool ContainsKey(SecurityDatabaseKey key)
|
||||
{
|
||||
return Entries.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether an entry exists for the specified market/symbol/security-type
|
||||
/// </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>
|
||||
/// <param name="securityType">The security type of the symbol</param>
|
||||
public bool ContainsKey(string market, string symbol, SecurityType securityType)
|
||||
{
|
||||
return ContainsKey(new SecurityDatabaseKey(market, symbol, securityType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether an entry exists for the specified market/symbol/security-type
|
||||
/// </summary>
|
||||
/// <param name="market">The market the exchange resides in, i.e, 'usa', 'fxcm', ect...</param>
|
||||
/// <param name="symbol">The particular symbol being traded (Symbol class)</param>
|
||||
/// <param name="securityType">The security type of the symbol</param>
|
||||
public bool ContainsKey(string market, Symbol symbol, SecurityType securityType)
|
||||
{
|
||||
return ContainsKey(
|
||||
market,
|
||||
GetDatabaseSymbolKey(symbol),
|
||||
securityType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the correct string symbol to use as a database key
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol</param>
|
||||
/// <returns>The symbol string used in the database ke</returns>
|
||||
#pragma warning disable CA1000 // Do not declare static members on generic types
|
||||
public static string GetDatabaseSymbolKey(Symbol symbol)
|
||||
#pragma warning restore CA1000 // Do not declare static members on generic types
|
||||
{
|
||||
string stringSymbol;
|
||||
if (symbol == null)
|
||||
{
|
||||
stringSymbol = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (symbol.ID.SecurityType)
|
||||
{
|
||||
case SecurityType.Option:
|
||||
stringSymbol = symbol.HasUnderlying ? symbol.Underlying.Value : string.Empty;
|
||||
break;
|
||||
case SecurityType.IndexOption:
|
||||
case SecurityType.FutureOption:
|
||||
stringSymbol = symbol.HasUnderlying ? symbol.ID.Symbol : string.Empty;
|
||||
break;
|
||||
case SecurityType.Base:
|
||||
case SecurityType.Future:
|
||||
stringSymbol = symbol.ID.Symbol;
|
||||
break;
|
||||
default:
|
||||
stringSymbol = symbol.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return stringSymbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.Brokerages;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="ISecurityInitializer"/> that initializes a security
|
||||
/// by settings the <see cref="Security.FillModel"/>, <see cref="Security.FeeModel"/>,
|
||||
/// <see cref="Security.SlippageModel"/>, and the <see cref="Security.SettlementModel"/> properties
|
||||
/// </summary>
|
||||
public class BrokerageModelSecurityInitializer : ISecurityInitializer
|
||||
{
|
||||
private readonly IBrokerageModel _brokerageModel;
|
||||
private readonly ISecuritySeeder _securitySeeder;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BrokerageModelSecurityInitializer"/> class
|
||||
/// for the specified algorithm
|
||||
/// </summary>
|
||||
public BrokerageModelSecurityInitializer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BrokerageModelSecurityInitializer"/> class
|
||||
/// for the specified algorithm
|
||||
/// </summary>
|
||||
/// <param name="brokerageModel">The brokerage model used to initialize the security models</param>
|
||||
/// <param name="securitySeeder">An <see cref="ISecuritySeeder"/> used to seed the initial price of the security</param>
|
||||
public BrokerageModelSecurityInitializer(IBrokerageModel brokerageModel, ISecuritySeeder securitySeeder)
|
||||
{
|
||||
_brokerageModel = brokerageModel;
|
||||
_securitySeeder = securitySeeder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the specified security by setting up the models
|
||||
/// </summary>
|
||||
/// <param name="security">The security to be initialized</param>
|
||||
public virtual void Initialize(Security security)
|
||||
{
|
||||
// Sets the security models
|
||||
security.FillModel = _brokerageModel.GetFillModel(security);
|
||||
security.FeeModel = _brokerageModel.GetFeeModel(security);
|
||||
security.SlippageModel = _brokerageModel.GetSlippageModel(security);
|
||||
security.SettlementModel = _brokerageModel.GetSettlementModel(security);
|
||||
security.BuyingPowerModel = _brokerageModel.GetBuyingPowerModel(security);
|
||||
security.MarginInterestRateModel = _brokerageModel.GetMarginInterestRateModel(security);
|
||||
// Sets the leverage after the buying power model. Otherwise we would set the leverage of the default model.
|
||||
security.SetLeverage(_brokerageModel.GetLeverage(security));
|
||||
security.SetShortableProvider(_brokerageModel.GetShortableProvider(security));
|
||||
|
||||
_securitySeeder.SeedSecurity(security);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Defines the result for <see cref="IBuyingPowerModel.GetBuyingPower"/>
|
||||
/// </summary>
|
||||
public class BuyingPower
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the buying power
|
||||
/// </summary>
|
||||
public decimal Value { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BuyingPower"/> class
|
||||
/// </summary>
|
||||
/// <param name="buyingPower">The buying power</param>
|
||||
public BuyingPower(decimal buyingPower)
|
||||
{
|
||||
Value = buyingPower;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,566 @@
|
||||
/*
|
||||
* 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.Orders;
|
||||
using QuantConnect.Orders.Fees;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using QuantConnect.Algorithm.Framework.Portfolio;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for all buying power models
|
||||
/// </summary>
|
||||
public class BuyingPowerModel : IBuyingPowerModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an implementation of <see cref="IBuyingPowerModel"/> that
|
||||
/// does not check for sufficient buying power
|
||||
/// </summary>
|
||||
public static readonly IBuyingPowerModel Null = new NullBuyingPowerModel();
|
||||
|
||||
private decimal _initialMarginRequirement;
|
||||
private decimal _maintenanceMarginRequirement;
|
||||
|
||||
/// <summary>
|
||||
/// The percentage used to determine the required unused buying power for the account.
|
||||
/// </summary>
|
||||
protected decimal RequiredFreeBuyingPowerPercent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BuyingPowerModel"/> with no leverage (1x)
|
||||
/// </summary>
|
||||
public BuyingPowerModel()
|
||||
: this(1m)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BuyingPowerModel"/>
|
||||
/// </summary>
|
||||
/// <param name="initialMarginRequirement">The percentage of an order's absolute cost
|
||||
/// that must be held in free cash in order to place the order</param>
|
||||
/// <param name="maintenanceMarginRequirement">The percentage of the holding's absolute
|
||||
/// cost that must be held in free cash in order to avoid a margin call</param>
|
||||
/// <param name="requiredFreeBuyingPowerPercent">The percentage used to determine the required
|
||||
/// unused buying power for the account.</param>
|
||||
public BuyingPowerModel(
|
||||
decimal initialMarginRequirement,
|
||||
decimal maintenanceMarginRequirement,
|
||||
decimal requiredFreeBuyingPowerPercent
|
||||
)
|
||||
{
|
||||
if (initialMarginRequirement < 0 || initialMarginRequirement > 1)
|
||||
{
|
||||
throw new ArgumentException(Messages.BuyingPowerModel.InvalidInitialMarginRequirement);
|
||||
}
|
||||
|
||||
if (maintenanceMarginRequirement < 0 || maintenanceMarginRequirement > 1)
|
||||
{
|
||||
throw new ArgumentException(Messages.BuyingPowerModel.InvalidMaintenanceMarginRequirement);
|
||||
}
|
||||
|
||||
if (requiredFreeBuyingPowerPercent < 0 || requiredFreeBuyingPowerPercent > 1)
|
||||
{
|
||||
throw new ArgumentException(Messages.BuyingPowerModel.InvalidFreeBuyingPowerPercentRequirement);
|
||||
}
|
||||
|
||||
_initialMarginRequirement = initialMarginRequirement;
|
||||
_maintenanceMarginRequirement = maintenanceMarginRequirement;
|
||||
RequiredFreeBuyingPowerPercent = requiredFreeBuyingPowerPercent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BuyingPowerModel"/>
|
||||
/// </summary>
|
||||
/// <param name="leverage">The leverage</param>
|
||||
/// <param name="requiredFreeBuyingPowerPercent">The percentage used to determine the required
|
||||
/// unused buying power for the account.</param>
|
||||
public BuyingPowerModel(decimal leverage, decimal requiredFreeBuyingPowerPercent = 0)
|
||||
{
|
||||
if (leverage < 1)
|
||||
{
|
||||
throw new ArgumentException(Messages.BuyingPowerModel.InvalidLeverage);
|
||||
}
|
||||
|
||||
if (requiredFreeBuyingPowerPercent < 0 || requiredFreeBuyingPowerPercent > 1)
|
||||
{
|
||||
throw new ArgumentException(Messages.BuyingPowerModel.InvalidFreeBuyingPowerPercentRequirement);
|
||||
}
|
||||
|
||||
_initialMarginRequirement = 1 / leverage;
|
||||
_maintenanceMarginRequirement = 1 / leverage;
|
||||
RequiredFreeBuyingPowerPercent = requiredFreeBuyingPowerPercent;
|
||||
}
|
||||
|
||||
/// <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 virtual decimal GetLeverage(Security security)
|
||||
{
|
||||
return 1 / _initialMarginRequirement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the leverage for the applicable securities, i.e, equities
|
||||
/// </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 virtual void SetLeverage(Security security, decimal leverage)
|
||||
{
|
||||
if (leverage < 1)
|
||||
{
|
||||
throw new ArgumentException(Messages.BuyingPowerModel.InvalidLeverage);
|
||||
}
|
||||
|
||||
var margin = 1 / leverage;
|
||||
_initialMarginRequirement = margin;
|
||||
_maintenanceMarginRequirement = margin;
|
||||
}
|
||||
|
||||
/// <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 virtual 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 orderMargin + Math.Sign(orderMargin) * feesInAccountCurrency;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin currently allocated to the specified holding
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the security and holdings quantity/cost/value</param>
|
||||
/// <returns>The maintenance margin required for the provided holdings quantity/cost/value</returns>
|
||||
public virtual MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters)
|
||||
{
|
||||
return parameters.AbsoluteHoldingsValue * _maintenanceMarginRequirement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin cash available for a trade
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The security to be traded</param>
|
||||
/// <param name="direction">The direction of the trade</param>
|
||||
/// <returns>The margin available for the trade</returns>
|
||||
protected virtual decimal GetMarginRemaining(
|
||||
SecurityPortfolioManager portfolio,
|
||||
Security security,
|
||||
OrderDirection direction
|
||||
)
|
||||
{
|
||||
var totalPortfolioValue = portfolio.TotalPortfolioValue;
|
||||
var result = portfolio.GetMarginRemaining(totalPortfolioValue);
|
||||
|
||||
if (direction != OrderDirection.Hold)
|
||||
{
|
||||
var holdings = security.Holdings;
|
||||
//If the order is in the same direction as holdings, our remaining cash is our cash
|
||||
//In the opposite direction, our remaining cash is 2 x current value of assets + our cash
|
||||
if (holdings.IsLong)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case OrderDirection.Sell:
|
||||
result +=
|
||||
// portion of margin to close the existing position
|
||||
this.GetMaintenanceMargin(security) +
|
||||
// portion of margin to open the new position
|
||||
this.GetInitialMarginRequirement(security, security.Holdings.AbsoluteQuantity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (holdings.IsShort)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case OrderDirection.Buy:
|
||||
result +=
|
||||
// portion of margin to close the existing position
|
||||
this.GetMaintenanceMargin(security) +
|
||||
// portion of margin to open the new position
|
||||
this.GetInitialMarginRequirement(security, security.Holdings.AbsoluteQuantity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result -= totalPortfolioValue * RequiredFreeBuyingPowerPercent;
|
||||
return result < 0 ? 0 : result;
|
||||
}
|
||||
|
||||
/// <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 provided security and quantity</returns>
|
||||
public virtual InitialMargin GetInitialMarginRequirement(InitialMarginParameters parameters)
|
||||
{
|
||||
var security = parameters.Security;
|
||||
var quantity = parameters.Quantity;
|
||||
return security.QuoteCurrency.ConversionRate
|
||||
* security.SymbolProperties.ContractMultiplier
|
||||
* security.Price
|
||||
* quantity
|
||||
* _initialMarginRequirement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if there is sufficient buying power to execute this order.
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the portfolio, the security and the order</param>
|
||||
/// <returns>Returns buying power information for an order</returns>
|
||||
public virtual HasSufficientBuyingPowerForOrderResult HasSufficientBuyingPowerForOrder(HasSufficientBuyingPowerForOrderParameters parameters)
|
||||
{
|
||||
// short circuit the div 0 case
|
||||
if (parameters.Order.Quantity == 0)
|
||||
{
|
||||
return parameters.Sufficient();
|
||||
}
|
||||
|
||||
var ticket = parameters.Portfolio.Transactions.GetOrderTicket(parameters.Order.Id);
|
||||
if (ticket == null)
|
||||
{
|
||||
return parameters.Insufficient(Messages.BuyingPowerModel.InsufficientBuyingPowerDueToNullOrderTicket(parameters.Order));
|
||||
}
|
||||
|
||||
if (parameters.Order.Type == OrderType.OptionExercise)
|
||||
{
|
||||
// for option assignment and exercise orders we look into the requirements to process the underlying security transaction
|
||||
var option = (Option.Option) parameters.Security;
|
||||
var underlying = option.Underlying;
|
||||
|
||||
if (option.IsAutoExercised(underlying.Close) && underlying.IsTradable)
|
||||
{
|
||||
var quantity = option.GetExerciseQuantity(parameters.Order.Quantity);
|
||||
|
||||
var newOrder = new LimitOrder
|
||||
{
|
||||
Id = parameters.Order.Id,
|
||||
Time = parameters.Order.Time,
|
||||
LimitPrice = option.StrikePrice,
|
||||
Symbol = underlying.Symbol,
|
||||
Quantity = quantity
|
||||
};
|
||||
|
||||
// we continue with this call for underlying
|
||||
var parametersForUnderlying = parameters.ForUnderlying(newOrder);
|
||||
|
||||
var freeMargin = underlying.BuyingPowerModel.GetBuyingPower(parametersForUnderlying.Portfolio, parametersForUnderlying.Security, parametersForUnderlying.Order.Direction);
|
||||
// we add the margin used by the option itself
|
||||
freeMargin += GetMaintenanceMargin(MaintenanceMarginParameters.ForQuantityAtCurrentPrice(option, -parameters.Order.Quantity));
|
||||
|
||||
var initialMarginRequired = underlying.BuyingPowerModel.GetInitialMarginRequiredForOrder(
|
||||
new InitialMarginRequiredForOrderParameters(parameters.Portfolio.CashBook, underlying, newOrder));
|
||||
|
||||
return HasSufficientBuyingPowerForOrder(parametersForUnderlying, ticket, freeMargin, initialMarginRequired);
|
||||
}
|
||||
|
||||
return parameters.Sufficient();
|
||||
}
|
||||
|
||||
return HasSufficientBuyingPowerForOrder(parameters, ticket);
|
||||
}
|
||||
|
||||
private HasSufficientBuyingPowerForOrderResult HasSufficientBuyingPowerForOrder(HasSufficientBuyingPowerForOrderParameters parameters, OrderTicket ticket,
|
||||
decimal? freeMarginToUse = null, decimal? initialMarginRequired = null)
|
||||
{
|
||||
// When order only reduces or closes a security position, capital is always sufficient
|
||||
if (parameters.Security.Holdings.Quantity * parameters.Order.Quantity < 0 && Math.Abs(parameters.Security.Holdings.Quantity) >= Math.Abs(parameters.Order.Quantity))
|
||||
{
|
||||
return parameters.Sufficient();
|
||||
}
|
||||
|
||||
var freeMargin = freeMarginToUse ?? GetMarginRemaining(parameters.Portfolio, parameters.Security, parameters.Order.Direction);
|
||||
var initialMarginRequiredForOrder = initialMarginRequired ?? GetInitialMarginRequiredForOrder(
|
||||
new InitialMarginRequiredForOrderParameters(
|
||||
parameters.Portfolio.CashBook, parameters.Security, parameters.Order
|
||||
));
|
||||
|
||||
// pro-rate the initial margin required for order based on how much has already been filled
|
||||
var percentUnfilled = (Math.Abs(parameters.Order.Quantity) - Math.Abs(ticket.QuantityFilled)) / Math.Abs(parameters.Order.Quantity);
|
||||
var initialMarginRequiredForRemainderOfOrder = percentUnfilled * initialMarginRequiredForOrder;
|
||||
|
||||
if (Math.Abs(initialMarginRequiredForRemainderOfOrder) > freeMargin)
|
||||
{
|
||||
return parameters.Insufficient(Messages.BuyingPowerModel.InsufficientBuyingPowerDueToUnsufficientMargin(parameters.Order,
|
||||
initialMarginRequiredForRemainderOfOrder, freeMargin));
|
||||
}
|
||||
|
||||
return parameters.Sufficient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the maximum market order quantity to obtain a delta in the buying power used by a security.
|
||||
/// The deltas sign defines the position side to apply it to, positive long, negative short.
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the portfolio, the security and the delta buying power</param>
|
||||
/// <returns>Returns the maximum allowed market order quantity and if zero, also the reason</returns>
|
||||
/// <remarks>Used by the margin call model to reduce the position by a delta percent.</remarks>
|
||||
public virtual GetMaximumOrderQuantityResult GetMaximumOrderQuantityForDeltaBuyingPower(
|
||||
GetMaximumOrderQuantityForDeltaBuyingPowerParameters parameters)
|
||||
{
|
||||
var usedBuyingPower = parameters.Security.BuyingPowerModel.GetReservedBuyingPowerForPosition(
|
||||
new ReservedBuyingPowerForPositionParameters(parameters.Security)).AbsoluteUsedBuyingPower;
|
||||
|
||||
var signedUsedBuyingPower = usedBuyingPower * (parameters.Security.Holdings.IsLong ? 1 : -1);
|
||||
|
||||
var targetBuyingPower = signedUsedBuyingPower + parameters.DeltaBuyingPower;
|
||||
|
||||
var target = 0m;
|
||||
if (parameters.Portfolio.TotalPortfolioValue != 0)
|
||||
{
|
||||
target = targetBuyingPower / parameters.Portfolio.TotalPortfolioValue;
|
||||
}
|
||||
|
||||
return GetMaximumOrderQuantityForTargetBuyingPower(
|
||||
new GetMaximumOrderQuantityForTargetBuyingPowerParameters(parameters.Portfolio,
|
||||
parameters.Security,
|
||||
target,
|
||||
parameters.MinimumOrderMarginPortfolioPercentage,
|
||||
parameters.SilenceNonErrorReasons));
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <remarks>This implementation ensures that our resulting holdings is less than the target, but it does not necessarily
|
||||
/// maximize the holdings to meet the target. To do that we need a minimizing algorithm that reduces the difference between
|
||||
/// the target final margin value and the target holdings margin.</remarks>
|
||||
public virtual GetMaximumOrderQuantityResult GetMaximumOrderQuantityForTargetBuyingPower(GetMaximumOrderQuantityForTargetBuyingPowerParameters parameters)
|
||||
{
|
||||
// this is expensive so lets fetch it once
|
||||
var totalPortfolioValue = parameters.Portfolio.TotalPortfolioValue;
|
||||
|
||||
// adjust target buying power to comply with required Free Buying Power Percent
|
||||
var signedTargetFinalMarginValue =
|
||||
parameters.TargetBuyingPower * (totalPortfolioValue - totalPortfolioValue * RequiredFreeBuyingPowerPercent);
|
||||
|
||||
// if targeting zero, simply return the negative of the quantity
|
||||
if (signedTargetFinalMarginValue == 0)
|
||||
{
|
||||
return new GetMaximumOrderQuantityResult(-parameters.Security.Holdings.Quantity, string.Empty, false);
|
||||
}
|
||||
|
||||
// we use initial margin requirement here to avoid the duplicate PortfolioTarget.Percent situation:
|
||||
// PortfolioTarget.Percent(1) -> fills -> PortfolioTarget.Percent(1) _could_ detect free buying power if we use Maintenance requirement here
|
||||
var signedCurrentUsedMargin = this.GetInitialMarginRequirement(parameters.Security, parameters.Security.Holdings.Quantity);
|
||||
|
||||
// determine the unit price in terms of the account currency
|
||||
var utcTime = parameters.Security.LocalTime.ConvertToUtc(parameters.Security.Exchange.TimeZone);
|
||||
|
||||
// determine the margin required for 1 unit
|
||||
var absUnitMargin = this.GetInitialMarginRequirement(parameters.Security, 1);
|
||||
if (absUnitMargin == 0)
|
||||
{
|
||||
return new GetMaximumOrderQuantityResult(0, parameters.Security.Symbol.GetZeroPriceMessage());
|
||||
}
|
||||
|
||||
// Check that the change of margin is above our models minimum percentage change
|
||||
var absDifferenceOfMargin = Math.Abs(signedTargetFinalMarginValue - signedCurrentUsedMargin);
|
||||
if (!BuyingPowerModelExtensions.AboveMinimumOrderMarginPortfolioPercentage(parameters.Portfolio,
|
||||
parameters.MinimumOrderMarginPortfolioPercentage, absDifferenceOfMargin))
|
||||
{
|
||||
string reason = null;
|
||||
if (!parameters.SilenceNonErrorReasons)
|
||||
{
|
||||
var minimumValue = totalPortfolioValue * parameters.MinimumOrderMarginPortfolioPercentage;
|
||||
reason = Messages.BuyingPowerModel.TargetOrderMarginNotAboveMinimum(absDifferenceOfMargin, minimumValue);
|
||||
}
|
||||
|
||||
if (!PortfolioTarget.MinimumOrderMarginPercentageWarningSent.HasValue)
|
||||
{
|
||||
// will trigger the warning if it has not already been sent
|
||||
PortfolioTarget.MinimumOrderMarginPercentageWarningSent = false;
|
||||
}
|
||||
return new GetMaximumOrderQuantityResult(0, reason, false);
|
||||
}
|
||||
|
||||
// Use the following loop to converge on a value that places us under our target allocation when adjusted for fees
|
||||
var lastOrderQuantity = 0m; // For safety check
|
||||
decimal orderFees = 0m;
|
||||
decimal signedTargetHoldingsMargin;
|
||||
decimal orderQuantity;
|
||||
|
||||
do
|
||||
{
|
||||
// Calculate our order quantity
|
||||
orderQuantity = GetAmountToOrder(parameters.Security, signedTargetFinalMarginValue, absUnitMargin, out signedTargetHoldingsMargin);
|
||||
if (orderQuantity == 0)
|
||||
{
|
||||
string reason = null;
|
||||
if (!parameters.SilenceNonErrorReasons)
|
||||
{
|
||||
reason = Messages.BuyingPowerModel.OrderQuantityLessThanLotSize(parameters.Security,
|
||||
signedTargetFinalMarginValue - signedCurrentUsedMargin);
|
||||
}
|
||||
|
||||
return new GetMaximumOrderQuantityResult(0, reason, false);
|
||||
}
|
||||
|
||||
// generate the order
|
||||
var order = new MarketOrder(parameters.Security.Symbol, orderQuantity, utcTime);
|
||||
var fees = parameters.Security.FeeModel.GetOrderFee(
|
||||
new OrderFeeParameters(parameters.Security,
|
||||
order)).Value;
|
||||
orderFees = parameters.Portfolio.CashBook.ConvertToAccountCurrency(fees).Amount;
|
||||
|
||||
// Update our target portfolio margin allocated when considering fees, then calculate the new FinalOrderMargin
|
||||
signedTargetFinalMarginValue = (totalPortfolioValue - orderFees - totalPortfolioValue * RequiredFreeBuyingPowerPercent) * parameters.TargetBuyingPower;
|
||||
|
||||
// Start safe check after first loop, stops endless recursion
|
||||
if (lastOrderQuantity == orderQuantity)
|
||||
{
|
||||
var message = Messages.BuyingPowerModel.FailedToConvergeOnTheTargetMargin(parameters, signedTargetFinalMarginValue, orderFees);
|
||||
|
||||
// Need to add underlying value to message to reproduce with options
|
||||
if (parameters.Security is Option.Option option && option.Underlying != null)
|
||||
{
|
||||
var underlying = option.Underlying;
|
||||
message += " " + Messages.BuyingPowerModel.FailedToConvergeOnTheTargetMarginUnderlyingSecurityInfo(underlying);
|
||||
}
|
||||
|
||||
throw new ArgumentException(message);
|
||||
}
|
||||
lastOrderQuantity = orderQuantity;
|
||||
|
||||
}
|
||||
// Ensure that our target holdings margin will be less than or equal to our target allocated margin
|
||||
while (Math.Abs(signedTargetHoldingsMargin) > Math.Abs(signedTargetFinalMarginValue));
|
||||
|
||||
// add directionality back in
|
||||
return new GetMaximumOrderQuantityResult(orderQuantity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function that determines the amount to order to get to a given target safely.
|
||||
/// Meaning it will either be at or just below target always.
|
||||
/// </summary>
|
||||
/// <param name="security">Security we are to determine order size for</param>
|
||||
/// <param name="targetMargin">Target margin allocated</param>
|
||||
/// <param name="marginForOneUnit">Margin requirement for one unit; used in our initial order guess</param>
|
||||
/// <param name="finalMargin">Output the final margin allocated to this security</param>
|
||||
/// <returns>The size of the order to get safely to our target</returns>
|
||||
public decimal GetAmountToOrder([NotNull]Security security, decimal targetMargin, decimal marginForOneUnit, out decimal finalMargin)
|
||||
{
|
||||
var lotSize = security.SymbolProperties.LotSize;
|
||||
|
||||
// Start with order size that puts us back to 0, in theory this means current margin is 0
|
||||
// so we can calculate holdings to get to the new target margin directly. This is very helpful for
|
||||
// odd cases where margin requirements aren't linear.
|
||||
var orderSize = -security.Holdings.Quantity;
|
||||
|
||||
// Use the margin for one unit to make our initial guess.
|
||||
orderSize += targetMargin / marginForOneUnit;
|
||||
|
||||
// Determine the rounding mode for this order size
|
||||
var roundingMode = targetMargin < 0
|
||||
// Ending in short position; orders need to be rounded towards positive so we end up under our target
|
||||
? MidpointRounding.ToPositiveInfinity
|
||||
// Ending in long position; orders need to be rounded towards negative so we end up under our target
|
||||
: MidpointRounding.ToNegativeInfinity;
|
||||
|
||||
// Round this order size appropriately
|
||||
orderSize = orderSize.DiscretelyRoundBy(lotSize, roundingMode);
|
||||
|
||||
// Use our model to calculate this final margin as a final check
|
||||
finalMargin = this.GetInitialMarginRequirement(security,
|
||||
orderSize + security.Holdings.Quantity);
|
||||
|
||||
// Until our absolute final margin is equal to or below target we need to adjust; ensures we don't overshoot target
|
||||
// This isn't usually the case, but for non-linear margin per unit cases this may be necessary.
|
||||
// For example https://www.quantconnect.com/forum/discussion/12470, (covered in OptionMarginBuyingPowerModelTests)
|
||||
var marginDifference = finalMargin - targetMargin;
|
||||
while ((targetMargin < 0 && marginDifference < 0) || (targetMargin > 0 && marginDifference > 0))
|
||||
{
|
||||
// TODO: Can this be smarter about its adjustment, instead of just stepping by lotsize?
|
||||
// We adjust according to the target margin being a short or long
|
||||
orderSize += targetMargin < 0 ? lotSize : -lotSize;
|
||||
|
||||
// Recalculate final margin with this adjusted orderSize
|
||||
finalMargin = this.GetInitialMarginRequirement(security,
|
||||
orderSize + security.Holdings.Quantity);
|
||||
|
||||
// Safety check, does not occur in any of our testing, but to be sure we don't enter a endless loop
|
||||
// have this guy check that the difference between the two is not growing.
|
||||
var newDifference = finalMargin - targetMargin;
|
||||
if (Math.Abs(newDifference) > Math.Abs(marginDifference) && Math.Sign(newDifference) == Math.Sign(marginDifference))
|
||||
{
|
||||
// We have a problem and are correcting in the wrong direction
|
||||
var errorMessage = "BuyingPowerModel().GetAmountToOrder(): " +
|
||||
Messages.BuyingPowerModel.MarginBeingAdjustedInTheWrongDirection(targetMargin, marginForOneUnit, security);
|
||||
|
||||
// Need to add underlying value to message to reproduce with options
|
||||
if (security is Option.Option option && option.Underlying != null)
|
||||
{
|
||||
errorMessage += " " + Messages.BuyingPowerModel.MarginBeingAdjustedInTheWrongDirectionUnderlyingSecurityInfo(option.Underlying);
|
||||
}
|
||||
|
||||
throw new ArgumentException(errorMessage);
|
||||
}
|
||||
|
||||
marginDifference = newDifference;
|
||||
}
|
||||
|
||||
return orderSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of buying power reserved to maintain the specified position
|
||||
/// </summary>
|
||||
/// <param name="parameters">A parameters object containing the security</param>
|
||||
/// <returns>The reserved buying power in account currency</returns>
|
||||
public virtual ReservedBuyingPowerForPosition GetReservedBuyingPowerForPosition(ReservedBuyingPowerForPositionParameters parameters)
|
||||
{
|
||||
var maintenanceMargin = this.GetMaintenanceMargin(parameters.Security);
|
||||
return parameters.ResultInAccountCurrency(maintenanceMargin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buying power available for a trade
|
||||
/// </summary>
|
||||
/// <param name="parameters">A parameters object containing the algorithm's portfolio, security, and order direction</param>
|
||||
/// <returns>The buying power available for the trade</returns>
|
||||
public virtual BuyingPower GetBuyingPower(BuyingPowerParameters parameters)
|
||||
{
|
||||
var marginRemaining = GetMarginRemaining(parameters.Portfolio, parameters.Security, parameters.Direction);
|
||||
return parameters.ResultInAccountCurrency(marginRemaining);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.Orders;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods as backwards compatibility shims
|
||||
/// </summary>
|
||||
public static class BuyingPowerModelExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the amount of buying power reserved to maintain the specified position
|
||||
/// </summary>
|
||||
/// <param name="model">The <see cref="IBuyingPowerModel"/></param>
|
||||
/// <param name="security">The security</param>
|
||||
/// <returns>The reserved buying power in account currency</returns>
|
||||
public static decimal GetReservedBuyingPowerForPosition(this IBuyingPowerModel model, Security security)
|
||||
{
|
||||
var context = new ReservedBuyingPowerForPositionParameters(security);
|
||||
var reservedBuyingPower = model.GetReservedBuyingPowerForPosition(context);
|
||||
return reservedBuyingPower.AbsoluteUsedBuyingPower;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if there is sufficient buying power to execute this order.
|
||||
/// </summary>
|
||||
/// <param name="model">The <see cref="IBuyingPowerModel"/></param>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The security to be traded</param>
|
||||
/// <param name="order">The order</param>
|
||||
/// <returns>Returns buying power information for an order</returns>
|
||||
public static HasSufficientBuyingPowerForOrderResult HasSufficientBuyingPowerForOrder(
|
||||
this IBuyingPowerModel model,
|
||||
SecurityPortfolioManager portfolio,
|
||||
Security security,
|
||||
Order order
|
||||
)
|
||||
{
|
||||
var parameters = new HasSufficientBuyingPowerForOrderParameters(portfolio, security, order);
|
||||
|
||||
return model.HasSufficientBuyingPowerForOrder(parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the maximum market order quantity to obtain a position with a given value in account currency
|
||||
/// </summary>
|
||||
/// <param name="model">The <see cref="IBuyingPowerModel"/></param>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The security to be traded</param>
|
||||
/// <param name="target">The target percent holdings</param>
|
||||
/// <param name="minimumOrderMarginPortfolioPercentage">Configurable minimum order margin portfolio percentage to ignore orders with unrealistic small sizes</param>
|
||||
/// <returns>Returns the maximum allowed market order quantity and if zero, also the reason</returns>
|
||||
public static GetMaximumOrderQuantityResult GetMaximumOrderQuantityForTargetBuyingPower(
|
||||
this IBuyingPowerModel model,
|
||||
SecurityPortfolioManager portfolio,
|
||||
Security security,
|
||||
decimal target,
|
||||
decimal minimumOrderMarginPortfolioPercentage
|
||||
)
|
||||
{
|
||||
var parameters = new GetMaximumOrderQuantityForTargetBuyingPowerParameters(portfolio, security, target, minimumOrderMarginPortfolioPercentage);
|
||||
|
||||
return model.GetMaximumOrderQuantityForTargetBuyingPower(parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buying power available for a trade
|
||||
/// </summary>
|
||||
/// <param name="model">The <see cref="IBuyingPowerModel"/></param>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The security to be traded</param>
|
||||
/// <param name="direction">The direction of the trade</param>
|
||||
/// <returns>The buying power available for the trade</returns>
|
||||
public static decimal GetBuyingPower(
|
||||
this IBuyingPowerModel model,
|
||||
SecurityPortfolioManager portfolio,
|
||||
Security security,
|
||||
OrderDirection direction
|
||||
)
|
||||
{
|
||||
var context = new BuyingPowerParameters(portfolio, security, direction);
|
||||
var buyingPower = model.GetBuyingPower(context);
|
||||
|
||||
// existing implementations assume certain non-account currency units, so return raw value
|
||||
return buyingPower.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin currently allocated to the specified holding
|
||||
/// </summary>
|
||||
/// <param name="model">The buying power model</param>
|
||||
/// <param name="security">The security</param>
|
||||
/// <returns>The maintenance margin required for the provided holdings quantity/cost/value</returns>
|
||||
public static decimal GetMaintenanceMargin(this IBuyingPowerModel model, Security security)
|
||||
{
|
||||
return model.GetMaintenanceMargin(MaintenanceMarginParameters.ForCurrentHoldings(security));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin currently allocated to the specified holding
|
||||
/// </summary>
|
||||
/// <param name="model">The buying power model</param>
|
||||
/// <param name="security">The security</param>
|
||||
/// <param name="quantity">The quantity of shares</param>
|
||||
/// <returns>The initial margin required for the provided security and quantity</returns>
|
||||
public static decimal GetInitialMarginRequirement(this IBuyingPowerModel model, Security security, decimal quantity)
|
||||
{
|
||||
return model.GetInitialMarginRequirement(new InitialMarginParameters(security, quantity));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to determine if the requested quantity is above the algorithm minimum order margin portfolio percentage
|
||||
/// </summary>
|
||||
/// <param name="model">The buying power model</param>
|
||||
/// <param name="security">The security</param>
|
||||
/// <param name="quantity">The quantity of shares</param>
|
||||
/// <param name="portfolioManager">The algorithm's portfolio</param>
|
||||
/// <param name="minimumOrderMarginPortfolioPercentage">Minimum order margin portfolio percentage to ignore bad orders, orders with unrealistic small sizes</param>
|
||||
/// <remarks>If we are trading with negative margin remaining this method will return true always</remarks>
|
||||
/// <returns>True if this order quantity is above the minimum requested</returns>
|
||||
public static bool AboveMinimumOrderMarginPortfolioPercentage(this IBuyingPowerModel model, Security security,
|
||||
decimal quantity, SecurityPortfolioManager portfolioManager, decimal minimumOrderMarginPortfolioPercentage)
|
||||
{
|
||||
if (minimumOrderMarginPortfolioPercentage == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
var absFinalOrderMargin = Math.Abs(model.GetInitialMarginRequirement(new InitialMarginParameters(
|
||||
security, quantity)).Value);
|
||||
|
||||
return AboveMinimumOrderMarginPortfolioPercentage(portfolioManager, minimumOrderMarginPortfolioPercentage, absFinalOrderMargin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to determine if the requested quantity is above the algorithm minimum order margin portfolio percentage
|
||||
/// </summary>
|
||||
/// <param name="portfolioManager">The algorithm's portfolio</param>
|
||||
/// <param name="minimumOrderMarginPortfolioPercentage">Minimum order margin portfolio percentage to ignore bad orders, orders with unrealistic small sizes</param>
|
||||
/// <param name="absFinalOrderMargin">The calculated order margin value</param>
|
||||
/// <remarks>If we are trading with negative margin remaining this method will return true always</remarks>
|
||||
/// <returns>True if this order quantity is above the minimum requested</returns>
|
||||
public static bool AboveMinimumOrderMarginPortfolioPercentage(SecurityPortfolioManager portfolioManager,
|
||||
decimal minimumOrderMarginPortfolioPercentage,
|
||||
decimal absFinalOrderMargin)
|
||||
{
|
||||
var minimumValue = portfolioManager.TotalPortfolioValue * minimumOrderMarginPortfolioPercentage;
|
||||
|
||||
if (minimumValue > absFinalOrderMargin
|
||||
// if margin remaining is negative allow the order to pass so we can reduce the position
|
||||
&& portfolioManager.GetMarginRemaining(portfolioManager.TotalPortfolioValue) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the parameters for <see cref="IBuyingPowerModel.GetBuyingPower"/>
|
||||
/// </summary>
|
||||
public class BuyingPowerParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the security
|
||||
/// </summary>
|
||||
public Security Security { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the algorithm's portfolio
|
||||
/// </summary>
|
||||
public SecurityPortfolioManager Portfolio { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the direction in which buying power is to be computed
|
||||
/// </summary>
|
||||
public OrderDirection Direction { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BuyingPowerParameters"/> class
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The security</param>
|
||||
/// <param name="direction">The direction to compute buying power in</param>
|
||||
public BuyingPowerParameters(SecurityPortfolioManager portfolio, Security security, OrderDirection direction)
|
||||
{
|
||||
Portfolio = portfolio;
|
||||
Security = security;
|
||||
Direction = direction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the result using the specified buying power
|
||||
/// </summary>
|
||||
/// <param name="buyingPower">The buying power</param>
|
||||
/// <param name="currency">The units the buying power is denominated in</param>
|
||||
/// <returns>The buying power</returns>
|
||||
public BuyingPower Result(decimal buyingPower, string currency)
|
||||
{
|
||||
// TODO: Properly account for 'currency' - not accounted for currently as only performing mechanical refactoring
|
||||
return new BuyingPower(buyingPower);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the result using the specified buying power in units of the account currency
|
||||
/// </summary>
|
||||
/// <param name="buyingPower">The buying power</param>
|
||||
/// <returns>The buying power</returns>
|
||||
public BuyingPower ResultInAccountCurrency(decimal buyingPower)
|
||||
{
|
||||
return new BuyingPower(buyingPower);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* 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 Newtonsoft.Json;
|
||||
using ProtoBuf;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Securities.CurrencyConversion;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a holding of a currency in cash.
|
||||
/// </summary>
|
||||
[ProtoContract(SkipConstructor = true)]
|
||||
public class Cash
|
||||
{
|
||||
private ICurrencyConversion _currencyConversion;
|
||||
|
||||
private readonly object _locker = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when this instance is updated
|
||||
/// <see cref="AddAmount"/>, <see cref="SetAmount"/>, <see cref="Update"/>
|
||||
/// </summary>
|
||||
public event EventHandler Updated;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when this instance's <see cref="CurrencyConversion"/> is set/updated
|
||||
/// </summary>
|
||||
public event EventHandler CurrencyConversionUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the symbols of the securities required to provide conversion rates.
|
||||
/// If this cash represents the account currency, then an empty enumerable is returned.
|
||||
/// </summary>
|
||||
public IEnumerable<Symbol> SecuritySymbols => CurrencyConversion.ConversionRateSecurities.Any()
|
||||
? CurrencyConversion.ConversionRateSecurities.Select(x => x.Symbol)
|
||||
// we do this only because Newtonsoft.Json complains about empty enumerables
|
||||
: new List<Symbol>(0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object that calculates the conversion rate to account currency
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICurrencyConversion CurrencyConversion
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currencyConversion;
|
||||
}
|
||||
internal set
|
||||
{
|
||||
|
||||
var lastConversionRate = 0m;
|
||||
if (_currencyConversion != null)
|
||||
{
|
||||
lastConversionRate = _currencyConversion.ConversionRate;
|
||||
_currencyConversion.ConversionRateUpdated -= OnConversionRateUpdated;
|
||||
}
|
||||
|
||||
_currencyConversion = value;
|
||||
if (_currencyConversion != null)
|
||||
{
|
||||
if (lastConversionRate != 0m)
|
||||
{
|
||||
// If a user adds cash with an initial conversion rate and then this is overriden to a SecurityCurrencyConversion,
|
||||
// we want to keep the previous rate until the new one is updated.
|
||||
_currencyConversion.ConversionRate = lastConversionRate;
|
||||
}
|
||||
_currencyConversion.ConversionRateUpdated += OnConversionRateUpdated;
|
||||
}
|
||||
CurrencyConversionUpdated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConversionRateUpdated(object sender, decimal e)
|
||||
{
|
||||
OnUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the symbol used to represent this cash
|
||||
/// </summary>
|
||||
[ProtoMember(1)]
|
||||
public string Symbol { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the amount of cash held
|
||||
/// </summary>
|
||||
[ProtoMember(2)]
|
||||
public decimal Amount { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the conversion rate into account currency
|
||||
/// </summary>
|
||||
[ProtoMember(3)]
|
||||
public decimal ConversionRate
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currencyConversion.ConversionRate;
|
||||
}
|
||||
internal set
|
||||
{
|
||||
if (_currencyConversion == null)
|
||||
{
|
||||
CurrencyConversion = new ConstantCurrencyConversion(Symbol, null, value);
|
||||
}
|
||||
|
||||
_currencyConversion.ConversionRate = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The symbol of the currency, such as $
|
||||
/// </summary>
|
||||
[ProtoMember(4)]
|
||||
public string CurrencySymbol { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of this cash in the account currency
|
||||
/// </summary>
|
||||
public decimal ValueInAccountCurrency => Amount * ConversionRate;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Cash"/> class
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol used to represent this cash</param>
|
||||
/// <param name="amount">The amount of this currency held</param>
|
||||
/// <param name="conversionRate">The initial conversion rate of this currency into the <see cref="CashBook.AccountCurrency"/></param>
|
||||
public Cash(string symbol, decimal amount, decimal conversionRate)
|
||||
{
|
||||
if (string.IsNullOrEmpty(symbol))
|
||||
{
|
||||
throw new ArgumentException(Messages.Cash.NullOrEmptyCashSymbol);
|
||||
}
|
||||
Amount = amount;
|
||||
Symbol = symbol.LazyToUpper();
|
||||
CurrencySymbol = Currencies.GetCurrencySymbol(Symbol);
|
||||
CurrencyConversion = new ConstantCurrencyConversion(Symbol, null, conversionRate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks this cash object's conversion rate as being potentially outdated
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
_currencyConversion.Update();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified amount of currency to this Cash instance and returns the new total.
|
||||
/// This operation is thread-safe
|
||||
/// </summary>
|
||||
/// <param name="amount">The amount of currency to be added</param>
|
||||
/// <returns>The amount of currency directly after the addition</returns>
|
||||
public decimal AddAmount(decimal amount)
|
||||
{
|
||||
lock (_locker)
|
||||
{
|
||||
Amount += amount;
|
||||
}
|
||||
OnUpdate();
|
||||
return Amount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Quantity to the specified amount
|
||||
/// </summary>
|
||||
/// <param name="amount">The amount to set the quantity to</param>
|
||||
public void SetAmount(decimal amount)
|
||||
{
|
||||
var updated = false;
|
||||
// lock can be null when proto deserializing this instance
|
||||
lock (_locker ?? new object())
|
||||
{
|
||||
if (Amount != amount)
|
||||
{
|
||||
Amount = amount;
|
||||
// only update if there was actually one
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
OnUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that we have a data feed to convert this currency into the base currency.
|
||||
/// This will add a <see cref="SubscriptionDataConfig"/> and create a <see cref="Security"/> at the lowest resolution if one is not found.
|
||||
/// </summary>
|
||||
/// <param name="securities">The security manager</param>
|
||||
/// <param name="subscriptions">The subscription manager used for searching and adding subscriptions</param>
|
||||
/// <param name="marketMap">The market map that decides which market the new security should be in</param>
|
||||
/// <param name="changes">Will be used to consume <see cref="SecurityChanges.AddedSecurities"/></param>
|
||||
/// <param name="securityService">Will be used to create required new <see cref="Security"/></param>
|
||||
/// <param name="accountCurrency">The account currency</param>
|
||||
/// <param name="defaultResolution">The default resolution to use for the internal subscriptions</param>
|
||||
/// <returns>Returns the added <see cref="SubscriptionDataConfig"/>, otherwise null</returns>
|
||||
public List<SubscriptionDataConfig> EnsureCurrencyDataFeed(SecurityManager securities,
|
||||
SubscriptionManager subscriptions,
|
||||
IReadOnlyDictionary<SecurityType, string> marketMap,
|
||||
SecurityChanges changes,
|
||||
ISecurityService securityService,
|
||||
string accountCurrency,
|
||||
Resolution defaultResolution = Resolution.Minute
|
||||
)
|
||||
{
|
||||
// this gets called every time we add securities using universe selection,
|
||||
// so must of the time we've already resolved the value and don't need to again
|
||||
if (CurrencyConversion.DestinationCurrency != null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Symbol == accountCurrency)
|
||||
{
|
||||
CurrencyConversion = ConstantCurrencyConversion.Identity(accountCurrency);
|
||||
return null;
|
||||
}
|
||||
|
||||
// existing securities
|
||||
var securitiesToSearch = securities.Select(kvp => kvp.Value)
|
||||
.Concat(changes.AddedSecurities)
|
||||
.Where(s => ProvidesConversionRate(s.Type));
|
||||
|
||||
// Create a SecurityType to Market mapping with the markets from SecurityManager members
|
||||
var markets = securities.Select(x => x.Key)
|
||||
.GroupBy(x => x.SecurityType)
|
||||
.ToDictionary(x => x.Key, y => y.Select(symbol => symbol.ID.Market).ToHashSet());
|
||||
if (markets.ContainsKey(SecurityType.Cfd) && !markets.ContainsKey(SecurityType.Forex))
|
||||
{
|
||||
markets.Add(SecurityType.Forex, markets[SecurityType.Cfd]);
|
||||
}
|
||||
if (markets.ContainsKey(SecurityType.Forex) && !markets.ContainsKey(SecurityType.Cfd))
|
||||
{
|
||||
markets.Add(SecurityType.Cfd, markets[SecurityType.Forex]);
|
||||
}
|
||||
|
||||
var forexEntries = GetAvailableSymbolPropertiesDatabaseEntries(SecurityType.Forex, marketMap, markets);
|
||||
var cfdEntries = GetAvailableSymbolPropertiesDatabaseEntries(SecurityType.Cfd, marketMap, markets);
|
||||
var cryptoEntries = GetAvailableSymbolPropertiesDatabaseEntries(SecurityType.Crypto, marketMap, markets);
|
||||
|
||||
if (marketMap.TryGetValue(SecurityType.CryptoFuture, out var cryptoFutureMarket) && cryptoFutureMarket == Market.DYDX)
|
||||
{
|
||||
// Put additional logic for dYdX crypto futures as they don't have Crypto (Spot) market
|
||||
// Also need to add them first to give the priority
|
||||
// TODO: remove once dydx SPOT market will be imlemented
|
||||
cryptoEntries = GetAvailableSymbolPropertiesDatabaseEntries(SecurityType.CryptoFuture, marketMap, markets).Concat(cryptoEntries);
|
||||
}
|
||||
|
||||
var potentialEntries = forexEntries
|
||||
.Concat(cfdEntries)
|
||||
.Concat(cryptoEntries)
|
||||
.ToList();
|
||||
|
||||
// Special case for crypto markets without direct pairs (They wont be found by the above)
|
||||
// This allows us to add cash for "StableCoins" that are 1-1 with our account currency without needing a conversion security.
|
||||
// Check out the StableCoinsWithoutPairs static var for those that are missing their 1-1 conversion pairs
|
||||
if (marketMap.TryGetValue(SecurityType.Crypto, out var market) && Currencies.IsStableCoinWithoutPair(accountCurrency, Symbol, market))
|
||||
{
|
||||
CurrencyConversion = ConstantCurrencyConversion.Identity(accountCurrency, Symbol);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!potentialEntries.Any(x =>
|
||||
Symbol == x.Key.Symbol.Substring(0, x.Key.Symbol.Length - x.Value.QuoteCurrency.Length) ||
|
||||
Symbol == x.Value.QuoteCurrency))
|
||||
{
|
||||
// currency not found in any tradeable pair
|
||||
Log.Error(Messages.Cash.NoTradablePairFoundForCurrencyConversion(Symbol, accountCurrency, marketMap.Where(kvp => ProvidesConversionRate(kvp.Key))));
|
||||
CurrencyConversion = ConstantCurrencyConversion.Null(accountCurrency, Symbol);
|
||||
return null;
|
||||
}
|
||||
|
||||
var requiredSecurities = new List<SubscriptionDataConfig>();
|
||||
|
||||
var potentials = potentialEntries
|
||||
.Select(x => QuantConnect.Symbol.Create(x.Key.Symbol, x.Key.SecurityType, x.Key.Market));
|
||||
|
||||
var minimumResolution = subscriptions.Subscriptions.Select(x => x.Resolution).DefaultIfEmpty(defaultResolution).Min();
|
||||
|
||||
var makeNewSecurity = new Func<Symbol, Security>(symbol =>
|
||||
{
|
||||
var securityType = symbol.ID.SecurityType;
|
||||
|
||||
// use the first subscription defined in the subscription manager
|
||||
var type = subscriptions.LookupSubscriptionConfigDataTypes(securityType, minimumResolution, false).First();
|
||||
var objectType = type.Item1;
|
||||
var tickType = type.Item2;
|
||||
|
||||
// set this as an internal feed so that the data doesn't get sent into the algorithm's OnData events
|
||||
var config = subscriptions.SubscriptionDataConfigService.Add(symbol,
|
||||
minimumResolution,
|
||||
fillForward: true,
|
||||
extendedMarketHours: false,
|
||||
isInternalFeed: true,
|
||||
subscriptionDataTypes: new List<Tuple<Type, TickType>>
|
||||
{new Tuple<Type, TickType>(objectType, tickType)}).First();
|
||||
|
||||
var newSecurity = securityService.CreateSecurity(symbol,
|
||||
config,
|
||||
addToSymbolCache: false,
|
||||
// All securities added for currency conversion will be seeded in batch after all are created
|
||||
seedSecurity: false);
|
||||
|
||||
Log.Trace("Cash.EnsureCurrencyDataFeed(): " + Messages.Cash.AddingSecuritySymbolForCashCurrencyFeed(symbol, Symbol));
|
||||
|
||||
securities.Add(symbol, newSecurity);
|
||||
requiredSecurities.Add(config);
|
||||
|
||||
return newSecurity;
|
||||
});
|
||||
|
||||
CurrencyConversion = SecurityCurrencyConversion.LinearSearch(Symbol,
|
||||
accountCurrency,
|
||||
securitiesToSearch.ToList(),
|
||||
potentials,
|
||||
makeNewSecurity);
|
||||
|
||||
return requiredSecurities;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string"/> that represents the current <see cref="Cash"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="string"/> that represents the current <see cref="Cash"/>.</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return ToString(Currencies.USD);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string"/> that represents the current <see cref="Cash"/>.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="string"/> that represents the current <see cref="Cash"/>.</returns>
|
||||
public string ToString(string accountCurrency)
|
||||
{
|
||||
return Messages.Cash.ToString(this, accountCurrency);
|
||||
}
|
||||
|
||||
private static IEnumerable<KeyValuePair<SecurityDatabaseKey, SymbolProperties>> GetAvailableSymbolPropertiesDatabaseEntries(
|
||||
SecurityType securityType,
|
||||
IReadOnlyDictionary<SecurityType, string> marketMap,
|
||||
IReadOnlyDictionary<SecurityType, HashSet<string>> markets
|
||||
)
|
||||
{
|
||||
var marketJoin = new HashSet<string>();
|
||||
{
|
||||
string market;
|
||||
if (marketMap.TryGetValue(securityType, out market))
|
||||
{
|
||||
marketJoin.Add(market);
|
||||
}
|
||||
HashSet<string> existingMarkets;
|
||||
if (markets.TryGetValue(securityType, out existingMarkets))
|
||||
{
|
||||
foreach (var existingMarket in existingMarkets)
|
||||
{
|
||||
marketJoin.Add(existingMarket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return marketJoin.SelectMany(market => SymbolPropertiesDatabase.FromDataFolder()
|
||||
.GetSymbolPropertiesList(market, securityType));
|
||||
}
|
||||
|
||||
private static bool ProvidesConversionRate(SecurityType securityType)
|
||||
{
|
||||
return securityType == SecurityType.Forex || securityType == SecurityType.Crypto || securityType == SecurityType.Cfd;
|
||||
}
|
||||
|
||||
private void OnUpdate()
|
||||
{
|
||||
Updated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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 ProtoBuf;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a cash amount which can be converted to account currency using a currency converter
|
||||
/// </summary>
|
||||
[ProtoContract(SkipConstructor = true)]
|
||||
public struct CashAmount
|
||||
{
|
||||
/// <summary>
|
||||
/// The amount of cash
|
||||
/// </summary>
|
||||
[ProtoMember(1)]
|
||||
public decimal Amount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The currency in which the cash amount is denominated
|
||||
/// </summary>
|
||||
[ProtoMember(2)]
|
||||
public string Currency { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CashAmount"/> class
|
||||
/// </summary>
|
||||
/// <param name="amount">The amount</param>
|
||||
/// <param name="currency">The currency</param>
|
||||
public CashAmount(decimal amount, string currency)
|
||||
{
|
||||
Amount = amount;
|
||||
Currency = currency;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will determine if two <see cref="CashAmount"/> instances are equal
|
||||
/// Useful to compare against the default instance
|
||||
/// </summary>
|
||||
/// <returns>True if <see cref="Currency"/> and <see cref="Amount"/> are equal</returns>
|
||||
public static bool operator ==(CashAmount lhs, CashAmount rhs)
|
||||
{
|
||||
return Equals(lhs, rhs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will determine if two <see cref="CashAmount"/> instances are different
|
||||
/// Useful to compare against the default instance
|
||||
/// </summary>
|
||||
/// <returns>True if <see cref="Currency"/> or <see cref="Amount"/> are different</returns>
|
||||
public static bool operator !=(CashAmount lhs, CashAmount rhs)
|
||||
{
|
||||
return !Equals(lhs, rhs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to compare two <see cref="CashAmount"/> instances.
|
||||
/// Useful to compare against the default instance
|
||||
/// </summary>
|
||||
/// <param name="obj">The other object to compare with</param>
|
||||
/// <returns>True if <see cref="Currency"/> and <see cref="Amount"/> are equal</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is CashAmount)
|
||||
{
|
||||
var cashAmountObj = (CashAmount) obj;
|
||||
return Amount == cashAmountObj.Amount
|
||||
&& Currency == cashAmountObj.Currency;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Hash Code for this Object
|
||||
/// </summary>
|
||||
/// <returns>Integer Hash Code</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
/*
|
||||
* 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a means of keeping track of the different cash holdings of an algorithm
|
||||
/// </summary>
|
||||
public class CashBook : ExtendedDictionary<string, Cash>, IDictionary<string, Cash>, ICurrencyConverter
|
||||
{
|
||||
private string _accountCurrency;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when a <see cref="Cash"/> instance is added or removed, and when
|
||||
/// the <see cref="Cash.Updated"/> is triggered for the currently hold instances
|
||||
/// </summary>
|
||||
public event EventHandler<CashBookUpdatedEventArgs> Updated;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the base currency used
|
||||
/// </summary>
|
||||
public string AccountCurrency
|
||||
{
|
||||
get { return _accountCurrency; }
|
||||
set
|
||||
{
|
||||
var amount = 0m;
|
||||
Cash accountCurrency;
|
||||
// remove previous account currency if any
|
||||
if (!_accountCurrency.IsNullOrEmpty()
|
||||
&& TryGetValue(_accountCurrency, out accountCurrency))
|
||||
{
|
||||
amount = accountCurrency.Amount;
|
||||
Remove(_accountCurrency);
|
||||
}
|
||||
|
||||
// add new account currency using same amount as previous
|
||||
_accountCurrency = value.LazyToUpper();
|
||||
Add(_accountCurrency, new Cash(_accountCurrency, amount, 1.0m));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// No need for concurrent collection, they are expensive. Currencies barely change and only on the start
|
||||
/// by the main thread, so if they do we will just create a new collection, reference change is atomic
|
||||
/// </summary>
|
||||
private Dictionary<string, Cash> _currencies;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total value of the cash book in units of the base currency
|
||||
/// </summary>
|
||||
public decimal TotalValueInAccountCurrency
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Aggregate(0m, (d, pair) => d + pair.Value.ValueInAccountCurrency);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CashBook"/> class.
|
||||
/// </summary>
|
||||
public CashBook()
|
||||
{
|
||||
_currencies = new();
|
||||
AccountCurrency = Currencies.USD;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new cash of the specified symbol and quantity
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol used to reference the new cash</param>
|
||||
/// <param name="quantity">The amount of new cash to start</param>
|
||||
/// <param name="conversionRate">The conversion rate used to determine the initial
|
||||
/// portfolio value/starting capital impact caused by this currency position.</param>
|
||||
/// <returns>The added cash instance</returns>
|
||||
public Cash Add(string symbol, decimal quantity, decimal conversionRate)
|
||||
{
|
||||
var cash = new Cash(symbol, quantity, conversionRate);
|
||||
// let's return the cash instance we are using
|
||||
return AddIternal(symbol, cash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the current subscriptions and adds necessary currency pair feeds to provide real time conversion data
|
||||
/// </summary>
|
||||
/// <param name="securities">The SecurityManager for the algorithm</param>
|
||||
/// <param name="subscriptions">The SubscriptionManager for the algorithm</param>
|
||||
/// <param name="marketMap">The market map that decides which market the new security should be in</param>
|
||||
/// <param name="changes">Will be used to consume <see cref="SecurityChanges.AddedSecurities"/></param>
|
||||
/// <param name="securityService">Will be used to create required new <see cref="Security"/></param>
|
||||
/// <param name="defaultResolution">The default resolution to use for the internal subscriptions</param>
|
||||
/// <returns>Returns a list of added currency <see cref="SubscriptionDataConfig"/></returns>
|
||||
public List<SubscriptionDataConfig> EnsureCurrencyDataFeeds(SecurityManager securities,
|
||||
SubscriptionManager subscriptions,
|
||||
IReadOnlyDictionary<SecurityType, string> marketMap,
|
||||
SecurityChanges changes,
|
||||
ISecurityService securityService,
|
||||
Resolution defaultResolution = Resolution.Minute)
|
||||
{
|
||||
var addedSubscriptionDataConfigs = new List<SubscriptionDataConfig>();
|
||||
foreach (var kvp in _currencies)
|
||||
{
|
||||
var cash = kvp.Value;
|
||||
|
||||
var subscriptionDataConfigs = cash.EnsureCurrencyDataFeed(
|
||||
securities,
|
||||
subscriptions,
|
||||
marketMap,
|
||||
changes,
|
||||
securityService,
|
||||
AccountCurrency,
|
||||
defaultResolution);
|
||||
if (subscriptionDataConfigs != null)
|
||||
{
|
||||
foreach (var subscriptionDataConfig in subscriptionDataConfigs)
|
||||
{
|
||||
addedSubscriptionDataConfigs.Add(subscriptionDataConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
return addedSubscriptionDataConfigs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a quantity of source currency units into the specified destination currency
|
||||
/// </summary>
|
||||
/// <param name="sourceQuantity">The quantity of source currency to be converted</param>
|
||||
/// <param name="sourceCurrency">The source currency symbol</param>
|
||||
/// <param name="destinationCurrency">The destination currency symbol</param>
|
||||
/// <returns>The converted value</returns>
|
||||
public decimal Convert(decimal sourceQuantity, string sourceCurrency, string destinationCurrency)
|
||||
{
|
||||
if (sourceQuantity == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var source = this[sourceCurrency];
|
||||
var destination = this[destinationCurrency];
|
||||
|
||||
if (source.ConversionRate == 0)
|
||||
{
|
||||
throw new ArgumentException(Messages.CashBook.ConversionRateNotFound(sourceCurrency));
|
||||
}
|
||||
|
||||
if (destination.ConversionRate == 0)
|
||||
{
|
||||
throw new ArgumentException(Messages.CashBook.ConversionRateNotFound(destinationCurrency));
|
||||
}
|
||||
|
||||
var conversionRate = source.ConversionRate / destination.ConversionRate;
|
||||
return sourceQuantity * conversionRate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a quantity of source currency units into the account currency
|
||||
/// </summary>
|
||||
/// <param name="sourceQuantity">The quantity of source currency to be converted</param>
|
||||
/// <param name="sourceCurrency">The source currency symbol</param>
|
||||
/// <returns>The converted value</returns>
|
||||
public decimal ConvertToAccountCurrency(decimal sourceQuantity, string sourceCurrency)
|
||||
{
|
||||
if (sourceCurrency == AccountCurrency)
|
||||
{
|
||||
return sourceQuantity;
|
||||
}
|
||||
return Convert(sourceQuantity, sourceCurrency, AccountCurrency);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string that represents the current object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A string that represents the current object.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public override string ToString()
|
||||
{
|
||||
return Messages.CashBook.ToString(this);
|
||||
}
|
||||
|
||||
#region IDictionary Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Gets the count of Cash items in this CashBook.
|
||||
/// </summary>
|
||||
/// <value>The count.</value>
|
||||
public override int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currencies.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is read only.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is read only; otherwise, <c>false</c>.</value>
|
||||
public override bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add the specified item to this CashBook.
|
||||
/// </summary>
|
||||
/// <param name="item">KeyValuePair of symbol -> Cash item</param>
|
||||
public void Add(KeyValuePair<string, Cash> item)
|
||||
{
|
||||
Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add the specified key and value.
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol of the Cash value.</param>
|
||||
/// <param name="value">Value.</param>
|
||||
public void Add(string symbol, Cash value)
|
||||
{
|
||||
AddIternal(symbol, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear this instance of all Cash entries.
|
||||
/// </summary>
|
||||
public override void Clear()
|
||||
{
|
||||
_currencies = new();
|
||||
OnUpdate(CashBookUpdateType.Removed, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the Cash item corresponding to the specified symbol
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbolto be removed</param>
|
||||
public override bool Remove(string symbol)
|
||||
{
|
||||
return Remove(symbol, calledInternally: false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item.</param>
|
||||
public bool Remove(KeyValuePair<string, Cash> item)
|
||||
{
|
||||
return Remove(item.Key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the current instance contains an entry with the specified symbol.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if key was contained, <c>false</c> otherwise.</returns>
|
||||
/// <param name="symbol">Key.</param>
|
||||
public override bool ContainsKey(string symbol)
|
||||
{
|
||||
return _currencies.ContainsKey(symbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try to get the value.
|
||||
/// </summary>
|
||||
/// <remarks>To be added.</remarks>
|
||||
/// <returns><c>true</c>, if get value was tryed, <c>false</c> otherwise.</returns>
|
||||
/// <param name="symbol">The symbol.</param>
|
||||
/// <param name="value">Value.</param>
|
||||
public override bool TryGetValue(string symbol, out Cash value)
|
||||
{
|
||||
return _currencies.TryGetValue(symbol, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the current collection contains the specified value.
|
||||
/// </summary>
|
||||
/// <param name="item">Item.</param>
|
||||
public bool Contains(KeyValuePair<string, Cash> item)
|
||||
{
|
||||
return _currencies.Contains(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies to the specified array.
|
||||
/// </summary>
|
||||
/// <param name="array">Array.</param>
|
||||
/// <param name="arrayIndex">Array index.</param>
|
||||
public void CopyTo(KeyValuePair<string, Cash>[] array, int arrayIndex)
|
||||
{
|
||||
((IDictionary<string, Cash>) _currencies).CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="QuantConnect.Securities.Cash"/> with the specified symbol.
|
||||
/// </summary>
|
||||
/// <param name="symbol">Symbol.</param>
|
||||
public override Cash this[string symbol]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (symbol == Currencies.NullCurrency)
|
||||
{
|
||||
throw new InvalidOperationException(Messages.CashBook.UnexpectedRequestForNullCurrency);
|
||||
}
|
||||
Cash cash;
|
||||
if (!_currencies.TryGetValue(symbol, out cash))
|
||||
{
|
||||
throw new KeyNotFoundException(Messages.CashBook.CashSymbolNotFound(symbol));
|
||||
}
|
||||
return cash;
|
||||
}
|
||||
set
|
||||
{
|
||||
Add(symbol, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the keys.
|
||||
/// </summary>
|
||||
/// <value>The keys.</value>
|
||||
public ICollection<string> Keys => _currencies.Keys;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the values.
|
||||
/// </summary>
|
||||
/// <value>The values.</value>
|
||||
public ICollection<Cash> Values => _currencies.Values;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the keys.
|
||||
/// </summary>
|
||||
/// <value>The keys.</value>
|
||||
protected override IEnumerable<string> GetKeys => Keys;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the values.
|
||||
/// </summary>
|
||||
/// <value>The values.</value>
|
||||
protected override IEnumerable<Cash> GetValues => Values;
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the items in the dictionary
|
||||
/// </summary>
|
||||
/// <returns>All the items in the dictionary</returns>
|
||||
public override IEnumerable<KeyValuePair<string, Cash>> GetItems() => _currencies;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the enumerator.
|
||||
/// </summary>
|
||||
/// <returns>The enumerator.</returns>
|
||||
public IEnumerator<KeyValuePair<string, Cash>> GetEnumerator()
|
||||
{
|
||||
return _currencies.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return _currencies.GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICurrencyConverter Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Converts a cash amount to the account currency
|
||||
/// </summary>
|
||||
/// <param name="cashAmount">The <see cref="CashAmount"/> instance to convert</param>
|
||||
/// <returns>A new <see cref="CashAmount"/> instance denominated in the account currency</returns>
|
||||
public CashAmount ConvertToAccountCurrency(CashAmount cashAmount)
|
||||
{
|
||||
if (cashAmount.Currency == AccountCurrency)
|
||||
{
|
||||
return cashAmount;
|
||||
}
|
||||
|
||||
var amount = Convert(cashAmount.Amount, cashAmount.Currency, AccountCurrency);
|
||||
return new CashAmount(amount, AccountCurrency);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Cash AddIternal(string symbol, Cash value)
|
||||
{
|
||||
if (symbol == Currencies.NullCurrency)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!_currencies.TryGetValue(symbol, out var cash))
|
||||
{
|
||||
// we link our Updated event with underlying cash instances
|
||||
// so interested listeners just subscribe to our event
|
||||
value.Updated += OnCashUpdate;
|
||||
var newCurrencies = new Dictionary<string, Cash>(_currencies)
|
||||
{
|
||||
[symbol] = value
|
||||
};
|
||||
_currencies = newCurrencies;
|
||||
|
||||
OnUpdate(CashBookUpdateType.Added, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// override the values, it will trigger an update event already
|
||||
// we keep the instance because it might be used by securities already
|
||||
cash.ConversionRate = value.ConversionRate;
|
||||
cash.SetAmount(value.Amount);
|
||||
|
||||
return cash;
|
||||
}
|
||||
}
|
||||
|
||||
private bool Remove(string symbol, bool calledInternally)
|
||||
{
|
||||
Cash cash = null;
|
||||
var newCurrencies = new Dictionary<string, Cash>(_currencies);
|
||||
var removed = newCurrencies.Remove(symbol, out cash);
|
||||
_currencies = newCurrencies;
|
||||
if (!removed)
|
||||
{
|
||||
if (!calledInternally)
|
||||
{
|
||||
Log.Error("CashBook.Remove(): " + Messages.CashBook.FailedToRemoveRecord(symbol));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cash.Updated -= OnCashUpdate;
|
||||
if (!calledInternally)
|
||||
{
|
||||
OnUpdate(CashBookUpdateType.Removed, cash);
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
private void OnCashUpdate(object sender, EventArgs eventArgs)
|
||||
{
|
||||
OnUpdate(CashBookUpdateType.Updated, sender as Cash);
|
||||
}
|
||||
|
||||
private void OnUpdate(CashBookUpdateType updateType, Cash cash)
|
||||
{
|
||||
Updated?.Invoke(this, new CashBookUpdatedEventArgs(updateType, cash));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Event fired when the cash book is updated
|
||||
/// </summary>
|
||||
public class CashBookUpdatedEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The update type
|
||||
/// </summary>
|
||||
public CashBookUpdateType UpdateType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The updated cash instance.
|
||||
/// </summary>
|
||||
/// <remarks>This will be null for <see cref="CashBookUpdateType.Removed"/> events that clear the whole cash book</remarks>
|
||||
public Cash Cash { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
public CashBookUpdatedEventArgs(CashBookUpdateType type, Cash cash)
|
||||
{
|
||||
UpdateType = type;
|
||||
Cash = cash;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
* 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.Orders;
|
||||
using QuantConnect.Orders.Fees;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a buying power model for cash accounts
|
||||
/// </summary>
|
||||
public class CashBuyingPowerModel : BuyingPowerModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CashBuyingPowerModel"/> class
|
||||
/// </summary>
|
||||
public CashBuyingPowerModel()
|
||||
: base(1m, 0m, 0m)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
// Always returns 1. Cash accounts have no leverage.
|
||||
return 1m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the leverage for the applicable securities, i.e, equities
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is added to maintain backwards compatibility with the old margin/leverage system
|
||||
/// </remarks>
|
||||
/// <param name="security">The security to set leverage for</param>
|
||||
/// <param name="leverage">The new leverage</param>
|
||||
public override void SetLeverage(Security security, decimal leverage)
|
||||
{
|
||||
if (leverage != 1)
|
||||
{
|
||||
throw new InvalidOperationException(Messages.CashBuyingPowerModel.UnsupportedLeverage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public override InitialMargin GetInitialMarginRequirement(InitialMarginParameters parameters)
|
||||
{
|
||||
var security = parameters.Security;
|
||||
var quantity = parameters.Quantity;
|
||||
return security.QuoteCurrency.ConversionRate
|
||||
* security.SymbolProperties.ContractMultiplier
|
||||
* security.Price
|
||||
* quantity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if there is sufficient buying power to execute this order.
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the portfolio, the security and the order</param>
|
||||
/// <returns>Returns buying power information for an order</returns>
|
||||
public override HasSufficientBuyingPowerForOrderResult HasSufficientBuyingPowerForOrder(HasSufficientBuyingPowerForOrderParameters parameters)
|
||||
{
|
||||
var baseCurrency = parameters.Security as IBaseCurrencySymbol;
|
||||
if (baseCurrency == null)
|
||||
{
|
||||
return parameters.Insufficient(Messages.CashBuyingPowerModel.UnsupportedSecurity(parameters.Security));
|
||||
}
|
||||
|
||||
decimal totalQuantity;
|
||||
decimal orderQuantity;
|
||||
if (parameters.Order.Direction == OrderDirection.Buy)
|
||||
{
|
||||
// quantity available for buying in quote currency
|
||||
totalQuantity = parameters.Security.QuoteCurrency.Amount;
|
||||
orderQuantity = parameters.Order.AbsoluteQuantity * GetOrderPrice(parameters.Security, parameters.Order);
|
||||
}
|
||||
else
|
||||
{
|
||||
// quantity available for selling in base currency
|
||||
totalQuantity = baseCurrency.BaseCurrency.Amount;
|
||||
orderQuantity = parameters.Order.AbsoluteQuantity;
|
||||
}
|
||||
|
||||
// calculate reserved quantity for open orders (in quote or base currency depending on direction)
|
||||
var openOrdersReservedQuantity = GetOpenOrdersReservedQuantity(parameters.Portfolio, parameters.Security, parameters.Order);
|
||||
|
||||
if (parameters.Order.Direction == OrderDirection.Sell)
|
||||
{
|
||||
// can sell available and non-reserved quantities
|
||||
if (orderQuantity <= totalQuantity - openOrdersReservedQuantity)
|
||||
{
|
||||
return parameters.Sufficient();
|
||||
}
|
||||
|
||||
return parameters.Insufficient(Messages.CashBuyingPowerModel.SellOrderShortHoldingsNotSupported(totalQuantity,
|
||||
openOrdersReservedQuantity, orderQuantity, baseCurrency));
|
||||
}
|
||||
|
||||
var maximumQuantity = 0m;
|
||||
if (parameters.Order.Type == OrderType.Market)
|
||||
{
|
||||
// include existing holdings (in quote currency)
|
||||
var holdingsValue =
|
||||
parameters.Portfolio.CashBook.Convert(baseCurrency.BaseCurrency.Amount, baseCurrency.BaseCurrency.Symbol, parameters.Security.QuoteCurrency.Symbol);
|
||||
|
||||
// find a target value in account currency for buy market orders
|
||||
var targetValue =
|
||||
parameters.Portfolio.CashBook.ConvertToAccountCurrency(totalQuantity - openOrdersReservedQuantity + holdingsValue,
|
||||
parameters.Security.QuoteCurrency.Symbol);
|
||||
|
||||
// convert the target into a percent in relation to TPV
|
||||
var targetPercent = parameters.Portfolio.TotalPortfolioValue == 0 ? 0 : targetValue / parameters.Portfolio.TotalPortfolioValue;
|
||||
|
||||
// maximum quantity that can be bought (in quote currency)
|
||||
maximumQuantity =
|
||||
GetMaximumOrderQuantityForTargetBuyingPower(
|
||||
new GetMaximumOrderQuantityForTargetBuyingPowerParameters(parameters.Portfolio, parameters.Security, targetPercent, 0)).Quantity * GetOrderPrice(parameters.Security, parameters.Order);
|
||||
|
||||
if (orderQuantity <= Math.Abs(maximumQuantity))
|
||||
{
|
||||
return parameters.Sufficient();
|
||||
}
|
||||
|
||||
return parameters.Insufficient(Messages.CashBuyingPowerModel.BuyOrderQuantityGreaterThanMaxForBuyingPower(totalQuantity,
|
||||
maximumQuantity, openOrdersReservedQuantity, orderQuantity, baseCurrency, parameters.Security, parameters.Order));
|
||||
}
|
||||
|
||||
// for limit orders, add fees to the order cost
|
||||
var orderFee = 0m;
|
||||
if (parameters.Order.Type == OrderType.Limit)
|
||||
{
|
||||
var fee = parameters.Security.FeeModel.GetOrderFee(
|
||||
new OrderFeeParameters(parameters.Security,
|
||||
parameters.Order)).Value;
|
||||
orderFee = parameters.Portfolio.CashBook.Convert(
|
||||
fee.Amount,
|
||||
fee.Currency,
|
||||
parameters.Security.QuoteCurrency.Symbol);
|
||||
}
|
||||
|
||||
maximumQuantity = totalQuantity - openOrdersReservedQuantity - orderFee;
|
||||
if (orderQuantity <= maximumQuantity)
|
||||
{
|
||||
return parameters.Sufficient();
|
||||
}
|
||||
|
||||
return parameters.Insufficient(Messages.CashBuyingPowerModel.BuyOrderQuantityGreaterThanMaxForBuyingPower(totalQuantity,
|
||||
maximumQuantity, openOrdersReservedQuantity, orderQuantity, baseCurrency, parameters.Security, parameters.Order));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the maximum market order quantity to obtain a delta in the buying power used by a security.
|
||||
/// The deltas sign defines the position side to apply it to, positive long, negative short.
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the portfolio, the security and the delta buying power</param>
|
||||
/// <returns>Returns the maximum allowed market order quantity and if zero, also the reason</returns>
|
||||
/// <remarks>Used by the margin call model to reduce the position by a delta percent.</remarks>
|
||||
public override GetMaximumOrderQuantityResult GetMaximumOrderQuantityForDeltaBuyingPower(
|
||||
GetMaximumOrderQuantityForDeltaBuyingPowerParameters parameters)
|
||||
{
|
||||
throw new NotImplementedException(Messages.CashBuyingPowerModel.GetMaximumOrderQuantityForDeltaBuyingPowerNotImplemented);
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
var targetPortfolioValue = parameters.TargetBuyingPower * parameters.Portfolio.TotalPortfolioValue;
|
||||
// no shorting allowed
|
||||
if (targetPortfolioValue < 0)
|
||||
{
|
||||
return new GetMaximumOrderQuantityResult(0, Messages.CashBuyingPowerModel.ShortingNotSupported);
|
||||
}
|
||||
|
||||
var baseCurrency = parameters.Security as IBaseCurrencySymbol;
|
||||
if (baseCurrency == null)
|
||||
{
|
||||
return new GetMaximumOrderQuantityResult(0, Messages.CashBuyingPowerModel.InvalidSecurity);
|
||||
}
|
||||
|
||||
// if target value is zero, return amount of base currency available to sell
|
||||
if (targetPortfolioValue == 0)
|
||||
{
|
||||
return new GetMaximumOrderQuantityResult(-baseCurrency.BaseCurrency.Amount);
|
||||
}
|
||||
|
||||
// convert base currency cash to account currency
|
||||
var baseCurrencyPosition = parameters.Portfolio.CashBook.ConvertToAccountCurrency(
|
||||
baseCurrency.BaseCurrency.Amount,
|
||||
baseCurrency.BaseCurrency.Symbol);
|
||||
|
||||
// remove directionality, we'll work in the land of absolutes
|
||||
var targetOrderValue = Math.Abs(targetPortfolioValue - baseCurrencyPosition);
|
||||
var direction = targetPortfolioValue > baseCurrencyPosition ? OrderDirection.Buy : OrderDirection.Sell;
|
||||
|
||||
// determine the unit price in terms of the account currency
|
||||
var unitPrice = direction == OrderDirection.Buy ? parameters.Security.AskPrice : parameters.Security.BidPrice;
|
||||
unitPrice *= parameters.Security.QuoteCurrency.ConversionRate * parameters.Security.SymbolProperties.ContractMultiplier;
|
||||
|
||||
if (unitPrice == 0)
|
||||
{
|
||||
if (parameters.Security.QuoteCurrency.ConversionRate == 0)
|
||||
{
|
||||
return new GetMaximumOrderQuantityResult(0,
|
||||
Messages.CashBuyingPowerModel.NoDataInInternalCashFeedYet(parameters.Security, parameters.Portfolio));
|
||||
}
|
||||
|
||||
if (parameters.Security.SymbolProperties.ContractMultiplier == 0)
|
||||
{
|
||||
return new GetMaximumOrderQuantityResult(0, Messages.CashBuyingPowerModel.ZeroContractMultiplier(parameters.Security));
|
||||
}
|
||||
|
||||
// security.Price == 0
|
||||
return new GetMaximumOrderQuantityResult(0, parameters.Security.Symbol.GetZeroPriceMessage());
|
||||
}
|
||||
|
||||
// continue iterating while we do not have enough cash for the order
|
||||
decimal orderFees = 0;
|
||||
decimal currentOrderValue = 0;
|
||||
// compute the initial order quantity
|
||||
var orderQuantity = targetOrderValue / unitPrice;
|
||||
|
||||
// rounding off Order Quantity to the nearest multiple of Lot Size
|
||||
orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize;
|
||||
if (orderQuantity == 0)
|
||||
{
|
||||
string reason = null;
|
||||
if (!parameters.SilenceNonErrorReasons)
|
||||
{
|
||||
reason = Messages.CashBuyingPowerModel.OrderQuantityLessThanLotSize(parameters.Security);
|
||||
}
|
||||
return new GetMaximumOrderQuantityResult(0, reason, false);
|
||||
}
|
||||
|
||||
// Just in case...
|
||||
var lastOrderQuantity = 0m;
|
||||
var utcTime = parameters.Security.LocalTime.ConvertToUtc(parameters.Security.Exchange.TimeZone);
|
||||
do
|
||||
{
|
||||
// Each loop will reduce the order quantity based on the difference between
|
||||
// (cashRequired + orderFees) and targetOrderValue
|
||||
if (currentOrderValue > targetOrderValue)
|
||||
{
|
||||
var currentOrderValuePerUnit = currentOrderValue / orderQuantity;
|
||||
var amountOfOrdersToRemove = (currentOrderValue - targetOrderValue) / currentOrderValuePerUnit;
|
||||
if (amountOfOrdersToRemove < parameters.Security.SymbolProperties.LotSize)
|
||||
{
|
||||
// we will always substract at leat 1 LotSize
|
||||
amountOfOrdersToRemove = parameters.Security.SymbolProperties.LotSize;
|
||||
}
|
||||
orderQuantity -= amountOfOrdersToRemove;
|
||||
}
|
||||
|
||||
// rounding off Order Quantity to the nearest multiple of Lot Size
|
||||
orderQuantity -= orderQuantity % parameters.Security.SymbolProperties.LotSize;
|
||||
if (orderQuantity <= 0)
|
||||
{
|
||||
return new GetMaximumOrderQuantityResult(0,
|
||||
Messages.CashBuyingPowerModel.OrderQuantityLessThanLotSize(parameters.Security) +
|
||||
Messages.CashBuyingPowerModel.OrderQuantityLessThanLotSizeOrderDetails(targetOrderValue, orderQuantity, orderFees)
|
||||
);
|
||||
}
|
||||
|
||||
if (lastOrderQuantity == orderQuantity)
|
||||
{
|
||||
throw new ArgumentException(Messages.CashBuyingPowerModel.FailedToConvergeOnTargetOrderValue(targetOrderValue, currentOrderValue,
|
||||
orderQuantity, orderFees, parameters.Security));
|
||||
}
|
||||
lastOrderQuantity = orderQuantity;
|
||||
|
||||
// generate the order
|
||||
var order = new MarketOrder(parameters.Security.Symbol, orderQuantity, utcTime);
|
||||
var orderValue = orderQuantity * unitPrice;
|
||||
|
||||
var fees = parameters.Security.FeeModel.GetOrderFee(
|
||||
new OrderFeeParameters(parameters.Security,
|
||||
order)).Value;
|
||||
orderFees = parameters.Portfolio.CashBook.ConvertToAccountCurrency(fees).Amount;
|
||||
|
||||
currentOrderValue = orderValue + orderFees;
|
||||
} while (currentOrderValue > targetOrderValue);
|
||||
|
||||
// add directionality back in
|
||||
return new GetMaximumOrderQuantityResult((direction == OrderDirection.Sell ? -1 : 1) * orderQuantity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of buying power reserved to maintain the specified position
|
||||
/// </summary>
|
||||
/// <param name="parameters">A parameters object containing the security</param>
|
||||
/// <returns>The reserved buying power in account currency</returns>
|
||||
public override ReservedBuyingPowerForPosition GetReservedBuyingPowerForPosition(ReservedBuyingPowerForPositionParameters parameters)
|
||||
{
|
||||
// Always returns 0. Since we're purchasing currencies outright, the position doesn't consume buying power
|
||||
return parameters.ResultInAccountCurrency(0m);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buying power available for a trade
|
||||
/// </summary>
|
||||
/// <param name="parameters">A parameters object containing the algorithm's portfolio, security, and order direction</param>
|
||||
/// <returns>The buying power available for the trade</returns>
|
||||
public override BuyingPower GetBuyingPower(BuyingPowerParameters parameters)
|
||||
{
|
||||
var security = parameters.Security;
|
||||
var portfolio = parameters.Portfolio;
|
||||
var direction = parameters.Direction;
|
||||
|
||||
var baseCurrency = security as IBaseCurrencySymbol;
|
||||
if (baseCurrency == null)
|
||||
{
|
||||
return parameters.ResultInAccountCurrency(0m);
|
||||
}
|
||||
|
||||
var baseCurrencyPosition = baseCurrency.BaseCurrency.Amount;
|
||||
var quoteCurrencyPosition = portfolio.CashBook[security.QuoteCurrency.Symbol].Amount;
|
||||
|
||||
// determine the unit price in terms of the quote currency
|
||||
var utcTime = parameters.Security.LocalTime.ConvertToUtc(parameters.Security.Exchange.TimeZone);
|
||||
var unitPrice = new MarketOrder(security.Symbol, 1, utcTime).GetValue(security) / security.QuoteCurrency.ConversionRate;
|
||||
if (unitPrice == 0)
|
||||
{
|
||||
return parameters.ResultInAccountCurrency(0m);
|
||||
}
|
||||
|
||||
// NOTE: This is returning in units of the BASE currency
|
||||
if (direction == OrderDirection.Buy)
|
||||
{
|
||||
// invert units for math, 6500USD per BTC, currency pairs aren't real fractions
|
||||
// (USD)/(BTC/USD) => 10kUSD/ (6500 USD/BTC) => 10kUSD * (1BTC/6500USD) => ~ 1.5BTC
|
||||
return parameters.Result(quoteCurrencyPosition / unitPrice, baseCurrency.BaseCurrency.Symbol);
|
||||
}
|
||||
|
||||
if (direction == OrderDirection.Sell)
|
||||
{
|
||||
return parameters.Result(baseCurrencyPosition, baseCurrency.BaseCurrency.Symbol);
|
||||
}
|
||||
|
||||
return parameters.ResultInAccountCurrency(0m);
|
||||
}
|
||||
|
||||
private static decimal GetOrderPrice(Security security, Order order)
|
||||
{
|
||||
var orderPrice = 0m;
|
||||
switch (order.Type)
|
||||
{
|
||||
case OrderType.Market:
|
||||
orderPrice = security.Price;
|
||||
break;
|
||||
|
||||
case OrderType.Limit:
|
||||
orderPrice = ((LimitOrder)order).LimitPrice;
|
||||
break;
|
||||
|
||||
case OrderType.StopMarket:
|
||||
orderPrice = ((StopMarketOrder)order).StopPrice;
|
||||
break;
|
||||
|
||||
case OrderType.StopLimit:
|
||||
orderPrice = ((StopLimitOrder)order).LimitPrice;
|
||||
break;
|
||||
|
||||
case OrderType.LimitIfTouched:
|
||||
orderPrice = ((LimitIfTouchedOrder)order).LimitPrice;
|
||||
break;
|
||||
|
||||
case OrderType.TrailingStop:
|
||||
orderPrice = ((TrailingStopOrder)order).StopPrice;
|
||||
break;
|
||||
}
|
||||
|
||||
return orderPrice;
|
||||
}
|
||||
|
||||
private static decimal GetOpenOrdersReservedQuantity(SecurityPortfolioManager portfolio, Security security, Order order)
|
||||
{
|
||||
var baseCurrency = security as IBaseCurrencySymbol;
|
||||
if (baseCurrency == null) return 0;
|
||||
|
||||
// find the target currency for the requested direction and the securities potentially involved
|
||||
var targetCurrency = order.Direction == OrderDirection.Buy
|
||||
? security.QuoteCurrency.Symbol
|
||||
: baseCurrency.BaseCurrency.Symbol;
|
||||
|
||||
var symbolDirectionPairs = new Dictionary<Symbol, OrderDirection>();
|
||||
foreach (var portfolioSecurity in portfolio.Securities.Values)
|
||||
{
|
||||
var basePortfolioSecurity = portfolioSecurity as IBaseCurrencySymbol;
|
||||
if (basePortfolioSecurity == null) continue;
|
||||
|
||||
if (basePortfolioSecurity.BaseCurrency.Symbol == targetCurrency)
|
||||
{
|
||||
symbolDirectionPairs.Add(portfolioSecurity.Symbol, OrderDirection.Sell);
|
||||
}
|
||||
else if (portfolioSecurity.QuoteCurrency.Symbol == targetCurrency)
|
||||
{
|
||||
symbolDirectionPairs.Add(portfolioSecurity.Symbol, OrderDirection.Buy);
|
||||
}
|
||||
}
|
||||
|
||||
// fetch open orders with matching symbol/side
|
||||
var openOrders = portfolio.Transactions.GetOpenOrders(x =>
|
||||
{
|
||||
OrderDirection dir;
|
||||
return symbolDirectionPairs.TryGetValue(x.Symbol, out dir) &&
|
||||
// same direction of our order
|
||||
dir == x.Direction &&
|
||||
// don't count our current order
|
||||
x.Id != order.Id &&
|
||||
// only count working orders
|
||||
(x.Type == OrderType.Limit || x.Type == OrderType.StopMarket);
|
||||
}
|
||||
);
|
||||
|
||||
// calculate reserved quantity for selected orders
|
||||
var openOrdersReservedQuantity = 0m;
|
||||
foreach (var openOrder in openOrders)
|
||||
{
|
||||
var orderSecurity = portfolio.Securities[openOrder.Symbol];
|
||||
var orderBaseCurrency = orderSecurity as IBaseCurrencySymbol;
|
||||
|
||||
if (orderBaseCurrency != null)
|
||||
{
|
||||
// convert order value to target currency
|
||||
var quantityInTargetCurrency = openOrder.AbsoluteQuantity;
|
||||
if (orderSecurity.QuoteCurrency.Symbol == targetCurrency)
|
||||
{
|
||||
quantityInTargetCurrency *= GetOrderPrice(security, openOrder);
|
||||
}
|
||||
|
||||
openOrdersReservedQuantity += quantityInTargetCurrency;
|
||||
}
|
||||
}
|
||||
|
||||
return openOrdersReservedQuantity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Securities.Cfd
|
||||
{
|
||||
/// <summary>
|
||||
/// CFD Security Object Implementation for CFD Assets
|
||||
/// </summary>
|
||||
/// <seealso cref="Security"/>
|
||||
public class Cfd : Security
|
||||
{
|
||||
private readonly ContractSymbolProperties _symbolProperties;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the CFD 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 Cfd(SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
SubscriptionDataConfig config,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes)
|
||||
: this(exchangeHours, quoteCurrency, config, new ContractSymbolProperties(symbolProperties), currencyConverter, registeredTypes)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the CFD 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 Cfd(SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
SubscriptionDataConfig config,
|
||||
ContractSymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes)
|
||||
: base(config,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new CfdExchange(exchangeHours),
|
||||
new CfdCache(),
|
||||
new SecurityPortfolioModel(),
|
||||
new ImmediateFillModel(),
|
||||
new ConstantFeeModel(0),
|
||||
NullSlippageModel.Instance,
|
||||
new ImmediateSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
new SecurityMarginModel(50m),
|
||||
new CfdDataFilter(),
|
||||
new SecurityPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
Holdings = new CfdHolding(this, currencyConverter);
|
||||
_symbolProperties = symbolProperties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the CFD security
|
||||
/// </summary>
|
||||
/// <param name="symbol">The security's 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 for storing Security data</param>
|
||||
public Cfd(Symbol symbol,
|
||||
SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes,
|
||||
SecurityCache securityCache)
|
||||
: this(symbol, exchangeHours, quoteCurrency, new ContractSymbolProperties(symbolProperties), currencyConverter, registeredTypes, securityCache)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the CFD security
|
||||
/// </summary>
|
||||
/// <param name="symbol">The security's 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 for storing Security data</param>
|
||||
public Cfd(Symbol symbol,
|
||||
SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
ContractSymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes,
|
||||
SecurityCache securityCache)
|
||||
: base(symbol,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new CfdExchange(exchangeHours),
|
||||
securityCache,
|
||||
new SecurityPortfolioModel(),
|
||||
new ImmediateFillModel(),
|
||||
new ConstantFeeModel(0),
|
||||
NullSlippageModel.Instance,
|
||||
new ImmediateSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
new SecurityMarginModel(50m),
|
||||
new CfdDataFilter(),
|
||||
new SecurityPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
Holdings = new CfdHolding(this, currencyConverter);
|
||||
_symbolProperties = symbolProperties;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the contract multiplier for this CFD security
|
||||
/// </summary>
|
||||
public decimal ContractMultiplier
|
||||
{
|
||||
get { return _symbolProperties.ContractMultiplier; }
|
||||
set { _symbolProperties.SetContractMultiplier(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minimum price variation for this CFD security
|
||||
/// </summary>
|
||||
public decimal MinimumPriceVariation
|
||||
{
|
||||
get { return SymbolProperties.MinimumPriceVariation; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decomposes the specified currency pair into a base and quote currency provided as out parameters
|
||||
/// </summary>
|
||||
/// <param name="symbol">The input symbol to be decomposed</param>
|
||||
/// <param name="symbolProperties">The symbol properties for this security</param>
|
||||
/// <param name="baseCurrency">The output base currency</param>
|
||||
/// <param name="quoteCurrency">The output quote currency</param>
|
||||
public static void DecomposeCurrencyPair(Symbol symbol, SymbolProperties symbolProperties, out string baseCurrency, out string quoteCurrency)
|
||||
{
|
||||
quoteCurrency = symbolProperties.QuoteCurrency;
|
||||
if (symbol.Value.EndsWith(quoteCurrency))
|
||||
{
|
||||
baseCurrency = symbol.Value.RemoveFromEnd(quoteCurrency);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"Symbol doesn't end with {quoteCurrency}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the securities symbol
|
||||
/// </summary>
|
||||
public static implicit operator Symbol(Cfd security) => security.Symbol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.Cfd
|
||||
{
|
||||
/// <summary>
|
||||
/// CFD specific caching support
|
||||
/// </summary>
|
||||
/// <remarks>Class is virtually empty and scheduled to be made obsolete. Potentially could be used for user data storage.</remarks>
|
||||
/// <seealso cref="SecurityCache"/>
|
||||
public class CfdCache : SecurityCache
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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.Cfd
|
||||
{
|
||||
/// <summary>
|
||||
/// CFD packet by packet data filtering mechanism for dynamically detecting bad ticks.
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityDataFilter"/>
|
||||
public class CfdDataFilter : SecurityDataFilter
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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.Cfd
|
||||
{
|
||||
/// <summary>
|
||||
/// CFD exchange class - information and helper tools for CFD exchange properties
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityExchange"/>
|
||||
public class CfdExchange : SecurityExchange
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of trading days per year for this security, used for performance statistics.
|
||||
/// </summary>
|
||||
public override int TradingDaysPerYear
|
||||
{
|
||||
// 365 - Saturdays = 313;
|
||||
get { return 313; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CfdExchange"/> class using the specified
|
||||
/// exchange hours to determine open/close times
|
||||
/// </summary>
|
||||
/// <param name="exchangeHours">Contains the weekly exchange schedule plus holidays</param>
|
||||
public CfdExchange(SecurityExchangeHours exchangeHours)
|
||||
: base(exchangeHours)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.Cfd
|
||||
{
|
||||
/// <summary>
|
||||
/// CFD holdings implementation of the base securities class
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityHolding"/>
|
||||
public class CfdHolding : SecurityHolding
|
||||
{
|
||||
/// <summary>
|
||||
/// CFD Holding Class constructor
|
||||
/// </summary>
|
||||
/// <param name="security">The CFD security being held</param>
|
||||
/// <param name="currencyConverter">A currency converter instance</param>
|
||||
public CfdHolding(Cfd security, ICurrencyConverter currencyConverter)
|
||||
: base(security, currencyConverter)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 Python.Runtime;
|
||||
using QuantConnect.Python;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="ISecurityInitializer"/> that executes
|
||||
/// each initializer in order
|
||||
/// </summary>
|
||||
public class CompositeSecurityInitializer : ISecurityInitializer
|
||||
{
|
||||
private readonly List<ISecurityInitializer> _initializers;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of internal security initializers
|
||||
/// </summary>
|
||||
public List<ISecurityInitializer> Initializers => _initializers.ToList();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CompositeSecurityInitializer"/> class
|
||||
/// </summary>
|
||||
/// <param name="initializers">The initializers to execute in order</param>
|
||||
public CompositeSecurityInitializer(params PyObject[] initializers)
|
||||
{
|
||||
_initializers = initializers.Select(x => (ISecurityInitializer)new SecurityInitializerPythonWrapper(x)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CompositeSecurityInitializer"/> class
|
||||
/// </summary>
|
||||
/// <param name="initializers">The initializers to execute in order</param>
|
||||
public CompositeSecurityInitializer(params ISecurityInitializer[] initializers)
|
||||
{
|
||||
_initializers = initializers.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute each of the internally held initializers in sequence
|
||||
/// </summary>
|
||||
/// <param name="security">The security to be initialized</param>
|
||||
public void Initialize(Security security)
|
||||
{
|
||||
foreach (var initializer in _initializers)
|
||||
{
|
||||
initializer.Initialize(security);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new security initializer to this composite initializer
|
||||
/// </summary>
|
||||
/// <param name="initializer">The initializer to add</param>
|
||||
public void AddSecurityInitializer(ISecurityInitializer initializer)
|
||||
{
|
||||
_initializers.Add(initializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Provides an implementation of <see cref="IBuyingPowerModel"/> that uses an absurdly low margin
|
||||
/// requirement to ensure all orders have sufficient margin provided the portfolio is not underwater.
|
||||
/// </summary>
|
||||
public class ConstantBuyingPowerModel : BuyingPowerModel
|
||||
{
|
||||
private readonly decimal _marginRequiredPerUnitInAccountCurrency;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConstantBuyingPowerModel"/> class
|
||||
/// </summary>
|
||||
/// <param name="marginRequiredPerUnitInAccountCurrency">The constant amount of margin required per single unit
|
||||
/// of an asset. Each unit is defined as a quantity of 1 and NOT based on the lot size.</param>
|
||||
public ConstantBuyingPowerModel(decimal marginRequiredPerUnitInAccountCurrency)
|
||||
{
|
||||
_marginRequiredPerUnitInAccountCurrency = marginRequiredPerUnitInAccountCurrency;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the leverage for the applicable securities, i.e, equities
|
||||
/// </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)
|
||||
{
|
||||
// ignored -- reasoning is user has an algorithm that has margin issues and so they quickly swap
|
||||
// this impl in, but their code calls set leverage, they would need to comment that out and such
|
||||
// said another way -- user made the decision to ignore margin/leverage by selecting this model
|
||||
}
|
||||
|
||||
/// <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 provided security and quantity</returns>
|
||||
public override InitialMargin GetInitialMarginRequirement(InitialMarginParameters parameters)
|
||||
{
|
||||
return parameters.Quantity * _marginRequiredPerUnitInAccountCurrency;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin currently allocated to the specified holding
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the security</param>
|
||||
/// <returns>The maintenance margin required for the provided holdings quantity/cost/value</returns>
|
||||
public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters)
|
||||
{
|
||||
return parameters.AbsoluteQuantity * _marginRequiredPerUnitInAccountCurrency;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* 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.Linq;
|
||||
using Python.Runtime;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for contract symbols filtering universes.
|
||||
/// Used by OptionFilterUniverse and FutureFilterUniverse
|
||||
/// </summary>
|
||||
public abstract class ContractSecurityFilterUniverse<T, TData> : IDerivativeSecurityFilterUniverse<TData>
|
||||
where T : ContractSecurityFilterUniverse<T, TData>
|
||||
where TData : IChainUniverseData
|
||||
{
|
||||
private bool _alreadyAppliedTypeFilters;
|
||||
|
||||
private IReadOnlyList<TData> _data;
|
||||
|
||||
/// <summary>
|
||||
/// Defines listed contract types with Flags attribute
|
||||
/// </summary>
|
||||
[Flags]
|
||||
protected enum ContractExpirationType : int
|
||||
{
|
||||
/// <summary>
|
||||
/// Standard contracts
|
||||
/// </summary>
|
||||
Standard = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Non standard weekly contracts
|
||||
/// </summary>
|
||||
Weekly = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default expiration type filter value
|
||||
/// </summary>
|
||||
protected static readonly ContractExpirationType DefaultExpirationType = ContractExpirationType.Standard | ContractExpirationType.Weekly;
|
||||
|
||||
/// <summary>
|
||||
/// Expiration Types allowed through the filter
|
||||
/// Standards only by default
|
||||
/// </summary>
|
||||
protected ContractExpirationType Type { get; set; } = DefaultExpirationType;
|
||||
|
||||
/// <summary>
|
||||
/// The local exchange current time
|
||||
/// </summary>
|
||||
public DateTime LocalTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of contracts in the universe
|
||||
/// </summary>
|
||||
public int Count => _data.Count;
|
||||
|
||||
/// <summary>
|
||||
/// All data in this filter
|
||||
/// Marked internal for use by extensions
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Setting it will also set AllSymbols
|
||||
/// </remarks>
|
||||
internal IReadOnlyList<TData> Data
|
||||
{
|
||||
get
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
set
|
||||
{
|
||||
_data = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All Symbols in this filter
|
||||
/// Marked internal for use by extensions
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Setting it will remove any data that doesn't have a symbol in AllSymbols
|
||||
/// </remarks>
|
||||
internal IEnumerable<Symbol> AllSymbols
|
||||
{
|
||||
get
|
||||
{
|
||||
return _data.Select(x => x.Symbol);
|
||||
}
|
||||
set
|
||||
{
|
||||
// We create a "fake" data instance for each symbol that is not in the data,
|
||||
// so we are polite to the user and keep backwards compatibility
|
||||
_data = value.Select(symbol => _data.FirstOrDefault(x => x.Symbol == symbol) ?? CreateDataInstance(symbol)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs ContractSecurityFilterUniverse
|
||||
/// </summary>
|
||||
protected ContractSecurityFilterUniverse()
|
||||
{
|
||||
Type = DefaultExpirationType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs ContractSecurityFilterUniverse
|
||||
/// </summary>
|
||||
protected ContractSecurityFilterUniverse(IReadOnlyList<TData> allData, DateTime localTime)
|
||||
{
|
||||
Data = allData;
|
||||
LocalTime = localTime;
|
||||
Type = DefaultExpirationType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Function to determine if the given symbol is a standard contract
|
||||
/// </summary>
|
||||
/// <returns>True if standard type</returns>
|
||||
protected abstract bool IsStandard(Symbol symbol);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the data type for the given symbol
|
||||
/// </summary>
|
||||
/// <returns>A data instance for the given symbol</returns>
|
||||
protected abstract TData CreateDataInstance(Symbol symbol);
|
||||
|
||||
/// <summary>
|
||||
/// Returns universe, filtered by contract type
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
internal T ApplyTypesFilter()
|
||||
{
|
||||
if (_alreadyAppliedTypeFilters)
|
||||
{
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
// memoization map for ApplyTypesFilter()
|
||||
var memoizedMap = new Dictionary<DateTime, bool>();
|
||||
|
||||
Func<TData, bool> memoizedIsStandardType = data =>
|
||||
{
|
||||
var dt = data.ID.Date;
|
||||
|
||||
bool result;
|
||||
if (memoizedMap.TryGetValue(dt, out result))
|
||||
return result;
|
||||
var res = IsStandard(data.Symbol);
|
||||
memoizedMap[dt] = res;
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
Data = Data.Where(x =>
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case ContractExpirationType.Weekly:
|
||||
return !memoizedIsStandardType(x);
|
||||
case ContractExpirationType.Standard:
|
||||
return memoizedIsStandardType(x);
|
||||
case ContractExpirationType.Standard | ContractExpirationType.Weekly:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}).ToList();
|
||||
|
||||
_alreadyAppliedTypeFilters = true;
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes this filter universe
|
||||
/// </summary>
|
||||
/// <param name="allData">All data for contracts in the Universe</param>
|
||||
/// <param name="localTime">The local exchange current time</param>
|
||||
public virtual void Refresh(IReadOnlyList<TData> allData, DateTime localTime)
|
||||
{
|
||||
Data = allData;
|
||||
LocalTime = localTime;
|
||||
Type = DefaultExpirationType;
|
||||
_alreadyAppliedTypeFilters = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets universe of standard contracts (if any) as selection
|
||||
/// Contracts by default are standards; only needed to switch back if changed
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T StandardsOnly()
|
||||
{
|
||||
if (_alreadyAppliedTypeFilters)
|
||||
{
|
||||
throw new InvalidOperationException("Type filters have already been applied, " +
|
||||
"please call StandardsOnly() before applying other filters such as FrontMonth() or BackMonths()");
|
||||
}
|
||||
|
||||
Type = ContractExpirationType.Standard;
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Includes universe of non-standard weeklys contracts (if any) into selection
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
[Obsolete("IncludeWeeklys is obsolete because weekly contracts are now included by default.")]
|
||||
public T IncludeWeeklys()
|
||||
{
|
||||
if (_alreadyAppliedTypeFilters)
|
||||
{
|
||||
throw new InvalidOperationException("Type filters have already been applied, " +
|
||||
"please call IncludeWeeklys() before applying other filters such as FrontMonth() or BackMonths()");
|
||||
}
|
||||
|
||||
Type |= ContractExpirationType.Weekly;
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets universe of weeklys contracts (if any) as selection
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T WeeklysOnly()
|
||||
{
|
||||
Type = ContractExpirationType.Weekly;
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns front month contract
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public virtual T FrontMonth()
|
||||
{
|
||||
ApplyTypesFilter();
|
||||
var ordered = Data.OrderBy(x => x.ID.Date).ToList();
|
||||
if (ordered.Count == 0) return (T)this;
|
||||
var frontMonth = ordered.TakeWhile(x => ordered[0].ID.Date == x.ID.Date);
|
||||
|
||||
Data = frontMonth.ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of back month contracts
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public virtual T BackMonths()
|
||||
{
|
||||
ApplyTypesFilter();
|
||||
var ordered = Data.OrderBy(x => x.ID.Date).ToList();
|
||||
if (ordered.Count == 0) return (T)this;
|
||||
var backMonths = ordered.SkipWhile(x => ordered[0].ID.Date == x.ID.Date);
|
||||
|
||||
Data = backMonths.ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns first of back month contracts
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T BackMonth()
|
||||
{
|
||||
return BackMonths().FrontMonth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjust the reference date used for expiration filtering. By default it just returns the same date.
|
||||
/// </summary>
|
||||
/// <param name="referenceDate">The reference date to be adjusted</param>
|
||||
/// <returns>The adjusted date</returns>
|
||||
protected virtual DateTime AdjustExpirationReferenceDate(DateTime referenceDate)
|
||||
{
|
||||
return referenceDate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies filter selecting options contracts based on a range of expiration dates relative to the current day
|
||||
/// </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>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public virtual T Expiration(TimeSpan minExpiry, TimeSpan maxExpiry)
|
||||
{
|
||||
if (LocalTime == default)
|
||||
{
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
if (maxExpiry > Time.MaxTimeSpan) maxExpiry = Time.MaxTimeSpan;
|
||||
|
||||
var referenceDate = AdjustExpirationReferenceDate(LocalTime.Date);
|
||||
|
||||
var minExpiryToDate = referenceDate + minExpiry;
|
||||
var maxExpiryToDate = referenceDate + maxExpiry;
|
||||
|
||||
Data = Data
|
||||
.Where(symbol => symbol.ID.Date.Date >= minExpiryToDate && symbol.ID.Date.Date <= maxExpiryToDate)
|
||||
.ToList();
|
||||
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies filter selecting contracts based on a range of expiration dates relative to the current day
|
||||
/// </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>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Expiration(int minExpiryDays, int maxExpiryDays)
|
||||
{
|
||||
return Expiration(TimeSpan.FromDays(minExpiryDays), TimeSpan.FromDays(maxExpiryDays));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Explicitly sets the selected contract symbols for this universe.
|
||||
/// This overrides and and all other methods of selecting symbols assuming it is called last.
|
||||
/// </summary>
|
||||
/// <param name="contracts">The option contract symbol objects to select</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Contracts(PyObject contracts)
|
||||
{
|
||||
// Let's first check if the object is a selector:
|
||||
if (contracts.TrySafeAs(out Func<IEnumerable<TData>, IEnumerable<Symbol>> contractSelector))
|
||||
{
|
||||
return Contracts(contractSelector);
|
||||
}
|
||||
|
||||
// Else, it should be a list of symbols:
|
||||
return Contracts(contracts.ConvertToSymbolEnumerable());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Explicitly sets the selected contract symbols for this universe.
|
||||
/// This overrides and and all other methods of selecting symbols assuming it is called last.
|
||||
/// </summary>
|
||||
/// <param name="contracts">The option contract symbol objects to select</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Contracts(IEnumerable<Symbol> contracts)
|
||||
{
|
||||
AllSymbols = contracts.ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Explicitly sets the selected contract symbols for this universe.
|
||||
/// This overrides and and all other methods of selecting symbols assuming it is called last.
|
||||
/// </summary>
|
||||
/// <param name="contracts">The option contract symbol objects to select</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Contracts(IEnumerable<TData> contracts)
|
||||
{
|
||||
Data = contracts.ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a function used to filter the set of available contract filters. The input to the 'contractSelector'
|
||||
/// function will be the already filtered list if any other filters have already been applied.
|
||||
/// </summary>
|
||||
/// <param name="contractSelector">The option contract symbol objects to select</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Contracts(Func<IEnumerable<TData>, IEnumerable<Symbol>> contractSelector)
|
||||
{
|
||||
// force materialization using ToList
|
||||
AllSymbols = contractSelector(Data).ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a function used to filter the set of available contract filters. The input to the 'contractSelector'
|
||||
/// function will be the already filtered list if any other filters have already been applied.
|
||||
/// </summary>
|
||||
/// <param name="contractSelector">The option contract symbol objects to select</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Contracts(Func<IEnumerable<TData>, IEnumerable<TData>> contractSelector)
|
||||
{
|
||||
// force materialization using ToList
|
||||
Data = contractSelector(Data).ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instructs the engine to only filter contracts on the first time step of each market day.
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
/// <remarks>Deprecated since filters are always non-dynamic now</remarks>
|
||||
[Obsolete("Deprecated as of 2023-12-13. Filters are always non-dynamic as of now, which means they will only bee applied daily.")]
|
||||
public T OnlyApplyFilterAtMarketOpen()
|
||||
{
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IEnumerable interface method implementation
|
||||
/// </summary>
|
||||
/// <returns>IEnumerator of Symbols in Universe</returns>
|
||||
public IEnumerator<TData> GetEnumerator()
|
||||
{
|
||||
return Data.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IEnumerable interface method implementation
|
||||
/// </summary>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return Data.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Represents common properties for contract-based securities such as options and CFDs
|
||||
/// </summary>
|
||||
public class ContractSymbolProperties : SymbolProperties
|
||||
{
|
||||
/// <summary>
|
||||
/// The contract multiplier for the security.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If manually set by a consumer, this value will be used instead of the
|
||||
/// <see cref="SymbolProperties.ContractMultiplier"/> and also allows to make
|
||||
/// sure it is not overridden when the symbol properties database gets updated.
|
||||
/// </remarks>
|
||||
private decimal? _contractMultiplier;
|
||||
|
||||
/// <summary>
|
||||
/// The contract multiplier for the security
|
||||
/// </summary>
|
||||
public override decimal ContractMultiplier => _contractMultiplier ?? base.ContractMultiplier;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="ContractSymbolProperties"/> class from a <see cref="SymbolProperties"/> instance
|
||||
/// </summary>
|
||||
public ContractSymbolProperties(SymbolProperties properties)
|
||||
: base(properties)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="ContractSymbolProperties"/> class
|
||||
/// </summary>
|
||||
public ContractSymbolProperties(string description, string quoteCurrency, decimal contractMultiplier,
|
||||
decimal minimumPriceVariation, decimal lotSize, string marketTicker,
|
||||
decimal? minimumOrderSize = null, decimal priceMagnifier = 1, decimal strikeMultiplier = 1)
|
||||
: base(description, quoteCurrency, contractMultiplier, minimumPriceVariation, lotSize, marketTicker,
|
||||
minimumOrderSize, priceMagnifier, strikeMultiplier)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a custom contract multiplier that persists through symbol properties database updates
|
||||
/// </summary>
|
||||
internal void SetContractMultiplier(decimal multiplier)
|
||||
{
|
||||
_contractMultiplier = multiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// A cash amount that can easily be converted into account currency
|
||||
/// </summary>
|
||||
public class ConvertibleCashAmount
|
||||
{
|
||||
/// <summary>
|
||||
/// The amount
|
||||
/// </summary>
|
||||
public decimal Amount { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The cash associated with the amount
|
||||
/// </summary>
|
||||
public Cash Cash { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount in account currency
|
||||
/// </summary>
|
||||
public decimal InAccountCurrency => Amount * Cash.ConversionRate;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
public ConvertibleCashAmount (decimal amount, Cash cash)
|
||||
{
|
||||
Amount = amount;
|
||||
Cash = cash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The amount in account currency
|
||||
/// </summary>
|
||||
public static implicit operator decimal(ConvertibleCashAmount convertibleCashAmount)
|
||||
{
|
||||
return convertibleCashAmount.InAccountCurrency;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The amount in account currency
|
||||
/// </summary>
|
||||
public static implicit operator CashAmount(ConvertibleCashAmount convertibleCashAmount)
|
||||
{
|
||||
return new CashAmount(convertibleCashAmount.Amount, convertibleCashAmount.Cash.Symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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.Data;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Orders.Fees;
|
||||
using QuantConnect.Orders.Fills;
|
||||
using QuantConnect.Orders.Slippage;
|
||||
using QuantConnect.Securities.Forex;
|
||||
using System;
|
||||
|
||||
namespace QuantConnect.Securities.Crypto
|
||||
{
|
||||
/// <summary>
|
||||
/// Crypto Security Object Implementation for Crypto Assets
|
||||
/// </summary>
|
||||
/// <seealso cref="Security"/>
|
||||
public class Crypto : Security, IBaseCurrencySymbol
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the currency acquired by going long this currency pair
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, the EUR/USD has a base currency of the euro, and as a result
|
||||
/// of going long the EUR/USD a trader is acquiring euros in exchange for US dollars
|
||||
/// </remarks>
|
||||
public Cash BaseCurrency { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the Crypto 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="baseCurrency">The cash object that represent the base 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 Crypto(SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
Cash baseCurrency,
|
||||
SubscriptionDataConfig config,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes)
|
||||
: base(config,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new CryptoExchange(exchangeHours),
|
||||
new ForexCache(),
|
||||
new SecurityPortfolioModel(),
|
||||
new ImmediateFillModel(),
|
||||
new GDAXFeeModel(),
|
||||
NullSlippageModel.Instance,
|
||||
new ImmediateSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
new CashBuyingPowerModel(),
|
||||
new ForexDataFilter(),
|
||||
new SecurityPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
BaseCurrency = baseCurrency;
|
||||
Holdings = new CryptoHolding(this, currencyConverter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the Crypto security
|
||||
/// </summary>
|
||||
/// <param name="symbol">The security's 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="baseCurrency">The cash object that represent the base 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 <see cref="Security"/> data</param>
|
||||
public Crypto(Symbol symbol,
|
||||
SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
Cash baseCurrency,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes,
|
||||
SecurityCache securityCache)
|
||||
: base(symbol,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new CryptoExchange(exchangeHours),
|
||||
securityCache,
|
||||
new SecurityPortfolioModel(),
|
||||
new ImmediateFillModel(),
|
||||
new GDAXFeeModel(),
|
||||
NullSlippageModel.Instance,
|
||||
new ImmediateSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
new CashBuyingPowerModel(),
|
||||
new ForexDataFilter(),
|
||||
new SecurityPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
BaseCurrency = baseCurrency;
|
||||
Holdings = new CryptoHolding(this, currencyConverter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current value of the security.
|
||||
/// </summary>
|
||||
public override decimal Price => Cache.GetData<TradeBar>()?.Close ?? Cache.Price;
|
||||
|
||||
/// <summary>
|
||||
/// Decomposes the specified currency pair into a base and quote currency provided as out parameters
|
||||
/// </summary>
|
||||
/// <param name="symbol">The input symbol to be decomposed</param>
|
||||
/// <param name="symbolProperties">The symbol properties for this security</param>
|
||||
/// <param name="baseCurrency">The output base currency</param>
|
||||
/// <param name="quoteCurrency">The output quote currency</param>
|
||||
public static void DecomposeCurrencyPair(Symbol symbol, SymbolProperties symbolProperties, out string baseCurrency, out string quoteCurrency)
|
||||
{
|
||||
quoteCurrency = symbolProperties.QuoteCurrency;
|
||||
if (symbol.Value.EndsWith(quoteCurrency))
|
||||
{
|
||||
baseCurrency = symbol.Value.RemoveFromEnd(quoteCurrency);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException($"symbol doesn't end with {quoteCurrency}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the securities symbol
|
||||
/// </summary>
|
||||
public static implicit operator Symbol(Crypto security) => security.Symbol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.Crypto
|
||||
{
|
||||
/// <summary>
|
||||
/// Crypto exchange class - information and helper tools for Crypto exchange properties
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityExchange"/>
|
||||
public class CryptoExchange : SecurityExchange
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CryptoExchange"/> class using market hours
|
||||
/// derived from the market-hours-database for the Crypto market
|
||||
/// </summary>
|
||||
public CryptoExchange(string market)
|
||||
: base(MarketHoursDatabase.FromDataFolder().GetExchangeHours(market, null, SecurityType.Crypto))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CryptoExchange"/> class using the specified
|
||||
/// exchange hours to determine open/close times
|
||||
/// </summary>
|
||||
/// <param name="exchangeHours">Contains the weekly exchange schedule plus holidays</param>
|
||||
public CryptoExchange(SecurityExchangeHours exchangeHours)
|
||||
: base(exchangeHours)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.Crypto
|
||||
{
|
||||
/// <summary>
|
||||
/// Crypto holdings implementation of the base securities class
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityHolding"/>
|
||||
public class CryptoHolding : SecurityHolding
|
||||
{
|
||||
/// <summary>
|
||||
/// Crypto Holding Class
|
||||
/// </summary>
|
||||
/// <param name="security">The Crypto security being held</param>
|
||||
/// <param name="currencyConverter">A currency converter instance</param>
|
||||
public CryptoHolding(Crypto security, ICurrencyConverter currencyConverter)
|
||||
: base(security, currencyConverter)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.CryptoFuture
|
||||
{
|
||||
/// <summary>
|
||||
/// Binance-specific crypto future margin model that includes supplementary stable coin
|
||||
/// currencies as alternative collateral for non-coin (USDⓈ-M) futures.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// EU/EEA users under MiCA Credits Trading Mode have BNFCR in their account.
|
||||
/// When BNFCR is present, this model aggregates all supplementary collateral assets
|
||||
/// using their walletBalance values converted to the primary collateral currency.
|
||||
/// Non-EU accounts don't have BNFCR — the check is a no-op for them.
|
||||
/// See: https://www.binance.com/en/support/faq/detail/0e857c392a2d47cebde0af762d9255ae
|
||||
/// </remarks>
|
||||
public class BinanceCryptoFutureMarginModel : CryptoFutureMarginModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Binance Futures Credits currency symbol, present in EU/EEA accounts under MiCA Credits Trading Mode.
|
||||
/// </summary>
|
||||
private const string BNFCRCurrency = "BNFCR";
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
/// <param name="leverage">The leverage to use, default 25x</param>
|
||||
public BinanceCryptoFutureMarginModel(decimal leverage = 25)
|
||||
: base(leverage)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total collateral amount for a Binance crypto future, including supplementary
|
||||
/// collateral assets for EU/EEA accounts in MiCA Credits Trading Mode.
|
||||
/// For coin futures (e.g. BTCUSD), only the primary collateral (base currency) is used.
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The crypto future security</param>
|
||||
/// <param name="primaryCollateral">The primary collateral cash (e.g. USDT)</param>
|
||||
/// <returns>Total collateral amount in terms of the primary collateral currency</returns>
|
||||
protected override decimal GetTotalCollateralAmount(
|
||||
SecurityPortfolioManager portfolio, Security security, Cash primaryCollateral)
|
||||
{
|
||||
// BNFCR presence means EU/EEA account in MiCA Credits Trading Mode.
|
||||
// Non-EU accounts don't have BNFCR in CashBook — skip entirely.
|
||||
var cashBook = portfolio.CashBook;
|
||||
if (!cashBook.ContainsKey(BNFCRCurrency))
|
||||
{
|
||||
return base.GetTotalCollateralAmount(portfolio, security, primaryCollateral);
|
||||
}
|
||||
|
||||
// Aggregate all collateral assets using walletBalance values.
|
||||
// Binance controls which assets are in the account — we sum everything
|
||||
// with a non-zero balance, converting to the primary collateral currency.
|
||||
// Negative amounts (e.g. BNFCR fees) correctly reduce the total.
|
||||
var total = 0m;
|
||||
foreach (var kvp in cashBook)
|
||||
{
|
||||
var cash = kvp.Value;
|
||||
if (cash.Amount == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
total += cashBook.Convert(cash.Amount, cash.Symbol, primaryCollateral.Symbol);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When BNFCR is present (EU/MiCA mode), all USDⓈ-M futures share the same collateral
|
||||
/// pool regardless of quote currency (USDT, USDC, etc.).
|
||||
/// </summary>
|
||||
protected override bool SharesCollateral(SecurityPortfolioManager portfolio, Cash collateralCurrency, Security otherCryptoFuture)
|
||||
{
|
||||
return portfolio.CashBook.ContainsKey(BNFCRCurrency) || base.SharesCollateral(portfolio, collateralCurrency, otherCryptoFuture);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.Market;
|
||||
|
||||
namespace QuantConnect.Securities.CryptoFuture
|
||||
{
|
||||
/// <summary>
|
||||
/// The responsability of this model is to apply future funding rate cash flows to the portfolio based on open positions
|
||||
/// </summary>
|
||||
public class BinanceFutureMarginInterestRateModel : IMarginInterestRateModel
|
||||
{
|
||||
private DateTime _nextFundingRateApplication = DateTime.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// Apply margin interest rates to the portfolio
|
||||
/// </summary>
|
||||
/// <param name="marginInterestRateParameters">The parameters to use</param>
|
||||
public void ApplyMarginInterestRate(MarginInterestRateParameters marginInterestRateParameters)
|
||||
{
|
||||
var security = marginInterestRateParameters.Security;
|
||||
var time = marginInterestRateParameters.Time;
|
||||
var cryptoFuture = (CryptoFuture)security;
|
||||
if (!cryptoFuture.Invested)
|
||||
{
|
||||
// nothing to do
|
||||
_nextFundingRateApplication = DateTime.MaxValue;
|
||||
return;
|
||||
}
|
||||
else if (_nextFundingRateApplication == DateTime.MaxValue)
|
||||
{
|
||||
// we opened a new position
|
||||
_nextFundingRateApplication = GetNextFundingRateApplication(time);
|
||||
}
|
||||
|
||||
var marginInterest = cryptoFuture.Cache.GetData<MarginInterestRate>();
|
||||
if(marginInterest == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while(time >= _nextFundingRateApplication)
|
||||
{
|
||||
// When the funding rate is positive, the price of the perpetual contract is higher than the mark price,
|
||||
// thus, traders who are long pay for short positions. Conversely, a negative funding rate indicates that perpetual
|
||||
// prices are below the mark price, which means that short positions pay for longs.
|
||||
// Funding Amount = Nominal Value of Positions * Funding Rate
|
||||
|
||||
var holdings = cryptoFuture.Holdings;
|
||||
|
||||
var positionValue = cryptoFuture.Holdings.GetQuantityValue(holdings.Quantity);
|
||||
|
||||
var funding = marginInterest.InterestRate * positionValue.Amount;
|
||||
|
||||
funding *= -1;
|
||||
// '* -1' because:
|
||||
// - we pay when 'funding' positive:
|
||||
// long position & positive rate
|
||||
// short position & negative rate
|
||||
// - we ear when 'funding' negative:
|
||||
// long position & negative rate
|
||||
// short position & positive rate
|
||||
positionValue.Cash.AddAmount(funding);
|
||||
|
||||
_nextFundingRateApplication = GetNextFundingRateApplication(_nextFundingRateApplication);
|
||||
}
|
||||
}
|
||||
|
||||
private static DateTime GetNextFundingRateApplication(DateTime currentTime)
|
||||
{
|
||||
if(currentTime.Hour >= 16)
|
||||
{
|
||||
// tomorrow 00:00
|
||||
return currentTime.Date.AddDays(1);
|
||||
}
|
||||
else if (currentTime.Hour >= 8)
|
||||
{
|
||||
return currentTime.Date.AddHours(16);
|
||||
}
|
||||
else
|
||||
{
|
||||
return currentTime.Date.AddHours(8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.CryptoFuture
|
||||
{
|
||||
/// <summary>
|
||||
/// The responsibility of this model is to apply future funding rate cash flows to the portfolio based on open positions
|
||||
/// </summary>
|
||||
public class BybitFutureMarginInterestRateModel : BinanceFutureMarginInterestRateModel
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Securities.CryptoFuture
|
||||
{
|
||||
/// <summary>
|
||||
/// Crypto Future Security Object Implementation for Crypto Future Assets
|
||||
/// </summary>
|
||||
public class CryptoFuture : Security, IBaseCurrencySymbol
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the currency acquired by going long this currency pair
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, the EUR/USD has a base currency of the euro, and as a result
|
||||
/// of going long the EUR/USD a trader is acquiring euros in exchange for US dollars
|
||||
/// </remarks>
|
||||
public Cash BaseCurrency { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the Crypto Future security
|
||||
/// </summary>
|
||||
/// <param name="symbol">The 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="baseCurrency">The cash object that represent the base 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="cache">The security cache</param>
|
||||
public CryptoFuture(Symbol symbol,
|
||||
SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
Cash baseCurrency,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes,
|
||||
SecurityCache cache)
|
||||
: base(symbol,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new CryptoFutureExchange(exchangeHours),
|
||||
cache,
|
||||
new SecurityPortfolioModel(),
|
||||
new ImmediateFillModel(),
|
||||
IsCryptoCoinFuture(quoteCurrency.Symbol) ? new BinanceCoinFuturesFeeModel() : new BinanceFuturesFeeModel(),
|
||||
NullSlippageModel.Instance,
|
||||
new ImmediateSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
new CryptoFutureMarginModel(),
|
||||
new SecurityDataFilter(),
|
||||
new SecurityPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
// only applies for perpetual futures
|
||||
symbol.ID.Date == SecurityIdentifier.DefaultDate ? new BinanceFutureMarginInterestRateModel() : Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
BaseCurrency = baseCurrency;
|
||||
Holdings = new CryptoFutureHolding(this, currencyConverter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the security is a crypto coin future
|
||||
/// </summary>
|
||||
/// <returns>True if the security is a crypto coin future</returns>
|
||||
public bool IsCryptoCoinFuture()
|
||||
{
|
||||
return IsCryptoCoinFuture(QuoteCurrency.Symbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the security is a crypto coin future
|
||||
/// </summary>
|
||||
/// <param name="quoteCurrency">The security quote currency</param>
|
||||
/// <returns>True if the security is a crypto coin future</returns>
|
||||
private static bool IsCryptoCoinFuture(string quoteCurrency)
|
||||
{
|
||||
return quoteCurrency != "USDT" && quoteCurrency != "BUSD" && quoteCurrency != "USDC";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the securities symbol
|
||||
/// </summary>
|
||||
public static implicit operator Symbol(CryptoFuture security) => security.Symbol;
|
||||
}
|
||||
}
|
||||
@@ -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.CryptoFuture
|
||||
{
|
||||
/// <summary>
|
||||
/// Crypto future exchange class - information and helper tools for Crypto future exchange properties
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityExchange"/>
|
||||
public class CryptoFutureExchange : SecurityExchange
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CryptoFutureExchange"/> class using market hours
|
||||
/// derived from the market-hours-database for the Crypto future market
|
||||
/// </summary>
|
||||
public CryptoFutureExchange(string market)
|
||||
: base(MarketHoursDatabase.FromDataFolder().GetExchangeHours(market, null, SecurityType.CryptoFuture))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CryptoFutureExchange"/> class using the specified
|
||||
/// exchange hours to determine open/close times
|
||||
/// </summary>
|
||||
/// <param name="exchangeHours">Contains the weekly exchange schedule plus holidays</param>
|
||||
public CryptoFutureExchange(SecurityExchangeHours exchangeHours)
|
||||
: base(exchangeHours)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Securities.CryptoFuture
|
||||
{
|
||||
/// <summary>
|
||||
/// Crypto Future holdings implementation of the base securities class
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityHolding"/>
|
||||
public class CryptoFutureHolding : SecurityHolding
|
||||
{
|
||||
/// <summary>
|
||||
/// Crypto Future Holding Class constructor
|
||||
/// </summary>
|
||||
/// <param name="security">The crypto future security being held</param>
|
||||
/// <param name="currencyConverter">A currency converter instance</param>
|
||||
public CryptoFutureHolding(Security security, ICurrencyConverter currencyConverter)
|
||||
: base(security, currencyConverter)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total value of the specified <paramref name="quantity"/> of shares of this security
|
||||
/// in the account currency
|
||||
/// </summary>
|
||||
/// <param name="quantity">The quantity of shares</param>
|
||||
/// <param name="price">The current price</param>
|
||||
/// <returns>The value of the quantity of shares in the account currency</returns>
|
||||
public override ConvertibleCashAmount GetQuantityValue(decimal quantity, decimal price)
|
||||
{
|
||||
if (Symbol.ID.Market == Market.DYDX)
|
||||
{
|
||||
// common math quantity * quote price
|
||||
return base.GetQuantityValue(quantity, price);
|
||||
}
|
||||
var cryptoFuture = (CryptoFuture)Security;
|
||||
|
||||
Cash cash;
|
||||
decimal notionalPositionValue;
|
||||
// We could check quote currency or the contract multiplier being 1
|
||||
if (!cryptoFuture.IsCryptoCoinFuture())
|
||||
{
|
||||
// https://www.binance.com/en/support/faq/how-to-calculate-cost-required-to-open-a-position-in-perpetual-futures-contracts-87fa7ee33b574f7084d42bd2ce2e463b
|
||||
// example BTCUSDT: (9,253.30 * 1 BTC) = 9,253.3 USDT
|
||||
notionalPositionValue = price * quantity * cryptoFuture.SymbolProperties.ContractMultiplier;
|
||||
|
||||
// USDT is the QUOTE currency we will need to convert it into account currency
|
||||
cash = cryptoFuture.QuoteCurrency;
|
||||
}
|
||||
else
|
||||
{
|
||||
// https://www.binance.com/en/support/faq/leverage-and-margin-in-coin-margined-futures-contracts-be2c7d9d95b04a7e8044ed02dd7dfe5c
|
||||
// example BTCUSD: [ (10*100 USD) / 9,800 USD ] = 0.10204 BTC
|
||||
notionalPositionValue = quantity * cryptoFuture.SymbolProperties.ContractMultiplier / price;
|
||||
|
||||
// BTC is the BASE currency we will need to convert it into account currency
|
||||
cash = cryptoFuture.BaseCurrency;
|
||||
}
|
||||
|
||||
return new ConvertibleCashAmount(notionalPositionValue, cash);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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.Linq;
|
||||
using QuantConnect.Orders;
|
||||
|
||||
namespace QuantConnect.Securities.CryptoFuture
|
||||
{
|
||||
/// <summary>
|
||||
/// The crypto future margin model which supports both Coin and USDT futures
|
||||
/// </summary>
|
||||
public class CryptoFutureMarginModel : SecurityMarginModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
/// <param name="leverage">The leverage to use, used on initial margin requirements, default 25x</param>
|
||||
/// <param name="maintenanceMarginRate">The maintenance margin rate, default 5%</param>
|
||||
/// <param name="maintenanceAmount">The maintenance amount which will reduce maintenance margin requirements, default 0</param>
|
||||
[Obsolete("This constructor is deprecated, please use the overload without maintenanceMarginRate and maintenanceAmount parameters.")]
|
||||
public CryptoFutureMarginModel(decimal leverage, decimal maintenanceMarginRate = 0.05m, decimal maintenanceAmount = 0)
|
||||
: base(leverage, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
/// <param name="leverage">The leverage to use, used on initial margin requirements, default 25x</param>
|
||||
public CryptoFutureMarginModel(decimal leverage = 25)
|
||||
: base(leverage, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters)
|
||||
{
|
||||
return new MaintenanceMargin(GetInitialMarginRequirement(new InitialMarginParameters(parameters.Security, parameters.Quantity)));
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public override InitialMargin GetInitialMarginRequirement(InitialMarginParameters parameters)
|
||||
{
|
||||
var security = parameters.Security;
|
||||
var quantity = parameters.Quantity;
|
||||
if (security?.GetLastData() == null || quantity == 0m)
|
||||
{
|
||||
return InitialMargin.Zero;
|
||||
}
|
||||
|
||||
var positionValue = security.Holdings.GetQuantityValue(quantity, security.Price);
|
||||
var marginRequirementInCollateral = Math.Abs(positionValue.Amount) / GetLeverage(security);
|
||||
|
||||
return new InitialMargin(marginRequirementInCollateral * positionValue.Cash.ConversionRate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin cash available for a trade
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The security to be traded</param>
|
||||
/// <param name="direction">The direction of the trade</param>
|
||||
/// <returns>The margin available for the trade</returns>
|
||||
/// <remarks>What we do specially here is that instead of using the total portfolio value as potential margin remaining we only consider the collateral currency</remarks>
|
||||
protected override decimal GetMarginRemaining(SecurityPortfolioManager portfolio, Security security, OrderDirection direction)
|
||||
{
|
||||
var collateralCurrency = GetCollateralCash(security);
|
||||
var totalCollateralCurrency = GetTotalCollateralAmount(portfolio, security, collateralCurrency);
|
||||
var result = totalCollateralCurrency;
|
||||
|
||||
foreach (var kvp in portfolio.Where(holdings => holdings.Value.Invested && holdings.Value.Type == SecurityType.CryptoFuture && holdings.Value.Symbol != security.Symbol))
|
||||
{
|
||||
var otherCryptoFuture = portfolio.Securities[kvp.Key];
|
||||
// check if we share the collateral
|
||||
if (SharesCollateral(portfolio, collateralCurrency, otherCryptoFuture))
|
||||
{
|
||||
// we reduce the available collateral based on total usage of all other positions too
|
||||
result -= otherCryptoFuture.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForCurrentHoldings(otherCryptoFuture));
|
||||
}
|
||||
}
|
||||
|
||||
if (direction != OrderDirection.Hold)
|
||||
{
|
||||
var holdings = security.Holdings;
|
||||
//If the order is in the same direction as holdings, our remaining cash is our cash
|
||||
//In the opposite direction, our remaining cash is 2 x current value of assets + our cash
|
||||
if (holdings.IsLong)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case OrderDirection.Sell:
|
||||
result +=
|
||||
// portion of margin to close the existing position
|
||||
this.GetMaintenanceMargin(security) +
|
||||
// portion of margin to open the new position
|
||||
this.GetInitialMarginRequirement(security, security.Holdings.AbsoluteQuantity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (holdings.IsShort)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case OrderDirection.Buy:
|
||||
result +=
|
||||
// portion of margin to close the existing position
|
||||
this.GetMaintenanceMargin(security) +
|
||||
// portion of margin to open the new position
|
||||
this.GetInitialMarginRequirement(security, security.Holdings.AbsoluteQuantity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result -= totalCollateralCurrency * RequiredFreeBuyingPowerPercent;
|
||||
// convert into account currency
|
||||
result *= collateralCurrency.ConversionRate;
|
||||
return result < 0 ? 0 : result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the given security shares collateral with another crypto future.
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="collateralCurrency">The collateral cash for the current security</param>
|
||||
/// <param name="otherCryptoFuture">The other crypto future security to check</param>
|
||||
/// <returns>True if both securities share the same collateral</returns>
|
||||
protected virtual bool SharesCollateral(SecurityPortfolioManager portfolio, Cash collateralCurrency, Security otherCryptoFuture)
|
||||
{
|
||||
return collateralCurrency == GetCollateralCash(otherCryptoFuture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to determine what's the collateral currency for the given crypto future
|
||||
/// </summary>
|
||||
private static Cash GetCollateralCash(Security security)
|
||||
{
|
||||
var cryptoFuture = (CryptoFuture)security;
|
||||
|
||||
var collateralCurrency = cryptoFuture.BaseCurrency;
|
||||
if (!cryptoFuture.IsCryptoCoinFuture())
|
||||
{
|
||||
collateralCurrency = cryptoFuture.QuoteCurrency;
|
||||
}
|
||||
|
||||
return collateralCurrency;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total collateral amount for the given crypto future position.
|
||||
/// The base implementation returns only the primary collateral amount.
|
||||
/// Override in subclasses to include supplementary collateral currencies.
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The crypto future security</param>
|
||||
/// <param name="primaryCollateral">The primary collateral cash (e.g. USDT for non-coin futures, BTC for coin futures)</param>
|
||||
/// <returns>Total collateral amount in terms of the primary collateral currency</returns>
|
||||
protected virtual decimal GetTotalCollateralAmount(SecurityPortfolioManager portfolio, Security security, Cash primaryCollateral)
|
||||
{
|
||||
return primaryCollateral.Amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.CryptoFuture
|
||||
{
|
||||
/// <summary>
|
||||
/// The responsibility of this model is to apply future funding rate cash flows to the portfolio based on open positions
|
||||
/// </summary>
|
||||
public class dYdXFutureMarginInterestRateModel : BinanceFutureMarginInterestRateModel
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.CurrencyConversion
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="ICurrencyConversion"/> with a fixed conversion rate
|
||||
/// </summary>
|
||||
public class ConstantCurrencyConversion : ICurrencyConversion
|
||||
{
|
||||
private decimal _conversionRate;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the conversion rate is updated
|
||||
/// </summary>
|
||||
public event EventHandler<decimal> ConversionRateUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// The currency this conversion converts from
|
||||
/// </summary>
|
||||
public string SourceCurrency { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The currency this conversion converts to
|
||||
/// </summary>
|
||||
public string DestinationCurrency { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The current conversion rate
|
||||
/// </summary>
|
||||
public decimal ConversionRate
|
||||
{
|
||||
get
|
||||
{
|
||||
return _conversionRate;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_conversionRate != value)
|
||||
{
|
||||
// only update if there was actually one
|
||||
_conversionRate = value;
|
||||
ConversionRateUpdated?.Invoke(this, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The securities which the conversion rate is based on
|
||||
/// </summary>
|
||||
public IEnumerable<Security> ConversionRateSecurities => Enumerable.Empty<Security>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConstantCurrencyConversion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sourceCurrency">The currency this conversion converts from</param>
|
||||
/// <param name="destinationCurrency">The currency this conversion converts to</param>
|
||||
/// <param name="conversionRate">The conversion rate between the currencies</param>
|
||||
public ConstantCurrencyConversion(string sourceCurrency, string destinationCurrency, decimal conversionRate = 1m)
|
||||
{
|
||||
SourceCurrency = sourceCurrency;
|
||||
DestinationCurrency = destinationCurrency;
|
||||
ConversionRate = conversionRate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks the conversion rate as potentially outdated, needing an update based on the latest data
|
||||
/// </summary>
|
||||
/// <remarks>This conversion is not based on securities, so we don't really need an update</remarks>
|
||||
public void Update()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new identity conversion, where the conversion rate is set to 1 and the source and destination currencies might the same
|
||||
/// </summary>
|
||||
/// <param name="sourceCurrency">The currency this conversion converts from</param>
|
||||
/// <param name="destinationCurrency">The currency this conversion converts to. If null, the destination and source currencies are the same</param>
|
||||
/// <returns>The identity currency conversion</returns>
|
||||
public static ConstantCurrencyConversion Identity(string sourceCurrency, string destinationCurrency = null)
|
||||
{
|
||||
return new ConstantCurrencyConversion(sourceCurrency, destinationCurrency ?? sourceCurrency);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of <see cref="ConstantCurrencyConversion"/> that represents a null conversion
|
||||
/// </summary>
|
||||
public static ConstantCurrencyConversion Null(string sourceCurrency, string destinationCurrency)
|
||||
{
|
||||
return new ConstantCurrencyConversion(sourceCurrency, destinationCurrency, 0m);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Securities.CurrencyConversion
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a type capable of calculating the conversion rate between two currencies
|
||||
/// </summary>
|
||||
public interface ICurrencyConversion
|
||||
{
|
||||
/// <summary>
|
||||
/// Event fired when the conversion rate is updated
|
||||
/// </summary>
|
||||
event EventHandler<decimal> ConversionRateUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// The currency this conversion converts from
|
||||
/// </summary>
|
||||
string SourceCurrency { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The currency this conversion converts to
|
||||
/// </summary>
|
||||
string DestinationCurrency { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The current conversion rate between <see cref="SourceCurrency"/> and <see cref="DestinationCurrency"/>
|
||||
/// </summary>
|
||||
decimal ConversionRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The securities which the conversion rate is based on
|
||||
/// </summary>
|
||||
IEnumerable<Security> ConversionRateSecurities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates the internal conversion rate based on the latest data, and returns the new conversion rate
|
||||
/// </summary>
|
||||
/// <returns>The new conversion rate</returns>
|
||||
void Update();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
|
||||
/*
|
||||
* 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.Util;
|
||||
|
||||
namespace QuantConnect.Securities.CurrencyConversion
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="ICurrencyConversion"/> to find and use multi-leg currency conversions
|
||||
/// </summary>
|
||||
public class SecurityCurrencyConversion : ICurrencyConversion
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that holds the information of a single step in a multi-leg currency conversion
|
||||
/// </summary>
|
||||
private class Step
|
||||
{
|
||||
/// <summary>
|
||||
/// The security used in this conversion step
|
||||
/// </summary>
|
||||
public Security RateSecurity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the price of the security must be inverted in the conversion
|
||||
/// </summary>
|
||||
public bool Inverted { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Step"/> class
|
||||
/// </summary>
|
||||
/// <param name="rateSecurity">The security to use in this currency conversion step</param>
|
||||
/// <param name="inverted">Whether the price of the security should be inverted in the conversion</param>
|
||||
public Step(Security rateSecurity, bool inverted)
|
||||
{
|
||||
RateSecurity = rateSecurity;
|
||||
Inverted = inverted;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<Step> _steps;
|
||||
|
||||
private decimal _conversionRate;
|
||||
private bool _conversionRateNeedsUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the conversion rate is updated
|
||||
/// </summary>
|
||||
public event EventHandler<decimal> ConversionRateUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// The currency this conversion converts from
|
||||
/// </summary>
|
||||
public string SourceCurrency { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The currency this conversion converts to
|
||||
/// </summary>
|
||||
public string DestinationCurrency { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The current conversion rate
|
||||
/// </summary>
|
||||
public decimal ConversionRate
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_conversionRateNeedsUpdate)
|
||||
{
|
||||
var newConversionRate = 1m;
|
||||
var stepWithoutDataFound = false;
|
||||
|
||||
_steps.ForEach(step =>
|
||||
{
|
||||
if (stepWithoutDataFound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var lastData = step.RateSecurity.GetLastData();
|
||||
if (lastData == null || lastData.Price == 0m)
|
||||
{
|
||||
newConversionRate = 0m;
|
||||
stepWithoutDataFound = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (step.Inverted)
|
||||
{
|
||||
newConversionRate /= lastData.Price;
|
||||
}
|
||||
else
|
||||
{
|
||||
newConversionRate *= lastData.Price;
|
||||
}
|
||||
});
|
||||
|
||||
_conversionRateNeedsUpdate = false;
|
||||
_conversionRate = newConversionRate;
|
||||
ConversionRateUpdated?.Invoke(this, _conversionRate);
|
||||
}
|
||||
|
||||
return _conversionRate;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_conversionRate != value)
|
||||
{
|
||||
// only update if there was actually one
|
||||
_conversionRate = value;
|
||||
_conversionRateNeedsUpdate = false;
|
||||
ConversionRateUpdated?.Invoke(this, _conversionRate);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The securities which the conversion rate is based on
|
||||
/// </summary>
|
||||
public IEnumerable<Security> ConversionRateSecurities => _steps.Select(step => step.RateSecurity);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SecurityCurrencyConversion"/> class.
|
||||
/// This constructor is intentionally private as only <see cref="LinearSearch"/> is supposed to create it.
|
||||
/// </summary>
|
||||
/// <param name="sourceCurrency">The currency this conversion converts from</param>
|
||||
/// <param name="destinationCurrency">The currency this conversion converts to</param>
|
||||
/// <param name="steps">The steps between sourceCurrency and destinationCurrency</param>
|
||||
private SecurityCurrencyConversion(string sourceCurrency, string destinationCurrency, List<Step> steps)
|
||||
{
|
||||
SourceCurrency = sourceCurrency;
|
||||
DestinationCurrency = destinationCurrency;
|
||||
|
||||
_steps = steps;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signals an updates to the internal conversion rate based on the latest data.
|
||||
/// It will set the conversion rate as potentially outdated so it gets re-calculated.
|
||||
/// </summary>
|
||||
public void Update()
|
||||
{
|
||||
_conversionRateNeedsUpdate = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a conversion between two currencies by looking through all available 1 and 2-leg options
|
||||
/// </summary>
|
||||
/// <param name="sourceCurrency">The currency to convert from</param>
|
||||
/// <param name="destinationCurrency">The currency to convert to</param>
|
||||
/// <param name="existingSecurities">The securities which are already added to the algorithm</param>
|
||||
/// <param name="potentialSymbols">The symbols to consider, may overlap with existingSecurities</param>
|
||||
/// <param name="makeNewSecurity">The function to call when a symbol becomes part of the conversion, must return the security that will provide price data about the symbol</param>
|
||||
/// <returns>A new <see cref="SecurityCurrencyConversion"/> instance representing the conversion from sourceCurrency to destinationCurrency</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when no conversion from sourceCurrency to destinationCurrency can be found</exception>
|
||||
public static SecurityCurrencyConversion LinearSearch(
|
||||
string sourceCurrency,
|
||||
string destinationCurrency,
|
||||
IList<Security> existingSecurities,
|
||||
IEnumerable<Symbol> potentialSymbols,
|
||||
Func<Symbol, Security> makeNewSecurity)
|
||||
{
|
||||
var allSymbols = existingSecurities.Select(sec => sec.Symbol).Concat(potentialSymbols)
|
||||
.Where(CurrencyPairUtil.IsDecomposable)
|
||||
.ToList();
|
||||
|
||||
var securitiesBySymbol = existingSecurities.Aggregate(new Dictionary<Symbol, Security>(),
|
||||
(mapping, security) =>
|
||||
{
|
||||
if (!mapping.ContainsKey(security.Symbol))
|
||||
{
|
||||
mapping[security.Symbol] = security;
|
||||
}
|
||||
|
||||
return mapping;
|
||||
});
|
||||
|
||||
// Search for 1 leg conversions
|
||||
foreach (var potentialConversionRateSymbol in allSymbols)
|
||||
{
|
||||
var leg1Match = potentialConversionRateSymbol.ComparePair(sourceCurrency, destinationCurrency);
|
||||
if (leg1Match == CurrencyPairUtil.Match.NoMatch)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var inverted = leg1Match == CurrencyPairUtil.Match.InverseMatch;
|
||||
|
||||
return new SecurityCurrencyConversion(sourceCurrency, destinationCurrency, new List<Step>(1)
|
||||
{
|
||||
CreateStep(potentialConversionRateSymbol, inverted, securitiesBySymbol, makeNewSecurity)
|
||||
});
|
||||
}
|
||||
|
||||
// Search for 2 leg conversions
|
||||
foreach (var potentialConversionRateSymbol1 in allSymbols)
|
||||
{
|
||||
var middleCurrency = potentialConversionRateSymbol1.CurrencyPairDual(sourceCurrency);
|
||||
if (middleCurrency == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var potentialConversionRateSymbol2 in allSymbols)
|
||||
{
|
||||
var leg2Match = potentialConversionRateSymbol2.ComparePair(middleCurrency, destinationCurrency);
|
||||
if (leg2Match == CurrencyPairUtil.Match.NoMatch)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var secondStepInverted = leg2Match == CurrencyPairUtil.Match.InverseMatch;
|
||||
|
||||
var steps = new List<Step>(2);
|
||||
|
||||
// Step 1
|
||||
string baseCurrency;
|
||||
string quoteCurrency;
|
||||
|
||||
CurrencyPairUtil.DecomposeCurrencyPair(
|
||||
potentialConversionRateSymbol1,
|
||||
out baseCurrency,
|
||||
out quoteCurrency);
|
||||
|
||||
steps.Add(CreateStep(potentialConversionRateSymbol1,
|
||||
sourceCurrency == quoteCurrency,
|
||||
securitiesBySymbol,
|
||||
makeNewSecurity));
|
||||
|
||||
// Step 2
|
||||
steps.Add(CreateStep(potentialConversionRateSymbol2,
|
||||
secondStepInverted,
|
||||
securitiesBySymbol,
|
||||
makeNewSecurity));
|
||||
|
||||
return new SecurityCurrencyConversion(sourceCurrency, destinationCurrency, steps);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException(
|
||||
$"No conversion path found between source currency {sourceCurrency} and destination currency {destinationCurrency}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new step
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol of the step</param>
|
||||
/// <param name="inverted">Whether the step is inverted or not</param>
|
||||
/// <param name="existingSecurities">The existing securities, which are preferred over creating new ones</param>
|
||||
/// <param name="makeNewSecurity">The function to call when a new security must be created</param>
|
||||
private static Step CreateStep(
|
||||
Symbol symbol,
|
||||
bool inverted,
|
||||
IDictionary<Symbol, Security> existingSecurities,
|
||||
Func<Symbol, Security> makeNewSecurity)
|
||||
{
|
||||
Security security;
|
||||
if (existingSecurities.TryGetValue(symbol, out security))
|
||||
{
|
||||
return new Step(security, inverted);
|
||||
}
|
||||
|
||||
return new Step(makeNewSecurity(symbol), inverted);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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;
|
||||
using QuantConnect.Orders;
|
||||
using QuantConnect.Securities.Positions;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the model responsible for picking which orders should be executed during a margin call
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a default implementation that orders the generated margin call orders by the unrealized
|
||||
/// profit (losers first) and executes each order synchronously until we're within the margin requirements
|
||||
/// </remarks>
|
||||
public class DefaultMarginCallModel : IMarginCallModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The percent margin buffer to use when checking whether the total margin used is
|
||||
/// above the total portfolio value to generate margin call orders
|
||||
/// </summary>
|
||||
private readonly decimal _marginBuffer;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the portfolio that margin calls will be transacted against
|
||||
/// </summary>
|
||||
protected SecurityPortfolioManager Portfolio { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default order properties to be used in margin call orders
|
||||
/// </summary>
|
||||
protected IOrderProperties DefaultOrderProperties { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DefaultMarginCallModel"/> class
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The portfolio object to receive margin calls</param>
|
||||
/// <param name="defaultOrderProperties">The default order properties to be used in margin call orders</param>
|
||||
/// <param name="marginBuffer">
|
||||
/// The percent margin buffer to use when checking whether the total margin used is
|
||||
/// above the total portfolio value to generate margin call orders
|
||||
/// </param>
|
||||
public DefaultMarginCallModel(SecurityPortfolioManager portfolio, IOrderProperties defaultOrderProperties, decimal marginBuffer = 0.10m)
|
||||
{
|
||||
Portfolio = portfolio;
|
||||
DefaultOrderProperties = defaultOrderProperties;
|
||||
_marginBuffer = marginBuffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan the portfolio and the updated data for a potential margin call situation which may get the holdings below zero!
|
||||
/// If there is a margin call, liquidate the portfolio immediately before the portfolio gets sub zero.
|
||||
/// </summary>
|
||||
/// <param name="issueMarginCallWarning">Set to true if a warning should be issued to the algorithm</param>
|
||||
/// <returns>True for a margin call on the holdings.</returns>
|
||||
public List<SubmitOrderRequest> GetMarginCallOrders(out bool issueMarginCallWarning)
|
||||
{
|
||||
issueMarginCallWarning = false;
|
||||
|
||||
var totalMarginUsed = Portfolio.TotalMarginUsed;
|
||||
|
||||
// don't issue a margin call if we're not using margin
|
||||
if (totalMarginUsed <= 0)
|
||||
{
|
||||
return new List<SubmitOrderRequest>();
|
||||
}
|
||||
|
||||
var totalPortfolioValue = Portfolio.TotalPortfolioValue;
|
||||
var marginRemaining = Portfolio.GetMarginRemaining(totalPortfolioValue);
|
||||
|
||||
// issue a margin warning when we're down to 5% margin remaining
|
||||
if (marginRemaining <= totalPortfolioValue * 0.05m)
|
||||
{
|
||||
issueMarginCallWarning = true;
|
||||
}
|
||||
|
||||
// generate a listing of margin call orders
|
||||
var marginCallOrders = new List<SubmitOrderRequest>();
|
||||
|
||||
// if we still have margin remaining then there's no need for a margin call
|
||||
if (marginRemaining <= 0)
|
||||
{
|
||||
if (totalMarginUsed > totalPortfolioValue * (1 + _marginBuffer))
|
||||
{
|
||||
foreach (var positionGroup in Portfolio.Positions.Groups)
|
||||
{
|
||||
var positionMarginCallOrders = GenerateMarginCallOrders(
|
||||
new MarginCallOrdersParameters(positionGroup, totalPortfolioValue, totalMarginUsed)).ToList();
|
||||
if (positionMarginCallOrders.Count > 0 && positionMarginCallOrders.All(x => x.Quantity != 0))
|
||||
{
|
||||
marginCallOrders.AddRange(positionMarginCallOrders);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issueMarginCallWarning = marginCallOrders.Count > 0;
|
||||
}
|
||||
|
||||
return marginCallOrders;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a new order for the specified security taking into account the total margin
|
||||
/// used by the account. Returns null when no margin call is to be issued.
|
||||
/// </summary>
|
||||
/// <param name="parameters">The set of parameters required to generate the margin call orders</param>
|
||||
/// <returns>An order object representing a liquidation order to be executed to bring the account within margin requirements</returns>
|
||||
protected virtual IEnumerable<SubmitOrderRequest> GenerateMarginCallOrders(MarginCallOrdersParameters parameters)
|
||||
{
|
||||
var positionGroup = parameters.PositionGroup;
|
||||
if (positionGroup.Positions.Any(position => Portfolio.Securities[position.Symbol].QuoteCurrency.ConversionRate == 0))
|
||||
{
|
||||
// check for div 0 - there's no conv rate, so we can't place an order
|
||||
return Enumerable.Empty<SubmitOrderRequest>();
|
||||
}
|
||||
|
||||
// compute the amount of quote currency we need to liquidate in order to get within margin requirements
|
||||
var deltaAccountCurrency = parameters.TotalUsedMargin - parameters.TotalPortfolioValue;
|
||||
|
||||
var currentlyUsedBuyingPower = positionGroup.BuyingPowerModel.GetReservedBuyingPowerForPositionGroup(Portfolio, positionGroup);
|
||||
|
||||
// if currentlyUsedBuyingPower > deltaAccountCurrency, means we can keep using the diff in buying power
|
||||
var buyingPowerToKeep = Math.Max(0, currentlyUsedBuyingPower - deltaAccountCurrency);
|
||||
|
||||
// we want a reduction so we send the inverse side of our position
|
||||
var deltaBuyingPower = (currentlyUsedBuyingPower - buyingPowerToKeep) * -Math.Sign(positionGroup.Quantity);
|
||||
|
||||
var result = positionGroup.BuyingPowerModel.GetMaximumLotsForDeltaBuyingPower(new GetMaximumLotsForDeltaBuyingPowerParameters(
|
||||
Portfolio, positionGroup, deltaBuyingPower,
|
||||
// margin is negative, we need to reduce positions, no minimum
|
||||
minimumOrderMarginPortfolioPercentage: 0
|
||||
));
|
||||
|
||||
var absQuantity = Math.Abs(result.NumberOfLots);
|
||||
var orderType = positionGroup.Count > 1 ? OrderType.ComboMarket : OrderType.Market;
|
||||
|
||||
GroupOrderManager groupOrderManager = null;
|
||||
if (orderType == OrderType.ComboMarket)
|
||||
{
|
||||
groupOrderManager = new GroupOrderManager(Portfolio.Transactions.GetIncrementGroupOrderManagerId(), positionGroup.Count,
|
||||
absQuantity);
|
||||
}
|
||||
|
||||
return positionGroup.Positions.Select(position =>
|
||||
{
|
||||
var security = Portfolio.Securities[position.Symbol];
|
||||
// Always reducing, so we take the absolute quantity times the opposite sign of the position
|
||||
var legQuantity = absQuantity * position.UnitQuantity * -Math.Sign(position.Quantity);
|
||||
|
||||
return new SubmitOrderRequest(
|
||||
orderType,
|
||||
security.Type,
|
||||
security.Symbol,
|
||||
legQuantity.GetOrderLegGroupQuantity(groupOrderManager),
|
||||
0,
|
||||
0,
|
||||
security.LocalTime.ConvertToUtc(security.Exchange.TimeZone),
|
||||
Messages.DefaultMarginCallModel.MarginCallOrderTag,
|
||||
DefaultOrderProperties?.Clone(),
|
||||
groupOrderManager);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes synchronous orders to bring the account within margin requirements.
|
||||
/// </summary>
|
||||
/// <param name="generatedMarginCallOrders">These are the margin call orders that were generated
|
||||
/// by individual security margin models.</param>
|
||||
/// <returns>The list of orders that were actually executed</returns>
|
||||
public virtual List<OrderTicket> ExecuteMarginCall(IEnumerable<SubmitOrderRequest> generatedMarginCallOrders)
|
||||
{
|
||||
// if our margin used is back under the portfolio value then we can stop liquidating
|
||||
if (Portfolio.MarginRemaining >= 0)
|
||||
{
|
||||
return new List<OrderTicket>();
|
||||
}
|
||||
|
||||
// order by losers first
|
||||
var executedOrders = new List<OrderTicket>();
|
||||
var ordersWithSecurities = generatedMarginCallOrders.ToDictionary(x => x, x => Portfolio[x.Symbol]);
|
||||
var groupManagerTemporalIds = -ordersWithSecurities.Count;
|
||||
var orderedByLosers = ordersWithSecurities
|
||||
// group orders by their group manager id so they are executed together
|
||||
.GroupBy(x => x.Key.GroupOrderManager?.Id ?? groupManagerTemporalIds++)
|
||||
.OrderBy(x => x.Sum(kvp => kvp.Value.UnrealizedProfit))
|
||||
.Select(x => x.Select(kvp => kvp.Key));
|
||||
foreach (var requests in orderedByLosers)
|
||||
{
|
||||
var tickets = new List<OrderTicket>();
|
||||
foreach (var request in requests)
|
||||
{
|
||||
tickets.Add(Portfolio.Transactions.AddOrder(request));
|
||||
}
|
||||
|
||||
foreach (var ticket in tickets)
|
||||
{
|
||||
if (ticket.Status.IsOpen())
|
||||
{
|
||||
Portfolio.Transactions.WaitForOrder(ticket.OrderId);
|
||||
}
|
||||
executedOrders.Add(ticket);
|
||||
}
|
||||
|
||||
// if our margin used is back under the portfolio value then we can stop liquidating
|
||||
if (Portfolio.MarginRemaining >= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return executedOrders;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 System.Linq;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the model responsible for applying cash settlement rules
|
||||
/// </summary>
|
||||
/// <remarks>This model applies cash settlement after T+N days</remarks>
|
||||
public class DelayedSettlementModel : ISettlementModel
|
||||
{
|
||||
private readonly int _numberOfDays;
|
||||
private readonly TimeSpan _timeOfDay;
|
||||
private CashBook _cashBook;
|
||||
|
||||
/// <summary>
|
||||
/// The list of pending funds waiting for settlement time
|
||||
/// </summary>
|
||||
private readonly Queue<UnsettledCashAmount> _unsettledCashAmounts;
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="DelayedSettlementModel"/> class
|
||||
/// </summary>
|
||||
/// <param name="numberOfDays">The number of days required for settlement</param>
|
||||
/// <param name="timeOfDay">The time of day used for settlement</param>
|
||||
public DelayedSettlementModel(int numberOfDays, TimeSpan timeOfDay)
|
||||
{
|
||||
_timeOfDay = timeOfDay;
|
||||
_numberOfDays = numberOfDays;
|
||||
_unsettledCashAmounts = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies cash settlement rules
|
||||
/// </summary>
|
||||
/// <param name="applyFundsParameters">The funds application parameters</param>
|
||||
public void ApplyFunds(ApplyFundsSettlementModelParameters applyFundsParameters)
|
||||
{
|
||||
var currency = applyFundsParameters.CashAmount.Currency;
|
||||
var amount = applyFundsParameters.CashAmount.Amount;
|
||||
var security = applyFundsParameters.Security;
|
||||
var portfolio = applyFundsParameters.Portfolio;
|
||||
if (amount > 0)
|
||||
{
|
||||
// positive amount: sell order filled
|
||||
|
||||
portfolio.UnsettledCashBook[currency].AddAmount(amount);
|
||||
|
||||
// find the correct settlement date (usually T+3 or T+1)
|
||||
var settlementDate = applyFundsParameters.UtcTime.ConvertFromUtc(security.Exchange.TimeZone).Date;
|
||||
for (var i = 0; i < _numberOfDays; i++)
|
||||
{
|
||||
settlementDate = settlementDate.AddDays(1);
|
||||
|
||||
// only count days when market is open
|
||||
if (!security.Exchange.Hours.IsDateOpen(settlementDate))
|
||||
i--;
|
||||
}
|
||||
|
||||
// use correct settlement time
|
||||
var settlementTimeUtc = settlementDate.Add(_timeOfDay).ConvertToUtc(security.Exchange.Hours.TimeZone);
|
||||
|
||||
lock (_unsettledCashAmounts)
|
||||
{
|
||||
_unsettledCashAmounts.Enqueue(new UnsettledCashAmount(settlementTimeUtc, currency, amount));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// negative amount: buy order filled
|
||||
|
||||
portfolio.CashBook[currency].AddAmount(amount);
|
||||
}
|
||||
|
||||
// We just keep it to use currency conversion in GetUnsettledCash method
|
||||
if (_cashBook == null)
|
||||
{
|
||||
_cashBook = portfolio.UnsettledCashBook;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scan for pending settlements
|
||||
/// </summary>
|
||||
/// <param name="settlementParameters">The settlement parameters</param>
|
||||
public void Scan(ScanSettlementModelParameters settlementParameters)
|
||||
{
|
||||
lock (_unsettledCashAmounts)
|
||||
{
|
||||
while (_unsettledCashAmounts.TryPeek(out var item)
|
||||
// check if settlement time has passed
|
||||
&& settlementParameters.UtcTime >= item.SettlementTimeUtc)
|
||||
{
|
||||
// remove item from unsettled funds list
|
||||
_unsettledCashAmounts.Dequeue();
|
||||
|
||||
// update unsettled cashbook
|
||||
settlementParameters.Portfolio.UnsettledCashBook[item.Currency].AddAmount(-item.Amount);
|
||||
|
||||
// update settled cashbook
|
||||
settlementParameters.Portfolio.CashBook[item.Currency].AddAmount(item.Amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unsettled cash amount for the security
|
||||
/// </summary>
|
||||
public CashAmount GetUnsettledCash()
|
||||
{
|
||||
var accountCurrency = _cashBook != null ? _cashBook.AccountCurrency : Currencies.USD;
|
||||
|
||||
lock (_unsettledCashAmounts)
|
||||
{
|
||||
if (_unsettledCashAmounts.Count == 0)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return new CashAmount(_unsettledCashAmounts.Sum(x => _cashBook.ConvertToAccountCurrency(x.Amount, x.Currency)), accountCurrency);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Data;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to a security's data via it's type. This implementation supports dynamic access
|
||||
/// by type name.
|
||||
/// </summary>
|
||||
public class DynamicSecurityData : IDynamicMetaObjectProvider
|
||||
{
|
||||
private static readonly MethodInfo SetPropertyMethodInfo = typeof(DynamicSecurityData).GetMethod("SetProperty");
|
||||
private static readonly MethodInfo GetPropertyMethodInfo = typeof(DynamicSecurityData).GetMethod("GetProperty");
|
||||
|
||||
private readonly IRegisteredSecurityDataTypesProvider _registeredTypes;
|
||||
private readonly ConcurrentDictionary<Type, Type> _genericTypes = new ConcurrentDictionary<Type, Type>();
|
||||
private readonly SecurityCache _cache;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DynamicSecurityData"/> class
|
||||
/// </summary>
|
||||
/// <param name="registeredTypes">Provides all the registered data types for the algorithm</param>
|
||||
/// <param name="cache">The security cache</param>
|
||||
public DynamicSecurityData(IRegisteredSecurityDataTypesProvider registeredTypes, SecurityCache cache)
|
||||
{
|
||||
_registeredTypes = registeredTypes;
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
/// <summary>Returns the <see cref="T:System.Dynamic.DynamicMetaObject" /> responsible for binding operations performed on this object.</summary>
|
||||
/// <returns>The <see cref="T:System.Dynamic.DynamicMetaObject" /> to bind this object.</returns>
|
||||
/// <param name="parameter">The expression tree representation of the runtime value.</param>
|
||||
public DynamicMetaObject GetMetaObject(Expression parameter)
|
||||
{
|
||||
return new GetSetPropertyDynamicMetaObject(parameter, this, SetPropertyMethodInfo, GetPropertyMethodInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not this dynamic data instance has data stored for the specified type
|
||||
/// </summary>
|
||||
public bool HasData<T>()
|
||||
{
|
||||
return _cache.HasData(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not this dynamic data instance has a property with the specified name.
|
||||
/// This is a case-insensitive search.
|
||||
/// </summary>
|
||||
/// <param name="name">The property name to check for</param>
|
||||
/// <returns>True if the property exists, false otherwise</returns>
|
||||
public bool HasProperty(string name)
|
||||
{
|
||||
Type type;
|
||||
if (_registeredTypes.TryGetType(name, out type))
|
||||
{
|
||||
return _cache.HasData(type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last item in the data list for the specified type
|
||||
/// </summary>
|
||||
public T Get<T>()
|
||||
{
|
||||
var list = GetAll<T>();
|
||||
return list.LastOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data list for the specified type
|
||||
/// </summary>
|
||||
public IReadOnlyList<T> GetAll<T>()
|
||||
{
|
||||
return GetAllImpl(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the matching cached object in a python friendly accessor
|
||||
/// </summary>
|
||||
/// <param name="type">Type to search for</param>
|
||||
/// <returns>Matching object</returns>
|
||||
public PyObject Get(Type type)
|
||||
{
|
||||
var list = GetAll(type);
|
||||
|
||||
if (list.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (Py.GIL())
|
||||
{
|
||||
return list[list.Count - 1].ToPython();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all the matching types with a python friendly overload.
|
||||
/// </summary>
|
||||
/// <param name="type">Search type</param>
|
||||
/// <returns>List of matching objects cached</returns>
|
||||
public IList GetAll(Type type)
|
||||
{
|
||||
return GetAllImpl(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the property with the specified name to the value. This is a case-insensitve search.
|
||||
/// </summary>
|
||||
/// <param name="name">The property name to set</param>
|
||||
/// <param name="value">The new property value</param>
|
||||
/// <returns>Returns the input value back to the caller</returns>
|
||||
[Obsolete("DynamicSecurityData is a view of the SecurityCache. It is readonly, properties can not be set")]
|
||||
public object SetProperty(string name, object value)
|
||||
{
|
||||
throw new InvalidOperationException(Messages.DynamicSecurityData.PropertiesCannotBeSet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property's value with the specified name. This is a case-insensitve search.
|
||||
/// </summary>
|
||||
/// <param name="name">The property name to access</param>
|
||||
/// <returns>object value of BaseData</returns>
|
||||
public object GetProperty(string name)
|
||||
{
|
||||
// check to see if the requested name matches one of the algorithm registered data types and if
|
||||
// so, we'll return a new empty list. this precludes us from always needing to check HasData<T>
|
||||
Type type;
|
||||
if (_registeredTypes.TryGetType(name, out type))
|
||||
{
|
||||
IReadOnlyList<BaseData> data;
|
||||
if (_cache.TryGetValue(type, out data))
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
var listType = GetGenericListType(type);
|
||||
return Activator.CreateInstance(listType);
|
||||
}
|
||||
|
||||
throw new KeyNotFoundException(Messages.DynamicSecurityData.PropertyNotFound(name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all implementation that covers both Python and C#
|
||||
/// </summary>
|
||||
private dynamic GetAllImpl(Type type)
|
||||
{
|
||||
var data = GetProperty(type.Name);
|
||||
|
||||
var dataType = data.GetType();
|
||||
if (dataType.GetElementType() == type // covers arrays
|
||||
// covers lists
|
||||
|| dataType.GenericTypeArguments.Length == 1
|
||||
&& dataType.GenericTypeArguments[0] == type)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
var baseDataList = data as IReadOnlyList<BaseData>;
|
||||
if (baseDataList != null)
|
||||
{
|
||||
var listType = GetGenericListType(type);
|
||||
var list = (IList)Activator.CreateInstance(listType);
|
||||
foreach (var baseData in baseDataList)
|
||||
{
|
||||
list.Add(baseData);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(Messages.DynamicSecurityData.UnexpectedTypesForGetAll(type, data));
|
||||
}
|
||||
|
||||
private Type GetGenericListType(Type type)
|
||||
{
|
||||
Type containerType;
|
||||
if (!_genericTypes.TryGetValue(type, out containerType))
|
||||
{
|
||||
// for performance we keep the generic type
|
||||
_genericTypes[type] = containerType = typeof(List<>).MakeGenericType(type);
|
||||
}
|
||||
|
||||
return containerType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.Linq;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Derivate security universe selection filter which will always return empty
|
||||
/// </summary>
|
||||
public class EmptyContractFilter<T> : IDerivativeSecurityFilter<T>
|
||||
where T : IChainUniverseData
|
||||
{
|
||||
/// <summary>
|
||||
/// True if this universe filter can run async in the data stack
|
||||
/// </summary>
|
||||
public bool Asynchronous { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Filters the input set of symbols represented by the universe
|
||||
/// </summary>
|
||||
/// <param name="universe">derivative symbols universe used in filtering</param>
|
||||
/// <returns>The filtered set of symbols</returns>
|
||||
public IDerivativeSecurityFilterUniverse<T> Filter(IDerivativeSecurityFilterUniverse<T> universe)
|
||||
{
|
||||
return new NoneIDerivativeSecurityFilterUniverse();
|
||||
}
|
||||
|
||||
private class NoneIDerivativeSecurityFilterUniverse : IDerivativeSecurityFilterUniverse<T>
|
||||
{
|
||||
public DateTime LocalTime => default;
|
||||
|
||||
public int Count => 0;
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return Enumerable.Empty<T>().GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return Enumerable.Empty<T>().GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Securities.Equity
|
||||
{
|
||||
/// <summary>
|
||||
/// Equity Security Type : Extension of the underlying Security class for equity specific behaviours.
|
||||
/// </summary>
|
||||
/// <seealso cref="Security"/>
|
||||
public class Equity : Security
|
||||
{
|
||||
/// <summary>
|
||||
/// The default number of days required to settle an equity sale
|
||||
/// </summary>
|
||||
public static int DefaultSettlementDays { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The default time of day for settlement
|
||||
/// </summary>
|
||||
public static readonly TimeSpan DefaultSettlementTime = new TimeSpan(6, 0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the equity is a shortable asset. Note that this does not
|
||||
/// take into account any open orders or existing holdings. To check if the asset
|
||||
/// is currently shortable, use QCAlgorithm's ShortableQuantity property instead.
|
||||
/// </summary>
|
||||
/// <returns>True if the security is a shortable equity</returns>
|
||||
public bool Shortable
|
||||
{
|
||||
get
|
||||
{
|
||||
var shortableQuantity = ShortableProvider.ShortableQuantity(Symbol, LocalTime);
|
||||
// null means we don't have the data
|
||||
return shortableQuantity == null || shortableQuantity > 0m;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total quantity shortable for this security. This does not take into account
|
||||
/// any open orders or existing holdings. To check the asset's currently shortable quantity,
|
||||
/// use QCAlgorithm's ShortableQuantity property instead.
|
||||
/// </summary>
|
||||
/// <returns>Zero if not shortable, null if infinitely shortable, or a number greater than zero if shortable</returns>
|
||||
public long? TotalShortableQuantity => ShortableProvider.ShortableQuantity(Symbol, LocalTime);
|
||||
|
||||
/// <summary>
|
||||
/// Equity primary exchange.
|
||||
/// </summary>
|
||||
public Exchange PrimaryExchange { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Construct the Equity Object
|
||||
/// </summary>
|
||||
public Equity(Symbol symbol,
|
||||
SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes,
|
||||
SecurityCache securityCache,
|
||||
Exchange primaryExchange = null)
|
||||
: base(symbol,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new EquityExchange(exchangeHours),
|
||||
securityCache,
|
||||
new SecurityPortfolioModel(),
|
||||
new EquityFillModel(),
|
||||
new InteractiveBrokersFeeModel(),
|
||||
NullSlippageModel.Instance,
|
||||
new ImmediateSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
new SecurityMarginModel(2m),
|
||||
new EquityDataFilter(),
|
||||
new AdjustedPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
Holdings = new EquityHolding(this, currencyConverter);
|
||||
PrimaryExchange = primaryExchange ?? QuantConnect.Exchange.UNKNOWN;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct the Equity Object
|
||||
/// </summary>
|
||||
public Equity(SecurityExchangeHours exchangeHours,
|
||||
SubscriptionDataConfig config,
|
||||
Cash quoteCurrency,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes,
|
||||
Exchange primaryExchange = null)
|
||||
: base(
|
||||
config,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new EquityExchange(exchangeHours),
|
||||
new EquityCache(),
|
||||
new SecurityPortfolioModel(),
|
||||
new EquityFillModel(),
|
||||
new InteractiveBrokersFeeModel(),
|
||||
NullSlippageModel.Instance,
|
||||
new ImmediateSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
new SecurityMarginModel(2m),
|
||||
new EquityDataFilter(),
|
||||
new AdjustedPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
Holdings = new EquityHolding(this, currencyConverter);
|
||||
PrimaryExchange = primaryExchange ?? QuantConnect.Exchange.UNKNOWN;;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the data normalization mode to be used by this security
|
||||
/// </summary>
|
||||
public override void SetDataNormalizationMode(DataNormalizationMode mode)
|
||||
{
|
||||
base.SetDataNormalizationMode(mode);
|
||||
|
||||
if (mode == DataNormalizationMode.Adjusted)
|
||||
{
|
||||
PriceVariationModel = new AdjustedPriceVariationModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
PriceVariationModel = new EquityPriceVariationModel();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the securities symbol
|
||||
/// </summary>
|
||||
public static implicit operator Symbol(Equity security) => security.Symbol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.Equity
|
||||
{
|
||||
/// <summary>
|
||||
/// Equity cache override.
|
||||
/// </summary>
|
||||
/// <remarks>Scheduled for obsolesence</remarks>
|
||||
/// <seealso cref="SecurityCache"/>
|
||||
public class EquityCache : SecurityCache
|
||||
{
|
||||
/// <summary>
|
||||
/// Start a new Cache for the set Index Code
|
||||
/// </summary>
|
||||
public EquityCache()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.Data;
|
||||
|
||||
namespace QuantConnect.Securities.Equity
|
||||
{
|
||||
/// <summary>
|
||||
/// Equity security type data filter
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityDataFilter"/>
|
||||
public class EquityDataFilter : SecurityDataFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize Data Filter Class:
|
||||
/// </summary>
|
||||
public EquityDataFilter() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Equity filter the data: true - accept, false - fail.
|
||||
/// </summary>
|
||||
/// <param name="data">Data class</param>
|
||||
/// <param name="vehicle">Security asset</param>
|
||||
public override bool Filter(Security vehicle, BaseData data)
|
||||
{
|
||||
// No data filter for bad ticks. All raw data will be piped into algorithm
|
||||
return true;
|
||||
}
|
||||
|
||||
} //End Filter
|
||||
|
||||
} //End Namespace
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.Equity
|
||||
{
|
||||
/// <summary>
|
||||
/// Equity exchange information
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityExchange"/>
|
||||
public class EquityExchange : SecurityExchange
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of trading days in an equity calendar year - 252
|
||||
/// </summary>
|
||||
public override int TradingDaysPerYear
|
||||
{
|
||||
get { return 252; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EquityExchange"/> class using market hours
|
||||
/// derived from the market-hours-database for the USA Equity market
|
||||
/// </summary>
|
||||
public EquityExchange()
|
||||
: base(MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.USA, null, SecurityType.Equity))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EquityExchange"/> class using the specified
|
||||
/// exchange hours to determine open/close times
|
||||
/// </summary>
|
||||
/// <param name="exchangeHours">Contains the weekly exchange schedule plus holidays</param>
|
||||
public EquityExchange(SecurityExchangeHours exchangeHours)
|
||||
: base(exchangeHours)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.Equity
|
||||
{
|
||||
/// <summary>
|
||||
/// Holdings class for equities securities: no specific properties here but it is a placeholder for future equities specific behaviours.
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityHolding"/>
|
||||
public class EquityHolding : SecurityHolding
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor for equities holdings.
|
||||
/// </summary>
|
||||
/// <param name="security">The security being held</param>
|
||||
/// <param name="currencyConverter">A currency converter instance</param>
|
||||
public EquityHolding(Security security, ICurrencyConverter currencyConverter)
|
||||
: base(security, currencyConverter)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.Equity
|
||||
{
|
||||
/// <summary>
|
||||
/// Short margin interest rate model
|
||||
///
|
||||
/// When shorting charges the fee rate provided by the <see cref="QuantConnect.Interfaces.IShortableProvider"/>.
|
||||
/// When long adds the rebate fee provided by the <see cref="QuantConnect.Interfaces.IShortableProvider"/>.
|
||||
/// </summary>
|
||||
public class ShortMarginInterestRateModel : IMarginInterestRateModel
|
||||
{
|
||||
private bool _isShort;
|
||||
private DateTime _previousTime;
|
||||
|
||||
/// <summary>
|
||||
/// Accumulated shorting fee, negative means paid, positive earned.
|
||||
///
|
||||
/// Negative due to borrowing the asset to short, the fee rate.
|
||||
/// Positive due to lending the asset for shorting, the rebate rate.
|
||||
/// </summary>
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Apply margin interest rates to the portfolio
|
||||
/// </summary>
|
||||
/// <param name="marginInterestRateParameters">The parameters to use</param>
|
||||
public void ApplyMarginInterestRate(MarginInterestRateParameters marginInterestRateParameters)
|
||||
{
|
||||
var security = marginInterestRateParameters.Security;
|
||||
if (!security.Holdings.HoldStock)
|
||||
{
|
||||
// clear state
|
||||
_previousTime = default;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_previousTime == default || _isShort != security.Holdings.IsShort)
|
||||
{
|
||||
// start the clock on initial state or when changing sides
|
||||
_isShort = security.Holdings.IsShort;
|
||||
_previousTime = marginInterestRateParameters.Time;
|
||||
return;
|
||||
}
|
||||
else if (marginInterestRateParameters.Time.Date == _previousTime.Date)
|
||||
{
|
||||
// charge once a day
|
||||
return;
|
||||
}
|
||||
|
||||
decimal? feeRate;
|
||||
if (_isShort)
|
||||
{
|
||||
feeRate = security.ShortableProvider?.FeeRate(security.Symbol, security.LocalTime.Date);
|
||||
}
|
||||
else
|
||||
{
|
||||
feeRate = security.ShortableProvider?.RebateRate(security.Symbol, security.LocalTime.Date);
|
||||
}
|
||||
|
||||
if (feeRate == null || feeRate.Value == 0)
|
||||
{
|
||||
// nothing todo
|
||||
_previousTime = default;
|
||||
return;
|
||||
}
|
||||
|
||||
var dailyFeeRate = ((feeRate.Value * security.Holdings.HoldingsValue) / 360);
|
||||
var fee = dailyFeeRate * (marginInterestRateParameters.Time.Date - _previousTime.Date).Days;
|
||||
|
||||
Amount += fee;
|
||||
security.QuoteCurrency.AddAmount(fee);
|
||||
// until next date
|
||||
_previousTime = marginInterestRateParameters.Time;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="IPriceVariationModel"/>
|
||||
/// for use in defining the minimum price variation for a given equity
|
||||
/// under Regulation NMS – Rule 612 (a.k.a – the “sub-penny rule”)
|
||||
/// </summary>
|
||||
public class EquityPriceVariationModel : SecurityPriceVariationModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the minimum price variation from a security
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the method parameters</param>
|
||||
/// <returns>Decimal minimum price variation of a given security</returns>
|
||||
public override decimal GetMinimumPriceVariation(GetMinimumPriceVariationParameters parameters)
|
||||
{
|
||||
if (parameters.Security.Type != SecurityType.Equity)
|
||||
{
|
||||
throw new ArgumentException("EquityPriceVariationModel.GetMinimumPriceVariation(): " +
|
||||
Messages.EquityPriceVariationModel.InvalidSecurityType(parameters.Security));
|
||||
}
|
||||
|
||||
// If the quotation is priced less than $1.00 per share, the minimum pricing increment is $0.0001.
|
||||
// Source: https://www.law.cornell.edu/cfr/text/17/242.612
|
||||
if (parameters.ReferencePrice < 1m)
|
||||
{
|
||||
return 0.0001m;
|
||||
}
|
||||
|
||||
return base.GetMinimumPriceVariation(parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="ICurrencyConverter"/> for use in
|
||||
/// tests that don't depend on this behavior.
|
||||
/// </summary>
|
||||
public class ErrorCurrencyConverter : ICurrencyConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets account currency
|
||||
/// </summary>
|
||||
public string AccountCurrency
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new InvalidOperationException(Messages.ErrorCurrencyConverter.AccountCurrencyUnexpectedUsage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to the single instance of <see cref="ErrorCurrencyConverter"/>.
|
||||
/// This is done this way to ensure usage is explicit.
|
||||
/// </summary>
|
||||
public static ICurrencyConverter Instance = new ErrorCurrencyConverter();
|
||||
|
||||
private ErrorCurrencyConverter()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a cash amount to the account currency
|
||||
/// </summary>
|
||||
/// <param name="cashAmount">The <see cref="CashAmount"/> instance to convert</param>
|
||||
/// <returns>A new <see cref="CashAmount"/> instance denominated in the account currency</returns>
|
||||
public CashAmount ConvertToAccountCurrency(CashAmount cashAmount)
|
||||
{
|
||||
throw new InvalidOperationException(Messages.ErrorCurrencyConverter.ConvertToAccountCurrencyPurposefullyThrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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 QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Securities.Forex
|
||||
{
|
||||
/// <summary>
|
||||
/// FOREX Security Object Implementation for FOREX Assets
|
||||
/// </summary>
|
||||
/// <seealso cref="Security"/>
|
||||
public class Forex : Security, IBaseCurrencySymbol
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the currency acquired by going long this currency pair
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, the EUR/USD has a base currency of the euro, and as a result
|
||||
/// of going long the EUR/USD a trader is acquiring euros in exchange for US dollars
|
||||
/// </remarks>
|
||||
public Cash BaseCurrency { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the forex 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="baseCurrency">The cash object that represent the base 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 Forex(SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
Cash baseCurrency,
|
||||
SubscriptionDataConfig config,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes)
|
||||
: base(config,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new ForexExchange(exchangeHours),
|
||||
new ForexCache(),
|
||||
new SecurityPortfolioModel(),
|
||||
new ImmediateFillModel(),
|
||||
new InteractiveBrokersFeeModel(),
|
||||
NullSlippageModel.Instance,
|
||||
new ImmediateSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
new SecurityMarginModel(50m),
|
||||
new ForexDataFilter(),
|
||||
new SecurityPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
BaseCurrency = baseCurrency;
|
||||
Holdings = new ForexHolding(this, currencyConverter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the forex security
|
||||
/// </summary>
|
||||
/// <param name="symbol">The security's 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="baseCurrency">The cash object that represent the base 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 for storing Security data</param>
|
||||
public Forex(Symbol symbol,
|
||||
SecurityExchangeHours exchangeHours,
|
||||
Cash quoteCurrency,
|
||||
Cash baseCurrency,
|
||||
SymbolProperties symbolProperties,
|
||||
ICurrencyConverter currencyConverter,
|
||||
IRegisteredSecurityDataTypesProvider registeredTypes,
|
||||
SecurityCache securityCache)
|
||||
: base(symbol,
|
||||
quoteCurrency,
|
||||
symbolProperties,
|
||||
new ForexExchange(exchangeHours),
|
||||
securityCache,
|
||||
new SecurityPortfolioModel(),
|
||||
new ImmediateFillModel(),
|
||||
new InteractiveBrokersFeeModel(),
|
||||
NullSlippageModel.Instance,
|
||||
new ImmediateSettlementModel(),
|
||||
Securities.VolatilityModel.Null,
|
||||
new SecurityMarginModel(50m),
|
||||
new ForexDataFilter(),
|
||||
new SecurityPriceVariationModel(),
|
||||
currencyConverter,
|
||||
registeredTypes,
|
||||
Securities.MarginInterestRateModel.Null
|
||||
)
|
||||
{
|
||||
BaseCurrency = baseCurrency;
|
||||
Holdings = new ForexHolding(this, currencyConverter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decomposes the specified currency pair into a base and quote currency provided as out parameters
|
||||
/// </summary>
|
||||
/// <param name="currencyPair">The input currency pair to be decomposed, for example, "EURUSD"</param>
|
||||
/// <param name="baseCurrency">The output base currency</param>
|
||||
/// <param name="quoteCurrency">The output quote currency</param>
|
||||
public static void DecomposeCurrencyPair(string currencyPair, out string baseCurrency, out string quoteCurrency)
|
||||
{
|
||||
if (!CurrencyPairUtil.IsForexDecomposable(currencyPair))
|
||||
{
|
||||
throw new ArgumentException($"Currency pairs must be exactly 6 characters: {currencyPair}");
|
||||
}
|
||||
|
||||
baseCurrency = currencyPair.Substring(0, 3);
|
||||
quoteCurrency = currencyPair.Substring(3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the securities symbol
|
||||
/// </summary>
|
||||
public static implicit operator Symbol(Forex security) => security.Symbol;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.Forex
|
||||
{
|
||||
/// <summary>
|
||||
/// Forex specific caching support
|
||||
/// </summary>
|
||||
/// <remarks>Class is vitually empty and scheduled to be made obsolete. Potentially could be used for user data storage.</remarks>
|
||||
/// <seealso cref="SecurityCache"/>
|
||||
public class ForexCache : SecurityCache
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize forex cache
|
||||
/// </summary>
|
||||
public ForexCache()
|
||||
: base()
|
||||
{
|
||||
//Nothing to do:
|
||||
}
|
||||
} //End ForexCache Class
|
||||
} //End Namespace
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.Data;
|
||||
|
||||
namespace QuantConnect.Securities.Forex
|
||||
{
|
||||
/// <summary>
|
||||
/// Forex packet by packet data filtering mechanism for dynamically detecting bad ticks.
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityDataFilter"/>
|
||||
public class ForexDataFilter : SecurityDataFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize forex data filter class:
|
||||
/// </summary>
|
||||
public ForexDataFilter()
|
||||
: base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forex data filter: a true value means accept the packet, a false means fail.
|
||||
/// </summary>
|
||||
/// <param name="data">Data object we're scanning to filter</param>
|
||||
/// <param name="vehicle">Security asset</param>
|
||||
public override bool Filter(Security vehicle, BaseData data)
|
||||
{
|
||||
//FX data is from FXCM and fairly clean already. Accept all packets.
|
||||
return true;
|
||||
}
|
||||
|
||||
} //End Filter
|
||||
|
||||
} //End Namespace
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.Forex
|
||||
{
|
||||
/// <summary>
|
||||
/// Forex exchange class - information and helper tools for forex exchange properties
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityExchange"/>
|
||||
public class ForexExchange : SecurityExchange
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of trading days per year for this security, used for performance statistics.
|
||||
/// </summary>
|
||||
public override int TradingDaysPerYear
|
||||
{
|
||||
// 365 - Saturdays = 313;
|
||||
get { return 313; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ForexExchange"/> class using market hours
|
||||
/// derived from the market-hours-database for the FXCM Forex market
|
||||
/// </summary>
|
||||
public ForexExchange()
|
||||
: base(MarketHoursDatabase.FromDataFolder().GetExchangeHours(Market.FXCM, null, SecurityType.Forex))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ForexExchange"/> class using the specified
|
||||
/// exchange hours to determine open/close times
|
||||
/// </summary>
|
||||
/// <param name="exchangeHours">Contains the weekly exchange schedule plus holidays</param>
|
||||
public ForexExchange(SecurityExchangeHours exchangeHours)
|
||||
: base(exchangeHours)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 static System.Math;
|
||||
|
||||
namespace QuantConnect.Securities.Forex
|
||||
{
|
||||
/// <summary>
|
||||
/// FOREX holdings implementation of the base securities class
|
||||
/// </summary>
|
||||
/// <seealso cref="SecurityHolding"/>
|
||||
public class ForexHolding : SecurityHolding
|
||||
{
|
||||
/// <summary>
|
||||
/// Forex Holding Class
|
||||
/// </summary>
|
||||
/// <param name="security">The forex security being held</param>
|
||||
/// <param name="currencyConverter">A currency converter instance</param>
|
||||
public ForexHolding(Forex security, ICurrencyConverter currencyConverter)
|
||||
: base(security, currencyConverter)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Profit in pips if we closed the holdings right now including the approximate fees
|
||||
/// </summary>
|
||||
public decimal TotalCloseProfitPips()
|
||||
{
|
||||
var pipDecimal = Security.SymbolProperties.MinimumPriceVariation * 10;
|
||||
var exchangeRate = Security.QuoteCurrency.ConversionRate;
|
||||
|
||||
var pipCashCurrencyValue = (pipDecimal * AbsoluteQuantity * exchangeRate);
|
||||
return Round((TotalCloseProfit() / pipCashCurrencyValue), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a functional implementation of <see cref="IDerivativeSecurityFilter{T}"/>
|
||||
/// </summary>
|
||||
public class FuncSecurityDerivativeFilter<T> : IDerivativeSecurityFilter<T>
|
||||
where T : IChainUniverseData
|
||||
{
|
||||
private readonly Func<IDerivativeSecurityFilterUniverse<T>, IDerivativeSecurityFilterUniverse<T>> _filter;
|
||||
|
||||
/// <summary>
|
||||
/// True if this universe filter can run async in the data stack
|
||||
/// </summary>
|
||||
public bool Asynchronous { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FuncSecurityDerivativeFilter{T}"/> class
|
||||
/// </summary>
|
||||
/// <param name="filter">The functional implementation of the <see cref="Filter"/> method</param>
|
||||
public FuncSecurityDerivativeFilter(Func<IDerivativeSecurityFilterUniverse<T>, IDerivativeSecurityFilterUniverse<T>> filter)
|
||||
{
|
||||
_filter = filter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filters the input set of symbols represented by the universe
|
||||
/// </summary>
|
||||
/// <param name="universe">Derivative symbols universe used in filtering</param>
|
||||
/// <returns>The filtered set of symbols</returns>
|
||||
public IDerivativeSecurityFilterUniverse<T> Filter(IDerivativeSecurityFilterUniverse<T> universe)
|
||||
{
|
||||
return _filter(universe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 Python.Runtime;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a functional implementation of <see cref="ISecurityInitializer"/>
|
||||
/// </summary>
|
||||
public class FuncSecurityInitializer : ISecurityInitializer
|
||||
{
|
||||
private readonly Action<Security> _initializer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FuncSecurityInitializer"/> class
|
||||
/// </summary>
|
||||
/// <param name="initializer">The functional implementation of <see cref="ISecurityInitializer.Initialize"/></param>
|
||||
public FuncSecurityInitializer(PyObject initializer)
|
||||
{
|
||||
_initializer = PythonUtil.ToAction<Security>(initializer);
|
||||
if (_initializer == null)
|
||||
{
|
||||
throw new InvalidOperationException("FuncSecurityInitializer constructor requires an action taking a single security instance as an argument");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FuncSecurityInitializer"/> class
|
||||
/// </summary>
|
||||
/// <param name="initializer">The functional implementation of <see cref="ISecurityInitializer.Initialize"/></param>
|
||||
public FuncSecurityInitializer(Action<Security> initializer)
|
||||
{
|
||||
_initializer = initializer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the specified security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to be initialized</param>
|
||||
public void Initialize(Security security)
|
||||
{
|
||||
_initializer(security);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Logging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Seed a security price from a history function
|
||||
/// </summary>
|
||||
public class FuncSecuritySeeder : ISecuritySeeder
|
||||
{
|
||||
private readonly Func<Security, IEnumerable<BaseData>> _seedFunction;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that takes as a parameter the security used to seed the price
|
||||
/// </summary>
|
||||
/// <param name="seedFunction">The seed function to use</param>
|
||||
public FuncSecuritySeeder(PyObject seedFunction)
|
||||
{
|
||||
var result = seedFunction.SafeAs<Func<Security, object>>();
|
||||
_seedFunction = security =>
|
||||
{
|
||||
var dataObject = result(security);
|
||||
var dataPoint = dataObject as BaseData;
|
||||
if (dataPoint != null)
|
||||
{
|
||||
return new[] { dataPoint };
|
||||
}
|
||||
|
||||
return (IEnumerable<BaseData>)dataObject;
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that takes as a parameter the security used to seed the price
|
||||
/// </summary>
|
||||
/// <param name="seedFunction">The seed function to use</param>
|
||||
public FuncSecuritySeeder(Func<Security, BaseData> seedFunction)
|
||||
: this(security => { return new []{ seedFunction(security) }; })
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that takes as a parameter the security used to seed the price
|
||||
/// </summary>
|
||||
/// <param name="seedFunction">The seed function to use</param>
|
||||
public FuncSecuritySeeder(Func<Security, IEnumerable<BaseData>> seedFunction)
|
||||
{
|
||||
_seedFunction = seedFunction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seed the security
|
||||
/// </summary>
|
||||
/// <param name="security"><see cref="Security"/> being seeded</param>
|
||||
/// <returns>true if the security was seeded, false otherwise</returns>
|
||||
public bool SeedSecurity(Security security)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Do not seed canonical symbols
|
||||
if (!security.Symbol.IsCanonical())
|
||||
{
|
||||
var gotData = false;
|
||||
foreach (var seedData in _seedFunction(security))
|
||||
{
|
||||
gotData = true;
|
||||
security.SetMarketPrice(seedData);
|
||||
Log.Debug("FuncSecuritySeeder.SeedSecurity(): " + Messages.FuncSecuritySeeder.SeededSecurityInfo(seedData));
|
||||
}
|
||||
|
||||
if (!gotData)
|
||||
{
|
||||
Log.Trace("FuncSecuritySeeder.SeedSecurity(): " + Messages.FuncSecuritySeeder.UnableToSeedSecurity(security));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Trace("FuncSecuritySeeder.SeedSecurity(): " + Messages.FuncSecuritySeeder.UnableToSecurityPrice(security) + $": {exception}");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Defines the parameters for <see cref="IBuyingPowerModel.GetMaximumOrderQuantityForDeltaBuyingPower"/>
|
||||
/// </summary>
|
||||
public class GetMaximumOrderQuantityForDeltaBuyingPowerParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the algorithm's portfolio
|
||||
/// </summary>
|
||||
public SecurityPortfolioManager Portfolio { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the security
|
||||
/// </summary>
|
||||
public Security Security { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The delta buying power.
|
||||
/// </summary>
|
||||
/// <remarks>Sign defines the position side to apply the delta, positive long, negative short side.</remarks>
|
||||
public decimal DeltaBuyingPower { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True enables the <see cref="IBuyingPowerModel"/> to skip setting <see cref="GetMaximumOrderQuantityResult.Reason"/>
|
||||
/// for non error situations, for performance
|
||||
/// </summary>
|
||||
public bool SilenceNonErrorReasons { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Configurable minimum order margin portfolio percentage to ignore bad orders, orders with unrealistic small sizes
|
||||
/// </summary>
|
||||
/// <remarks>Default value is 0. This setting is useful to avoid small trading noise when using SetHoldings</remarks>
|
||||
public decimal MinimumOrderMarginPortfolioPercentage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GetMaximumOrderQuantityForDeltaBuyingPowerParameters"/> class
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The security</param>
|
||||
/// <param name="deltaBuyingPower">The delta buying power to apply.
|
||||
/// Sign defines the position side to apply the delta</param>
|
||||
/// <param name="minimumOrderMarginPortfolioPercentage">Configurable minimum order margin portfolio percentage to ignore orders with unrealistic small sizes</param>
|
||||
/// <param name="silenceNonErrorReasons">True will not return <see cref="GetMaximumOrderQuantityResult.Reason"/>
|
||||
/// set for non error situation, this is for performance</param>
|
||||
public GetMaximumOrderQuantityForDeltaBuyingPowerParameters(SecurityPortfolioManager portfolio, Security security, decimal deltaBuyingPower,
|
||||
decimal minimumOrderMarginPortfolioPercentage, bool silenceNonErrorReasons = false)
|
||||
{
|
||||
Portfolio = portfolio;
|
||||
Security = security;
|
||||
DeltaBuyingPower = deltaBuyingPower;
|
||||
SilenceNonErrorReasons = silenceNonErrorReasons;
|
||||
MinimumOrderMarginPortfolioPercentage = minimumOrderMarginPortfolioPercentage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Defines the parameters for <see cref="IBuyingPowerModel.GetMaximumOrderQuantityForTargetBuyingPower"/>
|
||||
/// </summary>
|
||||
public class GetMaximumOrderQuantityForTargetBuyingPowerParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the algorithm's portfolio
|
||||
/// </summary>
|
||||
public SecurityPortfolioManager Portfolio { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the security
|
||||
/// </summary>
|
||||
public Security Security { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target signed percentage buying power
|
||||
/// </summary>
|
||||
public decimal TargetBuyingPower { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True enables the <see cref="IBuyingPowerModel"/> to skip setting <see cref="GetMaximumOrderQuantityResult.Reason"/>
|
||||
/// for non error situations, for performance
|
||||
/// </summary>
|
||||
public bool SilenceNonErrorReasons { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Configurable minimum order margin portfolio percentage to ignore bad orders, orders with unrealistic small sizes
|
||||
/// </summary>
|
||||
/// <remarks>Default value is 0. This setting is useful to avoid small trading noise when using SetHoldings</remarks>
|
||||
public decimal MinimumOrderMarginPortfolioPercentage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GetMaximumOrderQuantityForTargetBuyingPowerParameters"/> class
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The security</param>
|
||||
/// <param name="targetBuyingPower">The target percentage buying power</param>
|
||||
/// <param name="minimumOrderMarginPortfolioPercentage">Configurable minimum order margin portfolio percentage to ignore orders with unrealistic small sizes</param>
|
||||
/// <param name="silenceNonErrorReasons">True will not return <see cref="GetMaximumOrderQuantityResult.Reason"/>
|
||||
/// set for non error situation, this is for performance</param>
|
||||
public GetMaximumOrderQuantityForTargetBuyingPowerParameters(SecurityPortfolioManager portfolio, Security security,
|
||||
decimal targetBuyingPower, decimal minimumOrderMarginPortfolioPercentage, bool silenceNonErrorReasons = false)
|
||||
{
|
||||
Portfolio = portfolio;
|
||||
Security = security;
|
||||
TargetBuyingPower = targetBuyingPower;
|
||||
SilenceNonErrorReasons = silenceNonErrorReasons;
|
||||
MinimumOrderMarginPortfolioPercentage = minimumOrderMarginPortfolioPercentage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Contains the information returned by <see cref="IBuyingPowerModel.GetMaximumOrderQuantityForTargetBuyingPower"/>
|
||||
/// and <see cref="IBuyingPowerModel.GetMaximumOrderQuantityForDeltaBuyingPower"/>
|
||||
/// </summary>
|
||||
public class GetMaximumOrderQuantityResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the maximum quantity for the order
|
||||
/// </summary>
|
||||
public decimal Quantity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the reason for which the maximum order quantity is zero
|
||||
/// </summary>
|
||||
public string Reason { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the zero order quantity is an error condition and will be shown to the user.
|
||||
/// </summary>
|
||||
public bool IsError { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GetMaximumOrderQuantityResult"/> class
|
||||
/// </summary>
|
||||
/// <param name="quantity">Returns the maximum quantity for the order</param>
|
||||
/// <param name="reason">The reason for which the maximum order quantity is zero</param>
|
||||
public GetMaximumOrderQuantityResult(decimal quantity, string reason = null)
|
||||
{
|
||||
Quantity = quantity;
|
||||
Reason = reason ?? string.Empty;
|
||||
IsError = !string.IsNullOrEmpty(Reason);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GetMaximumOrderQuantityResult"/> class
|
||||
/// </summary>
|
||||
/// <param name="quantity">Returns the maximum quantity for the order</param>
|
||||
/// <param name="reason">The reason for which the maximum order quantity is zero</param>
|
||||
/// <param name="isError">True if the zero order quantity is an error condition</param>
|
||||
public GetMaximumOrderQuantityResult(decimal quantity, string reason, bool isError = true)
|
||||
{
|
||||
Quantity = quantity;
|
||||
Reason = reason ?? string.Empty;
|
||||
IsError = isError;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the parameters for <see cref="IPriceVariationModel.GetMinimumPriceVariation"/>
|
||||
/// </summary>
|
||||
public class GetMinimumPriceVariationParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the security
|
||||
/// </summary>
|
||||
public Security Security { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reference price to be used for the calculation
|
||||
/// </summary>
|
||||
public decimal ReferencePrice { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GetMinimumPriceVariationParameters"/> class
|
||||
/// </summary>
|
||||
/// <param name="security">The security</param>
|
||||
/// <param name="referencePrice">The reference price to be used for the calculation</param>
|
||||
public GetMinimumPriceVariationParameters(Security security, decimal referencePrice)
|
||||
{
|
||||
Security = security;
|
||||
ReferencePrice = referencePrice;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.Orders;
|
||||
using static QuantConnect.StringExtensions;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the parameters for <see cref="IBuyingPowerModel.HasSufficientBuyingPowerForOrder"/>
|
||||
/// </summary>
|
||||
public class HasSufficientBuyingPowerForOrderParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the algorithm's portfolio
|
||||
/// </summary>
|
||||
public SecurityPortfolioManager Portfolio { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the security
|
||||
/// </summary>
|
||||
public Security Security { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the order
|
||||
/// </summary>
|
||||
public Order Order { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HasSufficientBuyingPowerForOrderParameters"/> class
|
||||
/// </summary>
|
||||
/// <param name="portfolio">The algorithm's portfolio</param>
|
||||
/// <param name="security">The security</param>
|
||||
/// <param name="order">The order</param>
|
||||
public HasSufficientBuyingPowerForOrderParameters(SecurityPortfolioManager portfolio, Security security, Order order)
|
||||
{
|
||||
Portfolio = portfolio;
|
||||
Security = security;
|
||||
Order = order;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="HasSufficientBuyingPowerForOrderParameters"/> targeting the security's underlying.
|
||||
/// If the security does not implement <see cref="IDerivativeSecurity"/> then an <see cref="InvalidCastException"/>
|
||||
/// will be thrown. If the order's symbol does not match the underlying then an <see cref="ArgumentException"/> will
|
||||
/// be thrown.
|
||||
/// </summary>
|
||||
/// <param name="order">The new order targeting the underlying</param>
|
||||
/// <returns>New parameters instance suitable for invoking the sufficient capital method for the underlying security</returns>
|
||||
public HasSufficientBuyingPowerForOrderParameters ForUnderlying(Order order)
|
||||
{
|
||||
var derivative = (IDerivativeSecurity) Security;
|
||||
return new HasSufficientBuyingPowerForOrderParameters(Portfolio, derivative.Underlying, order);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new result indicating that there is sufficient buying power for the contemplated order
|
||||
/// </summary>
|
||||
public HasSufficientBuyingPowerForOrderResult Sufficient()
|
||||
{
|
||||
return new HasSufficientBuyingPowerForOrderResult(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new result indicating that there is insufficient buying power for the contemplated order
|
||||
/// </summary>
|
||||
public HasSufficientBuyingPowerForOrderResult Insufficient(string reason)
|
||||
{
|
||||
return new HasSufficientBuyingPowerForOrderResult(false, reason);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new result indicating that there is insufficient buying power for the contemplated order
|
||||
/// </summary>
|
||||
public HasSufficientBuyingPowerForOrderResult Insufficient(FormattableString reason)
|
||||
{
|
||||
return new HasSufficientBuyingPowerForOrderResult(false, Invariant(reason));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Contains the information returned by <see cref="IBuyingPowerModel.HasSufficientBuyingPowerForOrder"/>
|
||||
/// </summary>
|
||||
public class HasSufficientBuyingPowerForOrderResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets true if there is sufficient buying power to execute an order
|
||||
/// </summary>
|
||||
public bool IsSufficient { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reason for insufficient buying power to execute an order
|
||||
/// </summary>
|
||||
public string Reason { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HasSufficientBuyingPowerForOrderResult"/> class
|
||||
/// </summary>
|
||||
/// <param name="isSufficient">True if the order can be executed</param>
|
||||
/// <param name="reason">The reason for insufficient buying power</param>
|
||||
public HasSufficientBuyingPowerForOrderResult(bool isSufficient, string reason = null)
|
||||
{
|
||||
IsSufficient = isSufficient;
|
||||
Reason = reason ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Interface for various currency symbols
|
||||
/// </summary>
|
||||
public interface IBaseCurrencySymbol
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the currency acquired by going long this currency pair
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// For example, the EUR/USD has a base currency of the euro, and as a result
|
||||
/// of going long the EUR/USD a trader is acquiring euros in exchange for US dollars
|
||||
/// </remarks>
|
||||
public Cash BaseCurrency { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Represents a security's model of buying power
|
||||
/// </summary>
|
||||
public interface IBuyingPowerModel
|
||||
{
|
||||
/// <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>
|
||||
decimal GetLeverage(Security security);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the leverage for the applicable securities, i.e, equities
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is added to maintain backwards compatibility with the old margin/leverage system
|
||||
/// </remarks>
|
||||
/// <param name="security">The security to set leverage for</param>
|
||||
/// <param name="leverage">The new leverage</param>
|
||||
void SetLeverage(Security security, decimal leverage);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin currently allocated to the specified holding
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the security and holdings quantity/cost/value</param>
|
||||
/// <returns>The maintenance margin required for the provided holdings quantity/cost/value</returns>
|
||||
MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters);
|
||||
|
||||
/// <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</param>
|
||||
/// <returns>The initial margin required for the provided security and quantity</returns>
|
||||
InitialMargin GetInitialMarginRequirement(InitialMarginParameters 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>
|
||||
InitialMargin GetInitialMarginRequiredForOrder(InitialMarginRequiredForOrderParameters parameters);
|
||||
|
||||
/// <summary>
|
||||
/// Check if there is sufficient buying power to execute this order.
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the portfolio, the security and the order</param>
|
||||
/// <returns>Returns buying power information for an order</returns>
|
||||
HasSufficientBuyingPowerForOrderResult HasSufficientBuyingPowerForOrder(HasSufficientBuyingPowerForOrderParameters parameters);
|
||||
|
||||
/// <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>
|
||||
GetMaximumOrderQuantityResult GetMaximumOrderQuantityForTargetBuyingPower(GetMaximumOrderQuantityForTargetBuyingPowerParameters parameters);
|
||||
|
||||
/// <summary>
|
||||
/// Get the maximum market order quantity to obtain a delta in the buying power used by a security.
|
||||
/// The deltas sign defines the position side to apply it to, positive long, negative short.
|
||||
/// </summary>
|
||||
/// <param name="parameters">An object containing the portfolio, the security and the delta buying power</param>
|
||||
/// <returns>Returns the maximum allowed market order quantity and if zero, also the reason</returns>
|
||||
/// <remarks>Used by the margin call model to reduce the position by a delta percent.</remarks>
|
||||
GetMaximumOrderQuantityResult GetMaximumOrderQuantityForDeltaBuyingPower(GetMaximumOrderQuantityForDeltaBuyingPowerParameters parameters);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of buying power reserved to maintain the specified position
|
||||
/// </summary>
|
||||
/// <param name="parameters">A parameters object containing the security</param>
|
||||
/// <returns>The reserved buying power in account currency</returns>
|
||||
ReservedBuyingPowerForPosition GetReservedBuyingPowerForPosition(ReservedBuyingPowerForPositionParameters parameters);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buying power available for a trade
|
||||
/// </summary>
|
||||
/// <param name="parameters">A parameters object containing the algorithm's portfolio, security, and order direction</param>
|
||||
/// <returns>The buying power available for the trade</returns>
|
||||
BuyingPower GetBuyingPower(BuyingPowerParameters parameters);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.Data;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Base interface intended for chain universe data to have some of their symbol properties accessible directly.
|
||||
/// </summary>
|
||||
public interface IChainUniverseData : IBaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the security identifier.
|
||||
/// </summary>
|
||||
SecurityIdentifier ID { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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>
|
||||
/// A continuous security that get's mapped during his life
|
||||
/// </summary>
|
||||
public interface IContinuousSecurity
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the currently mapped symbol for the security
|
||||
/// </summary>
|
||||
Symbol Mapped { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Provides the ability to convert cash amounts to the account currency
|
||||
/// </summary>
|
||||
public interface ICurrencyConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets account currency
|
||||
/// </summary>
|
||||
string AccountCurrency { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Converts a cash amount to the account currency
|
||||
/// </summary>
|
||||
/// <param name="cashAmount">The <see cref="CashAmount"/> instance to convert</param>
|
||||
/// <returns>A new <see cref="CashAmount"/> instance denominated in the account currency</returns>
|
||||
CashAmount ConvertToAccountCurrency(CashAmount cashAmount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Defines a security as a derivative of another security
|
||||
/// </summary>
|
||||
public interface IDerivativeSecurity
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the underlying security for the derivative
|
||||
/// </summary>
|
||||
Security Underlying { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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>
|
||||
/// Filters a set of derivative symbols using the underlying price data.
|
||||
/// </summary>
|
||||
public interface IDerivativeSecurityFilter<T>
|
||||
where T : IChainUniverseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Filters the input set of symbols represented by the universe
|
||||
/// </summary>
|
||||
/// <param name="universe">derivative symbols universe used in filtering</param>
|
||||
/// <returns>The filtered set of symbols</returns>
|
||||
IDerivativeSecurityFilterUniverse<T> Filter(IDerivativeSecurityFilterUniverse<T> universe);
|
||||
|
||||
/// <summary>
|
||||
/// True if this universe filter can run async in the data stack
|
||||
/// </summary>
|
||||
bool Asynchronous { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents derivative symbols universe used in filtering.
|
||||
/// </summary>
|
||||
public interface IDerivativeSecurityFilterUniverse<T> : IEnumerable<T>
|
||||
where T : IChainUniverseData
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of contracts in the universe
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 QuantConnect.Orders;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the model responsible for picking which orders should be executed during a margin call
|
||||
/// </summary>
|
||||
public interface IMarginCallModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Scan the portfolio and the updated data for a potential margin call situation which may get the holdings below zero!
|
||||
/// If there is a margin call, liquidate the portfolio immediately before the portfolio gets sub zero.
|
||||
/// </summary>
|
||||
/// <param name="issueMarginCallWarning">Set to true if a warning should be issued to the algorithm</param>
|
||||
/// <returns>True for a margin call on the holdings.</returns>
|
||||
List<SubmitOrderRequest> GetMarginCallOrders(out bool issueMarginCallWarning);
|
||||
|
||||
/// <summary>
|
||||
/// Executes synchronous orders to bring the account within margin requirements.
|
||||
/// </summary>
|
||||
/// <param name="generatedMarginCallOrders">These are the margin call orders that were generated
|
||||
/// by individual security margin models.</param>
|
||||
/// <returns>The list of orders that were actually executed</returns>
|
||||
List<OrderTicket> ExecuteMarginCall(IEnumerable<SubmitOrderRequest> generatedMarginCallOrders);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to a null implementation for <see cref="IMarginCallModel"/>
|
||||
/// </summary>
|
||||
public static class MarginCallModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an instance of <see cref="IMarginCallModel"/> that will always
|
||||
/// return an empty list of executed orders.
|
||||
/// </summary>
|
||||
public static readonly IMarginCallModel Null = new NullMarginCallModel();
|
||||
|
||||
private sealed class NullMarginCallModel : IMarginCallModel
|
||||
{
|
||||
public List<SubmitOrderRequest> GetMarginCallOrders(out bool issueMarginCallWarning)
|
||||
{
|
||||
issueMarginCallWarning = false;
|
||||
return new List<SubmitOrderRequest>();
|
||||
}
|
||||
|
||||
public List<OrderTicket> ExecuteMarginCall(IEnumerable<SubmitOrderRequest> generatedMarginCallOrders)
|
||||
{
|
||||
return new List<OrderTicket>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user