Hello,
Is it possible to code a strategy like this?
Each day, I want an algorithm to use 25% of my account to long or short TQQQ. If the first 5-minute candle of the day is green, the algorithm opens a long position. If the first 5-minute candle of the day is red, the algorithm opens a short position. In other words, if during the first 5 minutes the market moved up, we take a bullish position starting from the second candle’s opening price. Conversely, if the first 5-minute candle was negative, we take a bearish position at the open of the second 5-minute candle. Please do not open a position when the first 5-minute candle is a doji (open price = close price). I want the algorithm to set the data normalization mode to RAW.
I want the algorithm to close the position if a stop loss of 5% of the 14-day Average True Range is hit. I want the algorithm to log Average True Range and price values at each entry to help with debugging. Something like the example debug pasted below if possible. If the stop loss is not hit during the day, I want the algorithm to close the position a few seconds before the market closes for the day. Thanks!
- self.debug(f"{self.time} Price: {price} ATR: {self._atr.current.value} StopDist: {stop_distance}")
Mia Alissi
This code fulfills your requirements and logs ATR/price/stop values at entry for debugging purposes.
Sources: docs writing algorithms securities asset classes us equity handling data, docs writing algorithms trading and orders order management order tickets, docs writing algorithms securities asset classes us equity data preparation, Logging - QuantConnect.com, docs writing algorithms portfolio key concepts
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.
Retrospective Green Ocelot
Thanks!
Ronny Kasabri
Plan for TQQQ 5-Minute Candle StrategyObjective: Create an algorithm that trades TQQQ based on the first 5-minute candle of each day.Key Requirements:Use 25% of account for each positionLong if first 5-minute candle is green, short if redSkip if first candle is a doji (open = close)Set data normalization to RAWStop loss: 5% of 14-day ATRClose position before market close if stop loss not hitLog ATR and price values for debuggingImplementation Approach:Initialize TQQQ with 5-minute resolution and RAW data normalizationAdd ATR indicator with 14-day periodTrack daily state (first candle processed, position opened)Use scheduled events for market open and closeImplement position management with ATR-based stop lossfrom from AlgorithmImports import *
from datetime import timedelta
class TQQQFiveMinuteCandleStrategy(QCAlgorithm):
"""
TQQQ 5-Minute Candle Strategy
Each day:
1. Check first 5-minute candle of the day
2. If green (close > open): Open long position with 25% of account
3. If red (close < open): Open short position with 25% of account
4. If doji (close = open): Skip trading for the day
5. Stop loss: 5% of 14-day Average True Range
6. Close position before market close if stop loss not hit
"""
def Initialize(self):
# Set start and end dates for backtesting
self.SetStartDate(2023, 1, 1)
self.SetEndDate(2024, 1, 1)
# Set initial cash
self.SetCash(100000)
# Add TQQQ with 5-minute resolution and RAW data normalization
self.tqqq = self.AddEquity(
"TQQQ",
Resolution.Minute,
dataNormalizationMode=DataNormalizationMode.Raw
)
# Add Average True Range indicator (14-day period)
self.atr = self.ATR(self.tqqq.Symbol, 14, resolution=Resolution.Daily)
# Set warm-up period for ATR indicator
self.SetWarmUp(20, Resolution.Daily)
# Initialize tracking variables
self.daily_state = {
'first_candle_processed': False,
'position_opened': False,
'entry_price': 0,
'stop_loss_price': 0,
'position_direction': 0, # 1 for long, -1 for short
'atr_value': 0
}
# Schedule daily reset at market open
self.Schedule.On(
self.DateRules.EveryDay("TQQQ"),
self.TimeRules.AfterMarketOpen("TQQQ", 0),
self.DailyReset
)
# Schedule position close before market close
self.Schedule.On(
self.DateRules.EveryDay("TQQQ"),
self.TimeRules.BeforeMarketClose("TQQQ", 5), # 5 min before close
self.ClosePositionBeforeClose
)
# Debug logging
self.Debug("TQQQ 5-Minute Candle Strategy Initialized")
self.Debug(f"Data Normalization Mode: {self.tqqq.DataNormalizationMode}")
def OnData(self, data):
"""Handle incoming data"""
# Skip if warming up
if self.IsWarmingUp:
return
# Skip if ATR not ready
if not self.atr.IsReady:
return
# Process first candle if not done yet
if (not self.daily_state['first_candle_processed'] and
data.ContainsKey(self.tqqq.Symbol)):
self.ProcessFirstCandle(data[self.tqqq.Symbol])
# Check stop loss if position is open
if (self.daily_state['position_opened'] and
data.ContainsKey(self.tqqq.Symbol)):
self.CheckStopLoss(data[self.tqqq.Symbol])
def ProcessFirstCandle(self, bar):
"""Process the first 5-minute candle of the day"""
# Check if this is the first 5-minute candle (9:30-9:35 AM ET)
current_time = self.Time
market_open = current_time.replace(hour=9, minute=30, second=0,
microsecond=0)
first_candle_end = market_open + timedelta(minutes=5)
if current_time < market_open or current_time >= first_candle_end:
return
# Mark first candle as processed
self.daily_state['first_candle_processed'] = True
# Get OHLC data
open_price = bar.Open
close_price = bar.Close
# Check for doji (open price = close price)
if abs(open_price - close_price) < 0.01: # Small tolerance
self.Debug(f"[{self.Time}] First candle is DOJI - Skipping trade "
f"today. Open: {open_price}, Close: {close_price}")
return
# Determine position direction
if close_price > open_price:
# Green candle - Long position
self.daily_state['position_direction'] = 1
self.Debug(f"[{self.Time}] First candle is GREEN - "
f"Preparing LONG position")
else:
# Red candle - Short position
self.daily_state['position_direction'] = -1
self.Debug(f"[{self.Time}] First candle is RED - "
f"Preparing SHORT position")
# Store ATR value for debugging
self.daily_state['atr_value'] = self.atr.Current.Value
# Log debug information
self.Debug(f"[{self.Time}] ATR (14-day): "
f"{self.daily_state['atr_value']:.4f}")
self.Debug(f"[{self.Time}] Open: {open_price:.2f}, "
f"Close: {close_price:.2f}")
# Schedule position opening at second candle open (9:35 AM)
self.Schedule.On(
self.DateRules.Today,
self.TimeRules.At(9, 35),
self.OpenPosition
)
def OpenPosition(self):
"""Open position at second candle open"""
if self.daily_state['position_opened']:
return
# Get current price (second candle open)
current_price = self.Securities[self.tqqq.Symbol].Price
if current_price == 0:
self.Debug(f"[{self.Time}] No valid price for position opening")
return
# Calculate stop loss price
atr_value = self.daily_state['atr_value']
stop_loss_atr = atr_value * 0.05 # 5% of ATR
if self.daily_state['position_direction'] == 1:
# Long position
stop_loss_price = current_price - stop_loss_atr
self.Debug(f"[{self.Time}] Opening LONG position at "
f"{current_price:.2f}")
self.Debug(f"[{self.Time}] Stop loss set at "
f"{stop_loss_price:.2f} (ATR: {atr_value:.4f}, "
f"5% ATR: {stop_loss_atr:.4f})")
else:
# Short position
stop_loss_price = current_price + stop_loss_atr
self.Debug(f"[{self.Time}] Opening SHORT position at "
f"{current_price:.2f}")
self.Debug(f"[{self.Time}] Stop loss set at "
f"{stop_loss_price:.2f} (ATR: {atr_value:.4f}, "
f"5% ATR: {stop_loss_atr:.4f})")
# Store position details
self.daily_state['entry_price'] = current_price
self.daily_state['stop_loss_price'] = stop_loss_price
self.daily_state['position_opened'] = True
# Open position
self.SetHoldings(self.tqqq.Symbol,
0.25 * self.daily_state['position_direction'])
def OnOrderEvent(self, orderEvent):
"""Handle order events"""
if orderEvent.Status == OrderStatus.Filled:
self.Debug(f"[{self.Time}] Order filled: {orderEvent}")
def CheckStopLoss(self, bar):
"""Check if stop loss should be triggered"""
current_price = bar.Close
if self.daily_state['position_direction'] == 1:
# Long position - check if price hit stop loss
if current_price <= self.daily_state['stop_loss_price']:
self.Debug(f"[{self.Time}] STOP LOSS HIT for LONG position. "
f"Current: {current_price:.2f}, "
f"Stop: {self.daily_state['stop_loss_price']:.2f}")
self.Liquidate(self.tqqq.Symbol)
self.daily_state['position_opened'] = False
else:
# Short position - check if price hit stop loss
if current_price >= self.daily_state['stop_loss_price']:
self.Debug(f"[{self.Time}] STOP LOSS HIT for SHORT position. "
f"Current: {current_price:.2f}, "
f"Stop: {self.daily_state['stop_loss_price']:.2f}")
self.Liquidate(self.tqqq.Symbol)
self.daily_state['position_opened'] = False
def ClosePositionBeforeClose(self):
"""Close position before market close"""
if self.daily_state['position_opened']:
current_price = self.Securities[self.tqqq.Symbol].Price
self.Debug(f"[{self.Time}] Closing position before market close "
f"at {current_price:.2f}")
self.Liquidate(self.tqqq.Symbol)
self.daily_state['position_opened'] = False
def DailyReset(self):
"""Reset daily state at market open"""
self.daily_state = {
'first_candle_processed': False,
'position_opened': False,
'entry_price': 0,
'stop_loss_price': 0,
'position_direction': 0,
'atr_value': 0
}
self.Debug(f"[{self.Time}] Daily reset completed")
Retrospective Green Ocelot
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!