I'm trying to create a minimum time delay between each position in a basket of positions, but keep getting this error:
During the algorithm initialization, the following exception has occurred: 'ForexCFDAlgorithm' object has no attribute 'TimeBasedPositionEntry' at Initialize self.TimeBasedPositionEntry) at Python.Runtime.PythonException.ThrowLastAsClrException() at src\runtime\PythonException.cs:line 52 at Python.Runtime.PyObject.Invoke(PyTuple args in main.py: line 28 'ForexCFDAlgorithm' object has no attribute 'TimeBasedPositionEntry'
Here's the algo code in its entirety:
from AlgorithmImports import *
class ForexCFDAlgorithm(QCAlgorithm):
def Initialize(self):
# Initialization settings
self.SetStartDate(2020, 1, 1)
self.SetCash(100000)
# Add Forex symbol
self.symbol = self.AddForex("EURUSD", Resolution.Daily).Symbol
# Indicators
self.monthly_ema = self.EMA(self.symbol, 10, Resolution.Daily)
self.last_monthly_ema_update = self.Time.month
self.daily_ema = self.EMA(self.symbol, 10, Resolution.Daily)
self.atr = self.ATR(self.symbol, 100, Resolution.Daily)
# State variables
self.is_long_term_bullish = False
self.batch_positions = []
self.batch_stop_loss = 0
self.batch_entry_prices = []
self.last_position_time = self.Time
self.trailing_stop = 0
# Schedule function for every 120 minutes
self.Schedule.On(self.DateRules.EveryDay(self.symbol),
self.TimeRules.Every(timedelta(minutes=120)),
self.TimeBasedPositionEntry)
def UpdateMonthlyEMA(self, data):
current_month = self.Time.month
if self.last_monthly_ema_update != current_month:
self.monthly_ema.Update(data[self.symbol])
self.last_monthly_ema_update = current_month
def OnData(self, data):
# Ensure data for the symbol is available
if not self.symbol in data:
return
self.UpdateMonthlyEMA(data)
# Check for monthly trend and update long term direction
if self.monthly_ema.IsReady:
self.is_long_term_bullish = data[self.symbol].Close > self.monthly_ema.Current.Value
# Execute strategy based on daily data
if self.daily_ema.IsReady and self.atr.IsReady:
self.ExecuteStrategy(data)
def ExecuteStrategy(self, data):
# Entry logic based on long-term trend and daily EMA
if not self.atr.IsReady or not self.daily_ema.IsReady:
return # Ensure that the ATR and EMA indicators are ready
# Check for long-term bullish trend and a positive crossover on daily EMA
if self.is_long_term_bullish and data[self.symbol].Close > self.daily_ema.Current.Value:
# Check if it's time to enter a new batch position
if len(self.batch_positions) < 5 and (self.Time - self.last_position_time) >= timedelta(minutes=120):
self.EnterPosition('Long')
# Check for long-term bearish trend and a negative crossover on daily EMA
elif not self.is_long_term_bullish and data[self.symbol].Close < self.daily_ema.Current.Value:
# Check if it's time to enter a new batch position
if len(self.batch_positions) < 5 and (self.Time - self.last_position_time) >= timedelta(minutes=120):
self.EnterPosition('Short')
# Update trailing stop and manage the batch
self.UpdateTrailingStopAndManageBatch()
def OnData(self, data):
# Ensure data for the symbol is available
if not self.symbol in data:
return
# Check for monthly trend and update long term direction
if self.monthly_ema.IsReady:
self.is_long_term_bullish = data[self.symbol].Close > self.monthly_ema.Current.Value
# Execute strategy based on daily data
if self.daily_ema.IsReady and self.atr.IsReady:
self.ExecuteStrategy(data)
def ExecuteTrailingStopLoss(self):
# Assuming the trailing stop is based on the ATR
atr_value = self.atr.Current.Value
trailing_stop_distance = 3 * atr_value # Example multiplier
# Update trailing stop for each position
for price, size in self.batch_entry_prices:
if self.Portfolio[self.symbol].IsLong:
# For long positions
self.trailing_stop = max(self.trailing_stop, price - trailing_stop_distance)
else:
# For short positions
self.trailing_stop = min(self.trailing_stop, price + trailing_stop_distance)
# Check if the current price has hit the trailing stop
current_price = self.Securities[self.symbol].Price
if (self.Portfolio[self.symbol].IsLong and current_price <= self.trailing_stop) or \
(self.Portfolio[self.symbol].IsShort and current_price >= self.trailing_stop):
self.Liquidate(self.symbol)
self.batch_positions.clear()
self.batch_entry_prices.clear()
def EnterPosition(self, direction):
# ... [Existing position size and stop-loss calculation]
# Enter the trade
if direction == 'Long':
self.Buy(self.symbol, lot_size)
else:
self.Sell(self.symbol, lot_size)
# Add this position to batch tracking
self.batch_positions.append(self.symbol)
self.batch_entry_prices.append((self.Securities[self.symbol].Price, lot_size))
def TimeBasedPositionEntry(self):
# Check if it's time to consider a new position
if self.Time - self.last_position_time >= timedelta(minutes=120):
# Check the strategy conditions
if self.is_long_term_bullish and self.Securities[self.symbol].Price > self.daily_ema.Current.Value:
self.EnterPosition('Long')
elif not self.is_long_term_bullish and self.Securities[self.symbol].Price < self.daily_ema.Current.Value:
self.EnterPosition('Short')
Ashutosh
Hi Ross,
There are a couple of very basic errors inside your code.
- You have 2 Ondata methods which is logically wrong. I combined both the Ondata methods into one.
- When you call EMA method you trigger the automatic indicator which you do not update with values. EMA indicator is a pre-built indicator that uses close prices for calculation. If you want to make your own EMA indicator and update values you can use “ExponentialMovingAverage” method.
Please refer to this document for more info.
I suggest going through our Boot camp, as it will provide you with a better understanding and grasp of the platform.
I have attached a backtest without any errors for your reference.
Best,
Ashutosh
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.
Ross Brook
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!