/*
* 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
{
///
/// The crypto future margin model which supports both Coin and USDT futures
///
public class CryptoFutureMarginModel : SecurityMarginModel
{
///
/// Creates a new instance
///
/// The leverage to use, used on initial margin requirements, default 25x
/// The maintenance margin rate, default 5%
/// The maintenance amount which will reduce maintenance margin requirements, default 0
[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)
{
}
///
/// Creates a new instance
///
/// The leverage to use, used on initial margin requirements, default 25x
public CryptoFutureMarginModel(decimal leverage = 25)
: base(leverage, 0)
{
}
///
/// Gets the margin currently alloted to the specified holding.
///
/// An object containing the security
/// The maintenance margin required for the option
public override MaintenanceMargin GetMaintenanceMargin(MaintenanceMarginParameters parameters)
{
return new MaintenanceMargin(GetInitialMarginRequirement(new InitialMarginParameters(parameters.Security, parameters.Quantity)));
}
///
/// The margin that must be held in order to increase the position by the provided quantity
///
/// An object containing the security and quantity of shares
/// The initial margin required for the option (i.e. the equity required to enter a position for this option)
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);
}
///
/// Gets the margin cash available for a trade
///
/// The algorithm's portfolio
/// The security to be traded
/// The direction of the trade
/// The margin available for the trade
/// What we do specially here is that instead of using the total portfolio value as potential margin remaining we only consider the collateral currency
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;
}
///
/// Determines whether the given security shares collateral with another crypto future.
///
/// The algorithm's portfolio
/// The collateral cash for the current security
/// The other crypto future security to check
/// True if both securities share the same collateral
protected virtual bool SharesCollateral(SecurityPortfolioManager portfolio, Cash collateralCurrency, Security otherCryptoFuture)
{
return collateralCurrency == GetCollateralCash(otherCryptoFuture);
}
///
/// Helper method to determine what's the collateral currency for the given crypto future
///
private static Cash GetCollateralCash(Security security)
{
var cryptoFuture = (CryptoFuture)security;
var collateralCurrency = cryptoFuture.BaseCurrency;
if (!cryptoFuture.IsCryptoCoinFuture())
{
collateralCurrency = cryptoFuture.QuoteCurrency;
}
return collateralCurrency;
}
///
/// 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.
///
/// The algorithm's portfolio
/// The crypto future security
/// The primary collateral cash (e.g. USDT for non-coin futures, BTC for coin futures)
/// Total collateral amount in terms of the primary collateral currency
protected virtual decimal GetTotalCollateralAmount(SecurityPortfolioManager portfolio, Security security, Cash primaryCollateral)
{
return primaryCollateral.Amount;
}
}
}