hi, i am having a hard time making my strategy work. i pretty much want to create a universe that filtter the tickers that have an rsi > 40 and that are bellow the bb.lowerband en return 3 tickers. then i want to set 33% of the account balance in those 3 tickers once the cross back above the bb.lowerband.
then i was trying to set the stoploss to the entry candle previous low and the take profit to 2* the difference between the entry price and the stoploss. i can't find a way to log the symbol low at the time of entry to use it as stoploss. and as the backtest doesn't give me error and is stuck on analyse, i can't quite figure out what is wrong with is.
any help is apreciated.
thanks
Mathieu Labelle
from AlgorithmImports import *
import numpy as np
import pandas as pd
class SmoothLightBrownKangaroo(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022, 1, 1) # Set start date for backtest
self.SetEndDate(2023, 1, 1) # Set end date for backtest
self.SetCash(100000) # Set cash for backtest
self.SetBrokerageModel(BrokerageName.OandaBrokerage) # Set brokerage model
self.currency = "EURUSD" # Set currency for backtest
self.AddForex(self.currency, Resolution.Hour) # Add forex to algorithm
self.AddForex("USDJPY", Resolution.Hour) # Add another forex
# self.AddForex("GBPUSD", Resolution.Hour) # Add another forex
# self.AddForex("AUDUSD", Resolution.Hour) # Add another forex
# self.AddForex("NZDUSD", Resolution.Hour) # Add another forex
# self.AddForex("USDCAD", Resolution.Hour) # Add another forex
# self.AddForex("USDCHF", Resolution.Hour) # Add another forex
# self.AddForex("EURGBP", Resolution.Hour) # Add another forex
# self.AddForex("EURJPY", Resolution.Hour) # Add another forex
# Set warmup period for indicators
self.warmup_period = 14
self.warmup = True
# Define universe selection
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
# Define indicators
self.rsi_period = 14
self.rsi = RelativeStrengthIndex(self.rsi_period)
self.bb_period = 20
self.bb_std_dev = 2
self.bb = BollingerBands(self.bb_period, self.bb_std_dev)
# Define variables for holding selected symbols
self.selected_coarse = None
self.selected_fine = None
# Define variables for holding positions
self.positions = []
self.stop_loss_pct = 0.01 # Set stop loss percentage
self.risk_reward_ratio = 2 # Set risk reward ratio
def CoarseSelectionFunction(self, coarse):
# Filter for symbols with volume and price above $5
filtered = [x for x in coarse if x.HasFundamentalData and x.Volume ]
# Sort symbols by lowest RSI on hourly timeframe
top = sorted(filtered, key=lambda x: self.rsi.Current.Value if not self.History([x.Symbol], 14, Resolution.Hour).empty and self.rsi.IsReady else float('inf'))
# Return top 10 symbols with RSI below 40 on hourly timeframe
selected = []
for symbol in top[:10]:
history = self.History([symbol.Symbol], 14, Resolution.Hour)
if not history.empty and self.rsi.IsReady:
rsi = self.rsi.Current.Value
if rsi < 40:
selected.append(symbol.Symbol)
self.selected_coarse = selected
for symbol in self.selected_coarse:
print(symbol)
return selected
def FineSelectionFunction(self, fine):
# Filter for symbols in coarse universe
filtered = [x for x in fine if x.Symbol in self.selected_coarse]
# Sort symbols by distance from lower Bollinger band on hourly timeframe
top = sorted(filtered, key=lambda x: abs(self.bb.LowerBand.Current.Value - x.Price), reverse=True)
# Return top 3 symbols below lower Bollinger band on hourly timeframe
selected = []
for symbol in top[:3]:
history = self.History([symbol.Symbol], 20, Resolution.Hour)
if not history.empty and self.bb.IsReady:
if history.iloc[-1].close < self.bb.LowerBand.Current.Value:
selected.append(symbol.Symbol)
self.selected_fine = selected
for symbol in self.selected_fine:
print(symbol)
return [x.Symbol for x in selected]
def OnData(self, data):
if self.warmup:
if not self.rsi.IsReady or not self.bb.IsReady:
return
self.warmup = False
return
# Coarse selection
if self.selected_coarse is None:
self.CoarseSelectionFunction(None)
coarse_symbols = [x.Symbol for x in self.selected_coarse]
# Fine selection
if self.selected_fine is None:
self.FineSelectionFunction(None)
fine_symbols = [x.Symbol for x in self.selected_fine]
self.UpdatePositions()
# Open positions for selected symbols
if fine_symbols:
for symbol in fine_symbols:
if symbol not in [x.Symbol for x in self.Portfolio]:
if self.Securities[symbol].Price > self.bb.LowerBand.Current.Value:
self.SetHoldings(symbol, 0.33)
position = self.Portfolio[symbol]
def UpdatePositions(self):
# Get all open positions
self.positions = [x.Symbol for x in self.Portfolio if x.Invested]
# Check if we need to sell any positions
for symbol in self.positions:
stop_loss_price = self.Securities[symbol].LowestPrice(60)
take_profit_price=(self.positions.AveragePrice - stop_loss_price)*2
if self.Portfolio[symbol].Price <= stop_loss_price:
self.Liquidate(symbol, f"Hit stop loss price of {stop_loss_price}")
self.Log(f"Liquidated {symbol} due to hitting stop loss price of {stop_loss_price}")
elif self.Portfolio[symbol].Price >= take_profit_price:
self.Liquidate(symbol, f"Hit risk reward ratio of {self.risk_reward_ratio}")
self.Log(f"Liquidated {symbol} due to hitting risk reward ratio of {self.risk_reward_ratio}")
# Log the current portfolio holdings
for holding in self.Portfolio:
self.Log(f"{holding.Symbol}: {holding.Quantity}")
Stephen Hyer
I suggest looking into rolling windows and consolidators to track your open/high/low/close/volume TradeBar information at any given slice or consolidated slice. I believe the RiskManagement class Framework receives those slices, so you can construct the symbolData there and use it to create artificial stop losses that trigger when your criteria is met.
Mathieu Labelle
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!