Hi!
I am trying to deploy a backtest on quantconnect platform based on the trading signals created by ML algorithms I have developed.
Due to the logistics and limitations on computing resources, I have already run the algorithm and have it as a .json file containing the hourly buy/sell signal for every hour between 2018 and 2023.
This would be an example of my .json file
Following is my code for data loading and backtest execution. When I run the backtest, no trade occurs and I get an error message stating “Runtime Error: 'list' object is not callable”.
I have been looking at tutorials and online resources to resolve the issue, but I am stuck. Any help will be greatly appreciated!
#CODE FOR EXTERNAL DATA LOADING
class ADA(PythonData):
def __init__(self):
self.Signal = ""
def GetSource(self, config, date, isLiveMode: False):
url = "URL_TO_MY_DROPBOX_FOR_JSON"
return SubscriptionDataSource(url, SubscriptionTransportMedium.RemoteFile)
def Reader(self, config, line, date, isLiveMode: False):
if not (line.strip() and line.startswith("{")):
return None
try:
data = json.loads(line)
signal = TradingSignal()
signal.Symbol = config.Symbol
signal.Time = datetime.strptime(data['Time'], "%Y-%m-%dT%H:%M:%SZ")
signal.Value = 0
signal["Signal"] = data['Signal']
return signal
except ValueError:
return None
#CODE FOR BACKTEST
class Algorirthm1(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetEndDate(2023, 6, 30)
self.SetCash("BUSD", 1000000)
self.SetBrokerageModel(BrokerageName.Binance, AccountType.Cash)
self.symbols = ["BTCBUSD", "ETHBUSD", "XRPBUSD", "ADABUSD", "EOSBUSD"]
self.symbolData = {}
# Add Crypto Assets and corresponding custom data
for symbol in self.symbols:
crypto = self.AddCrypto(symbol, Resolution.Hour, Market.Binance).Symbol
resolution = Resolution.Daily
self.AddData(BTC, "BTCBUSD", resolution)
self.AddData(ADA, "ADABUSD", resolution)
self.AddData(ETH, "ETHBUSD", resolution)
self.AddData(XRP, "XRPBUSD", resolution)
self.AddData(EOS, "EOSBUSD", resolution)
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.Every(timedelta(minutes=1440)), self.Liquidate())
def OnData(self, data):
self.Plot("Data Chart", self.symbol, self.Securities[self.symbol].Close)
for symbol in self.symbols:
self.Debug(symbol, data[symbol])
self.SetHoldings(symbol, 1.0 / len(self.symbols))
if data.ContainsKey(symbol) and data[symbol] is not None:
trading_signal = data[symbol].Signal
if trading_signal == "buy":
self.SetHoldings(symbol, 1.0 / len(self.symbols)) # Equally distribute cash among symbols
elif trading_signal == "sell" and self.Portfolio[symbol].Invested:
self.Liquidate(symbol)
Mia Alissi
It looks like there are a few issues in your code that need to be addressed to get your backtest running correctly. Here are some suggestions:
Custom Data Class Issue: In your
ADA
class, you're trying to set a dictionary item withsignal["Signal"] = data['Signal']
, butsignal
is an instance ofTradingSignal
, which doesn't support item assignment like a dictionary. You should directly assign the value to an attribute of thesignal
object.Custom Data Class Naming: When you add custom data with
self.AddData(ADA, "ADABUSD", resolution)
, the first argument should be the class that handles the custom data, not a symbol string. Make sure thatADA
,BTC
,ETH
,XRP
, andEOS
are classes derived fromPythonData
similar to yourADA
class. If they are meant to be symbols, you should correct theAddData
method to use the class intended for handling the custom data.Incorrect Use of
self.SetCash
: The methodself.SetCash
takes either a single argument as the initial cash balance (a number) or two arguments where the first is the currency symbol as a string (e.g., "USD") and the second is the amount. In yourInitialize
method, you haveself.SetCash("BUSD", 1000000)
, which seems to be an incorrect usage. If "BUSD" is meant to be the account currency, you should set the cash with just the amountself.SetCash(1000000)
and set the account currency separately if needed.Data Access in
OnData
: In theOnData
method, you're trying to accessdata[symbol]
directly, which might not work as expected with custom data. You should check if the data slice contains your custom data type. Also,self.Debug(symbol, data[symbol])
is not correctly formatted;self.Debug
takes a single string argument.Plotting Issue: The line
self.Plot("Data Chart", self.symbol, self.Securities[self.symbol].Close)
seems incorrect becauseself.symbol
is not defined anywhere in yourAlgorithm1
class. You might want to iterate through your symbols and plot their data individually.Here's a corrected snippet focusing on the custom data class and
OnData
method:```python
Corrected Custom Data Classclass ADA(PythonData): def init(self): self.Signal = "" def GetSource(self, config, date, isLiveMode): url = "URL_TO_MY_DROPBOX_FOR_JSON" return SubscriptionDataSource(url, SubscriptionTransportMedium.RemoteFile) def Reader(self, config, line, date, isLiveMode): if not (line.strip() and line.startswith("{")): return None try: data = json.loads(line) signal = ADA() signal.Symbol = config.Symbol signal.Time = datetime.strptime(data['Time'], "%Y-%m-%dT%H:%M:%SZ") signal.Value = 0 signal.Signal = data['Signal'] # Corrected attribute assignment return signal except ValueError: return None
Corrected OnData Methoddef OnData(self, data): for symbol in self.symbols: if data.ContainsKey(symbol) and data[symbol] is not None: trading_signal = data[symbol].Signal if trading_signal == "buy": self.SetHoldings(symbol, 1.0 / len(self.symbols)) elif trading_signal == "sell" and self.Portfolio[symbol
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.
Yuri Lopukhov
It would help if you provide specific line number where this happens, it should be in the error message. But I found some other issues with your code:
here you need to remove parenthesis for self.Liquidate, like this:
Also, in the OnData handler you should put self.Plot call inside the for loop, as Mia mentions in point 5.
And check points 1, 2 and 4 from Mia's answer. 3rd point is not correct.
P.S. perhaps admins should check code formatting issue in Mia's answer.
Mia Alissi
Thank you for pointing out the corrections and additional insights, Yuri. Let's address the issues based on your feedback and clarify the points:
self.Liquidate()
, you should not include the parentheses. This is because you're passing the method reference to be called by the scheduler, not calling the method at the point of scheduling. Here's the corrected line:Plotting Inside the Loop: To plot data for each symbol, you should indeed move the
self.Plot
call inside the loop where you iterate through symbols. This allows you to plot the close price for each symbol individually.Clarification on
self.SetCash
: My previous mention of an issue withself.SetCash("BUSD", 1000000)
was incorrect in the context of using Binance as the brokerage model, where "BUSD" can indeed be a valid currency symbol. I appreciate Yuri's correction on this point.Custom Data and
OnData
Method: Ensure that your custom data classes (likeADA
) are correctly defined and used. Each custom data type should have itsReader
method correctly parsing the JSON data. In theOnData
method, ensure you're correctly checking for the presence of data for each symbol and handling buy/sell signals as intended.Here's a revised snippet incorporating Yuri's feedback and corrections:
This revised code addresses the specific issues Yuri highlighted and incorporates the corrections and suggestions from both responses. Remember to ensure that your JSON data URL and the parsing logic in your custom data classes are correctly set up to match the structure of your JSON file.
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.
Sean Ryu
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!