diff --git a/Common/Orders/Fills/EquityFillModel.cs b/Common/Orders/Fills/EquityFillModel.cs
index a1c766b70d4f..d347fd4096e9 100644
--- a/Common/Orders/Fills/EquityFillModel.cs
+++ b/Common/Orders/Fills/EquityFillModel.cs
@@ -563,9 +563,6 @@ public override OrderEvent MarketOnOpenFill(Security asset, MarketOnOpenOrder or
fill.FillQuantity = order.Quantity;
fill.Status = OrderStatus.Filled;
- //Calculate the model slippage: e.g. 0.01c
- var slip = asset.SlippageModel.GetSlippageApproximation(asset, order);
-
var bestEffortMessage = "";
// If there is no trade information, get the bid or ask, then apply the slippage
@@ -578,7 +575,7 @@ public override OrderEvent MarketOnOpenFill(Security asset, MarketOnOpenOrder or
fill.Message += bestEffortMessage;
}
- fill.FillPrice += slip;
+ fill.FillPrice += asset.SlippageModel.GetSlippageApproximation(asset, order, fill.FillPrice);
break;
case OrderDirection.Sell:
if (fill.FillPrice == 0)
@@ -587,7 +584,7 @@ public override OrderEvent MarketOnOpenFill(Security asset, MarketOnOpenOrder or
fill.Message += bestEffortMessage;
}
- fill.FillPrice -= slip;
+ fill.FillPrice -= asset.SlippageModel.GetSlippageApproximation(asset, order, fill.FillPrice);
break;
}
diff --git a/Common/Orders/Slippage/ConstantSlippageModel.cs b/Common/Orders/Slippage/ConstantSlippageModel.cs
index 43e348060b68..c8991e403d19 100644
--- a/Common/Orders/Slippage/ConstantSlippageModel.cs
+++ b/Common/Orders/Slippage/ConstantSlippageModel.cs
@@ -43,5 +43,18 @@ public decimal GetSlippageApproximation(Security asset, Order order)
return lastData.Value*_slippagePercent;
}
+
+ ///
+ /// Slippage Model. Return a decimal cash slippage approximation on the order
+ /// using the provided reference price.
+ ///
+ /// The security matching the order
+ /// The order to compute slippage for
+ /// The price used as the reference for the slippage calculation
+ /// The slippage approximation
+ public decimal GetSlippageApproximation(Security asset, Order order, decimal referencePrice)
+ {
+ return referencePrice * _slippagePercent;
+ }
}
}
diff --git a/Common/Orders/Slippage/ISlippageModel.cs b/Common/Orders/Slippage/ISlippageModel.cs
index c0826f2560ab..589dabd9c7d6 100644
--- a/Common/Orders/Slippage/ISlippageModel.cs
+++ b/Common/Orders/Slippage/ISlippageModel.cs
@@ -26,5 +26,18 @@ public interface ISlippageModel
/// Slippage Model. Return a decimal cash slippage approximation on the order.
///
decimal GetSlippageApproximation(Security asset, Order order);
+
+ ///
+ /// Slippage Model. Return a decimal cash slippage approximation on the order
+ /// using the provided reference price.
+ ///
+ /// The security matching the order
+ /// The order to compute slippage for
+ /// The price used as the reference for the slippage calculation
+ /// The slippage approximation
+ decimal GetSlippageApproximation(Security asset, Order order, decimal referencePrice)
+ {
+ return GetSlippageApproximation(asset, order);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Tests/Common/Orders/Fills/EquityFillModelTests.cs b/Tests/Common/Orders/Fills/EquityFillModelTests.cs
index 8dc4c81bbe7a..9cec4fe8fb0a 100644
--- a/Tests/Common/Orders/Fills/EquityFillModelTests.cs
+++ b/Tests/Common/Orders/Fills/EquityFillModelTests.cs
@@ -22,6 +22,7 @@
using QuantConnect.Indicators;
using QuantConnect.Orders;
using QuantConnect.Orders.Fills;
+using QuantConnect.Orders.Slippage;
using QuantConnect.Securities;
using QuantConnect.Securities.Forex;
using QuantConnect.Tests.Common.Data;
@@ -446,6 +447,69 @@ public void PerformsMarketOnOpenUsingOpenPriceWithMinuteSubscription(int quantit
Assert.AreEqual(expected, fill.FillPrice);
}
+ [TestCase(-100, 103.896)]
+ [TestCase(100, 104.104)]
+ public void PerformsMarketOnOpenUsingOpenPriceForConstantSlippageWithDailySubscription(int quantity, decimal expected)
+ {
+ const decimal open = 104m;
+ const decimal baselineClose = 105m;
+ const decimal mutatedClose = 103.5m;
+ const decimal slippagePercent = 0.001m;
+
+ var reference = new DateTime(2015, 06, 05, 12, 0, 0);
+ var config = CreateTradeBarConfig(Symbols.SPY, Resolution.Daily);
+
+ var baselineEquity = CreateEquity(config);
+ var mutatedEquity = CreateEquity(config);
+
+ baselineEquity.SetSlippageModel(new ConstantSlippageModel(slippagePercent));
+ mutatedEquity.SetSlippageModel(new ConstantSlippageModel(slippagePercent));
+
+ var time = baselineEquity.Exchange.Hours.GetNextMarketOpen(reference, false);
+ TimeKeeper.SetUtcDateTime(time.ConvertToUtc(TimeZones.NewYork));
+
+ TradeBar GetTradeBar(decimal close) => new TradeBar(
+ time.RoundDown(Time.OneDay),
+ Symbols.SPY,
+ open,
+ 106m,
+ 100m,
+ close,
+ 100,
+ Time.OneDay);
+
+ baselineEquity.SetMarketPrice(GetTradeBar(baselineClose));
+ mutatedEquity.SetMarketPrice(GetTradeBar(mutatedClose));
+
+ var baselineOrder = new MarketOnOpenOrder(Symbols.SPY, quantity, reference);
+ var mutatedOrder = new MarketOnOpenOrder(Symbols.SPY, quantity, reference);
+
+ var configProvider = new MockSubscriptionDataConfigProvider(config);
+
+ var baselineFill = ((EquityFillModel)baselineEquity.FillModel)
+ .Fill(new FillModelParameters(
+ baselineEquity,
+ baselineOrder,
+ configProvider,
+ Time.OneHour,
+ null))
+ .Single();
+
+ var mutatedFill = ((EquityFillModel)mutatedEquity.FillModel)
+ .Fill(new FillModelParameters(
+ mutatedEquity,
+ mutatedOrder,
+ configProvider,
+ Time.OneHour,
+ null))
+ .Single();
+
+ Assert.AreEqual(quantity, baselineFill.FillQuantity);
+ Assert.AreEqual(quantity, mutatedFill.FillQuantity);
+ Assert.AreEqual(expected, baselineFill.FillPrice);
+ Assert.AreEqual(baselineFill.FillPrice, mutatedFill.FillPrice);
+ }
+
[TestCase(-100)]
[TestCase(100)]
public void PerformsMarketOnOpenUsingOpenPriceWithDailySubscription(int quantity)
diff --git a/Tests/Common/Orders/Slippage/SlippageModelsTests.cs b/Tests/Common/Orders/Slippage/SlippageModelsTests.cs
index b37dda8e0ccf..0a468e0dc31a 100644
--- a/Tests/Common/Orders/Slippage/SlippageModelsTests.cs
+++ b/Tests/Common/Orders/Slippage/SlippageModelsTests.cs
@@ -161,5 +161,22 @@ public void AlphaStreamsSlippageModel_ForexTest()
var actual = model.GetSlippageApproximation(_forex, _forexBuyOrder);
Assert.AreEqual(expected, actual);
}
+ [Test]
+ public void SlippageModelReferencePriceOverloadIsBackwardsCompatible()
+ {
+ ISlippageModel model = new LegacySlippageModel();
+
+ var actual = model.GetSlippageApproximation(_equity, _equityBuyOrder, 123m);
+
+ Assert.AreEqual(42m, actual);
+ }
+
+ private sealed class LegacySlippageModel : ISlippageModel
+ {
+ public decimal GetSlippageApproximation(Security asset, Order order)
+ {
+ return 42m;
+ }
+ }
}
}