Lean  $LEAN_TAG$
BrokerageModelPythonWrapper.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;
18 using Python.Runtime;
24 using QuantConnect.Orders;
29 
30 namespace QuantConnect.Python
31 {
32  /// <summary>
33  /// Provides an implementation of <see cref="IBrokerageModel"/> that wraps a <see cref="PyObject"/> object
34  /// </summary>
36  {
37  /// <summary>
38  /// Constructor for initialising the <see cref="BrokerageModelPythonWrapper"/> class with wrapped <see cref="PyObject"/> object
39  /// </summary>
40  /// <param name="model">Models brokerage transactions, fees, and order</param>
41  public BrokerageModelPythonWrapper(PyObject model)
42  : base(model)
43  {
44  }
45 
46  /// <summary>
47  /// Gets or sets the account type used by this model
48  /// </summary>
50  {
51  get
52  {
53  return GetProperty<AccountType>(nameof(AccountType));
54  }
55  }
56 
57  /// <summary>
58  /// Gets the brokerages model percentage factor used to determine the required unused buying power for the account.
59  /// 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.
60  /// </summary>
61  public decimal RequiredFreeBuyingPowerPercent
62  {
63  get
64  {
65  return GetProperty<decimal>(nameof(RequiredFreeBuyingPowerPercent));
66  }
67  }
68 
69  /// <summary>
70  /// Gets a map of the default markets to be used for each security type
71  /// </summary>
72  public IReadOnlyDictionary<SecurityType, string> DefaultMarkets
73  {
74  get
75  {
76  using (Py.GIL())
77  {
78  var markets = GetProperty(nameof(DefaultMarkets)) as dynamic;
79  if ((markets as PyObject).TryConvert(out IReadOnlyDictionary<SecurityType, string> csharpDic))
80  {
81  return csharpDic;
82  }
83 
84  var dic = new Dictionary<SecurityType, string>();
85  foreach (var item in markets)
86  {
87  using var pyItem = item as PyObject;
88  var market = pyItem.As<SecurityType>();
89  dic[market] = markets[item];
90  }
91 
92  (markets as PyObject).Dispose();
93  return dic;
94  }
95  }
96  }
97 
98  /// <summary>
99  /// Applies the split to the specified order ticket
100  /// </summary>
101  /// <param name="tickets">The open tickets matching the split event</param>
102  /// <param name="split">The split event data</param>
103  public void ApplySplit(List<OrderTicket> tickets, Split split)
104  {
105  InvokeMethod(nameof(ApplySplit), tickets, split);
106  }
107 
108  /// <summary>
109  /// Returns true if the brokerage would be able to execute this order at this time assuming
110  /// market prices are sufficient for the fill to take place. This is used to emulate the
111  /// brokerage fills in backtesting and paper trading. For example some brokerages may not perform
112  /// executions during extended market hours. This is not intended to be checking whether or not
113  /// the exchange is open, that is handled in the Security.Exchange property.
114  /// </summary>
115  /// <param name="security">The security being ordered</param>
116  /// <param name="order">The order to test for execution</param>
117  /// <returns>True if the brokerage would be able to perform the execution, false otherwise</returns>
118  public bool CanExecuteOrder(Security security, Order order)
119  {
120  return InvokeMethod<bool>(nameof(CanExecuteOrder), security, order);
121  }
122 
123  /// <summary>
124  /// Returns true if the brokerage could accept this order. This takes into account
125  /// order type, security type, and order size limits.
126  /// </summary>
127  /// <remarks>
128  /// For example, a brokerage may have no connectivity at certain times, or an order rate/size limit
129  /// </remarks>
130  /// <param name="security">The security being ordered</param>
131  /// <param name="order">The order to be processed</param>
132  /// <param name="message">If this function returns false, a brokerage message detailing why the order may not be submitted</param>
133  /// <returns>True if the brokerage could process the order, false otherwise</returns>
134  public bool CanSubmitOrder(Security security, Order order, out BrokerageMessageEvent message)
135  {
136  using (Py.GIL())
137  {
138  message = null;
139  using var result = InvokeMethod(nameof(CanSubmitOrder), security, order, message);
140  // Since pythonnet does not support out parameters, the methods return
141  // a tuple where the out parameter comes after the other returned values
142  if (!PyTuple.IsTupleType(result))
143  {
144  throw new ArgumentException($@"{(Instance as dynamic).__class__.__name__}.CanSubmitOrder(): Must return a tuple value where the first value is a bool and the second a BrokerageMessageEvent");
145  }
146 
147  message = result[1].As<BrokerageMessageEvent>();
148  return result[0].As<bool>();
149  }
150  }
151 
152  /// <summary>
153  /// Returns true if the brokerage would allow updating the order as specified by the request
154  /// </summary>
155  /// <param name="security">The security of the order</param>
156  /// <param name="order">The order to be updated</param>
157  /// <param name="request">The requested updated to be made to the order</param>
158  /// <param name="message">If this function returns false, a brokerage message detailing why the order may not be updated</param>
159  /// <returns>True if the brokerage would allow updating the order, false otherwise</returns>
160  public bool CanUpdateOrder(Security security, Order order, UpdateOrderRequest request, out BrokerageMessageEvent message)
161  {
162  using (Py.GIL())
163  {
164  message = null;
165  using var result = InvokeMethod(nameof(CanUpdateOrder), security, order, request, message);
166  // Since pythonnet does not support out parameters, the methods return
167  // a tuple where the out parameter comes after the other returned values
168  if (!PyTuple.IsTupleType(result))
169  {
170  throw new ArgumentException($@"{(Instance as dynamic).__class__.__name__}.CanUpdateOrder(): Must return a tuple value where the first value is a bool and the second a BrokerageMessageEvent");
171  }
172 
173  message = result[1].As<BrokerageMessageEvent>();
174  return result[0].As<bool>();
175  }
176  }
177 
178  /// <summary>
179  /// Get the benchmark for this model
180  /// </summary>
181  /// <param name="securities">SecurityService to create the security with if needed</param>
182  /// <returns>The benchmark for this brokerage</returns>
184  {
185  using (Py.GIL())
186  {
187  var benchmark = InvokeMethod(nameof(GetBenchmark), securities);
188  if (benchmark.TryConvert<IBenchmark>(out var csharpBenchmark))
189  {
190  return csharpBenchmark;
191  }
192  return new BenchmarkPythonWrapper(benchmark);
193  }
194  }
195 
196  /// <summary>
197  /// Gets a new fee model that represents this brokerage's fee structure
198  /// </summary>
199  /// <param name="security">The security to get a fee model for</param>
200  /// <returns>The new fee model for this brokerage</returns>
201  public IFeeModel GetFeeModel(Security security)
202  {
203  using (Py.GIL())
204  {
205  var feeModel = InvokeMethod(nameof(GetFeeModel), security);
206  if (feeModel.TryConvert<IFeeModel>(out var csharpFeeModel))
207  {
208  return csharpFeeModel;
209  }
210  return new FeeModelPythonWrapper(feeModel);
211  }
212  }
213 
214  /// <summary>
215  /// Gets a new fill model that represents this brokerage's fill behavior
216  /// </summary>
217  /// <param name="security">The security to get fill model for</param>
218  /// <returns>The new fill model for this brokerage</returns>
220  {
221  using (Py.GIL())
222  {
223  var fillModel = InvokeMethod(nameof(GetFillModel), security);
224  if (fillModel.TryConvert<IFillModel>(out var csharpFillModel))
225  {
226  return csharpFillModel;
227  }
228  return new FillModelPythonWrapper(fillModel);
229  }
230  }
231 
232  /// <summary>
233  /// Gets the brokerage's leverage for the specified security
234  /// </summary>
235  /// <param name="security">The security's whose leverage we seek</param>
236  /// <returns>The leverage for the specified security</returns>
237  public decimal GetLeverage(Security security)
238  {
239  return InvokeMethod<decimal>(nameof(GetLeverage), security);
240  }
241 
242  /// <summary>
243  /// Gets a new settlement model for the security
244  /// </summary>
245  /// <param name="security">The security to get a settlement model for</param>
246  /// <returns>The settlement model for this brokerage</returns>
248  {
249  using (Py.GIL())
250  {
251  var settlementModel = InvokeMethod(nameof(GetSettlementModel), security);
252  if (settlementModel.TryConvert<ISettlementModel>(out var csharpSettlementModel))
253  {
254  return csharpSettlementModel;
255  }
256  return new SettlementModelPythonWrapper(settlementModel);
257  }
258  }
259 
260  /// <summary>
261  /// Gets a new settlement model for the security
262  /// </summary>
263  /// <param name="security">The security to get a settlement model for</param>
264  /// <param name="accountType">The account type</param>
265  /// <returns>The settlement model for this brokerage</returns>
266  [Obsolete("Flagged deprecated and will remove December 1st 2018")]
268  {
269  return InvokeMethod<ISettlementModel>(nameof(GetSettlementModel), security, accountType);
270  }
271 
272  /// <summary>
273  /// Gets a new slippage model that represents this brokerage's fill slippage behavior
274  /// </summary>
275  /// <param name="security">The security to get a slippage model for</param>
276  /// <returns>The new slippage model for this brokerage</returns>
278  {
279  using (Py.GIL())
280  {
281  var slippageModel = InvokeMethod(nameof(GetSlippageModel), security);
282  if (slippageModel.TryConvert<ISlippageModel>(out var csharpSlippageModel))
283  {
284  return csharpSlippageModel;
285  }
286  return new SlippageModelPythonWrapper(slippageModel);
287  }
288  }
289 
290  /// <summary>
291  /// Determine if this symbol is shortable
292  /// </summary>
293  /// <param name="algorithm">The algorithm running</param>
294  /// <param name="symbol">The symbol to short</param>
295  /// <param name="quantity">The amount to short</param>
296  /// <returns></returns>
297  public bool Shortable(IAlgorithm algorithm, Symbol symbol, decimal quantity)
298  {
299  return InvokeMethod<bool>(nameof(Shortable), algorithm, symbol, quantity);
300  }
301 
302  /// <summary>
303  /// Gets a new buying power model for the security, returning the default model with the security's configured leverage.
304  /// For cash accounts, leverage = 1 is used.
305  /// </summary>
306  /// <param name="security">The security to get a buying power model for</param>
307  /// <returns>The buying power model for this brokerage/security</returns>
309  {
310  using (Py.GIL())
311  {
312  var buyingPowerModel = InvokeMethod(nameof(GetBuyingPowerModel), security);
313  if (buyingPowerModel.TryConvert<IBuyingPowerModel>(out var csharpBuyingPowerModel))
314  {
315  return csharpBuyingPowerModel;
316  }
317  return new BuyingPowerModelPythonWrapper(buyingPowerModel);
318  }
319  }
320 
321  /// <summary>
322  /// Gets a new buying power model for the security
323  /// </summary>
324  /// <param name="security">The security to get a buying power model for</param>
325  /// <param name="accountType">The account type</param>
326  /// <returns>The buying power model for this brokerage/security</returns>
327  [Obsolete("Flagged deprecated and will remove December 1st 2018")]
329  {
330  return InvokeMethod<IBuyingPowerModel>(nameof(GetBuyingPowerModel), security, accountType);
331  }
332 
333  /// <summary>
334  /// Gets the shortable provider
335  /// </summary>
336  /// <returns>Shortable provider</returns>
338  {
339  using (Py.GIL())
340  {
341  var shortableProvider = InvokeMethod(nameof(GetShortableProvider), security);
342  if (shortableProvider.TryConvert<IShortableProvider>(out var csharpShortableProvider))
343  {
344  return csharpShortableProvider;
345  }
346  return new ShortableProviderPythonWrapper(shortableProvider);
347  }
348  }
349 
350  /// <summary>
351  /// Convenience method to get the underlying <see cref="IBrokerageModel"/> object from the wrapper.
352  /// </summary>
353  /// <returns>Underlying <see cref="IBrokerageModel"/> object</returns>
355  {
356  using (Py.GIL())
357  {
358  return Instance.AsManagedObject(typeof(IBrokerageModel)) as IBrokerageModel;
359  }
360  }
361 
362  /// <summary>
363  /// Gets a new margin interest rate model for the security
364  /// </summary>
365  /// <param name="security">The security to get a margin interest rate model for</param>
366  /// <returns>The margin interest rate model for this brokerage</returns>
368  {
369  using (Py.GIL())
370  {
371  var marginInterestRateModel = InvokeMethod(nameof(GetMarginInterestRateModel), security);
372  if (marginInterestRateModel.TryConvert<IMarginInterestRateModel>(out var csharpBuyingPowerModel))
373  {
374  return csharpBuyingPowerModel;
375  }
376  return new MarginInterestRateModelPythonWrapper(marginInterestRateModel);
377  }
378  }
379  }
380 }