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

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ẽ:
- Kết nối tới API Binance sử dụng API key và secret
- Lấy 100 nến 1 giờ gần nhất cho cặp BTCUSDT
- Chuyển đổi dữ liệu thành DataFrame pandas
- 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
- 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 ý
-
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
-
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
-
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
-
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í | Matplotlib | Plotly |
|---|---|---|
| Tương tác | ❌ Ảnh tĩnh | ✅ Zoom, hover, tải ảnh |
| Cú pháp | Dài dòng | Ngắn gọn, có px (express) |
| Biểu đồ tài chính | Phải tự vẽ | Có sẵn Candlestick, OHLC |
| Chia sẻ trên web | Cần lưu ảnh | Xuất HTML tự chứa |
| Dùng trong báo cáo in | ✅ Tốt | Cần xuất ảnh tĩnh |
| Dashboard (Dash) | Không | Cù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ểm | Dùng khi |
|---|---|---|
.html | Giữ tương tác, 1 file duy nhất | Gửi cho đồng nghiệp |
.png | Nhúng vào báo cáo, slide | In ấn, trình bày |
.svg | Vector, phóng to không vỡ | Báo cáo chất lượng cao |
.json | Lư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
- 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".
- Tắt rangeslider (
xaxis_rangeslider_visible=False) — bạn đã có zoom bằng kéo chuột. - Màu xanh/đỏ nhất quán cho tăng/giảm.
- Đá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ư.