Xây Dựng Trình Theo Dõi Danh Mục Crypto Với PyQt6
Trong bài viết này, chúng ta sẽ cùng khám phá cách xây dựng một ứng dụng desktop nhẹ nhàng để theo dõi danh mục đầu tư tiền điện tử bằng cách sử dụng thư viện PyQt6. Dự án này sẽ giúp bạn hiểu rõ hơn về cách làm việc với giao diện người dùng, xử lý sự kiện và đa luồng trong PyQt6.
Giới Thiệu Dự Án
Ứng dụng của chúng ta sẽ cung cấp ba chức năng chính:
- Tải Danh Mục - Nhập tệp CSV chứa thông tin danh mục đầu tư.
- Làm Mới Giá - Lấy giá hiện tại từ API của Kraken.
- Xuất CSV - Lưu dữ liệu đã cập nhật trở lại đĩa.
Trong quá trình phát triển, chúng ta sẽ áp dụng đa luồng để giao diện người dùng không bị treo, thêm hệ thống ghi log và tệp cấu hình để ánh xạ các ký hiệu danh mục sang các cặp giao dịch của Kraken.
Giao Diện Người Dùng Chính
Giao diện chính của ứng dụng bao gồm:
- Một
QTableWidget
để hiển thị dữ liệu danh mục. - Các nút bấm để tải, làm mới và xuất dữ liệu.
Mã Nguồn Giao Diện Người Dùng
python
# Đặt cấu hình giao diện
def setUI(self):
self.setWindowTitle("CryptoTracker")
self.portfolio = pd.DataFrame(columns=["symbol", "amount", "price", "total_value"])
self.table = QTableWidget()
self.btn_load = QPushButton("Tải Danh Mục CSV")
self.btn_load.clicked.connect(self.load_portfolio)
self.btn_refresh = QPushButton("Làm Mới Giá Kraken")
self.btn_refresh.clicked.connect(self.refresh_prices)
self.btn_export = QPushButton("Xuất ra CSV")
self.btn_export.clicked.connect(self.export_csv)
layout = QVBoxLayout()
layout.addWidget(self.table)
layout.addWidget(self.btn_load)
layout.addWidget(self.btn_refresh)
layout.addWidget(self.btn_export)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
Tải Danh Mục
Chúng ta sẽ sử dụng một tệp CSV đơn giản để điều khiển ứng dụng. Khi nhấn nút Tải Danh Mục, một hộp thoại sẽ mở ra cho phép người dùng chọn tệp CSV và hiển thị dữ liệu trong bảng.
Mã Nguồn Tải Danh Mục
python
# Tải danh mục từ tệp CSV
def load_portfolio(self):
file_name, _ = QFileDialog.getOpenFileName(self, "Mở CSV", "", "Tệp CSV (*.csv)")
if file_name:
self.portfolio = pd.read_csv(file_name)
self.logger.info(f"Đã tải tệp {file_name}")
self.update_table()
Ví Dụ Tệp portfolio.csv
csv
symbol,amount
BTC,0.05
ETH,0.7
DOGE,1000
Lấy Giá (Với Đa Luồng)
Một trong những bài học quan trọng trong lập trình GUI là không bao giờ chặn luồng giao diện người dùng. Vì việc gọi API của Kraken có thể mất thời gian, chúng ta sẽ sử dụng QThreadPool
với một lớp Worker tùy chỉnh:
Mã Nguồn Worker
python
class Worker(QRunnable):
def __init__(self, fn, *args, **kwargs):
super().__init__()
self.fn = fn
self.args = args
self.kwargs = kwargs
@pyqtSlot()
def run(self):
self.fn(*self.args, **self.kwargs)
Khi người dùng nhấn nút Làm Mới Giá, mỗi ký hiệu sẽ được xử lý trong một luồng worker riêng biệt:
Mã Nguồn Làm Mới Giá
python
# Làm mới giá từ Kraken
def refresh_prices(self):
if self.portfolio.empty:
self.logger.error("Không tìm thấy dữ liệu trong danh mục")
return
for sym in self.portfolio["symbol"]:
kraken_pair = self.config['KrakenSymbols'][sym.upper()]
worker = Worker(self.update_pair_info, kraken_pair, sym)
self.threadPool.start(worker)
Ví Dụ Tệp config.ini với Ánh Xạ Ký Hiệu của Kraken
ini
[KrakenSymbols]
BTC=XXBTZUSD
ETH=XETHZUSD
DOGE=XDGUSD
USDT=USDTZUSD
SOL=SOLUSD
Cập Nhật Bảng
Sau khi lấy giá, ứng dụng sẽ cập nhật cả DataFrame và bảng hiển thị:
Mã Nguồn Cập Nhật Bảng
python
# Cập nhật bảng hiển thị
def update_table(self):
self.table.setRowCount(len(self.portfolio))
self.table.setColumnCount(len(self.portfolio.columns))
self.table.setHorizontalHeaderLabels(self.portfolio.columns)
for i, row in self.portfolio.iterrows():
for j, col in enumerate(self.portfolio.columns):
self.table.setItem(i, j, QTableWidgetItem(str(row[col])))
Mỗi hàng sẽ hiển thị:
- Ký hiệu (ví dụ, BTC)
- Số lượng (từ CSV)
- Giá (từ Kraken)
- Giá trị tổng (số lượng × giá)
Hệ Thống Ghi Log
Để theo dõi các hoạt động trong ứng dụng, chúng ta sẽ thêm một hệ thống ghi log đơn giản ghi vào cả app.log
và console. Điều này rất hữu ích khi gỡ lỗi phản hồi API và đóng gói bằng PyInstaller.
Những Bài Học Rút Ra
- Đa luồng là rất quan trọng: nếu không có nó, giao diện người dùng sẽ bị treo trong khi chờ phản hồi từ Kraken.
- Cấu trúc của PyQt6 rất linh hoạt, nhưng việc lồng ghép các cấu trúc có thể cần một số thử nghiệm.
- PyInstaller hoạt động, nhưng bạn cần xử lý các tài nguyên được đóng gói như
config.ini
một cách cẩn thận (mẹosys._MEIPASS
). - Kết hợp pandas với
QTableWidget
giúp dễ dàng đồng bộ hóa GUI và dữ liệu.
Demo và Mã Nguồn
Bạn có thể xem cách ứng dụng hoạt động tại đây. Mã nguồn có thể được tìm thấy tại đây.
Kết Luận
Hy vọng rằng bài viết này đã giúp bạn hiểu rõ hơn về cách xây dựng một ứng dụng theo dõi danh mục đầu tư tiền điện tử bằng PyQt6. Hãy thử triển khai và mở rộng ứng dụng của bạn để phù hợp với nhu cầu của mình. Nếu bạn có bất kỳ câu hỏi nào, đừng ngần ngại để lại câu hỏi bên dưới!
Câu Hỏi Thường Gặp (FAQ)
1. PyQt6 có khó học không?
PyQt6 có thể khó khăn cho người mới bắt đầu, nhưng với tài liệu và ví dụ rõ ràng, bạn có thể dễ dàng nắm bắt. Hãy thử làm theo các hướng dẫn và thực hành nhiều.
2. Tôi có thể sử dụng API khác không?
Có, bạn có thể thay thế API của Kraken bằng bất kỳ API nào khác phù hợp với nhu cầu của bạn. Hãy đảm bảo rằng bạn điều chỉnh mã theo API mà bạn đang sử dụng.