Hello! I was having some difficulties getting bracketed orders to work for me when entering using a market order and trying to place my limit out and stop markets from the on order event method so I wanted to share what I came up with to help anyone else save some time. Hope You enjoy and if your more experienced and see any flaws in my code, please let me know!
class CrawlingFluorescentYellowCaribou(QCAlgorithm):
stoplossTicket = None
takeprofitTicket = None
def Initialize(self):
self.SetStartDate(2020, 1, 1)
self.SetEndDate(2020,3,1)
self.SetCash(100000)
self.crudeoilwti = self.AddFuture(Futures.Energies.CrudeOilWTI, Resolution.Minute)
self.rsi = self.RSI(self.crudeoilwti.Symbol, 3, Resolution.Minute)
self.atr = self.ATR(self.crudeoilwti.Symbol, 20, Resolution.Minute)
self.ema = self.EMA(self.crudeoilwti.Symbol, 20)
self.RegisterIndicator(self.crudeoilwti.Symbol, self.ema, timedelta(days=1))
self.adx = self.ADX(self.crudeoilwti.Symbol, 20)
self.RegisterIndicator(self.crudeoilwti.Symbol, self.adx, timedelta(hours=1))
self.Schedule.On(self.DateRules.EveryDay(self.crudeoilwti.Symbol), self.TimeRules.At(14, 00), self.ClosePositions)
def OnData(self, data: Slice):
if not self.ema.IsReady:
return
price = self.Securities[self.crudeoilwti.Symbol].Price
strong_uptrend = price > self.ema.Current.Value and self.adx.Current.Value >= 50
strong_downtrend = price < self.ema.Current.Value and self.adx.Current.Value >= 50
atr = self.atr.Current.Value
if self.Time.hour >= 9 and self.Time.hour <= 14:
if not self.Portfolio.Invested:
if strong_uptrend is True:
if self.rsi.Current.Value < 30:
self.MarketOrder(self.crudeoilwti.Symbol, 3)
self.stoplossTicket = self.StopMarketOrder(self.crudeoilwti.Symbol, -3, price - atr*.5 )
self.takeprofitTicket = self.LimitOrder(self.crudeoilwti.Symbol, -3, price + atr*1.5)
if strong_downtrend is True:
if self.rsi.Current.Value > 70:
self.MarketOrder(self.crudeoilwti.Symbol, -3)
self.stoplossTicket = self.StopMarketOrder(self.crudeoilwti.Symbol, 3, price + atr*.5)
self.takeprofitTicket = self.LimitOrder(self.crudeoilwti.Symbol, 3, price - atr*1.5)
def OnOrderEvent(self, orderEvent):
if orderEvent.Status != OrderStatus.Filled:
return
if self.stoplossTicket is not None and self.stoplossTicket.OrderId == orderEvent.OrderId:
self.Transactions.CancelOpenOrders()
self.stoplossTicket = None
if self.takeprofitTicket is not None and self.takeprofitTicket.OrderId == orderEvent.OrderId:
self.Transactions.CancelOpenOrders()
self.takeprofitTicket = None
def ClosePositions(self):
self.Liquidate(self.crudeoilwti.Symbol)
self.Transactions.CancelOpenOrders()
Varad Kabade
Hi AegeanFutures,
Thank you for sharing your algorithm with the community.
In the above, the indicator would have wrong values as it would be updated twice as the helper method(self.ATR(), self.EMA()) already registers the indicator for updates.
Best,
Varad Kabade
.ekz.
Thanks for sharing, i'm curious about the futures bit. Does this effectively trade continuous futures? Versus a single contract?
AegeanFutures
I don't live trade any algo's currently .ekz, I use the platform here to backtest ideas I use for discretionary futures trading. In backtesting it is the industry standard in many cases to use continuous futures contracts, particularly if you are doing any kind of long/short trend following system. If I were to setup a shorter term algo to day trade akin to the one above I would always use the contact with the most traded volume currently. I posted the code above to show others a way they can implement oco orders as I was having trouble finding a useful example for myself. If you would like to use the code take Farads suggestions and implement
self.ema = self.EMA(self.crudeoilwti.Symbol, 20)
self.RegisterIndicator(self.crudeoilwti.Symbol, self.ema, timedelta(days=1))
self.adx = self.ADX(self.crudeoilwti.Symbol, 20)
self.RegisterIndicator(self.crudeoilwti.Symbol, self.adx, timedelta(hours=1))
instead using this format-
self.ema = ExponentialMovingAverage(20)
self.RegisterIndicator(self.crudeoilwti.Symbol, self.ema, Resolution.Daily)
Hope you found this helpful, Best Regards
.ekz.
Thanks for the reply AegeanFutures.
I realize now that my question was not entirely complete/well-worded.
For additional context: Most futures algos that I've seen in the forums trade individual contracts – I'm yet to see an example with continues futures, much like one would trade a stock symbol with technical indicators. It seems that is what you have here.
Varad Kabade : is the above a good implementation of a continuous futures strategy? Would you advise using this as a template?
AegeanFutures
.ekz, what I posted was just to show people how to place oco orders when entering with a market order. The examples I'd found only showed the adding of stop and take profit orders in the onorderevent handler and when entering with market orders this did not work for me. Here is the standard template for using continuous futures. If you use a trend following system and your broker offers continuous contracts this would be a good idea to use for trading pin order to reduce fee's when rolling to new contracts imho.
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from AlgorithmImports import *
### <summary>
### Basic Continuous Futures Template Algorithm
### </summary>
class BasicTemplateContinuousFutureAlgorithm(QCAlgorithm):
'''Basic template algorithm simply initializes the date range and cash'''
def Initialize(self):
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
self.SetStartDate(2013, 7, 1)
self.SetEndDate(2014, 1, 1)
self._continuousContract = self.AddFuture(Futures.Indices.SP500EMini,
dataNormalizationMode = DataNormalizationMode.BackwardsRatio,
dataMappingMode = DataMappingMode.LastTradingDay,
contractDepthOffset= 0)
self._fast = self.SMA(self._continuousContract.Symbol, 3, Resolution.Daily)
self._slow = self.SMA(self._continuousContract.Symbol, 10, Resolution.Daily)
self._currentContract = None
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Arguments:
data: Slice object keyed by symbol containing the stock data
'''
for changedEvent in data.SymbolChangedEvents.Values:
if changedEvent.Symbol == self._continuousContract.Symbol:
self.Log(f"SymbolChanged event: {changedEvent}")
if not self.Portfolio.Invested:
if self._fast.Current.Value > self._slow.Current.Value:
self._currentContract = self.Securities[self._continuousContract.Mapped]
self.Buy(self._currentContract.Symbol, 1)
elif self._fast.Current.Value < self._slow.Current.Value:
self.Liquidate()
if self._currentContract is not None and self._currentContract.Symbol != self._continuousContract.Mapped:
self.Log(f"{Time} - rolling position from {self._currentContract.Symbol} to {self._continuousContract.Mapped}")
currentPositionSize = self._currentContract.Holdings.Quantity
self.Liquidate(self._currentContract.Symbol)
self.Buy(self._continuousContract.Mapped, currentPositionSize)
self._currentContract = self.Securities[self._continuousContract.Mapped]
def OnOrderEvent(self, orderEvent):
self.Debug("Purchased Stock: {0}".format(orderEvent.Symbol))
def OnSecuritiesChanged(self, changes):
self.Debug(f"{self.Time}-{changes}")
Fred Painchaud
Hi .ekz.,
It must be because I see that thread pop out every other day but (re-)check
😊
First algo, second algo with SMAs, etc.
They look like they trade continuous futures.
Fred
.ekz.
Got it. thanks AegeanFutures and Fred Painchaud !
AegeanFutures
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!