Python cho Backtesting Forex — Stack, Vòng Lặp Nghiên Cứu và Những Lưu Ý Trung Thực
Strategy Tester của MT5 đủ dùng khi chiến lược còn nằm gọn trong các giả định của nó — quy tắc đơn giản, một công cụ, không cần xử lý dữ liệu từ bên ngoài. Nhưng ngay khi bạn muốn kết hợp dữ liệu vĩ mô, gộp nhiều cặp tiền vào một tín hiệu, hay tính tỷ số Sharpe cùng với phân phối sụt giảm vốn (drawdown), công cụ đó trở nên chật chội. Đó là lý do cộng đồng giao dịch hệ thống đã dùng Python cho kiểm thử ngược (backtesting) từ nhiều năm nay: toàn quyền kiểm soát quy tắc, thư viện tính toán cấp nghiên cứu, mọi nguồn dữ liệu trong một script, và vòng lặp từ ý tưởng đến đường cong vốn chỉ mất vài phút.
Tại sao trader rời bỏ Strategy Tester
Strategy Tester mạnh ở chỗ tối ưu hóa một expert advisor trên một cặp tiền và một khung thời gian — và dừng lại ở đó. Khi bạn muốn đưa dữ liệu từ ngoài broker vào, kết hợp nhiều cặp thành một tín hiệu, hay tính tỷ số Sharpe bên cạnh phân phối drawdown, bạn sẽ phải ngồi ghép thủ công các file CSV trong Excel. Python gom tất cả vào một script: dữ liệu từ broker chảy vào `pandas`, dữ liệu vĩ mô nhập cùng bằng `merge`, còn các chỉ số rủi ro được tính bởi thư viện học thuật. Để hiểu rõ hơn về nền tảng của tự động hóa giao dịch thực hành, bạn có thể tham khảo phần thực hành của chúng tôi; còn sự khác biệt giữa hệ sinh thái MetaQuotes và Python được phân tích trong bài so sánh bot MQL5 với Python.
Bộ công cụ thực tế
Bộ công cụ (stack) ngắn gọn và miễn phí. Xử lý dữ liệu dùng `pandas` và `numpy` — `pandas` quản lý chuỗi thời gian và resample từ M1 lên H1, `numpy` thực hiện phép tính vectơ nhanh cho các chỉ báo. Engine backtest thường là `backtrader` của Daniel Rodriguez theo phong cách event-driven với lớp Strategy và Cerebro, hoặc `vectorbt` của Oleg Polakov khi bạn cần quét hàng trăm tổ hợp tham số trong vài chục giây. Biểu đồ dùng `matplotlib` cho báo cáo tĩnh và `plotly` cho giao diện tương tác. Dữ liệu lịch sử lấy qua `yfinance` cho giá đóng cửa ngày, `ccxt` cho thị trường crypto, và gói chính thức `MetaTrader5` cho giá thật của broker. Toàn bộ stack đều mã nguồn mở.
Vòng lặp nghiên cứu — từ quy tắc đến kiểm định
Một dự án backtest gồm bốn bước nên giữ riêng biệt. Đầu tiên, viết quy tắc vào và ra bằng ngôn ngữ thường — nếu bạn không thể nói "tôi mua khi độ dốc EMA-50 dương và giá đóng cửa vượt đỉnh hai mươi ngày", mở editor cũng chưa cần thiết. Bước hai là dịch các quy tắc đó sang biểu thức vectơ trong `pandas`: áp điều kiện lên toàn bộ cột thay vì vòng lặp từng nến — nhờ vậy mười năm dữ liệu H1 chạy xong trong vài giây. Bước ba là cho engine chạy trên toàn bộ lịch sử với hoa hồng, trượt giá (slippage), cắt lỗ (stop loss) và chốt lời (take profit), rồi đọc đường cong vốn và danh sách lệnh. Bước bốn — và đây là nơi người mới thường bỏ qua — là kiểm định ngoài mẫu (out-of-sample): khóa hai năm cuối lại, tối ưu hóa chỉ trên giai đoạn trước, rồi đọc kết quả từ dữ liệu chưa từng được chạm đến. Cơ chế cửa sổ cuộn và các kỹ thuật kiểm định nâng cao thuộc phạm vi xây dựng chiến lược giao dịch, còn bối cảnh rộng hơn nằm trong hướng dẫn kiểm thử chiến lược của chúng tôi.
Những gì Python không tự làm được
Người mới đọc tài liệu `backtrader` và nghĩ thư viện lo hết mọi thứ. Không phải vậy. Engine mặc định không biết gì về spread của broker bạn, không hay biết giá dao động năm pip quanh các bản tin kinh tế, và không mô hình hóa hoa hồng ECN — thường bảy đô la mỗi lot, tính cả hai chiều. Tất cả phải nhập tay: `commission`, `slippage_perc`, và một mô hình spread tùy chỉnh thay đổi theo giờ giao dịch. Bẫy thứ hai là chất lượng dữ liệu: chuỗi miễn phí từ `yfinance` có khoảng trống cuối tuần, còn dữ liệu tick từ Dukascopy đôi khi thiếu với các cặp kỳ lạ. Cạm bẫy thứ ba là thói quen yêu thích đường cong mượt: backtest trong mẫu (in-sample) với năm tham số được tối ưu hóa gần như luôn "quảng cáo" 200% mỗi năm — cho đến khi bạn bỏ một biến và nhìn xem đường cong trông ra sao trên dữ liệu ngoài mẫu. Kết quả thực tế thường thấp hơn 30 đến 50% so với phiên bản ngây thơ ban đầu.
Ví dụ minh họa — dự án EUR/USD giả định
Giả sử chiến lược giao dịch phiên London trên EUR/USD với nến M15: mở vị thế mua EUR/USD khi giá vượt đỉnh năm nến trước đó sau 15:00 giờ Việt Nam (ICT, UTC+7), mở vị thế bán EUR/USD khi phá đáy; cắt lỗ bằng 1,5 lần ATR chu kỳ hai mươi, chốt lời bằng hai lần mức cắt lỗ. Bạn tải dữ liệu từ 2018 đến 2024 bằng gói `MetaTrader5`, đưa vào `pandas` và resample lên M15. Backtest với hoa hồng sáu đô la mỗi lot, spread cố định 0,8 pip ngoài giờ tin tức và một pip trượt giá ngẫu nhiên cho điểm vào, cho kết quả: tỷ lệ thắng 51%, profit factor 1,28, sụt giảm vốn tối đa 14% và chỉ số Sharpe 0,9. Chia lịch sử thành bốn năm trong mẫu và hai năm ngoài mẫu, kết quả trung bình ngoài mẫu giảm khoảng một phần ba — để lại quyết định triển khai ở mức hợp lý, không có gì ngoạn mục. Toàn bộ con số trên chỉ mang tính minh họa; chúng cho thấy hình dạng của kết quả, không phải lời hứa.
"Python đã trở thành ngôn ngữ lập trình và hệ sinh thái mạnh mẽ cho ngành tài chính — từ phân tích dữ liệu tài chính đến giao dịch thuật toán đến quản lý rủi ro." — Yves Hilpisch, Python for Finance: Mastering Data-Driven Finance, O'Reilly, 2018
Những cảnh báo trung thực nên đính kèm mọi báo cáo
Khi backtest kết thúc, hãy thêm một khung cảnh báo ngắn gồm bốn điểm. Thứ nhất: bạn đã giả định spread bao nhiêu và có mở rộng nó quanh các bản tin vĩ mô không — khoảng cách giữa 0,8 pip cố định và 2,5 pip thực tế trong phiên NFP thường chính là toàn bộ lợi thế của chiến lược. Thứ hai: dữ liệu có sạch khỏi look-ahead bias không, tức là bạn có tính chỉ báo từ giá đóng cửa của nến hiện tại mà trong thực tế chưa có không. Thứ ba: bạn đã tối ưu bao nhiêu tham số cùng lúc — năm là ngưỡng mà trên đó ngay cả walk-forward cũng không bảo vệ được bạn. Thứ tư: kết quả có giữ vững trên dữ liệu ngoài mẫu hay chỉ tốt trên toàn bộ lịch sử. Thiếu bốn câu đó, báo cáo là marketing, không phải kiểm định. Để hiểu sâu hơn về quản lý rủi ro trong giao dịch, bạn có thể tham khảo phần quản lý rủi ro. Và quy trình nghiên cứu rộng hơn được trình bày tại trader's workshop trên ForexMechanics.com.
Lưu ý pháp lý quan trọng: Giao dịch ngoại hối và CFD thông qua các nhà môi giới (broker) nước ngoài không được Ngân hàng Nhà nước Việt Nam (NHNN) cấp phép cho nhà đầu tư cá nhân tại Việt Nam theo quy định hiện hành. Giao dịch qua broker nước ngoài không có giấy phép của NHNN tiềm ẩn rủi ro pháp lý và tài chính đáng kể. Đây không phải lời khuyên đầu tư — hãy tham khảo chuyên gia pháp lý và thuế trước khi thực hiện bất kỳ giao dịch nào.
Bước đầu tiên của bạn
- Cài đặt Python 3.11 trở lên với các thư viện `pandas`, `numpy`, `backtrader`, `matplotlib` và gói chính thức `MetaTrader5` bằng một lệnh `pip install`, sau đó tải hai năm dữ liệu H1 cho cặp tiền bạn thường giao dịch và lưu dưới dạng CSV — để các vòng lặp sau dùng lại từ nguồn cục bộ ổn định mà không cần tải lại.
- Viết quy tắc chiến lược bằng ngôn ngữ thường trước — một câu cho điều kiện vào lệnh, một câu cho điều kiện ra lệnh, một câu cho cắt lỗ (stop loss) và một câu cho chốt lời (take profit) — rồi mới dịch sang biểu thức vectơ trong `pandas`; đặt mục tiêu toàn bộ bài kiểm thử nằm trong ba mươi dòng code, không vòng lặp từng nến, không tối ưu hóa tham số ở giai đoạn này.
- Chạy backtest với hoa hồng thực của broker, spread cố định và một pip trượt giá ngẫu nhiên, rồi so sánh với phiên bản không có chi phí; khoảng cách giữa hai đường cong cho bạn biết bao nhiêu lợi thế giả định là do giả định thực thi theo giá giữa — nếu chi phí chiếm hơn nửa lợi nhuận gộp, chiến lược quá mỏng để triển khai vào tài khoản thực.
- Chia lịch sử thành bốn năm trong mẫu và một năm ngoài mẫu, tối ưu hóa tối đa hai tham số chỉ trên phần trong mẫu, khóa bộ tham số tốt nhất lại và chạy kiểm định ngoài mẫu một lần duy nhất; nếu tỷ lệ thắng giảm hơn một phần ba, hãy đơn giản hóa logic thay vì tiếp tục tìm kiếm tối ưu hóa mới.
- Lập một sổ nhật ký đơn giản — file Markdown trong cùng repository — và sau mỗi backtest ghi lại bốn câu: spread giả định bao nhiêu, có tránh look-ahead bias không, tối ưu bao nhiêu tham số, và kết quả ngoài mẫu có trụ vững trên mức một nửa kết quả trong mẫu không; không có nhật ký đó, sau ba tháng bạn sẽ không còn nhớ báo cáo nào trung thực, báo cáo nào đã "được làm đẹp" một cách thầm lặng.
Nguồn và tài liệu tham khảo
-
Backtrader Backtrader documentation — Introduction · oficjalna dokumentacja open-source'owej biblioteki Daniela Rodrigueza: model event-driven, klasy Strategy i Cerebro, integracja danych www.backtrader.com ↗
-
vectorbt vectorbt usage documentation · oficjalny przewodnik po wektorowym backtestowaniu w numpy/pandas — przykłady i sweep parametrów vectorbt.dev ↗
-
O'Reilly Media Yves Hilpisch — Python for Finance, 2nd Edition (2018) · kanoniczna pozycja o zastosowaniach Pythona w analityce finansowej, algorytmice i zarządzaniu ryzykiem www.oreilly.com ↗
-
MQL5 MetaTrader 5 Python Integration — official reference · oficjalne API pakietu MetaTrader5: pobieranie historycznych OHLC i tików, dostęp do konta i składanie zleceń z Pythona www.mql5.com ↗
-
pandas pandas — Time series / date functionality · referencja czasu w pandas: konwersje, resampling, indeksowanie i przesunięcia używane w każdym backteście pandas.pydata.org ↗
Câu hỏi thường gặp
Tôi có cần kiến thức Python nâng cao để bắt đầu không?
Python cơ bản là đủ — vòng lặp, danh sách, hàm, import thư viện và đọc file CSV. Còn lại là pandas, và bạn sẽ học dần trong quá trình làm vì mọi dự án backtesting đều dùng cùng một nhóm thao tác: tải dữ liệu, resample, tính chỉ báo, định nghĩa điều kiện vào lệnh, tổng hợp kết quả. Chiến lược đầu tiên thường gói gọn trong ba mươi dòng code, nên không cần chờ đến khi "thành thạo Python hoàn toàn". Nhịp lành mạnh hơn là duy trì hai luồng song song: một khóa học ngắn về cơ bản (bốn đến sáu tuần, mỗi ngày một tiếng) và dự án thực tế đang luyện tập. Nếu bạn có thể lập bảng Excel với công thức và hiểu khái niệm hàm là gì, bạn đã có mức tối thiểu cần thiết — pandas thay thế bảng tính gần như hoàn toàn, chạy nhanh hơn và cho phép bạn kiểm định công việc đúng cách trên dữ liệu ngoài mẫu.
Tại sao chọn backtrader thay vì vectorbt — hay ngược lại?
Hai thư viện này theo hai triết lý khác nhau. Backtrader hoạt động theo sự kiện (event-driven): engine đi từng nến một, gọi phương thức next() trên lớp Strategy của bạn và phản ánh đúng luồng giao dịch thực tế — nên gắn thêm logic quản lý vị thế, trailing stop hay thoát lệnh một phần là rất tự nhiên. Cái giá phải trả là tốc độ: mười năm dữ liệu M5 trên một cặp tiền có thể mất vài phút. Vectorbt đi theo hướng ngược lại — bạn diễn đạt toàn bộ chiến lược như các phép tính vectơ trên cột pandas, engine tính tất cả song song qua numpy, và quét một trăm tổ hợp tham số xong trong vài chục giây. Cái giá là phạm vi diễn đạt: logic vào lệnh phức tạp phụ thuộc trạng thái danh mục khó mã hóa hơn. Trong thực tế, trader giữ cả hai — vectorbt để khám phá nhanh và quét tham số, backtrader để kiểm định cuối cùng ứng viên tốt nhất với mô hình hoa hồng và trượt giá thực tế.
Lấy dữ liệu lịch sử đáng tin cậy ở đâu?
Ba nguồn, theo thứ tự ưu tiên hợp lý. Thứ nhất, gói chính thức MetaTrader5 — bạn lấy lịch sử giá trực tiếp từ broker của mình, nên spread, phí qua đêm (swap) và hoa hồng trong backtest khớp với những gì bạn sẽ thấy sau này trên tài khoản thực. Đây là lựa chọn trung thực nhất cho bất kỳ chiến lược nào bạn định triển khai. Thứ hai, Dukascopy công bố dữ liệu tick và M1 cho các cặp tiền chính từ năm 2003 — chất lượng cơ sở, nhưng spread lấy từ nền tảng Dukascopy chứ không phải broker của bạn. Thứ ba, yfinance cho giá đóng cửa ngày và ccxt cho thị trường crypto — cả hai đều ổn để làm nguyên mẫu, nhưng khoảng trống cuối tuần và vài phút thiếu đôi khi khiến chúng không phù hợp để kiểm định chiến lược trong ngày. Ghi lại nguồn dữ liệu trong phần đầu script mỗi lần, để sáu tháng sau bạn vẫn biết báo cáo đó dựa trên cơ sở nào — một chi tiết nhỏ cứu được công việc mỗi lần kiểm toán.
Làm sao nhận biết một backtest đẹp đến mức không thực?
Bốn dấu hiệu là đủ. Thứ nhất, tỷ lệ thắng trên 75% qua hơn hai trăm lệnh — gần như không thể đạt được ngoài scalping trên thị trường rất hẹp, nên kết quả đó chỉ đến look-ahead bias hoặc lỗi dữ liệu. Thứ hai, đường cong vốn không có đợt giảm đáng kể — chiến lược thực tế ghi nhận sụt giảm vốn (drawdown) hai chữ số, nên đường đi lên mượt mà là cảnh báo curve-fit. Thứ ba, profit factor trên 3,5 — cực kỳ hiếm gặp trong Forex, nơi spread ECN một mình đã ăn vào lợi thế ở mức hai chữ số phần trăm. Thứ tư, độ nhạy cao với tham số — khi chuyển chu kỳ đường trung bình từ 14 sang 12 khiến kết quả sụp đổ, chiến lược đã học nhiễu chứ không học cấu trúc thị trường. Khi hai trong bốn dấu hiệu cùng xuất hiện, báo cáo là đáng nghi ngờ bất kể các chỉ số tổng thể; hãy đơn giản hóa logic, bỏ một hoặc hai tham số và chạy lại bài kiểm thử trên dữ liệu ngoài mẫu.