Skip to content

Commit 6ef70a3

Browse files
committed
Improve GetFillModel()
1 parent 2525824 commit 6ef70a3

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

Common/Python/BrokerageModelPythonWrapper.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,19 @@ public IFillModel GetFillModel(Security security)
221221
{
222222
using (Py.GIL())
223223
{
224-
return (_model.GetFillModel(security) as PyObject).GetAndDispose<IFillModel>();
224+
var fillModel = _model.GetFillModel(security) as PyObject;
225+
if (fillModel.TryConvert<IFillModel>(out var csharpFillModel))
226+
{
227+
return (_model.GetFillModel(security) as PyObject).GetAndDispose<FillModel>();
228+
}
229+
else if (Extensions.TryConvert<IFillModel>(fillModel, out _, allowPythonDerivative: true))
230+
{
231+
return (new FillModelPythonWrapper(fillModel));
232+
}
233+
else
234+
{
235+
throw new Exception($@"{_model.__class__.__name__} Fill Model type is not supported!");
236+
}
225237
}
226238
}
227239

Tests/Common/Brokerages/BrokerageModelTests.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
using QuantConnect.Python;
2323
using QuantConnect.Securities;
2424
using Moq;
25+
using QuantConnect.Orders.Fills;
26+
using QuantConnect.Interfaces;
27+
using System.Collections.Generic;
2528

2629
namespace QuantConnect.Tests.Common.Brokerages
2730
{
@@ -214,6 +217,66 @@ public void GetsCorrectBuyingPowerModelForSecurityAndAccountType(IBrokerageModel
214217
Assert.AreEqual(buyingPowerModel.GetType(), type);
215218
}
216219

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+
217280
private static Security GetSecurity(Symbol symbol) =>
218281
new(symbol,
219282
SecurityExchangeHours.AlwaysOpen(DateTimeZone.Utc),

0 commit comments

Comments
 (0)