Hiệu ứng ngày trong tuần trên VN30F1M: thứ Hai đỏ, thứ Ba xanh?

· · Nghiên cứu thị trường

Hiệu ứng ngày trong tuần trên VN30F1M: thứ Hai đỏ, thứ Ba xanh?

> Tóm tắt nhanh: Thứ Hai trên VN30F1M đúng là phiên yếu nhất (trung bình -0,188%), nhưng phần lỗ nằm trong phiên, còn khoảng trống qua cuối tuần lại hơi dương. Thứ Ba sau một thứ Hai giảm hơn 1% thì hồi trung bình +0,661% (98 lần), trong khi các ngày khác sau phiên giảm mạnh gần như không hồi.

"Thứ Hai đen tối" là câu anh em trên diễn đàn hay than mỗi đầu tuần. Cuối tuần nghe đủ thứ tin, sáng thứ Hai vào lệnh, chiều nhìn tài khoản đỏ lòm. Bên Mỹ còn có hẳn cái tên cho vế sau: "Turnaround Tuesday", tức thứ Ba hay hồi lại sau một thứ Hai bị bán quá tay.

Mình muốn kiểm tra hai chuyện trên hợp đồng tương lai VN30F1M. Một là có thứ nào trong tuần tăng hoặc giảm hơn hẳn không. Hai là nếu thứ Ba hay hồi, đó là "phép màu của thứ Ba" hay chỉ là thị trường hồi lại sau bất kỳ phiên giảm mạnh nào.

Kết quả có chỗ đúng với lời đồn, có chỗ lệch khá xa.

> Góc người mới (biết rồi thì lướt qua) > - VN30F1M: hợp đồng tương lai trên chỉ số VN30, đáo hạn gần nhất. Không sở hữu cổ phiếu, chỉ ăn chênh lệch; long là cược tăng, short là cược giảm. > - Điểm và tiền: giá tính bằng điểm, mỗi điểm biến động là 100.000 đồng lãi/lỗ cho một hợp đồng. Giống "giá mỗi ký" ngoài chợ. > - Trung bình và trung vị: 9 người lương 10 triệu, thêm một tỷ phú: trung bình vọt lên hàng chục tỷ, trung vị (người đứng giữa) vẫn 10 triệu. > - Thanh lỗi (khoảng tin cậy 95%): vạch dọc trên mỗi cột, vùng con số thật nhiều khả năng nằm trong. Cắt qua 0 thì chưa chắc khác 0. > - t-stat và p-value: t-stat là tín hiệu so với nhiễu, trị tuyệt đối từ khoảng 2 trở lên thì khó đổ cho may. p-value dưới 0,05 cũng hiểu tương tự. > - Khoảng trống giá (gap): chênh lệch giữa giá mở cửa hôm nay và giá đóng cửa hôm trước, tức phần giá chạy "qua đêm" khi chợ đóng cửa.

Vì sao thứ Hai có thể "đen" thật, và vì sao có thể chỉ là chuyện kể

Lời giải thích kinh điển bên Mỹ khá dễ nghe. Tin xấu dồn lại trong hai ngày nghỉ, người ta không làm gì được, nên sáng thứ Hai ai cũng muốn thoát hàng cùng lúc. Bán quá đà thì hôm sau có nhịp hồi. Ở Việt Nam, nhà đầu tư cá nhân giao dịch phái sinh rất đông, cuối tuần lại có cả hai ngày lướt nhóm chat và diễn đàn. Tâm lý "nghe tin rồi hoảng" hoàn toàn có thể lặp lại.

Nhưng cũng có đủ lý do để nghi. Mình chia dữ liệu thành năm thứ rồi nhìn xem thứ nào nổi bật. Kiểu chia này giống ném năm phi tiêu, kiểu gì cũng có một cái gần hồng tâm hơn mấy cái kia, dù tay mình chẳng có kỹ năng gì. Lợi suất thứ Hai còn gồm cả hai ngày cuối tuần, nên nó dễ "dị" hơn các thứ khác vì lý do cơ học. Và câu hỏi quan trọng nhất: nếu thứ Ba hồi, liệu thứ Tư hay thứ Sáu sau một phiên giảm mạnh có hồi y như vậy không? Nếu có thì "Turnaround Tuesday" chỉ là tên đẹp đặt cho hiện tượng hồi sau giảm nói chung.

Mình đo thế nào

Dữ liệu là VN30F1M nến ngày (gộp từ nến 1 phút), từ 11/08/2017 đến 08/10/2026, tổng cộng 2.162 phiên có lợi suất đóng cửa so với đóng cửa hôm trước. Mình bỏ các ngày đổi hợp đồng, vì lúc đó giá nhảy từ hợp đồng cũ sang hợp đồng mới, so hai giá đó với nhau là so táo với cam. Ngày đổi hợp đồng luôn rơi vào thứ Sáu (sau phiên đáo hạn thứ Năm), nên thứ Sáu có ít mẫu hơn các thứ khác.

Lợi suất mỗi phiên tính theo phần trăm, rồi gom theo thứ trong tuần để lấy trung bình, trung vị, tỷ lệ phiên tăng và t-stat. Với Turnaround Tuesday, mình chỉ lấy các thứ Ba có phiên liền trước đúng là thứ Hai, rồi chia theo thứ Hai đó giảm hơn 1%, giảm 0-1%, tăng 0-1% hay tăng hơn 1%.

Kết quả

Năm thứ trong tuần

Trung bình mọi phiên trong mẫu là +0,062%, đó là cái mốc. Thứ nào chênh hẳn so với con số này mới đáng bàn.

![Lợi suất trung bình của VN30F1M theo thứ trong tuần](https://quantvn.com/blog-assets/hieu-ung-ngay-trong-tuan-vn30f1m/weekdays.png)

Hình 1: Lợi suất trung bình của VN30F1M theo thứ trong tuần

Mỗi cột là lợi suất trung bình của một thứ, dưới chân cột có ghi số phiên. Thứ Hai là cột duy nhất cắm sâu xuống dưới 0, còn thứ Ba và thứ Tư vươn lên cao nhất. Thanh lỗi của thứ Hai và thứ Tư nằm tách hẳn nhau, trong khi thứ Năm và thứ Sáu có thanh lỗi đi xuyên qua 0, chưa phân biệt được với "không có gì".

Lợi suất đóng->đóng của VN30F1M theo thứ

| Thứ | Số mẫu | Trung bình | Trung vị | Tỷ lệ dương | t-stat | |:---|---:|---:|---:|---:|---:| | Thứ Hai | 441 | -0,188% | +0,031% | 50,8% | -2,22 | | Thứ Ba | 457 | +0,174% | +0,143% | 58,6% | 2,67 | | Thứ Tư | 455 | +0,258% | +0,170% | 59,6% | 4,45 | | Thứ Năm | 458 | -0,040% | +0,024% | 50,4% | -0,59 | | Thứ Sáu | 351 | +0,105% | +0,074% | 51,9% | 1,55 |

Riêng thứ Hai, trung bình là -0,188% trên 441 phiên, t-stat -2,22, đủ để không đổ hết cho may.

Quy ra tiền ở mức giá cuối mẫu 1.880,2 điểm, con số đó vào khoảng -3,5 điểm, tức chừng 352.600 đồng mỗi hợp đồng mỗi phiên thứ Hai, tính bình quân.

Có điều trung vị của thứ Hai lại +0,031%, và tỷ lệ phiên tăng 50,8%, gần như tung đồng xu. Trung bình âm mà trung vị dương cho thấy thứ Hai không giảm thường xuyên hơn, nó chỉ có những phiên giảm rất sâu kéo cả nhóm xuống.

Ngôi sao bất ngờ là thứ Tư: trung bình +0,258%, tỷ lệ tăng 59,6%, t-stat 4,45, mức khó gán cho may rủi nhất trong năm thứ. Thứ Ba đứng ngay sau với +0,174%.

Mình chạy thêm kiểm định Kruskal-Wallis (một phép kiểm tra xem năm nhóm có cùng phân phối hay không, không bị vài phiên cực đoan chi phối). Kết quả p < 0,001, nên khả năng năm thứ thật ra giống hệt nhau là rất thấp.

Thứ Hai "đen" vì cuối tuần hay vì chính phiên thứ Hai?

Câu chuyện bên Mỹ đổ cho tin xấu cuối tuần. Nếu đúng vậy, cú giảm phải nằm chủ yếu ở khoảng trống giá lúc mở cửa sáng thứ Hai. Mình tách lợi suất thứ Hai thành hai mảnh: gap (đóng cửa thứ Sáu đến mở cửa thứ Hai) và phần trong phiên (mở cửa đến đóng cửa thứ Hai).

Kết quả ngược với lời đồn. Gap thứ Hai trung bình +0,025%, hơi dương. Phần trong phiên mới là thủ phạm: -0,214%. Thị trường mở cửa thứ Hai không hề hoảng, cú bán diễn ra trong lúc giao dịch.

Để so, thứ Ba có gap +0,099% và phần trong phiên +0,075%, cả hai mảnh đều dương. Lời giải thích "tin xấu tích tụ qua cuối tuần" vì thế không khớp lắm với VN30F1M. Có thể áp lực bán đến từ nhịp giao dịch trong ngày, nhưng dữ liệu này chưa đủ để nói chính xác là gì.

Có ổn định qua các năm không

Một hiệu ứng thật thì phải xuất hiện ở nhiều giai đoạn, đâu thể sống nhờ một vài năm đặc biệt.

![Thứ 'tốt nhất' có đổi theo thời gian không?](https://quantvn.com/blog-assets/hieu-ung-ngay-trong-tuan-vn30f1m/era_heatmap.png)

Hình 2: Thứ 'tốt nhất' có đổi theo thời gian không?

Mỗi hàng là một giai đoạn, mỗi cột là một thứ, xanh là dương, đỏ là âm. Nếu thứ Hai "đen" thật, cột của nó phải đỏ đều từ trên xuống.

Ở đây thì lộn xộn hơn nhiều. Thứ Hai chỉ đội sổ trong giai đoạn 2021-2023, với -0,358%. Giai đoạn đầu, kẻ kém nhất lại là thứ Năm, còn giai đoạn gần nhất là thứ Sáu. Cái mác "thứ Hai đen tối" trên toàn mẫu dựa khá nhiều vào một giai đoạn.

Còn thứ Tư nhất quán hơn: dẫn đầu ở cả hai giai đoạn sau, cao nhất là +0,356% trong 2024-2026, dù giai đoạn đầu nhường ngôi cho thứ Sáu.

Turnaround Tuesday: thứ Ba sau một thứ Hai giảm mạnh

Giờ tới phần chính. Mình chia các thứ Ba theo diễn biến thứ Hai liền trước.

![Thứ Ba sau các kiểu thứ Hai khác nhau](https://quantvn.com/blog-assets/hieu-ung-ngay-trong-tuan-vn30f1m/tuesday.png)

Hình 3: Thứ Ba sau các kiểu thứ Hai khác nhau

Đường đứt nét màu xanh là trung bình mọi thứ Ba. Cột cam (thứ Ba sau một thứ Hai giảm hơn 1%) vọt hẳn lên trên, ba cột xám còn lại lẹt đẹt quanh 0 và đều có thanh lỗi cắt qua 0.

Lợi suất thứ Ba theo diễn biến thứ Hai

| Thứ Hai liền trước | Số mẫu | Trung bình | Trung vị | Tỷ lệ dương | t-stat | |:---|---:|---:|---:|---:|---:| | Thứ Hai giảm > 1% | 98 | +0,661% | +0,705% | 66,3% | 3,29 | | Thứ Hai giảm 0-1% | 118 | +0,091% | +0,137% | 61,0% | 0,93 | | Thứ Hai tăng 0-1% | 139 | -0,011% | +0,080% | 54,7% | -0,13 | | Thứ Hai tăng > 1% | 84 | +0,104% | +0,059% | 54,8% | 0,78 |

Sau một thứ Hai giảm hơn 1%, thứ Ba trung bình +0,661% trên 98 lần, tỷ lệ tăng 66,3%, t-stat 3,29.

Con số đó gấp 10,4 lần trung bình mọi phiên. Quy ra tiền ở cùng mức giá cuối mẫu, đó là khoảng +12,4 điểm, tức chừng 1.242.300 đồng mỗi hợp đồng.

Trung vị nhóm này là +0,705%, sát với trung bình, nên không phải vài phiên hồi khủng kéo cả nhóm lên. Còn nếu thứ Hai chỉ giảm nhẹ 0-1%, thứ Ba trung bình +0,091% với t-stat 0,93, vẫn nằm gọn trong vùng nhiễu.

Đến đây mới tới phép thử quyết định. Hồi sau giảm mạnh là chuyện bình thường của thị trường, vậy thứ Ba có gì riêng? Mình lấy nhóm đối chứng: các ngày không phải thứ Ba nhưng cũng đứng sau một phiên giảm hơn 1%. Nhóm này có 201 lần, trung bình -0,028%, tỷ lệ tăng 53,7%, gần như không hồi gì cả. So thứ Ba với nhóm đối chứng, p-value là 0,007, khá khó để bảo khác biệt này chỉ là trùng hợp.

Hiệu ứng cũng không sống nhờ một giai đoạn. Chia theo ba giai đoạn, thứ Ba sau thứ Hai giảm mạnh lần lượt cho +0,458%, +0,770% và +0,662%, cả ba đều dương và đều cao hơn hẳn mốc chung. Trên dữ liệu này, cú hồi gắn với thứ Ba thật, còn phiên giảm mạnh nói chung thì không kéo theo hồi.

Những chỗ mình có thể sai

Mẫu nhỏ là điểm yếu số một. Nhóm "thứ Hai giảm hơn 1%" chỉ có 98 lần, chia theo giai đoạn thì còn vài chục lần mỗi khúc. Các phiên giảm mạnh thường dồn cục vào những đợt thị trường hoảng loạn, nên 98 lần này không hẳn là 98 sự kiện độc lập. Một hai đợt bán tháo kéo dài cũng đủ đóng góp nhiều phiên cho nhóm.

Kế đến là chuyện thử nhiều cách. Mình so năm thứ, rồi chia thứ Ba thành bốn nhóm, tức đã nhìn dữ liệu ở khá nhiều góc. Càng chia nhiều nhóm, khả năng một nhóm "nổi bật" do ngẫu nhiên càng cao. Phép so với nhóm đối chứng giúp đỡ phần nào, nhưng không xóa được hoàn toàn rủi ro này.

Cuối cùng, toàn bộ con số chưa trừ phí giao dịch, thuế và trượt giá. Lợi suất đóng cửa so với đóng cửa cũng giả định mình vào lệnh đúng giá đóng cửa thứ Hai, điều mà ngoài đời không phải lúc nào cũng làm được.

Code để anh em tự chạy lại

Toàn bộ phần tính toán và vẽ hình nằm dưới đây.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

# daily: index = ngày, cột ret = lợi suất đóng->đóng (NaN ở ngày đổi hợp đồng), weekday = 0..4
# daily = pd.read_csv("vn30f1m_daily.csv", index_col="date", parse_dates=True)
# daily["ret"] = daily["close"].pct_change(); daily["weekday"] = daily.index.dayofweek

BLUE, ORANGE, NEUTRAL, INK2, AXIS = "#2a78d6", "#eb6834", "#b4b2a9", "#52514e", "#c3c2b7"
WEEKDAYS = ["Thứ Hai", "Thứ Ba", "Thứ Tư", "Thứ Năm", "Thứ Sáu"]
MONDAY_BINS = [-np.inf, -0.01, 0, 0.01, np.inf]
MONDAY_LABELS = ["Thứ Hai giảm > 1%", "Thứ Hai giảm 0-1%", "Thứ Hai tăng 0-1%", "Thứ Hai tăng > 1%"]
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 weekday_stats(daily: pd.DataFrame) -> pd.DataFrame:
    """Thống kê lợi suất đóng->đóng theo thứ trong tuần (thứ Hai gồm cả cuối tuần)."""
    return pd.DataFrame({WEEKDAYS[k]: summarize(g["ret"]) for k, g in daily.groupby("weekday")}).T


def tuesday_after_monday(daily: pd.DataFrame) -> pd.DataFrame:
    """Lợi suất thứ Ba, chia theo diễn biến của thứ Hai liền trước."""
    d = daily.copy()
    d["prev_ret"] = d["ret"].shift(1)
    d["prev_wd"] = d["weekday"].shift(1)
    tue = d[(d["weekday"] == 1) & (d["prev_wd"] == 0)].dropna(subset=["ret", "prev_ret"])
    group = pd.cut(tue["prev_ret"], MONDAY_BINS, labels=MONDAY_LABELS)
    return pd.DataFrame({k: summarize(g["ret"]) for k, g in tue.groupby(group, observed=True)}).T


def plot_weekdays(tab: pd.DataFrame):
    fig, ax = plt.subplots(figsize=(8.4, 4.4))
    x = np.arange(len(tab))
    ax.bar(x, tab["mean"], color=BLUE, width=0.6, zorder=2)
    ax.errorbar(x, tab["mean"], yerr=tab["ci95"], fmt="none", ecolor=INK2, elinewidth=1, capsize=3, zorder=3)
    ax.set_xticks(x, [f"{d}\n{int(n)} phiên" for d, n in zip(tab.index, tab["n"])])
    zero_line(ax)
    pct_axis(ax, decimals=2)
    ax.set_title("Lợi suất trung bình theo thứ (thanh lỗi = khoảng tin cậy 95%)")
    return fig


def plot_tuesday(tab: pd.DataFrame, baseline: float):
    fig, ax = plt.subplots(figsize=(8.4, 4.4))
    x = np.arange(len(tab))
    colors = [ORANGE if i == 0 else NEUTRAL for i in x]
    ax.bar(x, tab["mean"], color=colors, width=0.6, zorder=2)
    ax.errorbar(x, tab["mean"], yerr=tab["ci95"], fmt="none", ecolor=INK2, elinewidth=1, capsize=3, zorder=3)
    ax.axhline(baseline, color=BLUE, ls="--", lw=1.5, zorder=4)
    ax.annotate("Trung bình mọi thứ Ba", (len(tab) - 0.5, baseline), xytext=(0, 5), textcoords="offset points",
                ha="right", color=INK2, fontsize=9)
    ax.set_xticks(x, [f"{k}\n{int(n)} phiên" for k, n in zip(tab.index, tab["n"])])
    zero_line(ax)
    pct_axis(ax, decimals=2)
    ax.set_title("Lợi suất thứ Ba, chia theo diễn biến thứ Hai liền trước")
    return fig


print(weekday_stats(daily)[["n", "mean", "win_rate", "t_stat"]])
tue = tuesday_after_monday(daily)
print(tue[["n", "mean", "win_rate", "t_stat"]])
plot_weekdays(weekday_stats(daily)).savefig("weekdays.png", dpi=150)
plot_tuesday(tue, daily.loc[daily["weekday"] == 1, "ret"].mean()).savefig("tuesday.png", dpi=150)

Hàm summarize nhận một chuỗi lợi suất, bỏ ô trống, rồi tính số mẫu, trung bình, trung vị, tỷ lệ phiên dương, t-stat (trung bình chia sai số chuẩn) và độ dài thanh lỗi. Hàm weekday_stats gom các phiên theo thứ rồi gọi summarize cho từng thứ. Hàm tuesday_after_monday dịch dữ liệu lùi một dòng để mỗi phiên "nhìn thấy" phiên liền trước, chỉ giữ những thứ Ba có phiên trước đúng là thứ Hai, rồi cắt lợi suất thứ Hai thành bốn nhóm ở các mốc -1%, 0 và +1%. Hai hàm vẽ biểu đồ chỉ lấy kết quả đó ra vẽ cột, thanh lỗi và đường mốc.

Dùng được gì khi giao dịch

Với mình, đây là chuyện gió thuận gió ngược, chưa thành một hệ thống. Nếu thứ Hai vừa giảm hơn 1% mà sáng thứ Ba anh em đang định short theo đà, lịch sử cho thấy đó là đi ngược gió, vì thống kê nghiêng hẳn về phía hồi. Còn thấy một phiên giảm mạnh vào thứ Tư hay thứ Năm thì đừng mặc định hôm sau sẽ hồi, vì nhóm đối chứng gần như đứng im.

Phái sinh có đòn bẩy và giao dịch T+0, nên một thứ Ba ngoại lệ có thể ăn sạch lợi thế của nhiều lần trước, cộng thêm phí và trượt giá nữa.

Hỏi đáp

Thứ Hai trung vị dương mà sao bảo là thứ yếu nhất? Trung bình thứ Hai âm vì có những phiên giảm rất sâu, còn số phiên tăng và giảm thì gần chia đôi. Nên thứ Hai nguy hiểm ở độ sâu khi giảm hơn là ở tần suất giảm.

Vậy cứ thứ Hai giảm mạnh là chiều mua long giữ qua đêm à? Chưa tính phí, chưa tính trượt giá, mẫu chỉ 98 lần, và vẫn có những tuần thứ Hai giảm rồi thứ Ba giảm tiếp. Đây là thông tin để biết mình đang đứng phía thuận hay ngược với thống kê, chưa đủ để thành một chiến lược.

Biết đâu thứ Tư mới là hiệu ứng thật, thứ Ba chỉ ăn ké? Thứ Tư mạnh trên toàn mẫu và ổn định ở hai giai đoạn gần nhất, nhưng đó là câu chuyện khác. Biến thể đáng thử: lặp lại đúng phép chia này cho thứ Tư theo diễn biến thứ Ba, rồi so với nhóm đối chứng như mình đã làm.

Kết

Thứ Hai trên VN30F1M yếu thật trên toàn mẫu với trung bình -0,188%, nhưng cú giảm nằm trong phiên, gap cuối tuần thì hơi dương, và chỉ thật sự rõ trong một giai đoạn. Turnaround Tuesday đứng vững hơn: sau thứ Hai giảm hơn 1%, thứ Ba trung bình +0,661% trên 98 lần, trong khi các ngày khác sau phiên giảm mạnh chỉ -0,028%. Mẫu còn nhỏ, nên mình xem đây là điều đáng theo dõi tiếp, chưa dám coi là chân lý.

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ì.