chore: import upstream snapshot with attribution
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user