import numpy as np
np.NaN = np.nan # For pandas_ta compatibility
import matplotlib.pyplot as plt
import requests
from datetime import datetime, timedelta
import pandas_ta as ta
import mplfinance as mpf
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error
import warnings
warnings.filterwarnings(‘ignore’)
class BitcoinTechnicalAnalysisML:
def __init__(self):
“””Arrange our instruments for predicting Bitcoin costs”””
self.information = None # The place we’ll retailer Bitcoin data
self.api_url = “https://api.coingecko.com/api/v3/cash/bitcoin/market_chart”
# Our crystal ball: a wise mannequin that learns patterns, utilizing the GPU for pace
self.mannequin = xgb.XGBRegressor(n_estimators=100, tree_method=’hist’, machine=’cuda’, random_state=42)
self.scaler = StandardScaler() # A device to make numbers simpler for the mannequin
def fetch_bitcoin_data(self, days=365, vs_currency=’usd’):
“””Step 1: Seize Bitcoin’s value historical past, like checking a yr’s value of receipts”””
strive:
params = {‘vs_currency’: vs_currency, ‘days’: days, ‘interval’: ‘day by day’}
response = requests.get(self.api_url, params=params)
response.raise_for_status()
information = response.json()
df = pd.DataFrame({
‘Timestamp’: [x[0] for x in information[‘prices’]],
‘Shut’: [x[1] for x in information[‘prices’]],
‘Quantity’: [x[1] for x in information[‘total_volumes’]]
})
df[‘Timestamp’] = pd.to_datetime(df[‘Timestamp’], unit=’ms’)
df.set_index(‘Timestamp’, inplace=True)
df[‘High’] = df[‘Close’] * 1.02 # Guess the day’s excessive (just a little above shut)
df[‘Low’] = df[‘Close’] * 0.98 # Guess the day’s low (just a little under shut)
df[‘Open’] = df[‘Close’].shift(1) # Yesterday’s shut is right now’s open
self.information = df.dropna() # Take away any incomplete days
print(f”We’ve grabbed {len(self.information)} days of Bitcoin costs, from {self.information.index[0].strftime(‘%Y-%m-%d’)} to {self.information.index[-1].strftime(‘%Y-%m-%d’)}—like a year-long diary of Bitcoin’s ups and downs!”)
return self.information
besides requests.exceptions.RequestException as e:
print(f”Oops! Couldn’t get the Bitcoin information as a result of: {e}. Perhaps the web’s down?”)
return None
def calculate_indicators(self):
“””Step 2: Add clues to guess the place Bitcoin’s value is heading”””
if self.information is None:
print(“Maintain on! We’d like Bitcoin information first. Run fetch_bitcoin_data() to get it.”)
return None
df = self.information.copy()
print(“Now, we’re including some good clues—like checking Bitcoin’s temper, pace, and patterns—to assist us predict its subsequent transfer.”)
# Shifting averages: Like smoothing out a bumpy street to see the development
df[‘SMA7’] = ta.sma(df[‘Close’], size=7) # 7-day common
df[‘SMA25’] = ta.sma(df[‘Close’], size=25) # 25-day common
df[‘SMA50’] = ta.sma(df[‘Close’], size=50)
df[‘SMA99’] = ta.sma(df[‘Close’], size=99)
df[‘SMA200’] = ta.sma(df[‘Close’], size=200)
df[‘EMA12’] = ta.ema(df[‘Close’], size=12) # Fast 12-day development
df[‘EMA26’] = ta.ema(df[‘Close’], size=26) # Slower 26-day development
df[‘MA111’] = ta.sma(df[‘Close’], size=111)
df[‘MA350x2’] = ta.sma(df[‘Close’], size=350) * 2 # Lengthy-term doubled
macd = ta.macd(df[‘Close’], quick=12, gradual=26, sign=9) # Momentum checker
df[‘MACD’] = macd[‘MACD_12_26_9’]
df[‘MACD_Signal’] = macd[‘MACDs_12_26_9’]
df[‘MACD_Hist’] = macd[‘MACDh_12_26_9’]
df[‘SAR’] = ta.psar(df[‘High’], df[‘Low’], df[‘Close’])[‘PSARl_0.02_0.2’] # Development course
df[‘RSI’] = ta.rsi(df[‘Close’], size=14) # Is Bitcoin overexcited or sleepy?
stoch = ta.stoch(df[‘High’], df[‘Low’], df[‘Close’], ok=14, d=3, smooth_k=3) # Velocity gauge
df[‘StochK’] = stoch[‘STOCHk_14_3_3’]
df[‘StochD’] = stoch[‘STOCHd_14_3_3’]
bbands = ta.bbands(df[‘Close’], size=20, std=2) # Value vary bands
df[‘BB_Upper’] = bbands[‘BBU_20_2.0’]
df[‘BB_Middle’] = bbands[‘BBM_20_2.0’]
df[‘BB_Lower’] = bbands[‘BBL_20_2.0’]
df[‘CCI’] = ta.cci(df[‘High’], df[‘Low’], df[‘Close’], size=14) # Overbought/oversold
df[‘OBV’] = ta.obv(df[‘Close’], df[‘Volume’]) # Quantity development
df[‘CMF’] = ta.adosc(df[‘High’], df[‘Low’], df[‘Close’], df[‘Volume’], quick=3, gradual=10) # Cash circulate
df[‘ForceIndex’] = df[‘Close’].diff(1) * df[‘Volume’] # Value push
df[‘ForceIndex13’] = ta.ema(df[‘ForceIndex’], size=13)
df[‘ATR’] = ta.atr(df[‘High’], df[‘Low’], df[‘Close’], size=14) # Volatility
recent_high = df[‘High’].iloc[-100:].max() # Final 100 days’ peak
recent_low = df[‘Low’].iloc[-100:].min() # Final 100 days’ dip
df[‘Fib_0’] = recent_low
df[‘Fib_23.6’] = recent_low + 0.236 * (recent_high – recent_low) # Fibonacci ranges
df[‘Fib_38.2’] = recent_low + 0.382 * (recent_high – recent_low)
df[‘Fib_50’] = recent_low + 0.5 * (recent_high – recent_low)
df[‘Fib_61.8’] = recent_low + 0.618 * (recent_high – recent_low)
df[‘Fib_100’] = recent_high
self.information = df
print(f”Completed! We’ve added {len(df.columns)} clues—like Bitcoin’s temper swings and spending habits—to make our prediction smarter.”)
return df
def prepare_ml_data(self):
“””Step 3: Get our clues prepared for the prediction machine”””
if self.information is None:
print(“Oops! We’d like the clues first. Run calculate_indicators() after fetching information.”)
return None
df = self.information.copy()
print(“We’re organising the puzzle: tomorrow’s value is what we need to guess, utilizing right now’s clues.”)
df[‘Target’] = df[‘Close’].shift(-1) # Tomorrow’s value is our aim
df = df.dropna() # Skip days with lacking items
options = [‘Open’, ‘High’, ‘Low’, ‘Close’, ‘Volume’, ‘SMA7’, ‘SMA25’, ‘SMA50’, ‘SMA99’, ‘SMA200’,
‘EMA12’, ‘EMA26’, ‘MA111’, ‘MA350x2’, ‘MACD’, ‘MACD_Signal’, ‘MACD_Hist’, ‘SAR’,
‘RSI’, ‘StochK’, ‘StochD’, ‘BB_Upper’, ‘BB_Middle’, ‘BB_Lower’, ‘CCI’, ‘OBV’,
‘CMF’, ‘ForceIndex’, ‘ForceIndex13’, ‘ATR’]
X = df[features] # Our clue pile
y = df[‘Target’] # The reply we’re after
X_scaled = self.scaler.fit_transform(X) # Make clues simpler to check, like placing all of them in the identical language
print(f”Puzzle prepared! We have now {len(X)} days to study from, with {len(options)} clues every—like components for a Bitcoin value recipe.”)
return X_scaled, y, X.index
def train_model(self, test_size=0.2):
“””Step 4: Educate our crystal ball to foretell Bitcoin costs”””
X_scaled, y, dates = self.prepare_ml_data()
if X_scaled is None:
return None
X_train, X_test, y_train, y_test, dates_train, dates_test = train_test_split(
X_scaled, y, dates, test_size=test_size, shuffle=False
)
print(f”We’re educating our prediction machine with {len(X_train)} days of historical past and testing it on the final {len(X_test)} days—like training with outdated climate forecasts earlier than predicting tomorrow’s rain.”)
self.mannequin.match(X_train, y_train) # Let the machine study the patterns
y_pred = self.mannequin.predict(X_test) # Check its guesses
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
print(f”Coaching executed! Our machine’s guesses had been off by about ${rmse:.2f} on common (that’s the RMSE). The MSE ({mse:.2f}) is an even bigger quantity displaying the full error squared—smaller is healthier!”)
return X_test, y_test, y_pred, dates_test
def predict_next_day(self):
“””Step 5: Look into the long run with our skilled crystal ball”””
if self.information is None:
print(“Wait! We’d like information and clues first. Run the sooner steps.”)
return None
last_data = self.information.tail(1)
options = [‘Open’, ‘High’, ‘Low’, ‘Close’, ‘Volume’, ‘SMA7’, ‘SMA25’, ‘SMA50’, ‘SMA99’, ‘SMA200’,
‘EMA12’, ‘EMA26’, ‘MA111’, ‘MA350x2’, ‘MACD’, ‘MACD_Signal’, ‘MACD_Hist’, ‘SAR’,
‘RSI’, ‘StochK’, ‘StochD’, ‘BB_Upper’, ‘BB_Middle’, ‘BB_Lower’, ‘CCI’, ‘OBV’,
‘CMF’, ‘ForceIndex’, ‘ForceIndex13’, ‘ATR’]
X_last = last_data[features]
X_last_scaled = self.scaler.remodel(X_last)
prediction = self.mannequin.predict(X_last_scaled)[0]
last_date = self.information.index[-1]
next_date = last_date + timedelta(days=1)
print(f” yesterday ({last_date.strftime(‘%Y-%m-%d’)}, value was ${last_data[‘Close’].values[0]:.2f}), our crystal ball says tomorrow ({next_date.strftime(‘%Y-%m-%d’)}) will likely be ${prediction:.2f}. It’s utilizing all these clues we gathered!”)
return prediction
def plot_predictions(self, X_test, y_test, y_pred, dates_test):
“””Step 6: Draw an image of our guesses vs. actuality”””
plt.determine(figsize=(14, 7))
plt.plot(dates_test, y_test, label=’Precise Value’, colour=’blue’)
plt.plot(dates_test, y_pred, label=’Predicted Value’, colour=’purple’, linestyle=’–‘)
plt.title(‘Bitcoin Value Prediction (Our Sensible Guess vs. What Actually Occurred)’)
plt.xlabel(‘Date’)
plt.ylabel(‘Value (USD)’)
plt.legend()
plt.xticks(rotation=45)
plt.tight_layout()
plt.present()
print(“Right here’s an image! The blue line is what Bitcoin really did within the check days. The purple dashed line is what our machine guessed. Nearer strains imply higher guesses!”)
if __name__ == “__main__”:
print(“Let’s predict Bitcoin’s subsequent value, step-by-step, like baking a cake with a magic recipe!”)
btc = BitcoinTechnicalAnalysisML()
btc.fetch_bitcoin_data(days=365)
btc.calculate_indicators()
outcome = btc.train_model(test_size=0.2)
if outcome is just not None:
X_test, y_test, y_pred, dates_test = outcome
btc.plot_predictions(X_test, y_test, y_pred, dates_test)
btc.predict_next_day()