/* * 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; } } }