Chuyển tới nội dung chính

🐍 Ngày 44 Python 365 ngày | Phân tích giá BTCUSDT với Plotly

Phân tích giá BTCUSDT

Hôm nay, chúng ta sẽ thu thập dữ liệu từ cặp tiền mã hóa BTCUSDT trên sàn Binance và hiển thị biểu đồ tương tác bằng thư viện Plotly.

🎯 Mục tiêu​

  • Kết nối API Binance để lấy dữ liệu.
  • Phân tích và hiển thị giá BTC theo thời gian.
  • Tạo biểu đồ tương tác với Plotly.

🧰 Cài đặt thư viện​

Trước khi bắt đầu, chúng ta cần cài đặt các thư viện cần thiết:

pip install python-binance pandas plotly

🔌 Lấy dữ liệu từ Binance​

Chúng ta sẽ sử dụng thư viện python-binance để kết nối với API của Binance và lấy dữ liệu lịch sử giá của BTCUSDT.

from binance.client import Client
import pandas as pd
from datetime import datetime
import plotly.graph_objects as go

# Thay thế bằng API key và secret của bạn
api_key = 'your_api_key'
api_secret = 'your_api_secret'

client = Client(api_key, api_secret)

# Lấy dữ liệu nến (candlestick)
klines = client.get_klines(symbol='BTCUSDT', interval=Client.KLINE_INTERVAL_1HOUR, limit=100)

# Chuyển đổi dữ liệu thành DataFrame
df = pd.DataFrame(klines, 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'
])

# Chuyển đổi kiểu dữ liệu
df['open_time'] = pd.to_datetime(df['open_time'], unit='ms')
df['close_time'] = pd.to_datetime(df['close_time'], unit='ms')
df[['open', 'high', 'low', 'close', 'volume']] = df[['open', 'high', 'low', 'close', 'volume']].astype(float)

print(df[['open_time', 'open', 'high', 'low', 'close']].head())

Đoạn mã này sẽ:

  1. Kết nối tới API Binance sử dụng API key và secret
  2. Lấy 100 nến 1 giờ gần nhất cho cặp BTCUSDT
  3. Chuyển đổi dữ liệu thành DataFrame pandas
  4. Chuyển đổi các cột thời gian thành định dạng datetime và các cột giá trị thành số thực
  5. Hiển thị 5 dòng đầu tiên của dữ liệu

📊 Vẽ biểu đồ giá với Plotly​

Sau khi đã có dữ liệu, chúng ta sẽ sử dụng Plotly để vẽ biểu đồ nến tương tác:

fig = go.Figure(data=[go.Candlestick(
x=df['open_time'],
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close'],
name="BTCUSDT"
)])

fig.update_layout(
title='Biểu đồ giá BTCUSDT (1 giờ gần nhất)',
xaxis_title='Thời gian',
yaxis_title='Giá (USDT)',
xaxis_rangeslider_visible=False,
template='plotly_dark'
)

fig.show()

Đoạn mã này tạo một biểu đồ nến tương tác với:

  • Trục x là thời gian
  • Trục y là giá của BTC (tính bằng USDT)
  • Giao diện tối (plotly_dark)
  • Bỏ thanh trượt phạm vi trên trục x

📈 Phân tích dữ liệu nâng cao​

Thêm đường trung bình động (Moving Average)​

Chúng ta có thể thêm các chỉ báo kỹ thuật như đường trung bình động để hỗ trợ phân tích:

# Tính MA20 và MA50
df['MA20'] = df['close'].rolling(window=20).mean()
df['MA50'] = df['close'].rolling(window=50).mean()

# Tạo biểu đồ với MA
fig = go.Figure()

# Thêm biểu đồ nến
fig.add_trace(go.Candlestick(
x=df['open_time'],
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close'],
name="BTCUSDT"
))

# Thêm đường MA20
fig.add_trace(go.Scatter(
x=df['open_time'],
y=df['MA20'],
line=dict(color='orange', width=2),
name="MA20"
))

# Thêm đường MA50
fig.add_trace(go.Scatter(
x=df['open_time'],
y=df['MA50'],
line=dict(color='blue', width=2),
name="MA50"
))

fig.update_layout(
title='Biểu đồ giá BTCUSDT với đường trung bình động',
xaxis_title='Thời gian',
yaxis_title='Giá (USDT)',
xaxis_rangeslider_visible=False,
template='plotly_dark'
)

fig.show()

Biểu đồ khối lượng giao dịch (Volume)​

Để phân tích khối lượng giao dịch cùng với giá:

# Tạo biểu đồ với khối lượng
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
vertical_spacing=0.03, row_heights=[0.7, 0.3])

# Thêm biểu đồ nến vào hàng 1
fig.add_trace(go.Candlestick(
x=df['open_time'],
open=df['open'],
high=df['high'],
low=df['low'],
close=df['close'],
name="BTCUSDT"
), row=1, col=1)

# Thêm biểu đồ khối lượng vào hàng 2
colors = ['green' if row['close'] >= row['open'] else 'red' for _, row in df.iterrows()]
fig.add_trace(go.Bar(
x=df['open_time'],
y=df['volume'],
marker_color=colors,
name="Volume"
), row=2, col=1)

fig.update_layout(
title='Biểu đồ giá và khối lượng giao dịch BTCUSDT',
xaxis_title='Thời gian',
yaxis_title='Giá (USDT)',
xaxis2_title='Thời gian',
yaxis2_title='Khối lượng',
xaxis_rangeslider_visible=False,
template='plotly_dark'
)

fig.show()

📋 Lưu và tải dữ liệu​

Để lưu dữ liệu đã thu thập để sử dụng sau này:

# Lưu dữ liệu vào file CSV
df.to_csv('btcusdt_historical_data.csv', index=False)

# Để tải lại dữ liệu
# df = pd.read_csv('btcusdt_historical_data.csv')
# df['open_time'] = pd.to_datetime(df['open_time'])
# df['close_time'] = pd.to_datetime(df['close_time'])

🔄 So sánh BTCUSDT và ETHUSDT​

Chúng ta có thể so sánh biến động giá của Bitcoin và Ethereum:

# Lấy dữ liệu ETHUSDT
eth_klines = client.get_klines(symbol='ETHUSDT', interval=Client.KLINE_INTERVAL_1HOUR, limit=100)

# Chuyển đổi dữ liệu thành DataFrame
eth_df = pd.DataFrame(eth_klines, 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'
])

# Chuyển đổi kiểu dữ liệu
eth_df['open_time'] = pd.to_datetime(eth_df['open_time'], unit='ms')
eth_df['close'] = eth_df['close'].astype(float)

# Chuẩn hóa giá để so sánh
btc_normalized = df['close'] / df['close'].iloc[0]
eth_normalized = eth_df['close'] / eth_df['close'].iloc[0]

# Tạo biểu đồ so sánh
fig = go.Figure()

fig.add_trace(go.Scatter(
x=df['open_time'],
y=btc_normalized,
mode='lines',
name='BTCUSDT'
))

fig.add_trace(go.Scatter(
x=eth_df['open_time'],
y=eth_normalized,
mode='lines',
name='ETHUSDT'
))

fig.update_layout(
title='So sánh biến động giá BTCUSDT và ETHUSDT (chuẩn hóa)',
xaxis_title='Thời gian',
yaxis_title='Giá tương đối (so với giá ban đầu)',
template='plotly_dark'
)

fig.show()

📌 Bài tập gợi ý​

  1. Tạo biểu đồ volume giao dịch theo thời gian:

    • Sử dụng biểu đồ cột để hiển thị khối lượng giao dịch
    • Phân biệt khối lượng trong các phiên tăng/giảm bằng màu sắc khác nhau
  2. So sánh giá BTCUSDT với ETHUSDT:

    • Xem xét tương quan giữa hai cặp tiền
    • Vẽ biểu đồ tỷ lệ giá BTC/ETH theo thời gian
  3. Lưu dữ liệu nến về file .csv:

    • Thực hiện lưu dữ liệu lịch sử với các thông số thời gian
    • Tạo chức năng tự động cập nhật dữ liệu mới
  4. Phân tích thêm chỉ báo kỹ thuật:

    • Thêm các chỉ báo như RSI, MACD, Bollinger Bands
    • Tạo hệ thống cảnh báo dựa trên các chỉ báo

🚀 Nâng cao: Tự động hóa thu thập dữ liệu và cảnh báo​

Chúng ta có thể phát triển một hệ thống tự động thu thập dữ liệu định kỳ và gửi cảnh báo khi có tín hiệu kỹ thuật quan trọng:

import time
import schedule
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

def analyze_btc_price():
# Lấy dữ liệu mới nhất
klines = client.get_klines(symbol='BTCUSDT', interval=Client.KLINE_INTERVAL_1HOUR, limit=100)
df = pd.DataFrame(klines, columns=[...]) # Như đã định nghĩa trước đó

# Chuyển đổi kiểu dữ liệu
df['open_time'] = pd.to_datetime(df['open_time'], unit='ms')
df[['open', 'high', 'low', 'close', 'volume']] = df[['open', 'high', 'low', 'close', 'volume']].astype(float)

# Tính toán chỉ báo
df['MA20'] = df['close'].rolling(window=20).mean()
df['MA50'] = df['close'].rolling(window=50).mean()

# Kiểm tra tín hiệu giao nhau của MA
latest_row = df.iloc[-1]
previous_row = df.iloc[-2]

# Kiểm tra Golden Cross (MA20 cắt lên trên MA50)
golden_cross = previous_row['MA20'] <= previous_row['MA50'] and latest_row['MA20'] > latest_row['MA50']

# Kiểm tra Death Cross (MA20 cắt xuống dưới MA50)
death_cross = previous_row['MA20'] >= previous_row['MA50'] and latest_row['MA20'] < latest_row['MA50']

# Gửi thông báo nếu có tín hiệu
if golden_cross:
send_alert(f"Golden Cross trên BTCUSDT! Giá hiện tại: {latest_row['close']}")
elif death_cross:
send_alert(f"Death Cross trên BTCUSDT! Giá hiện tại: {latest_row['close']}")

# Lưu dữ liệu vào CSV
df.to_csv('btcusdt_historical_data.csv', index=False)

def send_alert(message):
# Cấu hình email
sender_email = "your_email@gmail.com"
receiver_email = "recipient_email@gmail.com"
password = "your_email_password"

# Tạo message
msg = MIMEMultipart()
msg['From'] = sender_email
msg['To'] = receiver_email
msg['Subject'] = "Cảnh báo Crypto!"

msg.attach(MIMEText(message, 'plain'))

# Gửi email
try:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(sender_email, password)
server.send_message(msg)
server.quit()
print("Đã gửi email cảnh báo thành công!")
except Exception as e:
print(f"Lỗi khi gửi email: {e}")

# Lên lịch chạy mỗi giờ
schedule.every().hour.do(analyze_btc_price)

# Chạy liên tục
while True:
schedule.run_pending()
time.sleep(60) # Kiểm tra mỗi phút

Lưu ý: Đoạn mã trên cần cài đặt thêm thư viện schedule bằng cách chạy pip install schedule.

📚 Kết luận​

Qua bài học này, chúng ta đã:

  • Kết nối với API của Binance để lấy dữ liệu giá BTCUSDT
  • Xử lý và phân tích dữ liệu với pandas
  • Tạo biểu đồ tương tác đẹp mắt và đầy đủ thông tin với Plotly
  • Học cách tính toán chỉ báo kỹ thuật và hiển thị chúng trên biểu đồ
  • Tạo hệ thống tự động phân tích và cảnh báo

Đây là nền tảng cho việc xây dựng các hệ thống phân tích kỹ thuật và giao dịch tự động phức tạp hơn. Từ đây, bạn có thể phát triển thêm:

  • Chiến lược giao dịch tự động dựa trên các tín hiệu kỹ thuật
  • Hệ thống quản lý danh mục đầu tư tiền mã hóa
  • Phân tích cảm xúc thị trường kết hợp với phân tích kỹ thuật
  • Dự đoán giá bằng mô hình học máy

🎨 Plotly vs Matplotlib — chọn công cụ nào​

Tiêu chíMatplotlibPlotly
Tương tác❌ Ảnh tĩnh✅ Zoom, hover, tải ảnh
Cú phápDài dòngNgắn gọn, có px (express)
Biểu đồ tài chínhPhải tự vẽCó sẵn Candlestick, OHLC
Chia sẻ trên webCần lưu ảnhXuất HTML tự chứa
Dùng trong báo cáo in✅ TốtCần xuất ảnh tĩnh
Dashboard (Dash)KhôngCùng hệ sinh thái

Khuyến nghị: dùng Plotly cho phân tích khám phá (bạn cần zoom vào từng đoạn để hiểu dữ liệu) và Matplotlib khi cần ảnh tĩnh để in hoặc nhúng báo cáo.

📈 Biểu đồ nến (Candlestick) — chuẩn cho phân tích giá​

import plotly.graph_objects as go

fig = go.Figure()

fig.add_trace(go.Candlestick(
x=df.index,
open=df["open"],
high=df["high"],
low=df["low"],
close=df["close"],
name="BTCUSDT",
increasing_line_color="#16a34a",
decreasing_line_color="#dc2626",
))

fig.update_layout(
title="BTCUSDT — Khung 1 giờ",
yaxis_title="Giá (USDT)",
xaxis_rangeslider_visible=False, # tắt slider cho gọn
template="plotly_white",
height=600,
hovermode="x unified", # tooltip gộp theo trục x
)

fig.show()

💡 hovermode="x unified" là chi tiết nhỏ nhưng tạo khác biệt lớn: thay vì phải di chuột đúng vào từng đường, bạn thấy giá trị của tất cả chỉ báo tại thời điểm đang xem cùng một lúc.

🔍 Thêm chỉ báo và đánh dấu điểm mua/bán​

import numpy as np
from plotly.subplots import make_subplots

df["sma20"] = df["close"].rolling(20).mean()
df["sma50"] = df["close"].rolling(50).mean()

# Tín hiệu: SMA20 cắt lên/xuống SMA50
df["tin_hieu"] = 0
df.loc[(df["sma20"] > df["sma50"]) & (df["sma20"].shift(1) <= df["sma50"].shift(1)),
"tin_hieu"] = 1
df.loc[(df["sma20"] < df["sma50"]) & (df["sma20"].shift(1) >= df["sma50"].shift(1)),
"tin_hieu"] = -1

mua = df[df["tin_hieu"] == 1]
ban = df[df["tin_hieu"] == -1]

fig = make_subplots(
rows=2, cols=1, shared_xaxes=True,
vertical_spacing=0.04, row_heights=[0.72, 0.28],
subplot_titles=("Giá và chỉ báo", "Khối lượng"),
)

fig.add_trace(go.Candlestick(
x=df.index, open=df["open"], high=df["high"],
low=df["low"], close=df["close"], name="Nến",
), row=1, col=1)

for cot, mau, ten in [("sma20", "#f59e0b", "SMA 20"), ("sma50", "#3b82f6", "SMA 50")]:
fig.add_trace(go.Scatter(
x=df.index, y=df[cot], name=ten, line=dict(color=mau, width=1.5),
), row=1, col=1)

# Đánh dấu điểm mua/bán
fig.add_trace(go.Scatter(
x=mua.index, y=mua["low"] * 0.998, mode="markers", name="MUA",
marker=dict(symbol="triangle-up", size=13, color="#16a34a",
line=dict(width=1, color="white")),
), row=1, col=1)

fig.add_trace(go.Scatter(
x=ban.index, y=ban["high"] * 1.002, mode="markers", name="BÁN",
marker=dict(symbol="triangle-down", size=13, color="#dc2626",
line=dict(width=1, color="white")),
), row=1, col=1)

# Khối lượng, tô màu theo chiều nến
fig.add_trace(go.Bar(
x=df.index, y=df["volume"], name="Khối lượng",
marker_color=np.where(df["close"] >= df["open"], "#16a34a", "#dc2626"),
opacity=0.6,
), row=2, col=1)

fig.update_layout(
title=f"Tín hiệu SMA crossover — {len(mua)} lần mua, {len(ban)} lần bán",
xaxis_rangeslider_visible=False,
template="plotly_white",
height=750,
hovermode="x unified",
legend=dict(orientation="h", yanchor="bottom", y=1.02),
)
fig.show()

Đánh dấu điểm mua/bán là kỹ thuật quan trọng nhất khi kiểm tra chiến lược — nhìn thấy chính xác bot mua bán ở đâu.

💾 Xuất biểu đồ để chia sẻ​

# 1. File HTML tự chứa — gửi cho người khác, họ mở là xem được (vẫn tương tác)
fig.write_html("phan-tich-btc.html", include_plotlyjs="cdn")

# 2. Ảnh tĩnh — dùng cho báo cáo, in ấn (cần pip install kaleido)
fig.write_image("phan-tich-btc.png", width=1400, height=800, scale=2)
Định dạngƯu điểmDùng khi
.htmlGiữ tương tác, 1 file duy nhấtGửi cho đồng nghiệp
.pngNhúng vào báo cáo, slideIn ấn, trình bày
.svgVector, phóng to không vỡBáo cáo chất lượng cao
.jsonLưu dữ liệu biểu đồTái sử dụng, web app

🎨 Bốn quy tắc trình bày biểu đồ tài chính​

  1. Một biểu đồ một thông điệp. Tiêu đề nên là kết luận: "SMA20 cắt lên SMA50 ngày 15/9", không phải "Biểu đồ BTC".
  2. Tắt rangeslider (xaxis_rangeslider_visible=False) — bạn đã có zoom bằng kéo chuột.
  3. Màu xanh/đỏ nhất quán cho tăng/giảm.
  4. Đánh dấu điểm sự kiện thay vì để người xem tự tìm.

📝 Bài tập mở rộng​

Bài 1: Biểu đồ có Bollinger Bands​

Thêm dải Bollinger (SMA20 ± 2×độ lệch chuẩn) và tô màu vùng giữa hai đường.

Bài 2: Biểu đồ RSI phụ​

Thêm hàng thứ ba hiển thị RSI(14), vẽ đường đứt ở mức 30 và 70.

Bài 3: So sánh nhiều cặp​

Vẽ biểu đồ đường thể hiện phần trăm thay đổi tích luỹ của BTC, ETH, SOL trong cùng khoảng thời gian (bắt đầu tất cả từ 0%).

Bài 4: Biểu đồ tương tác với dropdown​

Dùng updatemenus để tạo dropdown cho phép người xem chọn hiển thị SMA20, SMA50, hay cả hai.

Bài 5: Heatmap lợi nhuận​

Tạo heatmap thể hiện lợi nhuận trung bình theo từng thứ trong tuần và từng giờ trong ngày.

🎯 Tóm tắt ngày 44​

✅ Biết khi nào dùng Plotly thay Matplotlib ✅ Vẽ biểu đồ nến chuẩn cho phân tích giá ✅ Ghép nhiều hàng bằng make_subplots — giá và khối lượng ✅ Đánh dấu điểm mua/bán bằng marker tam giác ✅ Xuất HTML tương tác hoặc PNG cho báo cáo ✅ Bốn quy tắc trình bày biểu đồ rõ ràng, có thông điệp


Phân tích dữ liệu không đảm bảo lợi nhuận đầu tư. Hãy luôn cẩn trọng và nghiên cứu kỹ trước khi đầu tư.