Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Future Stop Market Order in Out Market Hours #7678

Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@
* limitations under the License.
*/

using System;
using QuantConnect.Data;
using QuantConnect.Orders;
using QuantConnect.Securities;
using QuantConnect.Interfaces;
using QuantConnect.Data.Market;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using QuantConnect.Securities.Future;
using System.Security.AccessControl;

namespace QuantConnect.Algorithm.CSharp
{
Expand All @@ -31,17 +34,18 @@ namespace QuantConnect.Algorithm.CSharp
public class FutureStopMarketOrderOnExtendedHoursRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private OrderTicket _ticket;
private Future _SP500EMini;
public override void Initialize()
{
SetStartDate(2013, 10, 6);
SetEndDate(2013, 10, 12);

var future = AddFuture(Futures.Indices.SP500EMini, Resolution.Minute, extendedMarketHours: true);
_SP500EMini = AddFuture(Futures.Indices.SP500EMini, Resolution.Minute, extendedMarketHours: true);

Schedule.On(DateRules.EveryDay(), TimeRules.At(19, 0), () =>
{
MarketOrder(future.Mapped, 1);
_ticket = StopMarketOrder(future.Mapped, -1, future.Price * 0.999m);
MarketOrder(_SP500EMini.Mapped, 1);
_ticket = StopMarketOrder(_SP500EMini.Mapped, -1, _SP500EMini.Price * 0.999m);
});
}

Expand Down Expand Up @@ -71,7 +75,15 @@ public override void OnData(Slice slice)
/// <param name="orderEvent">Order event details containing details of the events</param>
public override void OnOrderEvent(OrderEvent orderEvent)
{
Log($"orderEvent: {orderEvent}");
if (orderEvent != null && orderEvent.Status == OrderStatus.Filled)
{
var time = MarketHoursDatabase.GetExchangeHours(_SP500EMini.SubscriptionDataConfig);

if (!time.IsOpen(orderEvent.UtcTime, _SP500EMini.IsExtendedMarketHours))
{
throw new Exception($"The Exchange hours was closed, checko 'extendedMarketHours' flag in {nameof(Initialize)} when added new security(ies).");
}
}
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,46 @@
from AlgorithmImports import *
from QuantConnect import Orders

### <summary>
### This example demonstrates how to create future 'stopMarketOrder' in extended Market Hours time
### </summary>
class FutureStopMarketOrderOnExtendedHoursRegressionAlgorithm(QCAlgorithm):
# <summary>
# This example demonstrates how to create future 'stopMarketOrder' in extended Market Hours time
# </summary>


### Keep new created instance of stopMarketOrder
class FutureStopMarketOrderOnExtendedHoursRegressionAlgorithm(QCAlgorithm):
# Keep new created instance of stopMarketOrder
stopMarketTicket = None
SP500EMini = None

### Initialize the Algorithm and Prepare Required Data
# Initialize the Algorithm and Prepare Required Data
def Initialize(self):

self.SetStartDate(2013, 10, 6)
self.SetEndDate(2013, 10, 12)

### Add mini SP500 future with extended Market hours flag
self.future = self.AddFuture(Futures.Indices.SP500EMini, Resolution.Minute, extendedMarketHours=True);
# Add mini SP500 future with extended Market hours flag
self.SP500EMini = self.AddFuture(
Futures.Indices.SP500EMini, Resolution.Minute, extendedMarketHours=True
)

### Init new schedule event with params: everyDay, 19:00:00 PM, what should to do
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(19,0), self.MakeMarketAndStopMarketOrder)
# Init new schedule event with params: everyDay, 19:00:00 PM, what should to do
self.Schedule.On(
self.DateRules.EveryDay(),
self.TimeRules.At(19, 0),
self.MakeMarketAndStopMarketOrder,
)

### This method is opened 2 new orders by scheduler
# This method is opened 2 new orders by scheduler
def MakeMarketAndStopMarketOrder(self):
self.MarketOrder(self.future.Mapped, 1)
self.stopMarketTicket = self.StopMarketOrder(self.future.Mapped, -1, self.future.Price*0.999)
self.MarketOrder(self.SP500EMini.Mapped, 1)
self.stopMarketTicket = self.StopMarketOrder(
self.SP500EMini.Mapped, -1, self.SP500EMini.Price * 0.999
)

### New Data Event handler receiving all subscription data in a single event
# New Data Event handler receiving all subscription data in a single event
def OnData(self, slice):
if self.stopMarketTicket == None or self.stopMarketTicket.Status != OrderStatus.Submitted:
if (
self.stopMarketTicket == None
or self.stopMarketTicket.Status != OrderStatus.Submitted
):
return None

self.stopPrice = self.stopMarketTicket.Get(OrderField.StopPrice)
Expand All @@ -50,6 +62,21 @@ def OnData(self, slice):
if self.stopPrice > self.bar.Low:
self.Log(f"{self.stopPrice} -> {self.bar.Low}")

### An order fill update the resulting information is passed to this method.
# An order fill update the resulting information is passed to this method.
def OnOrderEvent(self, orderEvent):
self.Log(f"orderEvent: {orderEvent}");
if orderEvent is not None and orderEvent.Status == OrderStatus.Filled:
# Get Exchange Hours for specific security
exchangeHours = self.MarketHoursDatabase.GetExchangeHours(
self.SP500EMini.SubscriptionDataConfig
)

# Validate, Exchange is opened explicitly
if (
exchangeHours.IsOpen(
orderEvent.UtcTime, self.SP500EMini.IsExtendedMarketHours
)
== False
):
raise Exception(
"The Exchange hours was closed, checko 'extendedMarketHours' flag in Initialize() when added new security(ies)"
)
8 changes: 5 additions & 3 deletions Tests/Common/Orders/Fills/FutureFillModelTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ public void PerformsMarketFill([Values] bool isInternal,
[Test]
public void PerformsStopMarketFill(
[Values] bool extendedMarketHours,
[Values] bool isInternal,
[Values(OrderDirection.Buy, OrderDirection.Sell)] OrderDirection orderDirection)
{
var symbol = Symbols.ES_Future_Chain;
Expand All @@ -78,7 +77,7 @@ public void PerformsStopMarketFill(
var time = Noon.AddHours(-12);

var order = new StopMarketOrder(symbol, quantity, 101.124m, time);
var config = CreateTradeBarConfig(symbol, isInternal, extendedMarketHours);
var config = CreateTradeBarConfig(symbol, extendedMarketHours: extendedMarketHours);
var security = GetSecurity(config);
TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork).UpdateTime(time.ConvertToUtc(TimeZones.NewYork));
security.SetLocalTimeKeeper(TimeKeeper.GetLocalTimeKeeper(TimeZones.NewYork));
Expand All @@ -91,18 +90,21 @@ public void PerformsStopMarketFill(
Time.OneHour,
null)).Single();

if (extendedMarketHours && isInternal != true)
var exchangeHours = MarketHoursDatabase.FromDataFolder().GetExchangeHours(config);
if (extendedMarketHours)
{
Assert.AreEqual(order.Quantity, fill.FillQuantity);
Assert.AreEqual(security.Price, fill.FillPrice);
Assert.AreEqual(OrderStatus.Filled, fill.Status);
Assert.IsTrue(exchangeHours.IsOpen(fill.UtcTime, extendedMarketHours));
}
else
{
Assert.AreEqual(0m, fill.FillQuantity);
Assert.AreEqual(0m, fill.FillPrice);
Assert.AreNotEqual(OrderStatus.Filled, fill.Status);
Assert.AreNotEqual(OrderStatus.PartiallyFilled, fill.Status);
Assert.IsFalse(exchangeHours.IsOpen(fill.UtcTime, extendedMarketHours));
}

}
Expand Down