ira bajpai
ira bajpai

Reputation: 25

Trying to use Backtrader for backtesting getting this error AttributeError: 'tuple' object has no attribute 'lower'

I am trying to test out few algorithms for trading, however, I am getting the error

AttributeError: 'tuple' object has no attribute 'lower'

I am using YF data here is the code:

    import yfinance as yf
import pandas as pd
import numpy as np
import backtrader as bt
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score
import nltk
from nltk.sentiment.vader import SentimentIntensityAnalyzer
from datetime import datetime
from pylab import mpl,plt

# Ensure that nltk's VADER lexicon is downloaded
nltk.download('vader_lexicon')

# 1. Download historical data
ticker = 'AAPL'  # Example: Apple stock
start_date = '2010-01-01'
end_date = '2024-01-01'

data = yf.download(ticker, start=start_date, end=end_date)

data.head()
#calculating sma values for two different rolling window sizes
data['SMA_50'] = data['Close'].rolling(window=50).mean()
data['SMA_200'] = data['Close'].rolling(window=200).mean()
plt.figure(figsize=(12, 6))
plt.plot(data['Close'], label='Closing Price', alpha=0.5)
plt.plot(data['SMA_50'], label='shorter sma 50', linewidth=2)
plt.plot(data['SMA_200'], label='larger sma 200', linewidth=2)

plt.legend()
plt.title('AAPL with SMA (50 & 100 Days)')
plt.show()

data['Position']=np.where(data['SMA_50']>data['SMA_200'],1,-1)
data.dropna(inplace=True)

# Create the features and target variable
data['Price_Change'] = data['Close'].shift(-1) - data['Close']
data['Target'] = np.where(data['Price_Change'] > 0, 1, 0)  # 1 if price goes up, 0 if price goes down

# Remove NaN values (for backtesting and machine learning)
data = data.dropna()

# Features for machine learning models
features = ['SMA_50', 'SMA_200', 'Returns', 'Sentiment']

# 6. Train-Test Split for ML models
X = data[features]
y = data['Target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)

# 7. Machine Learning Models
# Random Forest
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(X_train, y_train)
rf_predictions = rf_model.predict(X_test)
rf_accuracy = accuracy_score(y_test, rf_predictions)

# XGBoost
xgb_model = XGBClassifier(n_estimators=100, random_state=42)
xgb_model.fit(X_train, y_train)
xgb_predictions = xgb_model.predict(X_test)
xgb_accuracy = accuracy_score(y_test, xgb_predictions)

print(f"Random Forest Accuracy: {rf_accuracy}")
print(f"XGBoost Accuracy: {xgb_accuracy}")


# 8. Backtesting Setup: Define Strategy Classes for Backtrader
class SMACrossover(bt.SignalStrategy):
    def __init__(self):
        self.signal_add(bt.SIGNAL_LONG, data['Position'])

class RandomForestStrategy(bt.SignalStrategy):
    def __init__(self):
        self.model = rf_model
        self.signal_add(bt.SIGNAL_LONG, self.predict_signal)

    def predict_signal(self):
        latest_data = np.array([data['SMA_50'][-1], data['SMA_200'][-1], data['Returns'][-1], data['Sentiment'][-1]]).reshape(1, -1)
        prediction = self.model.predict(latest_data)
        return prediction[0]

class XGBoostStrategy(bt.SignalStrategy):
    def __init__(self):
        self.model = xgb_model
        self.signal_add(bt.SIGNAL_LONG, self.predict_signal)

    def predict_signal(self):
        latest_data = np.array([data['SMA_50'][-1], data['SMA_200'][-1], data['Returns'][-1], data['Sentiment'][-1]]).reshape(1, -1)
        prediction = self.model.predict(latest_data)
        return prediction[0]

class SentimentStrategy(bt.SignalStrategy):
    def __init__(self):
        self.signal_add(bt.SIGNAL_LONG, self.predict_signal)

    def predict_signal(self):
        # Using sentiment directly in the strategy as a buy signal
        sentiment = data['Sentiment'][-1]
        if sentiment > 0.1:  # If sentiment is positive, go long
            return 1
        else:
            return -1  # If sentiment is negative, avoid or sell

# Ensure the index is in datetime format
data.index = pd.to_datetime(data.index)



# Backtesting function
def run_backtest(strategy_class):
    cerebro = bt.Cerebro()
    cerebro.addstrategy(strategy_class)
    
    # Pass filtered data
    data_feed = bt.feeds.PandasData(dataname=data)
    cerebro.adddata(data_feed)
    
    cerebro.broker.set_cash(10000)
    #cerebro.broker.set_commission(commission=0.001)
    cerebro.run()
    return cerebro.broker.get_value()

# Run backtests
sma_value = run_backtest(SMACrossover)
rf_value = run_backtest(RandomForestStrategy)
xgb_value = run_backtest(XGBoostStrategy)
sentiment_value = run_backtest(SentimentStrategy)

print(f"SMA Crossover Strategy Final Portfolio Value: {sma_value}")
print(f"Random Forest Strategy Final Portfolio Value: {rf_value}")
print(f"XGBoost Strategy Final Portfolio Value: {xgb_value}")

print(f"Sentiment Strategy Final Portfolio Value: {sentiment_value}")

The error is happening when I am running the backtestest, basically towards the last part of the code, I have tried multiple solutions , they don't seem to be working

sma_value = run_backtest(SMACrossover)

Please help!

Upvotes: 0

Views: 134

Answers (0)

Related Questions