Hello all,
Sorry for dumping the code as is instead of attaching the backtest. The backtest of another project keeps running instead.
Anyways, I'm trying to get familiar with stop market orders and I was wondering if someone would be able to help me with this:
I have a list of stocks as you can see, say: tickers = ["SPY", "TLT", "BND"]
I want to create a dictionary for stop buys and stop sells, each containing tickers as keys, and can be executed and updated. I am trying to do this with these two dictionaries: self.stopbuys[symbol] and self.stopsells[symbol] , and initializing both with values of None for each ticker. And afterwards be able to update each for each ticker accordingly. Also, I am trying to track the time that each stop market order was FILLED with these two dictionaries: self.stopbuys_time and self.stopsells_time.
This did not execute:
self.stopbuys[symbol] = self.StopMarketOrder(symbol, shares_to_buy, round(value.window3[0].High, 2))
but without assinging the variable to it, it works, like this:
self.StopMarketOrder(symbol, shares_to_buy, round(value.window3[0].High, 2))
I don't think the update is working either. Is there a better way of tracking stop market orders for a list of stocks?
Also, would this be if statement execute on the day a new stop market is ASSIGNED or the day it is FILLED?
if (self.Time - self.stopbuys_time[symbol]).days == 0:
# do something
Thanks a bunch, I appreciate it.
Code:
class MyAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019,1,1)
self.SetCash(100000)
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage)
tickers = ["SPY", "TLT", "BND"]
# Creates empty dictionary to later hold daily Tradebar price rolling windows
self.symbolData = {}
# Creates empty dictionary to later hold stop buy values
self.stopbuys = {}
# Creates empty dictionary to later hold stop sell values
self.stopsells = {}
# Creates empty dictionary to later hold time of buy breakout occurrence
self.stopbuys_time = {}
# Creates empty dictionary to later hold time of sell breakout occurrence
self.stopsells_time = {}
for ticker in tickers:
self.equity = self.AddEquity(ticker, Resolution.Hour)
self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.equity.SetLeverage(1.0)
#symbol_window = self.equity.Symbol
symbol = self.equity.Symbol
self.stopbuys[symbol] = None
self.stopsells[symbol] = None
self.stopbuys_time[symbol] = datetime.min
self.stopsells_time[symbol] = datetime.min
# Consolidator
consolidator_daily = TradeBarConsolidator(timedelta(days = 1))
consolidator_daily.DataConsolidated += self.OnDailyData
self.SubscriptionManager.AddConsolidator(symbol, consolidator_daily)
self.symbolData[symbol] = SymbolData(self, symbol)
self.SetWarmUp(1000)
# Adding daily bar data to 3,2,1 etc.. rolling windows
def OnDailyData(self, sender, bar):
self.symbolData[bar.Symbol].window4.Add(bar)
self.symbolData[bar.Symbol].window3.Add(bar)
self.symbolData[bar.Symbol].window2.Add(bar)
def OnData(self, data):
for symbol, value in self.symbolData.items():
if not data.ContainsKey(symbol.Value):
return
for symbol, value in self.symbolData.items():
value.window4.Add(data[symbol.Value])
value.window3.Add(data[symbol.Value])
value.window2.Add(data[symbol.Value])
if self.IsWarmingUp:
return
for symbol, value in self.symbolData.items():
if not (value.window4.IsReady and value.window3.IsReady and value.window2.IsReady):
return
for symbol, value in self.symbolData.items():
shares_to_buy = 50
if value.window3[0].Close > value.window3[1].Close > value.window3[2].Close:
if self.stopbuys[symbol] == None:
#self.stopbuys[symbol] = self.StopMarketOrder(symbol, shares_to_buy, round(value.window3[0].High, 2))
self.StopMarketOrder(symbol, shares_to_buy, round(value.window3[0].High, 2))
else:
updateSettings = UpdateOrderFields()
updateSettings.StopPrice = round(value.window3[0].High, 2)
updateSettings.Quantity = round(shares_to_buy)
updateSettings.Tag = "Stop Buy Updated for {}".format(symbol)
self.stopbuys[symbol].Update(updateSettings)
else:
if self.stopbuys[symbol] == None:
#self.stopsells[symbol] = self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, round(value.window3[0].Low, 2))
self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, round(value.window3[0].Low, 2))
else:
updateSettings = UpdateOrderFields()
updateSettings.StopPrice = round(value.window3[0].Low, 2)
updateSettings.Quantity = -self.Portfolio[symbol].Quantity
updateSettings.Tag = "Stop Sell Updated for {}".format(symbol)
self.stopsells[symbol].Update(updateSettings)
# Is this the time a stop buy was entered or updated ? Or is it the time it was filled??
# How do we get the time a stopbuy was filled instead?
# if (self.Time - self.stopbuys_time[symbol]).days == 0:
# do something
def OnOrderEvent(self, orderEvent):
# Event when the order is filled. Debug log the order fill. :OrderEvent:
#if OrderEvent.FillQuantity == 0:
if orderEvent.Status != OrderStatus.Filled:
return
fetched = self.Transactions.GetOrderById(orderEvent.OrderId)
self.Debug("{} was filled. Symbol: {}. Quantity: {}. Direction: {}"
.format(str(fetched.Type),
str(orderEvent.Symbol),
str(orderEvent.FillQuantity),
str(orderEvent.Direction)))
if self.stopbuys[orderEvent.Symbol] is not None and self.stopbuys[orderEvent.Symbol].OrderId == orderEvent.OrderId:
self.stopbuys_time[orderEvent.Symbol] = self.Time
self.Debug(str(self.stopbuys_time[orderEvent.Symbol]))
class SymbolData:
def __init__(self, algorithm, symbol):
self.algorithm = algorithm
self.symbol = symbol
self.window4 = RollingWindow[TradeBar](4)
self.window3 = RollingWindow[TradeBar](3)
self.window2 = RollingWindow[TradeBar](2)
Rahul Chowdhury
Hey Amine,
OrderTickets cannot be updated once the Order has been filled. For every separate order, you must create a new order ticket. It is easy to accomplish this by resetting the OrderTicket variables to None as they fill; you can do this in the OnOrderEvent method. I've updated your code to make updating stopbuys and stopsells work. However, you will still need to improve the logic of your algorithm to make it profitable.
Amine Kouta
Thanks a lot Rahul,
One more simple question. Now I know I cannot update the order once filled. Can I update the order in all the rest of the cases:
OrderStatus.New - OrderStatus.Submitted - OrderStatus.PartiallyFilled - OrderStatus.Canceled - OrderStatus.Invalid
Or should I reset the OrderTicket variable to None for some of these cases as well.
Cheers,
Rahul Chowdhury
Hey Amine,
You can update orders until they are completely filled, which means you can updated new, submitted, or partially filled orders. But, you can't update canceled or invalid orders. To learn more about updating orders check out the documentation.
Amine Kouta
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!