Skip to content

Instantly share code, notes, and snippets.

@behrank
Forked from kbagher/btc_chart.py
Created July 14, 2024 12:37
Show Gist options
  • Save behrank/5be207c5e1b99aaa1f122027663b4b62 to your computer and use it in GitHub Desktop.
Save behrank/5be207c5e1b99aaa1f122027663b4b62 to your computer and use it in GitHub Desktop.
This code fetches historical BTC/USD data from Binance API, calculates various technical indicators such as moving averages, Bollinger Bands, MACD, RSI, and MFI, and generates a plot showing the BTC/USD price with these indicators. Based on these indicators, the code also generates a recommendation for whether to buy, sell, or hold BTC/USD.
import textwrap
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from mplfinance.original_flavor import candlestick_ohlc
import requests
import ta
from reportlab.pdfgen import canvas
def get_data():
# Fetch historical BTC/USD data from Binance API
symbol = 'BTCUSDT' # Binance uses USDT instead of USD
interval = '1d' # 1-day candlestick data
url = f'https://api.binance.com/api/v3/klines?symbol={symbol}&interval={interval}'
response = requests.get(url)
data = pd.DataFrame(response.json(),
columns=['Open_time', 'Open', 'High', 'Low', 'Close', 'Volume', 'Close_time',
'Quote_asset_volume',
'Number_of_trades', 'Taker_buy_base_asset_volume', 'Taker_buy_quote_asset_volume',
'Ignore'])
# Convert timestamps and set the index
data['Date'] = pd.to_datetime(data['Open_time'], unit='ms')
data.set_index('Date', inplace=True)
# Convert data types
return data.astype({'Open': float, 'High': float, 'Low': float, 'Close': float, 'Volume': float})
def calculate_indicators(data):
# Calculate SMA, EMA, and Bollinger Bands
data['SMA50'] = data['Close'].rolling(window=50).mean()
data['SMA100'] = data['Close'].rolling(window=100).mean()
data['EMA12'] = data['Close'].ewm(span=12).mean()
data['EMA26'] = data['Close'].ewm(span=26).mean()
data['Upper_BB'], data['Lower_BB'] = data['Close'].rolling(window=20).mean() + 2 * data['Close'].rolling(
window=20).std(), data['Close'].rolling(window=20).mean() - 2 * data['Close'].rolling(window=20).std()
# Calculate MACD and Signal Line
data['MACD'] = data['EMA12'] - data['EMA26']
data['Signal'] = data['MACD'].ewm(span=9).mean()
# Calculate RSI
delta = data['Close'].diff().dropna()
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
avg_gain = gain.rolling(window=14).mean()
avg_loss = loss.rolling(window=14).mean()
rs = avg_gain / avg_loss
data['RSI'] = 100 - (100 / (1 + rs))
# Calculate support and resistance levels for 1D timeframe
data['High_Rolling'] = data['High'].rolling(50).max()
data['Low_Rolling'] = data['Low'].rolling(50).min()
data['Close_Shift'] = data['Close'].shift(1)
data['Pivot'] = (data['High_Rolling'] + data['Low_Rolling'] + data['Close_Shift']) / 3
data['R1'] = 2 * data['Pivot'] - data['Low_Rolling']
data['S1'] = 2 * data['Pivot'] - data['High_Rolling']
data['R2'] = data['Pivot'] + (data['High_Rolling'] - data['Low_Rolling'])
data['S2'] = data['Pivot'] - (data['High_Rolling'] - data['Low_Rolling'])
# Calculate MFI
data['MFI'] = ta.volume.money_flow_index(data['High'], data['Low'], data['Close'], data['Volume'], window=14)
def plot_data(data):
# Plot the results
fig, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=4, ncols=1, figsize=(12, 20), sharex=True,
gridspec_kw={'height_ratios': [3, 1, 1, 1], 'hspace': 0.03})
# Plot candlestick chart, SMA, EMA, and Bollinger Bands
ohlc_data = data.reset_index()[['Date', 'Open', 'High', 'Low', 'Close']]
ohlc_data['Date'] = ohlc_data['Date'].apply(mdates.date2num)
candlestick_ohlc(ax1, ohlc_data.values, width=0.6, colorup='g', colordown='r', alpha=0.8)
ax1.plot(data.index, data['SMA50'], label='SMA50', color='b', linewidth=1)
ax1.plot(data.index, data['SMA100'], label='SMA100', color='m', linewidth=1)
ax1.plot(data.index, data['Upper_BB'], label='Upper BB', color='c', linewidth=1)
ax1.plot(data.index, data['Lower_BB'], label='Lower BB', color='c', linewidth=1)
ax1.axhline(data['R1'][-1], color='r', linestyle='--', linewidth=1, label='Resistance')
ax1.axhline(data['R2'][-1], color='r', linestyle='-.', linewidth=1)
ax1.axhline(data['S1'][-1], color='g', linestyle='--', linewidth=1, label='Support')
ax1.axhline(data['S2'][-1], color='g', linestyle='-.', linewidth=1)
ax1.set_title('BTC/USD Price with Indicators')
ax1.set_ylabel('Price (USD)')
ax1.legend(loc='best')
ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
ax1.grid(True)
# Plot MACD and Signal Line
ax2.plot(data.index, data['MACD'], label='MACD', color='b', linewidth=1)
ax2.plot(data.index, data['Signal'], label='Signal', color='r', linewidth=1)
ax2.set_ylabel('MACD')
ax2.legend(loc='best')
ax2.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
ax2.grid(True)
# Plot RSI
ax3.plot(data.index, data['RSI'], label='RSI', color='b', linewidth=1)
ax3.axhline(70, color='r', linestyle='--', linewidth=1, label='Overbought')
ax3.axhline(30, color='g', linestyle='--', linewidth=1, label='Oversold')
ax3.set_ylabel('RSI')
ax3.legend(loc='best')
ax3.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
ax3.grid(True)
# Plot MFI
ax4.plot(data.index, data['MFI'], label='MFI', color='b', linewidth=1)
ax4.axhline(80, color='r', linestyle='--', linewidth=1, label='Overbought')
ax4.axhline(20, color='g', linestyle='--', linewidth=1, label='Oversold')
ax4.set_ylabel('MFI')
ax4.legend(loc='best')
ax4.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
ax4.grid(True)
def create_recommendations(data):
# Moving Averages
sma50_above_sma100 = data['SMA50'][-1] > data['SMA100'][-1]
sma50_cross_sma100 = data['SMA50'][-2] < data['SMA100'][-2] and sma50_above_sma100
sma_direction = 'upwards' if sma50_above_sma100 else 'downwards'
cross_direction = 'above' if sma50_above_sma100 else 'below'
# MACD
macd_above_signal = data['MACD'][-1] > data['Signal'][-1]
macd_cross_signal = data['MACD'][-2] < data['Signal'][-2] and macd_above_signal
signal_direction = 'above' if macd_above_signal else 'below'
# RSI
rsi = data['RSI'][-1]
# MFI
mfi = data['MFI'][-1]
window = 20
data['Middle_Band'] = data['Close'].rolling(window=window).mean()
data['Upper_Band'] = data['Middle_Band'] + 2 * data['Close'].rolling(window=window).std()
data['Lower_Band'] = data['Middle_Band'] - 2 * data['Close'].rolling(window=window).std()
price = data['Close'][-1]
upper_band = data['Upper_Band'][-1]
lower_band = data['Lower_Band'][-1]
middle_band = data['Middle_Band'][-1]
if sma50_cross_sma100:
recommendation = 'BUY'
confidence_level = 0.8
elif macd_cross_signal:
recommendation = 'BUY'
confidence_level = 0.7
elif rsi < 30:
recommendation = 'BUY'
confidence_level = 0.6
elif mfi < 20:
recommendation = 'BUY'
confidence_level = 0.5
elif price > upper_band:
recommendation = 'SELL'
confidence_level = 0.8
elif price < lower_band:
recommendation = 'BUY'
confidence_level = 0.8
else:
recommendation = 'HOLD'
confidence_level = 0.5
print(f'Recommendation: {recommendation} with {confidence_level * 100}% confidence level.')
recommendation_text = ''
recommendation_text += f"1. Support Levels: S1: {data['S1'][-1]}, S2: {data['S2'][-1]}\n"
recommendation_text += f"2. Resistance Levels: R1: {data['R1'][-1]}, R2: {data['R2'][-1]}\n"
recommendation_text += f"3. The 50-day SMA is {cross_direction} the 100-day SMA, indicating a(n) {sma_direction} trend.\n"
recommendation_text += f"4. MACD line is {signal_direction} the Signal line.\n"
recommendation_text += f"5. RSI: {rsi}\n"
recommendation_text += f"6. MFI: {mfi}\n"
recommendation_text += f"7. Price: {price}, Upper Bollinger Band: {upper_band}, Middle Bollinger Band: {middle_band}, Lower Bollinger Band: {lower_band}\n"
# Calculate confidence level for each condition
sma_confidence = 0.8 if sma50_cross_sma100 else 0
macd_confidence = 0.7 if macd_cross_signal else 0
rsi_confidence = 0.6 if rsi < 30 else 0
mfi_confidence = 0.5 if mfi < 20 else 0
upper_band_confidence = 0.8 if price > upper_band else 0
lower_band_confidence = 0.8 if price < lower_band else 0
# Calculate overall confidence level
confidence_level = np.mean(
[sma_confidence, macd_confidence, rsi_confidence, mfi_confidence, upper_band_confidence, lower_band_confidence])
# Determine recommendation based on highest confidence level
if confidence_level == 0:
recommendation = 'HOLD'
else:
recommendation = 'BUY' if confidence_level >= 0.6 else 'SELL'
# Print recommendation and confidence level
recommendation_text += f"\nRecommendation: {recommendation}\nConfidence Level: {round(confidence_level * 100)}%"
print(recommendation_text)
return recommendation_text
def save_pdf(recommendation_text):
# Show the plot
plt.savefig('btc_analysis.pdf', bbox_inches='tight')
plt.show()
# Wrap the recommendation text
wrapper = textwrap.TextWrapper(width=80, break_long_words=False)
recommendation_list = []
for line in recommendation_text.splitlines():
recommendation_list.extend(wrapper.wrap(text=line))
# Save the PDF packet as a file on disk
filename = 'recommendations.pdf'
can = canvas.Canvas(filename)
can.setFont("Helvetica-Bold", 20)
can.drawString(100, 700, "Summary")
can.setFont("Helvetica", 12)
for i in range(len(recommendation_list)):
if recommendation_list[i]:
can.drawString(100, 680 - i * 20, recommendation_list[i])
can.setFont("Helvetica-Bold", 14)
can.save()
token_data = get_data()
calculate_indicators(token_data)
plot_data(token_data)
rec = create_recommendations(token_data)
save_pdf(rec)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment