Bắt đáy cổ phiếu VN30 sau 4–5 phiên giảm liên tiếp: có lời không?
Duy Nguyen · · Nghiên cứu thị trường
> Tóm tắt nhanh: Mua cổ phiếu VN30 sau từ 4 phiên giảm liên tiếp trở lên rồi giữ 5 phiên thì trung bình lời hơn mua bừa khoảng 0,25%, khó đổ cho may. Trừ phí thuế xong còn cỡ 226.000 đồng trên 100 triệu, tức là có lợi thế thật nhưng mỏng.
"Đỏ 4 phiên liền rồi, giảm thế này là quá đà, vào thôi anh em." Phiên đỏ nào mở diễn đàn ra cũng gặp câu này. Chiều ngược lại thì lúc nào cũng có người nhắc "đừng bắt dao rơi".
Hai phe cãi nhau nhiều năm mà hiếm ai đưa số ra. Vì vậy mình lôi dữ liệu rổ VN30 từ 2015 đến nay ra để trả lời ba câu. Mua sau chuỗi giảm có lời hơn mua bình thường không? Chuỗi giảm càng dài thì có hồi càng mạnh không? Tính cả T+2 và phí thuế thì còn lại bao nhiêu?
Kết quả không chiều lòng phe nào hoàn toàn. Phe bắt đáy đúng một phần, có điều miếng bánh nhỏ hơn họ tưởng khá nhiều.
> Góc người mới (biết rồi thì lướt qua) > - Chu kỳ T+2: mua hôm nay thì chiều phiên T+2 hàng mới về để bán, giống mua hàng online, trả tiền xong chờ hai ngày mới nhận. > - Trung bình và trung vị: 9 người lương 10 triệu, một tỷ phú bước vào thì trung bình vọt lên, còn trung vị (người đứng giữa) vẫn 10 triệu. > - Tỷ lệ thắng: phần trăm số lần có lãi. Thắng nhiều ván lãi lẻ, thua một ván mất đậm thì tỷ lệ thắng cao vẫn lỗ. > - Thanh lỗi (khoảng tin cậy 95%): vạch dọc trên cột, cho biết con số thật nhiều khả năng nằm trong khoảng nào. Cắt qua 0 thì chưa chắc khác 0. > - t-stat: tín hiệu to hơn nhiễu bao nhiêu lần, như nghe người nói giữa quán nhậu ồn. Từ khoảng 2 trở lên thì khó đổ cho may. > - Đường trung bình 200 phiên (MA200): giá trung bình khoảng 10 tháng gần nhất. Giá nằm trên đường này thường được coi là xu hướng dài hạn đang tăng.
Vì sao bắt đáy có thể ăn tiền, và vì sao có thể không
Phe bắt đáy có một cơ chế nghe khá thuyết phục. Thị trường mình đông nhà đầu tư cá nhân dùng margin (vay tiền công ty chứng khoán để mua). Giá giảm vài phiên liền thì tài khoản chạm ngưỡng call, công ty chứng khoán bán giải chấp mà chẳng cần biết doanh nghiệp tốt hay xấu. Kiểu bán bắt buộc này hay đẩy giá thấp hơn mức hợp lý, đến lúc lực bán cạn thì giá bật lại. Thêm yếu tố tâm lý: sau một chuỗi đỏ dài, ai cần bán thì phần nhiều đã bán rồi.
Chiều ngược lại cũng có lý lẽ riêng. Cổ phiếu giảm đều đặn nhiều khi vì tin xấu thật, như lợi nhuận đi xuống hay vướng pháp lý, mà người biết sớm thì rút dần từng phiên. Khi đó người bắt đáy đang đỡ hàng cho người biết nhiều hơn mình. Biên độ ±7% của HOSE còn khiến một cú sập lớn bị chia ra nhiều phiên, nên chuỗi giảm dài đôi khi chỉ là một tin xấu được giá "tiêu hóa" từ từ.
Riêng ở Việt Nam còn vướng T+2. Mua ATC (lệnh khớp ở giá đóng cửa) hôm nay thì sớm nhất chiều phiên T+2 mới bán được. Nhịp hồi chỉ kéo dài đúng một phiên hôm sau thì người mua cổ phiếu cơ sở đứng nhìn.
Mình đo thế nào
Nguồn là giá ngày đã điều chỉnh cổ tức, chia tách của DNSE cho các mã đang nằm trong rổ VN30, từ 05/01/2015 đến 23/10/2026.
Gộp lại được 77.801 quan sát, mỗi quan sát là một mã trong một ngày. Một phiên tính là "giảm" nếu giá đóng cửa thấp hơn phiên trước, và với mỗi ngày mình đếm xem đã có bao nhiêu phiên giảm liền nhau tính đến hôm đó. Giả định mua ở giá đóng cửa, rồi đo lợi suất ở hai mốc: bán ở T+2 (sớm nhất được phép) và giữ 5 phiên, cỡ một tuần. Mốc so sánh là mua vào một ngày bất kỳ, vì bắt đáy chỉ đáng công khi nó hơn được việc mua bừa.
Kết quả: có hồi, nhưng không phải cứ giảm càng lâu càng ngon
Trước hết là mốc mua bừa. Mua một ngày bất kỳ rồi giữ 5 phiên thì trung bình lãi +0,374%, khoảng 374.000 đồng trên 100 triệu vốn. Tỷ lệ dương 49,8%, chẳng khác tung đồng xu là mấy. Rổ VN30 đi lên trong giai đoạn này nên mua đại cũng có chút lãi về mặt trung bình.
Ở hình chính, trục ngang là số phiên giảm liên tiếp tính đến ngày mua, kèm số lần xảy ra. Cột xanh là bán ở T+2, cột cam là giữ 5 phiên, đường nét đứt là mốc mua bừa.

Hình 1: Lợi suất sau khi mua theo độ dài chuỗi giảm
Các cột không leo đều từ trái sang phải. Ngay sau một hai phiên đỏ, mua vào còn kém mua bừa. Riêng sau đúng một phiên giảm, bán ở T+2 trung bình lỗ -0,022%, vì một phiên đỏ thường chỉ là phiên mở màn của nhịp chỉnh.
Phải từ 3 phiên trở đi cột cam mới vượt đường nét đứt. Mốc 4 phiên đạt +0,58%, sang 5 phiên lại tụt về +0,38% với t-stat 1,80, vẫn trong vùng nhiễu.
Lợi suất giữ 5 phiên sau khi mua ở giá đóng cửa
| Số phiên giảm liên tiếp | Số mẫu | Trung bình | Trung vị | Tỷ lệ dương | t-stat | |:---|---:|---:|---:|---:|---:| | 0 | 43.133 | +0,47% | +0,05% | 50,0% | 20,06 | | 1 | 19.085 | +0,18% | 0,00% | 48,5% | 5,25 | | 2 | 8.828 | +0,22% | 0,00% | 49,7% | 4,22 | | 3 | 3.975 | +0,39% | +0,23% | 51,5% | 4,66 | | 4 | 1.672 | +0,58% | +0,30% | 52,5% | 4,22 | | 5 | 653 | +0,38% | +0,26% | 52,7% | 1,80 | | 6+ | 455 | +1,15% | +1,04% | 57,8% | 4,72 |
Cột trung vị trong bảng đáng để ý. Ở dòng không có phiên giảm nào, trung bình +0,47% nhưng trung vị chỉ +0,05%, tức là trung bình đang được vài phiên tăng vọt kéo lên.
Nhóm 6+ thì khác hẳn: trung vị +1,04%, sát với trung bình, tỷ lệ dương 57,8%. Nhóm này hồi khá đều chứ không nhờ vài cú bật đột biến. Có điều nó chỉ có 455 lần, và các lần ấy không độc lập với nhau như con số gợi ý.
Từng nhóm lẻ khá nhiễu, nên mình gộp các trường hợp từ 4 phiên giảm trở lên, được 2.780 lần. Giữ 5 phiên thì trung bình lãi +0,626%, hơn mốc mua bừa +0,252%. Kiểm định Welch (so hai trung bình mà không cần giả định hai nhóm dao động như nhau) cho p-value 0,017, tức là nếu thật ra không có hiệu ứng gì thì khả năng thấy chênh lệch cỡ này chỉ nhờ may là khá thấp. Đủ để tin là có gì đó, chưa đủ để gọi là bằng chứng thép.
Do cả rổ hay do vài mã kéo lên?
Đây là chỗ mình lo nhất. Nếu vài mã hồi cực mạnh kéo trung bình lên thì con số gộp chẳng nói được bao nhiêu.

Hình 2: Từng mã sau ≥ 4 phiên giảm liên tiếp
May là hiệu ứng khá phổ biến: 27/30 mã có trung bình 5 phiên dương. Đứng đầu là SHB với +2,93%, cuối bảng là BVH với -0,40%, có âm nhưng âm nhẹ. Kết quả gộp vì thế không phải do một hai mã gánh cả rổ.
Giảm trong xu hướng tăng hay xu hướng giảm?
Anh em trên diễn đàn hay khuyên chỉ bắt đáy khi xu hướng lớn còn tăng. Mình chia mẫu theo việc giá đang nằm trên hay dưới đường trung bình dài hạn ở hộp đầu bài. Nằm trên thì nhóm từ 4 phiên giảm trở lên cho trung bình +0,719% (n = 988), nằm dưới thì +0,523% (n = 1.619). Lời khuyên kia có lý, nhưng cả hai nhóm đều hơn mốc mua bừa, và khoảng cách giữa chúng không lớn như người ta hay đồn.
Có đúng ở mọi giai đoạn không?
Chia mẫu thành ba giai đoạn thì giai đoạn nào nhóm gộp cũng thắng mốc. Khoảng cách hẹp nhất rơi vào 2023-2026: +0,511% so với +0,346%. Hiệu ứng có thể đang yếu đi mấy năm gần đây, nhưng chừng này dữ liệu chưa đủ để khẳng định.
Trừ phí thuế xong còn bao nhiêu
Mình giả định chi phí khứ hồi 0,4%, gồm phí mua, phí bán và thuế bán 0,1%, tương đương khoảng 400.000 đồng trên 100 triệu.
Khoản lãi trung bình 626.000 đồng của nhóm gộp, sau phí còn khoảng 226.000 đồng (+0,226%). Còn mua bừa giữ 5 phiên thì sau phí thành lỗ -0,026%. Bắt đáy kiểu này vẫn dương sau phí, nhưng phí đã ăn mất phần lớn miếng lãi.
Mình có thể sai ở đâu
- Thiên lệch sống sót (chỉ nhìn kẻ còn trụ lại). Mình dùng danh sách VN30 hiện tại, nên những mã từng bị loại khỏi rổ, thường vì giảm mạnh, không có trong mẫu. Đó lại đúng là những mã bắt đáy dễ chết nhất, nên kết quả thật nhiều khả năng xấu hơn ở đây.
- Sự kiện dồn cục. Thị trường chung đỏ thì hàng chục mã cùng lúc có chuỗi giảm, nên mấy trăm "lần" trong mẫu thực chất chỉ là vài đợt bán tháo. Các quan sát không độc lập, nên t-stat và p-value đang lạc quan hơn thực tế.
- Đếm trùng. Một đợt giảm 5 phiên được tính một lần ở mốc 4 phiên và thêm một lần ở mốc 5 phiên, với cửa sổ nắm giữ chồng lên nhau. Lượng thông tin độc lập trong nhóm gộp vì thế ít hơn con số mẫu cho thấy.
Code để anh em tự kiểm tra
Đoạn Python dưới đây tạo ra bảng và hình chính:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
# panel: dict {mã: DataFrame giá ngày đã điều chỉnh, index = ngày, có cột close}
# Ví dụ tải từ DNSE (miễn phí, không cần key):
# url = "https://services.entrade.com.vn/chart-api/v2/ohlcs/stock?from=1420070400&to=1790000000&symbol=FPT&resolution=1D"
# d = requests.get(url).json(); px = pd.DataFrame({"close": d["c"]}, index=pd.to_datetime(d["t"], unit="s"))
BLUE, ORANGE, INK2, AXIS = "#2a78d6", "#eb6834", "#52514e", "#c3c2b7"
pct_axis = lambda ax, decimals=1: ax.yaxis.set_major_formatter(FuncFormatter(lambda v, _: f"{v*100:.{decimals}f}%"))
zero_line = lambda ax: ax.axhline(0, color=AXIS, linewidth=1)
def summarize(x) -> dict:
"""Số mẫu, trung bình, trung vị, tỷ lệ dương và t-stat của một chuỗi lợi suất."""
x = pd.Series(x, dtype=float).dropna()
n = len(x)
std = x.std(ddof=1) if n > 1 else np.nan
se = std / np.sqrt(n) if n > 1 else np.nan
return {
"n": n,
"mean": x.mean(),
"median": x.median(),
"std": std,
"win_rate": (x > 0).mean() if n else np.nan,
"t_stat": x.mean() / se if n > 1 and se > 0 else np.nan,
"ci95": 1.96 * se,
}
def add_streaks(px: pd.DataFrame) -> pd.DataFrame:
"""Đếm số phiên giảm liên tiếp tính đến hôm nay, và lợi suất nắm giữ sau đó.
Mua ATC hôm nay (T), cổ phiếu về chiều T+2 => sớm nhất bán được ở phiên T+2."""
d = px.copy()
down = d["close"].pct_change() < 0
d["streak"] = down.groupby((~down).cumsum()).cumsum()
d["fwd2"] = d["close"].shift(-2) / d["close"] - 1 # bán sớm nhất (T+2)
d["fwd5"] = d["close"].shift(-5) / d["close"] - 1 # giữ 1 tuần
d["ma200"] = d["close"].rolling(200).mean()
return d
def streak_panel(panel: dict[str, pd.DataFrame]) -> pd.DataFrame:
"""Gộp mọi mã thành một bảng dài: mỗi dòng là một (mã, ngày)."""
rows = [add_streaks(px).assign(ticker=t) for t, px in panel.items()]
long = pd.concat(rows).dropna(subset=["fwd5"])
long["streak_bin"] = long["streak"].clip(upper=6).astype(int).astype(str).replace({"6": "6+"})
return long
def plot_streaks(tab2: pd.DataFrame, tab5: pd.DataFrame, base5: float):
fig, ax = plt.subplots(figsize=(8.6, 4.6))
x = np.arange(len(tab5))
w = 0.38
ax.bar(x - w / 2, tab2["mean"], width=w - 0.03, color=BLUE, label="Bán ở T+2", zorder=2)
ax.bar(x + w / 2, tab5["mean"], width=w - 0.03, color=ORANGE, label="Giữ 5 phiên", zorder=2)
ax.errorbar(x + w / 2, tab5["mean"], yerr=tab5["ci95"], fmt="none", ecolor=INK2, elinewidth=1, capsize=3, zorder=3)
ax.axhline(base5, color=INK2, ls="--", lw=1.2, zorder=4)
ax.annotate("TB 5 phiên của mọi ngày", (len(tab5) - 0.5, base5), xytext=(0, -12), textcoords="offset points",
ha="right", color=INK2, fontsize=9)
ax.set_xticks(x, [f"{k}\n{int(n):,} lần".replace(",", ".") for k, n in zip(tab5.index, tab5["n"])])
ax.set_xlabel("Số phiên giảm liên tiếp tính đến ngày mua")
zero_line(ax)
pct_axis(ax, decimals=2)
ax.set_title("Lợi suất trung bình sau khi mua ở giá đóng cửa, rổ VN30")
ax.legend(loc="upper left")
return fig
long = streak_panel(panel)
tab2 = pd.DataFrame({k: summarize(g["fwd2"]) for k, g in long.groupby("streak_bin")}).T
tab5 = pd.DataFrame({k: summarize(g["fwd5"]) for k, g in long.groupby("streak_bin")}).T
print(tab5[["n", "mean", "win_rate", "t_stat"]])
plot_streaks(tab2, tab5, long["fwd5"].mean()).savefig("streaks.png", dpi=150)
Hàm add_streaks xét từng mã: phiên nào đóng cửa thấp hơn hôm trước thì đánh dấu là giảm, rồi đếm số phiên giảm liền nhau, gặp phiên không giảm thì đếm lại từ đầu. Cũng trong hàm này, code lấy giá 2 phiên và 5 phiên sau chia cho giá hôm nay để ra lợi suất bán ở T+2 và giữ 5 phiên, đồng thời tính đường trung bình dài hạn. streak_panel ghép tất cả các mã thành một bảng dài và gom các chuỗi dài từ 6 phiên vào nhóm "6+". Cuối cùng summarize tính cho từng nhóm số mẫu, trung bình, trung vị, tỷ lệ dương, t-stat và độ dài thanh lỗi. Code này chưa trừ phí và chưa có kiểm định Welch, cần thì anh em tự thêm.
Dùng được gì khi giao dịch
Mình coi kết quả này là một chút "gió thuận", chưa phải hệ thống giao dịch. Nếu anh em vốn đã muốn gom một mã VN30 mình hiểu rõ, thì kiên nhẫn chờ nó đỏ vài phiên thường cho giá vào tốt hơn đuổi theo phiên xanh. Còn nhảy vào ngay sau một hai phiên đỏ thì số liệu không ủng hộ.
Lợi thế trung bình rất mỏng so với độ giật của một cổ phiếu, lại còn T+2 và phí thuế, nên chỉ cần một lần mua trúng mã có tin xấu thật là bay phần lãi của nhiều lần trước. Quản lý khối lượng lệnh vẫn quan trọng hơn chuyện chọn điểm vào.
Hỏi đáp
Vậy chỉ đánh nhóm giảm từ 6 phiên trở lên cho lãi to hơn, chẳng phải ngon hơn? Trên giấy thì ngon, nhưng mẫu nhỏ và dồn vào vài đợt thị trường sập chung. Nhóm 5 phiên đứng ngay cạnh lại nằm trong vùng nhiễu. Các nhóm liền nhau nhảy lên xuống như vậy thì mình không dám coi nhóm cao nhất là quy luật.
Gặp mã kiểu BVH, BCM thì bắt đáy làm sao? Hai mã này trung bình còn âm sau chuỗi giảm, mà mẫu còn chưa có những mã đã rớt khỏi rổ. Thống kê chỉ cho biết mức trung bình của cả rổ, không cho biết lần này mã của bạn có tin xấu hay không. Phần đó phải tự đọc doanh nghiệp.
Sao không đo lãi ngay phiên hôm sau cho nhanh? Mua cổ phiếu cơ sở thì hôm sau chưa bán được, nên con số đó đẹp mấy cũng không ăn được. Biến thể đáng thử là thêm điều kiện VN-Index cũng đang có chuỗi giảm, để xem cổ phiếu giảm cùng cả chợ có hồi khác với cổ phiếu giảm một mình không.
Kết
Mua cổ phiếu VN30 sau từ 4 phiên giảm liên tiếp trở lên rồi giữ 5 phiên thì trung bình lời hơn mua bừa 0,25%, với 27/30 mã cho kết quả dương. Trừ phí thuế còn cỡ 226.000 đồng trên 100 triệu, trong khi thiên lệch sống sót có thể đang tô đẹp con số này. Phe bắt đáy có cơ sở, nhưng lợi thế mỏng hơn nhiều so với lời đồn trên diễn đàn.
Bài viết chỉ nhằm mục đích nghiên cứu và chia sẻ kiến thức, không phải khuyến nghị đầu tư.
---
Muốn tự kiểm chứng một ý tưởng như thế này? Bạn có thể dựng chiến lược, backtest và chạy paper trading ngay trên nền tảng QuantVN. Xem thêm các nghiên cứu khác về phái sinh trong bài tổng hợp Chứng khoán phái sinh VN30F1M: dữ liệu nói gì.