Lean  $LEAN_TAG$
CryptoFutureMarginModel.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Linq;
18 using QuantConnect.Orders;
19 
21 {
22  /// <summary>
23  /// The crypto future margin model which supports both Coin and USDT futures
24  /// </summary>
26  {
27  private readonly decimal _maintenanceMarginRate;
28  private readonly decimal _maintenanceAmount;
29 
30  /// <summary>
31  /// Creates a new instance
32  /// </summary>
33  /// <param name="leverage">The leverage to use, used on initial margin requirements, default 25x</param>
34  /// <param name="maintenanceMarginRate">The maintenance margin rate, default 5%</param>
35  /// <param name="maintenanceAmount">The maintenance amount which will reduce maintenance margin requirements, default 0</param>
36  public CryptoFutureMarginModel(decimal leverage = 25, decimal maintenanceMarginRate = 0.05m, decimal maintenanceAmount = 0)
37  : base(leverage, 0)
38  {
39  _maintenanceAmount = maintenanceAmount;
40  _maintenanceMarginRate = maintenanceMarginRate;
41  }
42 
43  /// <summary>
44  /// Gets the margin currently alloted to the specified holding.
45  /// </summary>
46  /// <param name="parameters">An object containing the security</param>
47  /// <returns>The maintenance margin required for the option</returns>
49  {
50  var security = parameters.Security;
51  var quantity = parameters.Quantity;
52  if (security?.GetLastData() == null || quantity == 0m)
53  {
54  return MaintenanceMargin.Zero;
55  }
56 
57  var positionValue = security.Holdings.GetQuantityValue(quantity, security.Price);
58  var marginRequirementInCollateral = Math.Abs(positionValue.Amount) * _maintenanceMarginRate - _maintenanceAmount;
59 
60  return new MaintenanceMargin(marginRequirementInCollateral * positionValue.Cash.ConversionRate);
61  }
62 
63  /// <summary>
64  /// The margin that must be held in order to increase the position by the provided quantity
65  /// </summary>
66  /// <param name="parameters">An object containing the security and quantity of shares</param>
67  /// <returns>The initial margin required for the option (i.e. the equity required to enter a position for this option)</returns>
69  {
70  var security = parameters.Security;
71  var quantity = parameters.Quantity;
72  if (security?.GetLastData() == null || quantity == 0m)
73  {
74  return InitialMargin.Zero;
75  }
76 
77  var positionValue = security.Holdings.GetQuantityValue(quantity, security.Price);
78  var marginRequirementInCollateral = Math.Abs(positionValue.Amount) / GetLeverage(security);
79 
80  return new InitialMargin(marginRequirementInCollateral * positionValue.Cash.ConversionRate);
81  }
82 
83  /// <summary>
84  /// Gets the margin cash available for a trade
85  /// </summary>
86  /// <param name="portfolio">The algorithm's portfolio</param>
87  /// <param name="security">The security to be traded</param>
88  /// <param name="direction">The direction of the trade</param>
89  /// <returns>The margin available for the trade</returns>
90  /// <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>
91  protected override decimal GetMarginRemaining(SecurityPortfolioManager portfolio, Security security, OrderDirection direction)
92  {
93  var collateralCurrency = GetCollateralCash(security);
94  var totalCollateralCurrency = collateralCurrency.Amount;
95  var result = totalCollateralCurrency;
96 
97  foreach (var kvp in portfolio.Where(holdings => holdings.Value.Invested && holdings.Value.Type == SecurityType.CryptoFuture && holdings.Value.Symbol != security.Symbol))
98  {
99  var otherCryptoFuture = portfolio.Securities[kvp.Key];
100  // check if we share the collateral
101  if (collateralCurrency == GetCollateralCash(otherCryptoFuture))
102  {
103  // we reduce the available collateral based on total usage of all other positions too
104  result -= otherCryptoFuture.BuyingPowerModel.GetMaintenanceMargin(MaintenanceMarginParameters.ForCurrentHoldings(otherCryptoFuture));
105  }
106  }
107 
108  if (direction != OrderDirection.Hold)
109  {
110  var holdings = security.Holdings;
111  //If the order is in the same direction as holdings, our remaining cash is our cash
112  //In the opposite direction, our remaining cash is 2 x current value of assets + our cash
113  if (holdings.IsLong)
114  {
115  switch (direction)
116  {
117  case OrderDirection.Sell:
118  result +=
119  // portion of margin to close the existing position
120  this.GetMaintenanceMargin(security) +
121  // portion of margin to open the new position
122  this.GetInitialMarginRequirement(security, security.Holdings.AbsoluteQuantity);
123  break;
124  }
125  }
126  else if (holdings.IsShort)
127  {
128  switch (direction)
129  {
130  case OrderDirection.Buy:
131  result +=
132  // portion of margin to close the existing position
133  this.GetMaintenanceMargin(security) +
134  // portion of margin to open the new position
135  this.GetInitialMarginRequirement(security, security.Holdings.AbsoluteQuantity);
136  break;
137  }
138  }
139  }
140 
141  result -= totalCollateralCurrency * RequiredFreeBuyingPowerPercent;
142  // convert into account currency
143  result *= collateralCurrency.ConversionRate;
144  return result < 0 ? 0 : result;
145  }
146 
147  /// <summary>
148  /// Helper method to determine what's the collateral currency for the given crypto future
149  /// </summary>
150  private static Cash GetCollateralCash(Security security)
151  {
152  var cryptoFuture = (CryptoFuture)security;
153 
154  var collateralCurrency = cryptoFuture.BaseCurrency;
155  if (!cryptoFuture.IsCryptoCoinFuture())
156  {
157  collateralCurrency = cryptoFuture.QuoteCurrency;
158  }
159 
160  return collateralCurrency;
161  }
162  }
163 }