FinDualFormer — dự báo lợi nhuận cổ phiếu VNX50 từ OHLCV + BCTC quý (point-in-time)
Checkpoint của đồ án FinanceForecast: mô hình đề xuất FinDualFormer và hai baseline, mỗi mô hình 5 seed.
Code: github.com/ducnx/FinanceForecast, nhánh thang/ml/deep-learning
(báo cáo: docs/plan/quarterly-features/ket-qua-deep-learning.md, hướng dẫn chạy:
docs/plan/quarterly-features/huong-dan-chay-deep-learning.md).
Bài toán
Với mỗi phiên t và mỗi mã trong rổ VNX50 (50 mã), dự báo log-return tích luỹ t→t+h, h ∈ {1, 5, 20} phiên. Đầu vào: cửa sổ 60 phiên giá/khối lượng/định giá, các BCTC quý đã công bố trước phiên t (ngày công bố thật HOSE/HNX), trạng thái thị trường của rổ. Train 06/2014–12/2021, val 2022, test 01/2023–12/2025.
Mô hình
FinDualFormer phát triển từ PAN+NAN (Hadizadeh et al. 2025): Transformer causal trên chuỗi giá; mỗi BCTC quý là một token (kèm tuổi báo cáo), rank theo mặt cắt ngang các mã; ghép vào luồng giá; attention giữa các mã cùng ngày; market-guided gating; hybrid loss (MSE + IC + hướng + margin ranking). Mỗi checkpoint chứa trọng số của 5 epoch có val RankIC cao nhất — dự báo là trung bình của 5 mô hình đó.
Kết quả trên tập test (2023–2025, mean ± std qua 5 seed)
Horizon 5 phiên
| Mô hình | RankIC | t | DA % | MASE | Sharpe LS | Top-10 ròng/năm |
|---|---|---|---|---|---|---|
| FinDualFormer (đề xuất) | +0.075 ± 0.006 | +4.58 ± 0.35 | 53.9 ± 0.4 | 0.999 ± 0.002 | +2.11 ± 0.27 | +12.4% ± 1.6% |
| FinDualFormer chỉ dùng giá | +0.058 ± 0.029 | +3.37 ± 1.64 | 53.5 ± 0.8 | 1.010 ± 0.014 | +1.70 ± 0.42 | +5.3% ± 3.3% |
| PAN+NAN (Hadizadeh et al. 2025, baseline) | +0.036 ± 0.013 | +2.33 ± 0.73 | 50.6 ± 3.3 | 1.135 ± 0.048 | +1.00 ± 0.53 | +3.9% ± 4.2% |
Horizon 20 phiên
| Mô hình | RankIC | t | DA % | MASE | Sharpe LS | Top-10 ròng/năm |
|---|---|---|---|---|---|---|
| FinDualFormer (đề xuất) | +0.094 ± 0.012 | +2.82 ± 0.42 | 55.8 ± 1.1 | 1.011 ± 0.013 | +1.98 ± 0.36 | +14.6% ± 1.1% |
| FinDualFormer chỉ dùng giá | +0.077 ± 0.035 | +2.05 ± 0.84 | 55.5 ± 1.0 | 1.013 ± 0.009 | +1.56 ± 0.32 | +10.3% ± 2.0% |
| PAN+NAN (Hadizadeh et al. 2025, baseline) | +0.045 ± 0.012 | +1.44 ± 0.38 | 55.2 ± 0.6 | 1.262 ± 0.114 | +0.64 ± 0.34 | +6.0% ± 3.1% |
RankIC: tương quan hạng Spearman giữa dự báo và lợi nhuận thật theo từng ngày. MASE: MAE trên giá chuẩn hoá chia MAE của dự báo ngây thơ "giá tương lai = giá hôm nay" (< 1 là tốt hơn ngây thơ). Sharpe LS: danh mục long top 10 / short bottom 10, không chồng lấn. Top-10 ròng: long 10 mã điểm cao nhất so với bình quân rổ, trừ phí 0,25%/chiều.
Cấu trúc repo
configs/ config đã dùng (default_quant.yaml + file thí nghiệm của baseline)
<mô hình>/seed_<k>/
checkpoint.pt trọng số 5 epoch snapshot + config + kích thước dữ liệu + hệ số hiệu chỉnh
metrics.json metric val/test mọi horizon, lịch sử train
test_predictions.parquet dự báo tập test (bảng model_signals: symbol, date, score, expected_return)
results_summary.json metric test từng seed
Thư mục: findualformer (đề xuất), findualformer_price_only (bỏ nhánh BCTC), paper_pan_nan (baseline PAN+NAN).
Dùng checkpoint
from pathlib import Path
import torch
from src.contract.config import ConfigLoader # trong repo FinanceForecast, nhánh thang/ml/deep-learning
from src.models.deep.base import ModelDims
from src.models.deep.factory import DeepModelFactory
ckpt = torch.load("findualformer/seed_0/checkpoint.pt", map_location="cpu", weights_only=False)
config = ConfigLoader().load(Path("configs/default_quant.yaml")).deep # baseline: thêm file trong configs/
models = []
for state in ckpt["snapshot_states"]:
model = DeepModelFactory.create(config, ModelDims(**ckpt["dims"]))
model.load_state_dict(state)
models.append(model.eval())
# dữ liệu đầu vào: SequenceDatasetBuilder + SequenceBatcher (xem scripts/run.py, bước deep-train);
# dự báo = trung bình models(batch); nhân ckpt["calibration"] nếu cần biên độ lợi nhuận
Giới hạn
- Rổ VNX50 là danh sách hiện tại → có thiên lệch sống sót; chỉ 50 mã vốn hoá lớn.
- Kết quả là thực nghiệm học thuật cho đồ án, không phải khuyến nghị đầu tư. Long-short chỉ là thước đo (thị trường VN hạn chế bán khống); chưa backtest đủ luật T+2, biên độ, lô.
- Phụ thuộc dữ liệu: giá
datnkhptit/vn-stock-ohlcv(gated), BCTC/ngày công bốthangkt/financeforecast-bronze-online.