-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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