Lean  $LEAN_TAG$
DefaultBrokerageModel.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;
22 using QuantConnect.Orders;
31 using QuantConnect.Util;
32 
34 {
35  /// <summary>
36  /// Provides a default implementation of <see cref="IBrokerageModel"/> that allows all orders and uses
37  /// the default transaction models
38  /// </summary>
40  {
41  /// <summary>
42  /// The default markets for the backtesting brokerage
43  /// </summary>
44  public static readonly IReadOnlyDictionary<SecurityType, string> DefaultMarketMap = new Dictionary<SecurityType, string>
45  {
46  {SecurityType.Base, Market.USA},
47  {SecurityType.Equity, Market.USA},
48  {SecurityType.Option, Market.USA},
49  {SecurityType.Future, Market.CME},
50  {SecurityType.FutureOption, Market.CME},
51  {SecurityType.Forex, Market.Oanda},
52  {SecurityType.Cfd, Market.Oanda},
53  {SecurityType.Crypto, Market.Coinbase},
54  {SecurityType.CryptoFuture, Market.Binance},
55  {SecurityType.Index, Market.USA},
56  {SecurityType.IndexOption, Market.USA}
57  }.ToReadOnlyDictionary();
58 
59  /// <summary>
60  /// Gets or sets the account type used by this model
61  /// </summary>
62  public virtual AccountType AccountType
63  {
64  get;
65  private set;
66  }
67 
68  /// <summary>
69  /// Gets the brokerages model percentage factor used to determine the required unused buying power for the account.
70  /// From 1 to 0. Example: 0 means no unused buying power is required. 0.5 means 50% of the buying power should be left unused.
71  /// </summary>
72  public virtual decimal RequiredFreeBuyingPowerPercent => 0m;
73 
74  /// <summary>
75  /// Gets a map of the default markets to be used for each security type
76  /// </summary>
77  public virtual IReadOnlyDictionary<SecurityType, string> DefaultMarkets
78  {
79  get { return DefaultMarketMap; }
80  }
81 
82  /// <summary>
83  /// Initializes a new instance of the <see cref="DefaultBrokerageModel"/> class
84  /// </summary>
85  /// <param name="accountType">The type of account to be modelled, defaults to
86  /// <see cref="QuantConnect.AccountType.Margin"/></param>
87  public DefaultBrokerageModel(AccountType accountType = AccountType.Margin)
88  {
89  AccountType = accountType;
90  }
91 
92  /// <summary>
93  /// Returns true if the brokerage could accept this order. This takes into account
94  /// order type, security type, and order size limits.
95  /// </summary>
96  /// <remarks>
97  /// For example, a brokerage may have no connectivity at certain times, or an order rate/size limit
98  /// </remarks>
99  /// <param name="security">The security being ordered</param>
100  /// <param name="order">The order to be processed</param>
101  /// <param name="message">If this function returns false, a brokerage message detailing why the order may not be submitted</param>
102  /// <returns>True if the brokerage could process the order, false otherwise</returns>
103  public virtual bool CanSubmitOrder(Security security, Order order, out BrokerageMessageEvent message)
104  {
105  if ((security.Type == SecurityType.Future || security.Type == SecurityType.FutureOption) && order.Type == OrderType.MarketOnOpen)
106  {
107  message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported",
109  return false;
110  }
111 
112  message = null;
113  return true;
114  }
115 
116  /// <summary>
117  /// Returns true if the brokerage would allow updating the order as specified by the request
118  /// </summary>
119  /// <param name="security">The security of the order</param>
120  /// <param name="order">The order to be updated</param>
121  /// <param name="request">The requested update to be made to the order</param>
122  /// <param name="message">If this function returns false, a brokerage message detailing why the order may not be updated</param>
123  /// <returns>True if the brokerage would allow updating the order, false otherwise</returns>
124  public virtual bool CanUpdateOrder(Security security, Order order, UpdateOrderRequest request, out BrokerageMessageEvent message)
125  {
126  message = null;
127  return true;
128  }
129 
130  /// <summary>
131  /// Returns true if the brokerage would be able to execute this order at this time assuming
132  /// market prices are sufficient for the fill to take place. This is used to emulate the
133  /// brokerage fills in backtesting and paper trading. For example some brokerages may not perform
134  /// executions during extended market hours. This is not intended to be checking whether or not
135  /// the exchange is open, that is handled in the Security.Exchange property.
136  /// </summary>
137  /// <param name="security">The security being traded</param>
138  /// <param name="order">The order to test for execution</param>
139  /// <returns>True if the brokerage would be able to perform the execution, false otherwise</returns>
140  public virtual bool CanExecuteOrder(Security security, Order order)
141  {
142  return true;
143  }
144 
145  /// <summary>
146  /// Applies the split to the specified order ticket
147  /// </summary>
148  /// <remarks>
149  /// This default implementation will update the orders to maintain a similar market value
150  /// </remarks>
151  /// <param name="tickets">The open tickets matching the split event</param>
152  /// <param name="split">The split event data</param>
153  public virtual void ApplySplit(List<OrderTicket> tickets, Split split)
154  {
155  // by default we'll just update the orders to have the same notional value
156  var splitFactor = split.SplitFactor;
157  tickets.ForEach(ticket => ticket.Update(new UpdateOrderFields
158  {
159  Quantity = (int?) (ticket.Quantity/splitFactor),
160  LimitPrice = ticket.OrderType.IsLimitOrder() ? ticket.Get(OrderField.LimitPrice)*splitFactor : (decimal?) null,
161  StopPrice = ticket.OrderType.IsStopOrder() ? ticket.Get(OrderField.StopPrice)*splitFactor : (decimal?) null,
162  TriggerPrice = ticket.OrderType == OrderType.LimitIfTouched ? ticket.Get(OrderField.TriggerPrice) * splitFactor : (decimal?) null,
163  TrailingAmount = ticket.OrderType == OrderType.TrailingStop && !ticket.Get<bool>(OrderField.TrailingAsPercentage) ? ticket.Get(OrderField.TrailingAmount) * splitFactor : (decimal?) null
164  }));
165  }
166 
167  /// <summary>
168  /// Gets the brokerage's leverage for the specified security
169  /// </summary>
170  /// <param name="security">The security's whose leverage we seek</param>
171  /// <returns>The leverage for the specified security</returns>
172  public virtual decimal GetLeverage(Security security)
173  {
174  if (AccountType == AccountType.Cash)
175  {
176  return 1m;
177  }
178 
179  switch (security.Type)
180  {
181  case SecurityType.CryptoFuture:
182  return 25m;
183 
184  case SecurityType.Equity:
185  return 2m;
186 
187  case SecurityType.Forex:
188  case SecurityType.Cfd:
189  return 50m;
190 
191  case SecurityType.Crypto:
192  return 1m;
193 
194  case SecurityType.Base:
195  case SecurityType.Commodity:
196  case SecurityType.Option:
197  case SecurityType.FutureOption:
198  case SecurityType.Future:
199  case SecurityType.Index:
200  case SecurityType.IndexOption:
201  default:
202  return 1m;
203  }
204  }
205 
206  /// <summary>
207  /// Get the benchmark for this model
208  /// </summary>
209  /// <param name="securities">SecurityService to create the security with if needed</param>
210  /// <returns>The benchmark for this brokerage</returns>
211  public virtual IBenchmark GetBenchmark(SecurityManager securities)
212  {
213  var symbol = Symbol.Create("SPY", SecurityType.Equity, Market.USA);
214  return SecurityBenchmark.CreateInstance(securities, symbol);
215  }
216 
217  /// <summary>
218  /// Gets a new fill model that represents this brokerage's fill behavior
219  /// </summary>
220  /// <param name="security">The security to get fill model for</param>
221  /// <returns>The new fill model for this brokerage</returns>
222  public virtual IFillModel GetFillModel(Security security)
223  {
224  switch (security.Type)
225  {
226  case SecurityType.Equity:
227  return new EquityFillModel();
228  case SecurityType.FutureOption:
229  return new FutureOptionFillModel();
230  case SecurityType.Future:
231  return new FutureFillModel();
232  case SecurityType.Base:
233  case SecurityType.Option:
234  case SecurityType.Commodity:
235  case SecurityType.Forex:
236  case SecurityType.Cfd:
237  case SecurityType.Crypto:
238  case SecurityType.CryptoFuture:
239  case SecurityType.Index:
240  case SecurityType.IndexOption:
241  return new ImmediateFillModel();
242  default:
243  throw new ArgumentOutOfRangeException(Messages.DefaultBrokerageModel.InvalidSecurityTypeToGetFillModel(this, security));
244  }
245  }
246 
247  /// <summary>
248  /// Gets a new fee model that represents this brokerage's fee structure
249  /// </summary>
250  /// <param name="security">The security to get a fee model for</param>
251  /// <returns>The new fee model for this brokerage</returns>
252  public virtual IFeeModel GetFeeModel(Security security)
253  {
254  switch (security.Type)
255  {
256  case SecurityType.Base:
257  case SecurityType.Forex:
258  case SecurityType.Cfd:
259  case SecurityType.Crypto:
260  case SecurityType.CryptoFuture:
261  case SecurityType.Index:
262  return new ConstantFeeModel(0m);
263 
264  case SecurityType.Equity:
265  case SecurityType.Option:
266  case SecurityType.Future:
267  case SecurityType.FutureOption:
268  return new InteractiveBrokersFeeModel();
269 
270  case SecurityType.Commodity:
271  default:
272  return new ConstantFeeModel(0m);
273  }
274  }
275 
276  /// <summary>
277  /// Gets a new slippage model that represents this brokerage's fill slippage behavior
278  /// </summary>
279  /// <param name="security">The security to get a slippage model for</param>
280  /// <returns>The new slippage model for this brokerage</returns>
281  public virtual ISlippageModel GetSlippageModel(Security security)
282  {
284  }
285 
286  /// <summary>
287  /// Gets a new settlement model for the security
288  /// </summary>
289  /// <param name="security">The security to get a settlement model for</param>
290  /// <returns>The settlement model for this brokerage</returns>
292  {
293  if (AccountType == AccountType.Cash)
294  {
295  switch (security.Type)
296  {
297  case SecurityType.Equity:
299 
300  case SecurityType.Option:
302  }
303  }
304 
305  if(security.Symbol.SecurityType == SecurityType.Future)
306  {
307  return new FutureSettlementModel();
308  }
309 
310  return new ImmediateSettlementModel();
311  }
312 
313  /// <summary>
314  /// Gets a new settlement model for the security
315  /// </summary>
316  /// <param name="security">The security to get a settlement model for</param>
317  /// <param name="accountType">The account type</param>
318  /// <returns>The settlement model for this brokerage</returns>
319  [Obsolete("Flagged deprecated and will remove December 1st 2018")]
321  {
322  return GetSettlementModel(security);
323  }
324 
325  /// <summary>
326  /// Gets a new buying power model for the security, returning the default model with the security's configured leverage.
327  /// For cash accounts, leverage = 1 is used.
328  /// </summary>
329  /// <param name="security">The security to get a buying power model for</param>
330  /// <returns>The buying power model for this brokerage/security</returns>
332  {
333  IBuyingPowerModel getCurrencyBuyingPowerModel() =>
334  AccountType == AccountType.Cash
335  ? new CashBuyingPowerModel()
337 
338  return security?.Type switch
339  {
340  SecurityType.Crypto => getCurrencyBuyingPowerModel(),
341  SecurityType.Forex => getCurrencyBuyingPowerModel(),
342  SecurityType.CryptoFuture => new CryptoFutureMarginModel(GetLeverage(security)),
348  };
349  }
350 
351  /// <summary>
352  /// Gets the shortable provider
353  /// </summary>
354  /// <returns>Shortable provider</returns>
356  {
357  // Shortable provider, responsible for loading the data that indicates how much
358  // quantity we can short for a given asset. The NullShortableProvider default will
359  // allow for infinite quantities of any asset to be shorted.
361  }
362 
363  /// <summary>
364  /// Gets a new margin interest rate model for the security
365  /// </summary>
366  /// <param name="security">The security to get a margin interest rate model for</param>
367  /// <returns>The margin interest rate model for this brokerage</returns>
369  {
371  }
372 
373  /// <summary>
374  /// Gets a new buying power model for the security
375  /// </summary>
376  /// <param name="security">The security to get a buying power model for</param>
377  /// <param name="accountType">The account type</param>
378  /// <returns>The buying power model for this brokerage/security</returns>
379  [Obsolete("Flagged deprecated and will remove December 1st 2018")]
381  {
382  return GetBuyingPowerModel(security);
383  }
384 
385  /// <summary>
386  /// Checks if the order quantity is valid, it means, the order size is bigger than the minimum size allowed
387  /// </summary>
388  /// <param name="security">The security of the order</param>
389  /// <param name="orderQuantity">The quantity of the order to be processed</param>
390  /// <param name="message">If this function returns false, a brokerage message detailing why the order may be invalid</param>
391  /// <returns>True if the order quantity is bigger than the minimum allowed, false otherwise</returns>
392  public static bool IsValidOrderSize(Security security, decimal orderQuantity, out BrokerageMessageEvent message)
393  {
394  var minimumOrderSize = security.SymbolProperties.MinimumOrderSize;
395  if (minimumOrderSize != null && Math.Abs(orderQuantity) < minimumOrderSize)
396  {
397  message = new BrokerageMessageEvent(BrokerageMessageType.Warning, "NotSupported",
398  Messages.DefaultBrokerageModel.InvalidOrderQuantity(security, orderQuantity));
399 
400  return false;
401  }
402 
403  message = null;
404  return true;
405  }
406  }
407 }