Kiểm định Market Efficiency bằng Python: Run Test của Bachelier

30/12/2025

420 lượt đọc

Khi làm trading định lượng, một câu hỏi rất căn bản nhưng thường bị bỏ qua là: thị trường mình đang nghiên cứu có thực sự cho phép tồn tại edge hay không? Trước khi xây momentum, mean reversion hay bất kỳ mô hình ML nào, việc kiểm tra mức độ “ngẫu nhiên” của chuỗi lợi suất là bước rất nên làm.

Một trong những kiểm định cổ điển, đơn giản nhưng vẫn có giá trị thực tiễn là Run Test, được đề xuất bởi Louis Bachelier – người đặt nền móng cho tài chính định lượng từ đầu thế kỷ 20.

Ý tưởng của Run Test

Một run là một chuỗi các lợi suất cùng dấu liên tiếp.

Ví dụ:

.....→ một positive run dài 5

.– – – → một negative run dài 3

Nếu thị trường hiệu quả theo nghĩa yếu, dấu của lợi suất ngày hôm nay không cung cấp thông tin cho ngày mai. Khi đó:

  1. Số run sẽ gần với kỳ vọng ngẫu nhiên
  2. Run dài bất thường sẽ rất hiếm

Ngược lại, nếu tồn tại positive serial autocorrelation, ta sẽ thấy:

  1. Ít run hơn kỳ vọng
  2. Các chuỗi tăng/giảm kéo dài → môi trường thuận lợi cho momentum

Bước 1: Import thư viện và dữ liệu

import warnings
warnings.filterwarnings('ignore')

import numpy as np
import pandas as pd
from scipy.stats import norm

Trong ví dụ này, ta dùng dữ liệu giá cổ phiếu Netflix (NFLX). Bạn có thể lấy từ Yahoo Finance hoặc bất kỳ nguồn nào khác.

df = pd.read_csv('NFLX.csv', encoding='UTF-8')

Bước 2: Tính daily returns

df['daily_return'] = df['Close'][1:].values / df['Close'][:-1] - 1
df['runs'] = "X"

Ở đây ta chỉ quan tâm dấu của lợi suất, không phải độ lớn. Điều này rất quan trọng:

Run test không đo volatility hay magnitude, mà đo cấu trúc chuỗi của dấu lợi suất.

Bước 3: Xác định các positive và negative runs

if np.sign(df['daily_return'].iloc[0]) == 1:
df['runs'].iloc[0] = "P1"
positive_run = 1
negative_run = 0
positive_returns = 1
negative_returns = 0
else:
df['runs'].iloc[0] = "N1"
positive_run = 0
negative_run = 1
positive_returns = 0
negative_returns = 1

Ta khởi tạo run đầu tiên dựa trên dấu của lợi suất ngày đầu.

Sau đó duyệt toàn bộ chuỗi thời gian:

for i in range(0, df.shape[0] - 1):

if np.sign(df['daily_return'].iloc[i+1]) == 1:
positive_returns += 1

if df['runs'].iloc[i][:1] == "P":
df['runs'].iloc[i+1] = "P" + str(positive_run)
else:
positive_run += 1
df['runs'].iloc[i+1] = "P" + str(positive_run)

else:
negative_returns += 1

if df['runs'].iloc[i][:1] == "N":
df['runs'].iloc[i+1] = "N" + str(negative_run)
else:
negative_run += 1
df['runs'].iloc[i+1] = "N" + str(negative_run)

Cuối cùng:

print("Positive returns P =", positive_returns)
print("Negative returns N =", negative_returns)
print("Runs U =", positive_run + negative_run)

Ở đây:

  1. P = số ngày lợi suất dương
  2. N = số ngày lợi suất âm
  3. U = tổng số run quan sát được

Bước 4: Thống kê kiểm định Run Test

Theo lý thuyết, nếu lợi suất là ngẫu nhiên:

Kỳ vọng số run:

x = (2 * positive_returns * negative_returns /
(positive_returns + negative_returns)) + 1

Độ lệch chuẩn:

s = np.sqrt(
(2 * positive_returns * negative_returns *
(2 * positive_returns * negative_returns -
(positive_returns + negative_returns))) /
((positive_returns + negative_returns)**2 *
((positive_returns + negative_returns) - 1))
)

Thống kê Z:


u = positive_run + negative_run
Z = (u - x - 0.5) / s
ABSZ = np.abs(Z)

Bước 5: Kiểm định giả thuyết


alpha = 0.05
score = norm.ppf(1 - alpha / 2)

if ABSZ > score:
print("Reject H0: returns are not random")
else:
print("Fail to reject H0: returns appear random")

Trong ví dụ này, kết quả là: Không thể bác bỏ giả thuyết rằng lợi suất là ngẫu nhiên

Diễn giải kết quả cho đúng (rất quan trọng)

Kết quả này không nói rằng:

  1. Không thể kiếm tiền từ Netflix
  2. Momentum hay mean reversion là vô nghĩa

Nó chỉ nói rằng:

  1. Ở tần suất ngày
  2. Xét theo dấu lợi suất
  3. Không có bằng chứng mạnh về phụ thuộc chuỗi

Market efficiency không phải đúng/sai, mà là theo mức độ, theo tần suất, theo đặc điểm thống kê.

Một thị trường có thể:

  1. Ngẫu nhiên về dấu
  2. Nhưng vẫn có volatility clustering
  3. Hoặc skew / tail risk
  4. Hoặc structure ở weekly / monthly horizon

Run Test dùng để làm gì trong thực tế?

Trong practice, run test thường dùng để:

  1. Kiểm tra giả định ban đầu trước khi build model
  2. Tránh “tự vẽ pattern” bằng mắt
  3. Lọc thị trường / timeframe không phù hợp cho momentum

Nó không phải công cụ tạo alpha, mà là công cụ tránh ảo tưởng alpha.

Kết luận

Run test của Bachelier là một ví dụ rất hay cho tư duy định lượng: trước khi hỏi “mô hình nào kiếm tiền?”, hãy hỏi “dữ liệu này có cho phép tồn tại edge không?”.

Trong nhiều trường hợp, việc biết khi nào không nên kỳ vọng cấu trúc còn quan trọng hơn việc cố gắng tìm ra cấu trúc bằng mọi giá.

Chia sẻ bài viết

Đánh giá

Hãy là người đầu tiên nhận xét bài viết này!

Đăng ký nhận tin

Nhập Email để nhận được bản tin mới nhất từ QM Capital.

Bài viết liên quan

Vectorized backtesting có ích gì trong thực tế?
06/04/2026
0 lượt đọc

Vectorized backtesting có ích gì trong thực tế? C

Trong thực tế, rất nhiều ý tưởng giao dịch nghe qua đều có vẻ hợp lý. Ví dụ như mua khi giá vượt MA dài hạn, mua khi cổ phiếu breakout kèm thanh khoản tăng, hoặc đứng ngoài khi thị trường chung nằm dưới đường trung bình dài hạn. Nếu chỉ nhìn chart bằng mắt, rất dễ cảm thấy những ý tưởng như vậy “có vẻ đúng”. Vấn đề là cảm giác đó không đủ để dùng tiền thật. Với QM Capital, giá trị đầu tiên và lớn nhất của vectorized backtesting không phải là để khoe một equity curve đẹp, mà là để biến một ý tưởng mơ hồ thành một bộ quy tắc kiểm tra được.

Vì sao thực thi quan trọng hơn dự báo trong quant trading
05/04/2026
27 lượt đọc

Vì sao thực thi quan trọng hơn dự báo trong quant trading C

Khi mới học quant trading, nhiều người thường tập trung gần như toàn bộ vào phần mô hình. Họ nghĩ rằng nếu dự báo đúng hơn một chút, hoặc nếu tìm được một tín hiệu chính xác hơn phần còn lại của thị trường, thì kết quả giao dịch chắc chắn sẽ tốt. Cách nghĩ này không sai hoàn toàn, nhưng mới đúng một nửa. Trong giao dịch thực tế, dự báo chỉ là điểm bắt đầu. Sau đó còn một bước quan trọng hơn nhiều: biến tín hiệu đó thành vị thế thật, giao dịch thật, lợi nhuận thật.

Overfitting là “kẻ thù số 1” trong quant trading
02/04/2026
90 lượt đọc

Overfitting là “kẻ thù số 1” trong quant trading C

Nếu phải chọn một rủi ro làm hỏng nhiều chiến lược định lượng nhất, thì đó thường không phải là thiếu mô hình hiện đại, mà là overfitting. Nói đơn giản, overfitting xảy ra khi mô hình học quá kỹ dữ liệu quá khứ đến mức nó không chỉ học tín hiệu thật, mà còn học luôn cả nhiễu. Khi nhìn lại lịch sử, mọi thứ trông rất đẹp: độ chính xác cao, equity curve mượt, drawdown dễ chịu, Sharpe ratio hấp dẫn. Nhưng đến khi đem sang giai đoạn mới, hoặc live trading, mô hình bắt đầu hỏng rất nhanh.

Vì sao các quỹ quant lớn vẫn kiếm tiền bằng những mô hình rất đơn giản?
31/03/2026
174 lượt đọc

Vì sao các quỹ quant lớn vẫn kiếm tiền bằng những mô hình rất đơn giản? C

Có một hiểu lầm rất phổ biến khi mới bước vào quant trading: cứ nghe đến “quant” là nghĩ ngay đến deep learning, transformers, reinforcement learning, foundation models, hay ít nhất cũng phải có một thứ gì đó đủ phức tạp để nghe giống phòng lab hơn là bàn giao dịch. Nhưng nếu nhìn vào cách nhiều tổ chức thật đang vận hành, bức tranh lại bớt hào nhoáng hơn nhiều.

Ngày đáo hạn phái sinh có tạo ra một “anomaly” đủ rõ để đưa vào hệ thống giao dịch hay không?
31/03/2026
81 lượt đọc

Ngày đáo hạn phái sinh có tạo ra một “anomaly” đủ rõ để đưa vào hệ thống giao dịch hay không? C

Nếu nhìn theo kiểu tin tức, ngày đáo hạn phái sinh thường bị gắn với những cụm như rung lắc, kéo trụ, ép ATC. Nhưng với quant trading, cách hỏi như vậy vẫn còn cảm tính. Câu hỏi đúng hơn là: ngày đáo hạn có tạo ra một mẫu biến động lặp lại, đủ ổn định, đủ rõ, để mình đưa vào bộ lọc của hệ thống hay không. Đây là một câu hỏi rất hợp với thị trường Việt Nam, vì hợp đồng tương lai VN30 có lịch đáo hạn cố định vào thứ Năm lần thứ ba của tháng đáo hạn, nên bản thân nó đã là một event định kỳ, rất phù hợp để làm event study. Ngoài ra, hợp đồng VN30 hiện có hệ số nhân 100.000 đồng mỗi điểm chỉ số, nên đây không phải một sản phẩm quá nhỏ để bỏ qua khi nhìn hành vi của nhóm cổ phiếu trụ.

Làm sao biết một chart có đáng mua hay không chỉ trong vài giây?
29/03/2026
204 lượt đọc

Làm sao biết một chart có đáng mua hay không chỉ trong vài giây? C

Một trong những lỗi phổ biến nhất của nhà đầu tư cá nhân ở Việt Nam là quyết định mua trước, rồi mới mở chart ra sau để tìm lý do xác nhận. Có thể là một mã được nhắc nhiều trong room chat, một câu chuyện đầu tư công đang nóng, một cổ phiếu bất động sản “đã giảm quá sâu”, hay một mã ngân hàng “nghe nói sắp vào sóng”. Cách ra quyết định như vậy nghe quen vì nó rất đời thường, nhưng chính nó làm nhiều người kẹt hàng hàng tháng trời. Mua xong thì chart không chạy. Hoặc tệ hơn, chart vẫn tiếp tục bleed xuống nhưng người cầm hàng cứ bấu víu vào câu chuyện vì không biết nhìn chart thế nào để thừa nhận rằng mình đang đứng sai phía.

video-image

Truy Cập Miễn Phí Thư Viện Bot Tín Hiệu Giao Dịch Tự Động

Được nghiên cứu và phát triển bởi các chuyên gia từ QMTrade và cộng đồng nhà đầu tư chuyên nghiệp.

Truy cập ngay!