Lean  $LEAN_TAG$
CoinbaseFeeModel.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014-2023 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;
18 
20 {
21  /// <summary>
22  /// Represents a fee model specific to Coinbase.
23  /// This class extends the base fee model.
24  /// </summary>
25  public class CoinbaseFeeModel : FeeModel
26  {
27  /// <summary>
28  /// Level Advanced 1 maker fee
29  /// Tab "Fee tiers" on <see href="https://www.coinbase.com/advanced-fees"/>
30  /// </summary>
31  public const decimal MakerAdvanced1 = 0.006m;
32 
33  /// <summary>
34  /// Level Advanced 1 taker fee
35  /// Tab "Fee tiers" on <see href="https://www.coinbase.com/advanced-fees"/>
36  /// </summary>
37  public const decimal TakerAdvanced1 = 0.008m;
38 
39  /// <summary>
40  /// Stable Pairs maker fee
41  /// Tab "Stable pairs" on <see href="https://www.coinbase.com/advanced-fees"/>
42  /// </summary>
43  public const decimal MakerStablePairs = 0m;
44 
45  /// <summary>
46  /// Stable Pairs taker fee
47  /// Tab "Stable pairs" on <see href="https://www.coinbase.com/advanced-fees"/>
48  /// </summary>
49  public const decimal TakerStableParis = 0.00001m;
50 
51  private readonly decimal _makerFee;
52 
53  private readonly decimal _takerFee;
54 
55  /// <summary>
56  /// Create Coinbase Fee model setting fee values
57  /// </summary>
58  /// <param name="makerFee">Maker fee value</param>
59  /// <param name="takerFee">Taker fee value</param>
60  /// <remarks>By default: use Level Advanced 1 fees</remarks>
61  public CoinbaseFeeModel(decimal makerFee = MakerAdvanced1, decimal takerFee = TakerAdvanced1)
62  {
63  _makerFee = makerFee;
64  _takerFee = takerFee;
65  }
66 
67  /// <summary>
68  /// Get the fee for this order in quote currency
69  /// </summary>
70  /// <param name="parameters">A <see cref="OrderFeeParameters"/> object
71  /// containing the security and order</param>
72  /// <returns>The cost of the order in quote currency</returns>
73  public override OrderFee GetOrderFee(OrderFeeParameters parameters)
74  {
75  if (parameters == null)
76  {
77  throw new ArgumentNullException(nameof(parameters), "The 'parameters' argument cannot be null.");
78  }
79 
80  var order = parameters.Order;
81  var security = parameters.Security;
82  var props = order.Properties as CoinbaseOrderProperties;
83 
84  // marketable limit orders are considered takers
85  var isMaker = order.Type == OrderType.Limit && ((props != null && props.PostOnly) || !order.IsMarketable);
86 
87  // Check if the current symbol is a StableCoin
88  var isStableCoin = Currencies.StablePairsCoinbase.Contains(security.Symbol.Value);
89 
90  var feePercentage = GetFeePercentage(order.Time, isMaker, isStableCoin, _makerFee, _takerFee);
91 
92  // get order value in quote currency, then apply maker/taker fee factor
93  var unitPrice = order.Direction == OrderDirection.Buy ? security.AskPrice : security.BidPrice;
94  unitPrice *= security.SymbolProperties.ContractMultiplier;
95 
96  // currently we do not model 30-day volume, so we use the first tier
97 
98  var fee = unitPrice * order.AbsoluteQuantity * feePercentage;
99 
100  return new OrderFee(new CashAmount(fee, security.QuoteCurrency.Symbol));
101  }
102 
103  /// <summary>
104  /// Returns the maker/taker fee percentage effective at the requested date.
105  /// </summary>
106  /// <param name="utcTime">The date/time requested (UTC)</param>
107  /// <param name="isMaker">true if the maker percentage fee is requested, false otherwise</param>
108  /// <param name="isStableCoin">true if the order security symbol is a StableCoin, false otherwise</param>
109  /// <param name="makerFee">maker fee amount</param>
110  /// <param name="takerFee">taker fee amount</param>
111  /// <returns>The fee percentage</returns>
112  protected static decimal GetFeePercentage(DateTime utcTime, bool isMaker, bool isStableCoin, decimal makerFee, decimal takerFee)
113  {
114  if (isStableCoin && utcTime < new DateTime(2022, 6, 1))
115  {
116  return isMaker ? 0m : 0.001m;
117  }
118  else if(isStableCoin)
119  {
120  return isMaker ? MakerStablePairs : TakerStableParis;
121  }
122  else if (utcTime < new DateTime(2019, 3, 23, 1, 30, 0))
123  {
124  return isMaker ? 0m : 0.003m;
125  }
126  else if (utcTime < new DateTime(2019, 10, 8, 0, 30, 0))
127  {
128  return isMaker ? 0.0015m : 0.0025m;
129  }
130 
131  // https://www.coinbase.com/advanced-fees
132  // Level | Trading amount | Spot fees (Maker | Taker)
133  // Advanced 1 | >= $0 | 0.60% | 0.80%
134  return isMaker ? makerFee : takerFee;
135  }
136  }
137 }