Hello! I'm new to quantconnect. I've had some limited experience coding for MetaTrader4 and coding in Python for the OANDA Web API. After taking a look at Greg Bland's QuantConnect Guide and the corresponding code at GitHub, I thought I'd try working out a similar example for a Bollinger Bands strategy with FX data. I understand that this may be a fairly limited strategy. I was hoping mainly that it would help towards getting familiar with the API for quantconnect.
I've tried a backtest with the following Python code as my main.py
# region imports
from datetime import timedelta
from enum import StrEnum
import pandas as pd
from typing import TYPE_CHECKING, Any
from AlgorithmImports import (
QCAlgorithm, Resolution, Slice, Market, TimeSpan,
MovingAverageType, TradeBarConsolidator, SubscriptionManager,
TradeBar, BollingerBands, BaseDataConsolidator
)
import numpy as np
# endregion
# after
# https://algotrading101.com/learn/quantconnect-guide/
# https://github.com/GregBland/QuantConnect_article/blob/main/leanHogsAlgo.py
SYMBOL: str = "NZDUSD"
TEST_ORDER_SIZE: int = 100
BB_PERIOD: int = 15
BB_K = 1.5
BB_MA = MovingAverageType.WILDERS
BB_RESOL = Resolution.MINUTE
class Const(StrEnum):
SYMBOL = "symbol"
WARMUP = "warmup"
INDICATOR = "indicator"
class LeanTest00(QCAlgorithm):
initialized: bool = False
if TYPE_CHECKING:
params: dict[str, Any]
def __init__(self) -> None:
super().__init__()
self.params = dict()
def initialize(self):
global SYMBOL, WARMUP_DELTA
self.set_start_date(2024, 6, 1) # Set Start Date
self.set_end_date(2024, 8, 31) # Set End Date
self.set_cash(2000) # Set Strategy Cash
fx = self.add_forex(SYMBOL, resolution=Resolution.MINUTE,
market=Market.OANDA, leverage=50)
symbol = fx.symbol
self.log("-- symbol %r" % symbol)
consol_15m = self.create_consolidator(np.timedelta64(
15, "m").astype("O"), TradeBarConsolidator) # tick_type ??
consol_15m.data_consolidated += self.on_15m # ??
mng: SubscriptionManager = self.subscription_manager
mng.add_consolidator(symbol, consol_15m)
self.log("-- Added consolidator %r" % consol_15m)
bb = self.bb(symbol, BB_PERIOD, BB_K, BB_MA, BB_RESOL)
self.params[Const.INDICATOR] = bb
self.params[Const.SYMBOL] = symbol
def on_data(self, data: Slice):
symbol = self.params[Const.SYMBOL]
bar: TradeBar = data.bars.get(symbol)
bb: BollingerBands = self.params[Const.INDICATOR]
if bar:
bb.update(bar.EndTime, np.mean(
[bar.high, bar.low, bar.close, bar.close]))
if bb.is_ready:
self.plot("BollingerBands", "bb", bb.current.value)
self.plot("BollingerBands", "standard_deviation",
bb.standard_deviation.current.value)
self.plot("BollingerBands", "middle_band",
bb.middle_band.current.value)
self.plot("BollingerBands", "upper_band",
bb.upper_band.current.value)
self.plot("BollingerBands", "lower_band",
bb.lower_band.current.value)
self.plot("BollingerBands", "band_width",
bb.band_width.current.value)
self.plot("BollingerBands", "percent_b",
bb.percent_b.current.value)
self.plot("BollingerBands", "price", bb.price.current.value)
def on_15m(self, sender: BaseDataConsolidator, bar: TradeBar):
# event handler for M15 consolidator
if self.is_warming_up:
self.log("Consolidator [warmup] %r " % (bar.time,))
return
self.log("Consolidator %r" % (bar.time,))
bb: BollingerBands = self.params[Const.INDICATOR]
if bb.is_ready:
price = np.mean([bar.high, bar.low, bar.close, bar.close])
if price < bb.lower_band.current.value:
symbol = self.params[Const.SYMBOL]
self.sell(symbol, TEST_ORDER_SIZE)
elif price > bb.upper_band.current.value:
symbol = self.params[Const.SYMBOL]
self.liquidate(symbol)
I'm certain that there must be a number of issues in this implementation. In trying to debug this, I was running this under local tests using the quantconnect Python tooling, the `'lean' command and a local docker image from quantconnect.
With this code, I've been seeing the following under the backtest log for a local backtest:
--
2024-09-28T06:06:50.5156592Z DEBUG:: DataMonitor.OnNewDataRequest(): Data from /forex/oanda/minute/nzdusd/20240619_quote.zip could not be fetched, error: Could not find file '/Lean/Data/forex/oanda/minute/nzdusd/20240619_quote.zip'.
2024-09-28T06:06:50.5157188Z ERROR:: SubscriptionDataSourceReader.InvalidSource(): File not found: /Lean/Data/forex/oanda/minute/nzdusd/20240619_quote.zip
2024-09-28T06:06:50.5158510Z DEBUG:: DataMonitor.OnNewDataRequest(): Data from /forex/oanda/minute/nzdusd/20240620_quote.zip could not be fetched, error: Could not find file '/Lean/Data/forex/oanda/minute/nzdusd/20240620_quote.zip'.
--
It seems there's some missing data for the backtest. I wonder if anyone would have any idea as to how to fix this for the local backtest?
When I've run the same code under backtest with the quantconnect cloud, I'm seeing only one trade, a loss of net 9 cents USD. From what I'm seeing for the BolllingerBands indicator there, I'm certain that there may be some issues in how I've implemented the indicator.
If I could figure out how to get the local backtest running, I'm hoping I'd be able to debug the main code then.
Trying to diagnose the log messages about the backtest's missing data, could it be related to the start date and the end date that I'd set under initialize()?
Thanks for any help!
Mia Alissi
Here's the revised version of the code with corrections and improvements:
Key Corrections and Improvements:
TradeBarConsolidator
is correctly initialized with atimedelta
for 15 minutes, and the event handleron_15m
is properly assigned.update
method of theBollingerBands
indicator is used with the correct parameters:bar.end_time
and the average price.Next Steps:
Sources: Momentum Effect In Commodities Futures, Gradient Boosting Model, Momentum And State Of Market Filters, Indicator Warmup Algorithm, Bybit Crypto Futures Regression Algorithm
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 Champ
I've published a gist with the same main.py code, formatted for the content presentation at GitHub. I'm not certain if the backtest error could be located in the code in itself, though. The error may seem to be in how the backtest is being run?
I'm running the backtest under the local docker image, just like so:
lean backtest --verbose bollinger00
I'm not certain of how the missing data was supposed to be made available for the backtest. Thanks for any help here
Sean Champ
When running this with forex data, it seems that I've needed to use a QuoteBarConsolidator. I've updated the code for this and the patches above. I'm still seeing the same error messages.
I believe NZDUSD data should be available for some days in this duration? I'd assumed that the backtest system would just skip any weekends and holidays when trying to draw data.
From all of the error messages that I'm seeing like the excerpt above, it seems like the backtest is being run with no data?
I've tried running this under the cloud. It ran without error there, but I was unable to debug how it's failing in a functional sense.
I'm trying to debug the functional aspects with the local backtest. except that the local backtest isn't running at all.
Sean Champ
I've updated the main.py code to use start and end days on weekdays. I'm still seeing the same series of errors for missing data files in the backtest system, for every single day in the duration of start to end days.
It was my hope to get familiar with quantconnect under the free tier, before any commitment to a subscription. I understand that the OANDA and QuantConnect data providers would need some form of a subscription.
Could there be some unpublished limits on the data available for testing in the free tier?
Sean Champ
After reviewing the files under <cloud_root>/data/forex/oanda/minute/nzdusd/ I've updated the start, end dates to the following:
This much seems to have worked out. The backtest is running, presently, and it's running on into 2015 right now. I'll try to figure out that part, next.
Thanks for the quick advice!
Sean Champ
lol I'd used two set_start_date and no set_end_date.
The backtest is running pretty quickly though. ngl this is wildly faster than under metatrader backtesting
Sean Champ
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!