|
22 | 22 | using QuantConnect.Python;
|
23 | 23 | using QuantConnect.Securities;
|
24 | 24 | using Moq;
|
| 25 | +using QuantConnect.Orders.Fills; |
| 26 | +using QuantConnect.Interfaces; |
| 27 | +using System.Collections.Generic; |
25 | 28 |
|
26 | 29 | namespace QuantConnect.Tests.Common.Brokerages
|
27 | 30 | {
|
@@ -214,6 +217,66 @@ public void GetsCorrectBuyingPowerModelForSecurityAndAccountType(IBrokerageModel
|
214 | 217 | Assert.AreEqual(buyingPowerModel.GetType(), type);
|
215 | 218 | }
|
216 | 219 |
|
| 220 | + [Test] |
| 221 | + public void BrokerageModelPythonWrapperWorksWithCustomPythonFillModel() |
| 222 | + { |
| 223 | + using (Py.GIL()) |
| 224 | + { |
| 225 | + dynamic PyCustomBrokerageModel = PyModule.FromString("testModule", |
| 226 | + @$" |
| 227 | +from AlgorithmImports import * |
| 228 | +
|
| 229 | +class CustomFillModel(ImmediateFillModel): |
| 230 | + def __init__(self): |
| 231 | + super().__init__() |
| 232 | +
|
| 233 | + def MarketFill(self, asset, order): |
| 234 | + raise ValueError(""Pepe"") |
| 235 | +
|
| 236 | +class CustomBrokerageModel(DefaultBrokerageModel): |
| 237 | + def GetFillModel(self, security): |
| 238 | + return CustomFillModel() |
| 239 | + ").GetAttr("CustomBrokerageModel"); |
| 240 | + |
| 241 | + var security = GetSecurity(Symbols.SPY); |
| 242 | + var model = new BrokerageModelPythonWrapper(PyCustomBrokerageModel()); |
| 243 | + var fillModel = model.GetFillModel(security); |
| 244 | + Assert.AreEqual(typeof(FillModelPythonWrapper), fillModel.GetType()); |
| 245 | + Assert.Throws<PythonException>(() => ((dynamic)fillModel).MarketFill(security, new Mock<MarketOrder>().Object)); |
| 246 | + } |
| 247 | + } |
| 248 | + |
| 249 | + [Test] |
| 250 | + public void BrokerageModelPythonWrapperWorksWithCSharpFillModel() |
| 251 | + { |
| 252 | + using (Py.GIL()) |
| 253 | + { |
| 254 | + dynamic PyCustomBrokerageModel = PyModule.FromString("testModule", |
| 255 | + @$" |
| 256 | +from AlgorithmImports import * |
| 257 | +
|
| 258 | +class CustomBrokerageModel(DefaultBrokerageModel): |
| 259 | + def GetFillModel(self, security): |
| 260 | + return ImmediateFillModel() |
| 261 | + ").GetAttr("CustomBrokerageModel"); |
| 262 | + |
| 263 | + var security = GetSecurity(Symbols.SPY); |
| 264 | + security.SetLocalTimeKeeper(new LocalTimeKeeper(DateTime.Now, DateTimeZone.Utc)); |
| 265 | + var model = new BrokerageModelPythonWrapper(PyCustomBrokerageModel()); |
| 266 | + var fillModel = model.GetFillModel(security); |
| 267 | + Assert.AreEqual(typeof(ImmediateFillModel), fillModel.GetType()); |
| 268 | + var order = new Mock<MarketOrder>(); |
| 269 | + var subscriptionDataConfigProvider = new Mock<ISubscriptionDataConfigProvider>(); |
| 270 | + var securitiesForOrders = new Dictionary<Order, Security>() { { order.Object, security} }; |
| 271 | + var fillModelParameters = new FillModelParameters(security, order.Object, subscriptionDataConfigProvider.Object, TimeSpan.Zero, securitiesForOrders); |
| 272 | + var result = fillModel.Fill(fillModelParameters); |
| 273 | + foreach( var entry in result) |
| 274 | + { |
| 275 | + Assert.AreEqual(OrderStatus.Filled, entry.Status); |
| 276 | + } |
| 277 | + } |
| 278 | + } |
| 279 | + |
217 | 280 | private static Security GetSecurity(Symbol symbol) =>
|
218 | 281 | new(symbol,
|
219 | 282 | SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc),
|
|
0 commit comments