Hi,
Attached you can find a backtest in which I use custom indicator on 3 minute data. I am getting Runtime error, but can't find the source of the problem.
I am posting the code, because I can't attach backtest with an error.
#region imports
from AlgorithmImports import *
#endregion
from datetime import timedelta
from collections import deque
class LogicalBrownKoala(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022, 4, 1)
# self.SetEndDate(2020, 11, 1)
self.SetCash(100000)
future = self.AddFuture(Futures.Energies.CrudeOilWTI, Resolution.Minute)
future.SetFilter(timedelta(10), timedelta(180))
# parameters
self.slow_sma = None
self.slow_sma_period = 25
self.fast_sma = None
self.fast_sma_period = 12
self.CCIPeriod = 30 # CCI period
self.CCIupperBound = 100 # CCI upper bound line
self.CCIlowerBound = -100 # CCI lower bound line
self.volume_sma_period = 30
# init
self.consolidator_by_symbol = {}
def OnData(self, slice):
# define time we trade
stop_time_start = self.Time.replace(hour=15, minute=00)
stop_time_end = self.Time.replace(hour=16, minute=30)
if self.Time > stop_time_end or self.Time < stop_time_start:
return
for chain in slice.FutureChains.Values:
contracts = chain.Contracts
if len(contracts) == 0:
continue
sorted_by_oi_contracts = sorted(contracts.Values, key=lambda k: k.OpenInterest, reverse=True)
# self.Debug(f"contract 1: {sorted_by_oi_contracts[0].Symbol}, underlying {sorted_by_oi_contracts[0].UnderlyingSymbol}, expiry {sorted_by_oi_contracts[0].Expiry}, last price {sorted_by_oi_contracts[0].LastPrice}")
# self.Debug(f"contract 1: {sorted_by_oi_contracts[1].Symbol}, underlying {sorted_by_oi_contracts[1].UnderlyingSymbol}, expiry {sorted_by_oi_contracts[1].Expiry}, last price {sorted_by_oi_contracts[1].LastPrice}")
popular_contract = sorted_by_oi_contracts[0]
# class FuturesContract:
# self.Symbol # (Symbol) Symbol for contract needed to trade.
# self.UnderlyingSymbol # (Symbol) Underlying futures asset.
# self.Expiry # (datetime) When the future expires
# self.OpenInterest # (decimal) Number of open interest.
# self.LastPrice # (decimal) Last sale price.
# self.Volume # (long) reported volume.
# self.BidPrice # (decimal) bid quote price.
# self.BidSize # (long) bid quote size.
# self.AskPrice # (decimal) ask quote price.
# self.AskSize # (long) ask quote size.
# calculate TrueRange
# if close_window[1] > slice[popular_contract.Symbol].High:
# TH = close_window[1]
# else:
# TH = slice[popular_contract.Symbol].High
# if close_window[1] < slice[popular_contract.Symbol].Low:
# TL = close_window[1]
# else:
# TL = slice[popular_contract.Symbol].Low
# TrueRange = TH - TL
# plot indicators
#if self.slow_sma:
# self.Plot("Indicators", "SMA", self.slow_sma.Current.Value)
if popular_contract.Symbol not in self.consolidator_by_symbol:
# rolling windows
# close_window = RollingWindow[float](2)
# high_window = RollingWindow[float](2)
# low_window = RollingWindow[float](2)
minutesConsolidator = TradeBarConsolidator(timedelta(minutes=3))
#minutesLongConsolidator = TradeBarConsolidator(timedelta(minutes=3))
minutesConsolidator.DataConsolidated += self.MinutesHandler
# minutesLongConsolidator.DataConsolidated += self.MinutesLongHandler
self.SubscriptionManager.AddConsolidator(popular_contract.Symbol, minutesConsolidator)
# self.SubscriptionManager.AddConsolidator(popular_contract.Symbol, minutesLongConsolidator)
self.consolidator_by_symbol[popular_contract.Symbol] = minutesConsolidator
self.slow_sma = LinearWeightedMovingAverage(self.slow_sma_period)
self.fast_sma = LinearWeightedMovingAverage(self.fast_sma_period)
self.volume_sma = LinearWeightedMovingAverage(self.fast_sma_period)
self.true_range = TrueRange("TrueRange", 2)
# Commodity Channel Index (https://en.wikipedia.org/wiki/Commodity_channel_index)
self.cci = self.CCI(popular_contract.Symbol, self.CCIPeriod, MovingAverageType.Simple, Resolution.Daily)
self.RegisterIndicator(popular_contract.Symbol, self.slow_sma, minutesConsolidator)
self.WarmUpIndicator(popular_contract.Symbol, self.slow_sma, Resolution.Minute)
self.RegisterIndicator(popular_contract.Symbol, self.fast_sma, minutesConsolidator)
self.WarmUpIndicator(popular_contract.Symbol, self.fast_sma, Resolution.Minute)
self.RegisterIndicator(popular_contract.Symbol, self.volume_sma, minutesConsolidator, Field.Volume)
self.WarmUpIndicator(popular_contract.Symbol, self.volume_sma, Resolution.Minute)
self.RegisterIndicator(popular_contract.Symbol, self.cci, minutesConsolidator)
self.WarmUpIndicator(popular_contract.Symbol, self.cci, Resolution.Minute)
self.RegisterIndicator(popular_contract.Symbol, self.true_range, minutesConsolidator)
self.WarmUpIndicator(popular_contract.Symbol, self.true_range, Resolution.Minute)
self.Plot("Indicator", "SMA slow", self.slow_sma.Current.Value)
self.Plot("Indicator", "SMA fast", self.fast_sma.Current.Value)
# self.Plot("Indicator", "TrueRange", self.true_range.Value)
self.Plot("Indicator 2", "SMA Volume", self.volume_sma.Current.Value)
self.Plot("CCI", "CCI value", self.cci.Current.Value)
# trading rule
if self.slow_sma.Current.Value > self.fast_sma.Current.Value:
self.SetHoldings(popular_contract.Symbol, 1)
def MinutesHandler(self, sender: DataConsolidator, bar: TradeBar):
# close_window.Add(bar.Close)
# high_window.Add(bar.High)
# low_window.Add(bar.low)
pass
class TrueRange(PythonIndicator):
def __init__(self, name, period):
self.Name = name
self.Value = None
self.period = period
self.WarmUpPeriod = period
self.Time = datetime.min
self.queue_close = deque(maxlen=period)
self.queueTime = deque(maxlen=period)
def Update(self, input):
self.queue_close.appendleft(input.Close)
self.queueTime.appendleft(input.EndTime)
self.Time = input.EndTime
count = len(self.queue)
if self.queue_close[0] > input.High:
TH = self.queue_close[0]
else:
TH = input.High
if self.queue_close[0] < input.Low:
TL = self.queue_close[0]
else:
TL = input.Low
self.Value = TH - TL
self.IsReady = count == self.queue.maxlen
return self.IsReady
Vladimir
Mislav
Just wondering why you use a custom indicator when there is a QC indicator with the same name and functionality.
Vladimir
Mislav
Here is your algorithm with my changes.
It doesn't issue any of the Runtime errors you mentioned.
If you are satisfied with my answer, please accept it and don't forget to like it.
Mislav Sagovac
I don't use QC TrueRange indicator, because it is different from mine.
I am sending changed code. I have change indicato class to make it simpler. But it still doesn't work.
Vladimir
Mislav
Here is your algorithm with my changes and fixed custom True_Range indicator.
It doesn't issue any of the Runtime errors you mentioned.
If you are satisfied with my answer, please accept it and don't forget to like it.
Vladimir
Mislav
--> I don't use QC TrueRange indicator, because it is different from mine.
Try “Compare QC TrueRange and Custom True_Range indicators”.
The results are absolutely identical.
Mislav Sagovac
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!