Bot Python Chứng KhoánBacktestPythonChứng khoánSharpe Ratio
Được viết bởithanhdtvào ngày 06/07/2026

Backtest Chiến Lược Đầu Tư Chứng Khoán Bằng Python: Hướng Dẫn Thực Hành

Hướng dẫn backtest chiến lược đầu tư chứng khoán bằng Python với backtesting.py và vectorbt. Đánh giá Sharpe Ratio, Drawdown và Win Rate chính xác.

Backtest Chiến Lược Đầu Tư Chứng Khoán Bằng Python: Hướng Dẫn Thực Hành

Backtesting là bước bắt buộc trước khi deploy bất kỳ chiến lược giao dịch nào. Bài viết này hướng dẫn thực hành backtest chiến lược chứng khoán Việt Nam bằng Python.

Tại Sao Backtest Quan Trọng?

Backtest cho biết chiến lược hoạt động như thế nào trên dữ liệu quá khứ — trước khi đặt tiền thật vào rủi ro. Tuy nhiên: past performance không đảm bảo future results.

Các chỉ số cần quan tâm:

  • Total Return (%): Tổng lợi nhuận
  • Sharpe Ratio: Lợi nhuận điều chỉnh rủi ro. > 1.0 tốt, > 2.0 xuất sắc
  • Max Drawdown (%): Thua lỗ tối đa từ đỉnh xuống đáy. < 20% chấp nhận được
  • Win Rate (%): Tỷ lệ lệnh thắng
  • Profit Factor: Tổng lời / Tổng lỗ. > 1.3 là tốt

Cài Đặt

pip install backtesting pandas numpy

Backtest Với backtesting.py

from backtesting import Backtest, Strategy
from backtesting.lib import crossover
import pandas as pd

class MACross(Strategy):
    fast = 9
    slow = 21

    def init(self):
        self.ema_fast = self.I(
            lambda x: pd.Series(x).ewm(span=self.fast).mean(),
            self.data.Close
        )
        self.ema_slow = self.I(
            lambda x: pd.Series(x).ewm(span=self.slow).mean(),
            self.data.Close
        )

    def next(self):
        if crossover(self.ema_fast, self.ema_slow):
            self.buy()
        elif crossover(self.ema_slow, self.ema_fast):
            self.position.close()

# df phải có columns: Open, High, Low, Close, Volume, index là datetime
bt = Backtest(df, MACross, cash=100_000_000, commission=0.0025)
stats = bt.run()
print(stats)
bt.plot()

Optimization — Tìm Tham Số Tốt Nhất

stats, heatmap = bt.optimize(
    fast=range(5, 20, 2),
    slow=range(15, 35, 2),
    maximize='Sharpe Ratio',
    constraint=lambda p: p.fast < p.slow,
    return_heatmap=True
)
print(f"Best: fast={stats._strategy.fast}, slow={stats._strategy.slow}")
print(f"Sharpe: {stats['Sharpe Ratio']:.2f}")
print(f"Drawdown: {stats['Max. Drawdown [%]']:.1f}%")

Backtest Nhiều Mã Cùng Lúc Với vectorbt

import vectorbt as vbt

# prices: DataFrame với index=date, columns=symbol names
fast_ma = vbt.MA.run(prices, window=9)
slow_ma = vbt.MA.run(prices, window=21)

entries = fast_ma.ma_crossed_above(slow_ma)
exits = fast_ma.ma_crossed_below(slow_ma)

portfolio = vbt.Portfolio.from_signals(
    prices, entries, exits,
    init_cash=100_000_000,
    fees=0.0025
)
print(portfolio.stats())

Cái Bẫy Lớn Nhất: Overfitting

Overfitting xảy ra khi tối ưu quá nhiều tham số trên cùng một dataset — bot hoàn hảo trong backtest nhưng thất bại trong live trading.

Cách tránh:

  • Train/Test split: 70% để optimize, 30% để validate (không được dùng khi optimize)
  • Walk-forward analysis: Backtest cuốn chiếu theo thời gian thực
  • Giữ ít tham số nhất có thể — mỗi tham số thêm vào là thêm nguồn overfitting

Kết Luận

Backtest tốt không đảm bảo live trading thành công, nhưng backtest kém gần như chắc chắn dẫn đến thất bại. Hãy coi backtest như điều kiện cần — không phải điều kiện đủ.

Học phương pháp backtest và phân tích định lượng chuyên nghiệp tại Hướng Nghiệp Dữ Liệu.