Lean  $LEAN_TAG$
AlphaStreamsFeeModel.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.Collections.Generic;
19 
21 {
22  /// <summary>
23  /// Provides an implementation of <see cref="FeeModel"/> that models order fees that alpha stream clients pay/receive
24  /// </summary>
26  {
27  private readonly Dictionary<string, EquityFee> _equityFee =
28  new Dictionary<string, EquityFee> {
29  { Market.USA, new EquityFee("USD", feePerShare: 0.005m, minimumFee: 1, maximumFeeRate: 0.005m) }
30  };
31 
32  private readonly IDictionary<SecurityType, decimal> _feeRates = new Dictionary<SecurityType, decimal>
33  {
34  // Commission
35  {SecurityType.Forex, 0.000002m},
36  // Commission plus clearing fee
37  {SecurityType.Future, 0.4m + 0.1m},
38  {SecurityType.FutureOption, 0.4m + 0.1m},
39  {SecurityType.Option, 0.4m + 0.1m},
40  {SecurityType.IndexOption, 0.4m + 0.1m},
41  {SecurityType.Cfd, 0m}
42  };
43  private const decimal _makerFee = 0.001m;
44  private const decimal _takerFee = 0.002m;
45 
46  /// <summary>
47  /// Gets the order fee associated with the specified order. This returns the cost
48  /// of the transaction in the account currency
49  /// </summary>
50  /// <param name="parameters">A <see cref="OrderFeeParameters"/> object
51  /// containing the security and order</param>
52  /// <returns>The cost of the order in units of the account currency</returns>
53  public override OrderFee GetOrderFee(OrderFeeParameters parameters)
54  {
55  var order = parameters.Order;
56  var security = parameters.Security;
57 
58  // Option exercise is free of charge
59  if (order.Type == OrderType.OptionExercise)
60  {
61  return OrderFee.Zero;
62  }
63 
64  var market = security.Symbol.ID.Market;
65  decimal feeRate;
66 
67  switch (security.Type)
68  {
69  case SecurityType.Option:
70  case SecurityType.Future:
71  case SecurityType.FutureOption:
72  case SecurityType.Cfd:
73  _feeRates.TryGetValue(security.Type, out feeRate);
74  return new OrderFee(new CashAmount(feeRate * order.AbsoluteQuantity, Currencies.USD));
75 
76  case SecurityType.Forex:
77  _feeRates.TryGetValue(security.Type, out feeRate);
78  return new OrderFee(new CashAmount(feeRate * Math.Abs(order.GetValue(security)), Currencies.USD));
79 
80  case SecurityType.Crypto:
81  decimal fee = _takerFee;
82  var props = order.Properties as BitfinexOrderProperties;
83 
84  if (order.Type == OrderType.Limit &&
85  props?.Hidden != true &&
86  (props?.PostOnly == true || !order.IsMarketable))
87  {
88  // limit order posted to the order book
89  fee = _makerFee;
90  }
91 
92  // get order value in quote currency
93  var unitPrice = order.Direction == OrderDirection.Buy ? security.AskPrice : security.BidPrice;
94  if (order.Type == OrderType.Limit)
95  {
96  // limit order posted to the order book
97  unitPrice = ((LimitOrder)order).LimitPrice;
98  }
99 
100  unitPrice *= security.SymbolProperties.ContractMultiplier;
101 
102  // apply fee factor, currently we do not model 30-day volume, so we use the first tier
103  return new OrderFee(new CashAmount(
104  unitPrice * order.AbsoluteQuantity * fee,
105  security.QuoteCurrency.Symbol));
106 
107  // Use the IB fee model
108  case SecurityType.Equity:
109  EquityFee equityFee;
110  if (!_equityFee.TryGetValue(market, out equityFee))
111  {
112  throw new KeyNotFoundException(Messages.AlphaStreamsFeeModel.UnexpectedEquityMarket(market));
113  }
114  var tradeValue = Math.Abs(order.GetValue(security));
115 
116  //Per share fees
117  var tradeFee = equityFee.FeePerShare * order.AbsoluteQuantity;
118 
119  //Maximum Per Order: equityFee.MaximumFeeRate
120  //Minimum per order. $equityFee.MinimumFee
121  var maximumPerOrder = equityFee.MaximumFeeRate * tradeValue;
122  if (tradeFee < equityFee.MinimumFee)
123  {
124  tradeFee = equityFee.MinimumFee;
125  }
126  else if (tradeFee > maximumPerOrder)
127  {
128  tradeFee = maximumPerOrder;
129  }
130 
131  return new OrderFee(new CashAmount(Math.Abs(tradeFee), equityFee.Currency));
132 
133  default:
134  // unsupported security type
135  throw new ArgumentException(Messages.FeeModel.UnsupportedSecurityType(security));
136  }
137  }
138 
139  /// <summary>
140  /// Helper class to handle Equity fees
141  /// </summary>
142  private class EquityFee
143  {
144  public string Currency { get; }
145  public decimal FeePerShare { get; }
146  public decimal MinimumFee { get; }
147  public decimal MaximumFeeRate { get; }
148 
149  public EquityFee(string currency,
150  decimal feePerShare,
151  decimal minimumFee,
152  decimal maximumFeeRate)
153  {
154  Currency = currency;
155  FeePerShare = feePerShare;
156  MinimumFee = minimumFee;
157  MaximumFeeRate = maximumFeeRate;
158  }
159  }
160  }
161 }