Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions Common/Orders/Fills/EquityFillModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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;
}

Expand Down
13 changes: 13 additions & 0 deletions Common/Orders/Slippage/ConstantSlippageModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,18 @@ public decimal GetSlippageApproximation(Security asset, Order order)

return lastData.Value*_slippagePercent;
}

/// <summary>
/// Slippage Model. Return a decimal cash slippage approximation on the order
/// using the provided reference price.
/// </summary>
/// <param name="asset">The security matching the order</param>
/// <param name="order">The order to compute slippage for</param>
/// <param name="referencePrice">The price used as the reference for the slippage calculation</param>
/// <returns>The slippage approximation</returns>
public decimal GetSlippageApproximation(Security asset, Order order, decimal referencePrice)
{
return referencePrice * _slippagePercent;
}
}
}
15 changes: 14 additions & 1 deletion Common/Orders/Slippage/ISlippageModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,18 @@ public interface ISlippageModel
/// Slippage Model. Return a decimal cash slippage approximation on the order.
/// </summary>
decimal GetSlippageApproximation(Security asset, Order order);

/// <summary>
/// Slippage Model. Return a decimal cash slippage approximation on the order
/// using the provided reference price.
/// </summary>
/// <param name="asset">The security matching the order</param>
/// <param name="order">The order to compute slippage for</param>
/// <param name="referencePrice">The price used as the reference for the slippage calculation</param>
/// <returns>The slippage approximation</returns>
decimal GetSlippageApproximation(Security asset, Order order, decimal referencePrice)
{
return GetSlippageApproximation(asset, order);
}
}
}
}
64 changes: 64 additions & 0 deletions Tests/Common/Orders/Fills/EquityFillModelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
17 changes: 17 additions & 0 deletions Tests/Common/Orders/Slippage/SlippageModelsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
}
Loading