(P2) CW Market Overview

CW Market Overview tải dữ liệu chứng quyền có bảo đảm (CW) của toàn thị trường HOSE từ các nguồn công khai, tính định giá, biến động và rủi ro, ghi vào một file Excel và dựng một file dashboard HTML duy nhất gồm 4 tab. Bài này mô tả đủ chi tiết để bạn dựng lại một hệ thống tương tự từ đầu: lấy dữ liệu ở đâu, tính từng con số thế nào, lưu trung gian ra sao, ráp dashboard bằng cách nào, và nên làm theo thứ tự nào.

1. Hệ thống làm gì

Đầu vào là bảng giá và thống kê công khai. Đầu ra là ba thứ:

  • CW Dashboard.html: một file tự chứa (dữ liệu nhúng sẵn), 4 tab, đổi Sáng/Tối và EN/VI, mở bằng trình duyệt, gửi được qua email.
  • CW Market Overview.xlsx: sheet Horizon (mỗi CW một dòng, 35 cột chỉ số) và RawData (dữ liệu thô từng nguồn).
  • GARCH Volatility Result/: tham số, dự báo và kiểm định của mô hình GARCH / GJR-GARCH.
TabTrả lời câu hỏiNội dung chính
1. Competitor OverviewThị trường đang thế nào, mỗi tổ chức phát hành (TCPH) đứng ở đâu?KPI thị trường · thị phần theo TCPH · định giá so với mức phân phối · phân phối theo lô của TCPH nhà · treemap mua/bán ròng · bảng toàn bộ CW
2. Client OverviewNhà đầu tư mua gì, bán gì?Dòng tiền nhà đầu tư theo kỳ, theo mã cơ sở, theo ngày · sở thích theo moneyness, kỳ hạn, đòn bẩy hiệu dụng tại thời điểm giao dịch
3. VolatilityIV của từng CW đang đi đâu, phiên tới nên quote thế nào?3.1 kiểm tra trước phiên tới · 3.2 theo dõi IV và tín hiệu · 3.3 lịch sử IV · 3.4 IV các TCPH trên cùng mã cơ sở
4. Risk & EventsSổ CW của TCPH nhà rủi ro bao nhiêu, sắp có sự kiện gì, tạo lập thị trường tốt không?4.1 Greeks quy ra tiền, kịch bản ±7% · 4.2 lịch đáo hạn, sự kiện quyền, CW mới · 4.3 chất lượng chào giá trong phiên
Trong code, TCPH nhà được gọi là ME (một hằng số trong JavaScript) và các tham số có tiền tố KAFI_. Muốn dùng cho TCPH khác chỉ cần đổi hằng số này và từ khoá nhận diện trong cấu hình.

2. Kiến trúc và ba chế độ chạy

Hệ thống chia ba lớp, mỗi lớp chỉ đọc đầu ra của lớp trước. Nhờ vậy có thể dựng lại dashboard mà không tải lại dữ liệu, và sửa giao diện mà không chạm vào phần tính toán.

LớpViệc làmĐầu ra
Thu thậpGọi API công khai, chọn một ngày dữ liệu chung, cắt mọi nguồn về ngày đó, lưu cache theo bướcdata/cache/*.pkl, data/*.csv, data/quotes/
Tính toánBảng master từng CW (IV, delta, đòn bẩy…), HV, Yang-Zhang, GARCH, tự doanhSheet Horizon, RawData, workbook GARCH
Trình bàyCác module src/dashboard/*.py biến Excel + CSV thành JSON, nhúng vào khuôn HTMLCW Dashboard.html

2.1 Các bước của main.py

BướcViệc làmFile
0Chọn ngày dữ liệu (as-of), mục 5as_of.py
1Tải bảng CW HOSE, cắt giá về ngày as-ofapi_client.py, as_of.py
2Số lượng CW niêm yết (chỉ tải mã mới, mã cũ đọc lại từ Excel)api_client.py
3Bảng cổ phiếu VNALL (giá cơ sở)api_client.py
4Giá trị khớp lệnh cơ sở, ADV 1 tháng / 3 tháng / từ đầu nămunderlying_liquidity.py
5Lịch sử giá cơ sở, HV và Yang-Zhang theo kỳ hạn gốc của CWhistorical_loader.py
5bLịch sử giá đóng cửa từng CW → data/cw_daily.csvcw_history.py
5cBảng giá trong phiên từ LiveDragon → giá chào cuối phiên data/quotes/ và chất lượng chào giá data/quotes_mm/vdsc_quotes.py
6Tự doanh của TCPH theo từng CW, luỹ kế và theo ngàyproprietary_trading.py
7Bảng master: IV, delta, hoà vốn, đòn bẩy, % phân phốicw_processor.py, option_pricing.py
8GARCH / GJR-GARCH cho từng mã cơ sở, quy về kỳ hạn CWgarch_pipeline.py, volatility_models.py
RTẢnh chụp phiên mới nhất nếu đã có phiên đóng mới hơn ngày as-ofrealtime.py
9Ghi Excel, CSV trung gian, bảng DATA CHECK, rồi dựng dashboardexcel_exporter.py, dashboard/build.py

2.2 Ba chế độ chạy

File bấm đúpKhi nàoLàm gìThời gian
Run CW Market Overview.batMỗi ngày, sau 15:00Chạy đủ các bước trên, ghi Excel, dựng dashboardLần đầu 10–40 phút (tải lịch sử); sau đó vài phút
Run Live.batTrong giờ giao dịchChạy đầy đủ một lần, rồi cứ N phút lấy lại bảng giá, tính lại phần Real-time và dựng lại dashboard; trang đang mở tự tải lại, giữ tab và bộ lọc. Tự dừng 14:50Vài giây mỗi vòng
Rebuild Dashboard.batSau khi sửa giao diện hoặc tham số hiển thịKhông gọi API, dựng lại dashboard từ dữ liệu đã lưuDưới 1 phút

Dashboard có hai góc nhìn chuyển bằng nút: Sync (mọi số liệu cùng một ngày as-of) và Real-time (giá của phiên mới nhất; các số chỉ công bố sau phiên như tự doanh vẫn giữ ngày Sync và được ghi rõ ngày).

3. Cây thư mục

CW_Market_Overview/
├─ Run CW Market Overview.bat   chạy đầy đủ (Sync)
├─ Run Live.bat                 cập nhật trong phiên
├─ Rebuild Dashboard.bat        chỉ dựng lại dashboard
├─ main.py                      điều phối các bước 0 → 9
├─ live.py                      vòng lặp chế độ Live
├─ build_dashboard.py           lệnh cho Rebuild
├─ CW Market Overview.xlsx      khuôn Excel: Horizon, RawData
├─ config/api_config.py         MỌI THAM SỐ (mục 11)
├─ src/
│  ├─ ensure_python.bat         tìm / tự cài Python lần đầu
│  ├─ as_of.py                  chọn ngày dữ liệu, bảng DATA CHECK
│  ├─ api_client.py             gọi SSI
│  ├─ step_cache.py             cache kết quả từng bước theo ngày
│  ├─ historical_loader.py      lịch sử giá, HV, Yang-Zhang
│  ├─ underlying_liquidity.py   giá trị khớp, ADV
│  ├─ cw_history.py             giá đóng cửa CW theo ngày
│  ├─ vdsc_quotes.py            giá chào trong phiên (LiveDragon)
│  ├─ proprietary_trading.py    tự doanh (VNDIRECT)
│  ├─ option_pricing.py         Black-Scholes, IV, delta
│  ├─ cw_processor.py           bảng master từng CW
│  ├─ volatility_models.py      GARCH, GJR-GARCH, backtest
│  ├─ garch_pipeline.py         GARCH theo kỳ hạn CW
│  ├─ iv_monitor.py             giải IV dạng mảng, tín hiệu IV
│  ├─ realtime.py               ảnh chụp phiên mới nhất
│  ├─ kafi_inventory.py         tồn kho nội bộ (tuỳ chọn)
│  ├─ raw_data.py, excel_exporter.py, workbook_io.py   ghi Excel
│  └─ dashboard/
│     ├─ build.py               ráp dashboard
│     ├─ market_data.py         tab 1
│     ├─ client_data.py         tab 2
│     ├─ vol_data.py, iv_db.py  tab 3 (IV hằng ngày)
│     ├─ kafi_batches.py        phân phối theo lô
│     ├─ kafi_extra.py          CW đã hết ngày giao dịch nhưng chưa đáo hạn
│     ├─ events_data.py         sự kiện quyền (tự phát hiện)
│     ├─ mm_data.py             chất lượng chào giá
│     └─ template/              head.html · body.html · app.js.html · settings.js.html · logo
└─ data/                        CSV trung gian, cache, quotes, realtime (mục 8)

4. Nguồn dữ liệu và cách gọi

Lưu ý. Các địa chỉ dưới đây là địa chỉ mà bảng giá web công khai của SSI iBoard, VNDIRECT dstock và VDSC LiveDragon tự gọi để hiển thị. Chúng không phải API chính thức nên có thể đổi định dạng hoặc chặn bất cứ lúc nào. Gọi vừa phải (nghỉ 0,03–0,05 giây giữa các lần, tối đa vài luồng song song) và đọc điều khoản sử dụng của từng nơi trước khi dùng.

4.1 Bảy địa chỉ đang dùng

#Dữ liệuĐịa chỉTham sốTrường dùng tới
1Bảng CW HOSEGET https://iboard-query.ssi.com.vn/stock/cw/hose—data.coveredWarrantData[]: stockSymbol, underlyingSymbol, issuerName, exercisePrice, exerciseRatio (“1.7245:1”), firstTradingDate, lastTradingDate, maturityDate, tradingDate, refPrice, ceiling, floor, matchedPrice, best1Bid, best1Offer, nmTotalTradedQty, nmTotalTradedValue
2Bảng cổ phiếuGET https://iboard-query.ssi.com.vn/stock/group/VNALL—data[]: stockSymbol, refPrice, matchedPrice, nmTotalTradedValue, tradingDate
3Giá lịch sử nến ngày (CW và cổ phiếu)GET https://iboard-api.ssi.com.vn/statistics/charts/historyresolution=1D, symbol, from, to (Unix giây)data.t/o/h/l/c/v (mảng song song; giá theo nghìn đồng)
4Số lượng niêm yếtGET https://iboard-query.ssi.com.vn/stock/{symbol}—data.listedShare
5Lịch sử giao dịch cổ phiếuGET https://iboard-api.ssi.com.vn/statistics/company/ssmi/stock-infosymbol, page, pageSize, fromDate, toDate (dd/mm/yyyy)tradingDate, close, totalMatchVal; paging
6Tự doanh theo mã CWGET https://api-finfo.vndirect.com.vn/v4/proprietary_tradingq=code:<mã CW> hoặc q=date:YYYY-MM-DD, sort=date, page, sizecode, type, date, buyingVol, buyingVal, sellingVol, sellingVal; totalPages
7Bảng giá trong phiên (mọi ảnh chụp: 3 mức giá mua/bán tốt nhất, giá khớp)GET https://livedragon.vdsc.com.vn/general/intradayBoard.rv (lấy cookie JSESSIONID), rồi POST …/general/intradaySearch.rvstockCode, boardDate (dd/mm/yyyy); header X-Requested-With: XMLHttpRequestlist[]: TradeTime, BidPrice1–3, OfferPrice1–3, BidVol1–3, OfferVol1–3, MatchedPrice, MatchedTotalVol (giá theo nghìn đồng). Máy chủ chỉ giữ khoảng 3 tháng

4.2 Quy tắc chung

  • Gửi header giống trình duyệt (User-Agent, Accept). VNDIRECT cần thêm Referer và Origin = https://dstock.vndirect.com.vn.
  • SSI trả "code": "SUCCESS" khi thành công. API có phân trang thì lặp page tới hết.
  • Đơn vị: giá lịch sử SSI và giá LiveDragon theo nghìn đồng (nhân 1.000). Mốc thời gian nến ngày là 00:00 giờ Việt Nam: đổi sang múi Asia/Ho_Chi_Minh trước khi lấy ngày.
  • Tỷ lệ chuyển đổi dạng chữ “1.7245:1”: lấy số trước dấu hai chấm.
  • Tự doanh: lượng CW nhà đầu tư nắm = luỹ kế sellingVol − buyingVol của TCPH. Không dùng netVol của VNDIRECT vì ngược dấu. Lỗi mạng phải gọi lại (tối đa 3 lần), không được biến thành số 0.
  • Tải bù, không tải lại: mỗi lần chạy chỉ tải phần còn thiếu (mã mới, ngày mới). Dữ liệu LiveDragon phải lưu lại hằng ngày vì máy chủ chỉ giữ khoảng 3 tháng.
  • Tìm lại một API khi nó đổi: mở trang bảng giá bằng Chrome, F12 → Network → Fetch/XHR, thao tác trên trang, chọn yêu cầu mới, xem Headers và Response, chuột phải → Copy as cURL để thử lại.

4.3 Ví dụ gọi nhanh

import requests
H = {"User-Agent": "Mozilla/5.0", "Accept": "application/json, text/plain, */*"}

# 1. Bảng CW
cw = requests.get("https://iboard-query.ssi.com.vn/stock/cw/hose", headers=H, timeout=30).json()
rows = cw["data"]["coveredWarrantData"]
print(len(rows), "CW", rows[0]["stockSymbol"], rows[0]["exerciseRatio"])

# 6. Tự doanh một mã CW
HV = {**H, "Referer": "https://dstock.vndirect.com.vn/", "Origin": "https://dstock.vndirect.com.vn"}
p = requests.get("https://api-finfo.vndirect.com.vn/v4/proprietary_trading",
                 params={"q": f"code:{rows[0]['stockSymbol']}", "sort": "date", "page": 1, "size": 100},
                 headers=HV, timeout=30).json()

# 7. Bảng giá trong phiên của một CW, một ngày
s = requests.Session(); s.headers.update({**H, "X-Requested-With": "XMLHttpRequest",
                                          "Referer": "https://livedragon.vdsc.com.vn/general/intradayBoard.rv"})
s.get("https://livedragon.vdsc.com.vn/general/intradayBoard.rv", timeout=20)          # cookie
snap = s.post("https://livedragon.vdsc.com.vn/general/intradaySearch.rv",
              data={"stockCode": rows[0]["stockSymbol"], "boardDate": "16/10/2026"}, timeout=30).json()
print(len(snap.get("list") or []), "ảnh chụp")

4.4 Nguồn nội bộ (tuỳ chọn)

Hai biểu đồ dùng số chính xác hơn nếu có dữ liệu nội bộ của TCPH nhà; không có thì hệ thống tự ước tính:

Dữ liệuĐịnh dạng tối thiểuKhông có thì
Tồn kho CW của TCPH theo ngàyExcel/CSV: Ngày · Mã CW · Tồn kho (gồm lệnh chờ thanh toán T+2)Lượng lưu hành ước tính = số niêm yết − (tự doanh mua − tự doanh bán luỹ kế)
Cổ phiếu phòng hộ đang nắmNhập tay trong cấu hình: {"<mã cơ sở>": <số cổ phiếu>}Delta Exposure = Delta CW (coi như chưa phòng hộ)
IV quét trong phiên (nếu có công cụ quét riêng)SQLite: thời điểm · mã CW · IVTự tính IV từ giá chào (mục 7.4)

5. Một ngày dữ liệu cho mọi nguồn

Mọi con số trong Excel và chế độ Sync phải mô tả cùng một phiên đã đóng. Quy tắc trong as_of.py:

  1. Ngày làm việc, chạy từ 15:00 trở đi → ứng viên là hôm nay. Chạy trước 15:00 hoặc cuối tuần → ngày làm việc liền trước.
  2. Ứng viên chỉ được dùng khi mọi nguồn đã có ngày đó: tự doanh VNDIRECT (thường công bố muộn nhất; kiểm tra bằng q=date:YYYY-MM-DD&size=5), nến ngày của CW, nến ngày của cổ phiếu, stock-info.
  3. Thiếu một nguồn → lùi một ngày làm việc và kiểm tra lại, tối đa 7 lần.
  4. Chốt ngày xong thì cắt mọi nguồn về ngày đó: giá và khối lượng CW, giá cơ sở, thanh khoản, lịch sử cho HV/GARCH, tự doanh luỹ kế, số ngày còn lại.
  5. In bảng DATA CHECK: mỗi nguồn một dòng, OK nếu đúng ngày, XX nếu lệch. Dashboard từ chối dựng nếu workbook và các CSV khác ngày.

6. Công thức cho từng CW

Ký hiệu: S giá cơ sở, K giá thực hiện, CR tỷ lệ chuyển đổi (số CW đổi 1 cổ phiếu), W giá CW, T = số ngày lịch còn lại / 365, r lãi suất phi rủi ro (mặc định 7%, một mức cho mọi CW), N(·) hàm phân phối chuẩn tích luỹ, n(·) hàm mật độ.

Giá CW lý thuyết = [ S·N(d1) − K·e−rT·N(d2) ] / CR, d1 = [ ln(S/K) + (r + σ²/2)T ] / (σ√T), d2 = d1 − σ√T
Chỉ số (cột Horizon)Công thứcGhi chú
DTENgày đáo hạn − ngày as-of (ngày lịch)Đáo hạn = ngày giao dịch cuối + 2 ngày làm việc
Breakeven priceK + W × CR
% Increase to BreakevenBreakeven / S − 1Cơ sở phải tăng bao nhiêu để hoà vốn
Intrinsic Valuemax(S − K, 0) / CRGiá trị nội tại mỗi CW
StatusITM nếu S > K, OTM nếu S < K, còn lại ATMMoneyness = S/K − 1
LeverageS / (W × CR)Đòn bẩy đơn thuần
Đòn bẩy hiệu dụng (dashboard)Leverage × N(d1)σ = IV của CW, không có thì HV. Đây là % thay đổi giá CW khi cơ sở +1%
CW price theoryBlack-Scholes với σ = HVSo sánh với giá thị trường
IVNghiệm σ của BS(σ) = W, tìm bằng Brent trong [0,0001; 5]W dưới giá trị nội tại chiết khấu → không có nghiệm, để trống
DeltaN(d1) / CR với σ = IVSố cổ phiếu tương đương mỗi CW
IV-HVIV − HV
Net soldLuỹ kế (tự doanh bán − tự doanh mua) từ ngày giao dịch đầuLượng nhà đầu tư nắm giữ ước tính
% distributionmin(Net sold / số niêm yết, 100%)Mức phân phối

6.1 Ví dụ tính tay

Một CW giả định: S = 30.000 đ, K = 32.000 đ, CR = 4, W = 900 đ, còn 120 ngày, r = 7%.

Chỉ sốTínhKết quả
Moneyness30.000 / 32.000 − 1−6,25% (OTM)
Hoà vốn32.000 + 900 × 435.600 đ; cơ sở cần tăng 18,7%
Giá trị nội tạimax(30.000 − 32.000, 0) / 40 đ: toàn bộ 900 đ là giá trị thời gian
IVGiải BS(σ) = 90060,3%
N(d1)d1 = 0,05290,521
Delta mỗi CW0,521 / 40,130 cổ phiếu
Đòn bẩy đơn thuần30.000 / (900 × 4)8,33x
Đòn bẩy hiệu dụng8,33 × 0,5214,34x
Đòn bẩy đơn thuần 8,33x nghĩa là bỏ 900 đ được tiếp xúc với 1/4 cổ phiếu 30.000 đ. Nhưng giá CW chỉ nhạy bằng 52% giá cổ phiếu, nên khi cơ sở +1% thì CW chỉ +4,3%. Vì vậy dashboard dùng đòn bẩy hiệu dụng để phân nhóm.

7. Biến động: HV, Yang-Zhang, GARCH, IV hằng ngày

7.1 HV và Yang-Zhang theo kỳ hạn gốc

Mỗi CW có kỳ hạn gốc = ngày đáo hạn − ngày giao dịch đầu (ví dụ 12 tháng). HV đo trên đúng khoảng ngày lịch đó, tính ngược từ ngày as-of; ít hơn 20 lợi suất thì lấy 20 phiên gần nhất.

HV = độ lệch chuẩn của ln(Ct / Ct−1) × √252
Yang-Zhang: σ² = Var(ln Ot/Ct−1) + k·Var(ln Ct/Ot) + (1 − k)·mean[ ln(H/O)·ln(H/C) + ln(L/O)·ln(L/C) ], k = 0,34 / (1,34 + (n+1)/(n−1)), YZ = √(252·σ²)

7.2 GARCH và GJR-GARCH

  • Tải khoảng 5 năm giá cơ sở, ước lượng trên 750 phiên gần nhất, phân phối Student-t (thư viện arch).
  • Bỏ những ngày có |lợi suất| > 7,5% (thường do sự kiện quyền chưa điều chỉnh).
  • Giới hạn persistence α + β + γ/2 ≤ 0,99 để vol dài hạn không bùng nổ.
  • Dự báo vol bình quân cho các kỳ hạn 21, 63, 126, 189, 252, 315 phiên; mỗi CW lấy kỳ hạn khớp với kỳ hạn gốc của nó.
  • Tuỳ chọn backtest walk-forward: huấn luyện tối thiểu 500 phiên, ước lượng lại mỗi 20 phiên, chấm điểm bằng QLIKE, kiểm định Diebold-Mariano và VaR Kupiec.

7.3 IV hằng ngày cho tab 3

IV trong bảng master dùng giá đóng cửa, dễ nhiễu vì phiên ATC. Tab 3 dùng một chuỗi IV hằng ngày ổn định hơn, ưu tiên theo thứ tự:

  1. Có công cụ quét IV trong phiên (ví dụ 10 phút/lần, giá giữa bid/ask): IV ngày = trung bình các lần quét; ngày có ít hơn 3 lần quét thì bỏ.
  2. Không có: tự tính từ giá giữa (Bid + Ask)/2 của ảnh chụp chào giá chặt cuối cùng trước 14:30 (chênh lệch ≤ max(3 bước giá, 6% giá giữa)). Giá cơ sở lấy cùng thời điểm: giá khớp cuối trước 14:30 của cổ phiếu, quy đổi theo hệ số điều chỉnh của SSI.
  3. Không có giá chào hai chiều thì dùng giá đóng cửa của ngày có khớp lệnh.
Khi cơ sở có sự kiện quyền (chia cổ tức bằng cổ phiếu, phát hành thêm), giá lịch sử của SSI đã được điều chỉnh còn giá chào thì chưa. Phải nhân giá cơ sở chưa điều chỉnh với hệ số (giá điều chỉnh / giá chưa điều chỉnh) của ngày đó, nếu không IV sẽ nhảy sai trong khoảng trước ngày giao dịch không hưởng quyền.

8. Dữ liệu trung gian và workbook

Dashboard không đọc API mà đọc các file dưới đây. Đây là “hợp đồng” giữa lớp tính toán và lớp trình bày: giữ đúng tên cột thì có thể thay phần lấy dữ liệu mà không sửa dashboard.

FileCộtNội dung
data/pdt_cache.csvCW, PDT Buy Volume, PDT Buy Value, PDT Sell Volume, PDT Sell Value, Net Sold, PDT Trading Days, Net Sold Today, Net Value Today, As-ofTự doanh luỹ kế đến ngày as-of
data/pdt_daily.csvCW, date, buyingVol, buyingVal, sellingVol, sellingVal, As-ofTự doanh từng ngày (tab 2, phân phối theo lô)
data/cw_eod.csvCW, Close, Prev Close, Ceiling, Floor, Volume, Bid, Ask, As-ofGiá CW ngày as-of
data/underlying_daily.csvTicker, Date, Close, As-ofGiá đóng cửa cơ sở (đã điều chỉnh)
data/cw_daily.csvCW, Date, Close, Volume, As-ofLịch sử giá đóng cửa CW
data/cw_listing.csvCW, First trading date, Last trading dateVòng đời CW, kể cả mã đã hết hạn
data/cw_terms.csvCW, Ticker, Issuer, ltd, K, CR, listed, seenĐiều khoản đã biết của mọi CW, để tính cả CW đã rời bảng giá nhưng chưa đáo hạn
data/quotes/YYYY-MM-DD.csvCW, Date, Bid, Ask, BidVol, AskVol, QuoteTime, Last, Close, VolumeMỗi mã một dòng mỗi phiên: giá chào chặt cuối cùng trước 14:30 (cả CW và cổ phiếu cơ sở)
data/quotes_mm/YYYY-MM-DD.csvCW, Date, Snaps, Sec, Two, SprTk, SprRel, Tk1, DepB, DepA, EffTk, EffRel, EffVol, Ok{n}_{x}Chất lượng chào giá trong phiên, lưu dạng TỔNG (giây, giây × giá trị) để cộng dồn chính xác (mục 10.4)
data/realtime/horizon.csv, cw_eod.csv, underlying_daily.csv, meta.jsonẢnh chụp phiên mới nhất cho chế độ Real-time
data/cache/*.pkl, web_data.jsonKết quả từng bước theo ngày; JSON của dashboard

8.1 Sheet Horizon

Dòng 7 là tiêu đề, dữ liệu từ dòng 8. Code tìm cột theo tên, không theo vị trí, nên có thể chèn cột hoặc đổi định dạng trong Excel. 35 cột theo thứ tự:

CW · Ticker · Issuer · Last trading date · Listed volume · DTE · Conversion ratio · Delta · CW price trading · CW price theory · Strike price · Spot price · Breakeven price · % Increase to Breakeven · Intrinsic Value / CW Price · Status · Leverage · HV · IV · IV-HV · Yang-Zhang vol · GARCH · GJR-GARCH · Market trading value · Market ADV 1 months · Market ADV 3 months · YTD Market ADV · CW trading volume · CW trading value · Buy volume · Buy value · Sell volume · Sell value · Net sold · % distribution

Ghi Excel qua chính ứng dụng Excel (thư viện xlwings) để giữ nguyên định dạng, công thức và biểu đồ của khuôn. Trước khi ghi: hỏi đóng file nếu đang mở, sao lưu bản cũ (giữ 30 bản trong data/backup/), ghi ra file tạm rồi mới thay.

9. Ráp dashboard thành một file

Ý tưởng: Python tính sẵn mọi thứ thành JSON; khuôn HTML có các chỗ giữ chỗ dạng __TÊN__; build.py thay chỗ giữ chỗ bằng JSON rồi ghép thành một file. Trình duyệt chỉ việc vẽ và lọc, không cần máy chủ.

  1. build.py kiểm tra các file đầu vào cùng ngày as-of, rồi lần lượt gọi từng module. Mỗi module đọc data/cache/web_data.json, thêm một khoá, ghi lại. Module phụ lỗi thì chỉ in WARNING, dashboard vẫn dựng (phần đó trống).
  2. Đọc 4 khuôn: head.html (CSS, biến màu sáng/tối), body.html (bố cục 4 tab), app.js.html (toàn bộ JavaScript), settings.js.html (đổi giao diện, từ điển EN→VI).
  3. Thay chỗ giữ chỗ bằng json.dumps(..., ensure_ascii=False), ghi ra file tạm rồi đổi tên (không bao giờ để lại file dở dang).
Chỗ giữ chỗModule tạoNội dung
__K__, __COMP__, __CLIENT__, __CWS__market_data.pyKPI thị trường, chỉ số theo TCPH, nhóm sản phẩm, danh sách CW (tab 1)
__RT__market_data.pyBộ số liệu tương tự cho chế độ Real-time
__CL2__, __FIRST__client_data.pyDòng tiền nhà đầu tư theo ngày và nhóm; ngày giao dịch đầu từng CW (tab 2)
__KB__, __KBRT__kafi_batches.pyPhân phối theo lô của TCPH nhà (Sync / Real-time)
__VOL__, __IVR__vol_data.py, iv_db.pyChuỗi IV hằng ngày từng CW, giá cơ sở, lãi suất (tab 3)
__XK__kafi_extra.pyCW của TCPH nhà đã rời bảng giá nhưng chưa đáo hạn (tab 4)
__EV__events_data.pySự kiện quyền phát hiện từ dữ liệu giá (tab 4)
__MMQ__mm_data.pyChất lượng chào giá trong phiên (tab 4.3)
__ASOF__build.pyNgày as-of

9.1 Những kỹ thuật giúp file nhẹ và dễ sửa

  • Chuỗi IV dạng mảng gọn: mỗi CW-ngày là một mảng [chỉ số ngày, S, W, bid, ask, close, IV, IV P10, IV P90, vega, nguồn, số lần quét] thay vì đối tượng có tên trường, giảm dung lượng nhiều lần.
  • Biểu đồ SVG tự vẽ bằng chuỗi HTML, không phụ thuộc thư viện hay mạng.
  • Bảng sắp xếp dùng chung: một hàm sortTable(id, cột, dòng, {key, asc}), mỗi cột khai báo khoá, tiêu đề, hàm hiển thị, hàm tô màu.
  • Song ngữ không sửa HTML: giao diện viết bằng tiếng Anh; settings.js.html giữ từ điển cụm từ Anh → Việt và một MutationObserver dịch mọi nút chữ mới xuất hiện. Thêm nhãn mới thì thêm một dòng vào từ điển.
  • Sáng/Tối: mọi màu là biến CSS, đổi bằng thuộc tính data-theme trên thẻ html; lựa chọn được trình duyệt ghi nhớ.
  • Chế độ Live: khi dựng từ live.py, trang được chèn giờ cập nhật kế tiếp và tự tải lại đúng lúc đó, giữ tab đang xem qua phần # của địa chỉ.

10. Nội dung và công thức từng tab

10.1 Tab 1 · Competitor Overview

PhầnCông thức chính
KPI thị trườngSố CW, số TCPH, số mã cơ sở · giá trị niêm yết = Σ số niêm yết × W · giá trị nhà đầu tư nắm = Σ min(max(Net sold, 0), số niêm yết) × W · giá trị giao dịch · % CW có giao dịch · số ITM/OTM/ATM · trung vị (IV − GARCH)
Thị phần theo TCPHTỷ trọng theo số mã, theo giá trị nắm giữ, theo giá trị giao dịch, theo Net sold · trung vị % phân phối, đòn bẩy, giá, DTE · tỷ lệ CW “chết” (phân phối < 5%) · 3 mã cơ sở lớn nhất
Định giá so với phân phốiIV tương đối = IV của CW − trung vị IV các CW cùng mã cơ sở. Đặt cạnh % phân phối để thấy TCPH định giá rẻ có phân phối tốt hơn không
Nhóm sản phẩmChia CW theo moneyness (OTM >20%, 10–20%, 0–10%, ITM 0–10%, >10%), đòn bẩy hiệu dụng (<4x, 4–6x, 6–8x, >8x), DTE (≤30, 31–90, 91–180, >180 ngày), giá CW, IV tương đối. Mỗi nhóm: % cung, % nắm giữ, % giao dịch, vòng quay = KL giao dịch / KL nắm giữ, chỉ số ưa chuộng = % nắm giữ / % cung
Phân phối theo lôMỗi lô phát hành của TCPH nhà: % phân phối(t) = Σ lượng lưu hành / Σ số niêm yết. Có tồn kho nội bộ thì lưu hành = niêm yết − tồn kho; sau ngày tồn kho cuối thì nối tiếp bằng tự doanh
Bảng toàn bộ CWMọi cột của Horizon kèm % thay đổi giá, trạng thái trần/sàn (biên độ ±7% giá cơ sở chia CR, làm tròn bước 10 đ)

10.2 Tab 2 · Client Overview

“Nhà đầu tư” là phía đối diện của tự doanh TCPH: nhà đầu tư mua = TCPH bán. Mỗi giao dịch tự doanh trong ngày được gắn đặc điểm của CW tại ngày đó: moneyness theo giá cơ sở ngày đó, DTE ngày đó, đòn bẩy hiệu dụng = S / (giá bình quân × CR) × N(d1) với σ = HV 60 phiên tại ngày đó. Cộng theo kỳ chọn (Hôm nay, 1 tuần, 1 tháng, 3 tháng hoặc tự chọn) ra dòng tiền mua, bán, ròng theo nhóm, theo mã cơ sở và theo ngày.

10.3 Tab 3 · Volatility

PhầnCách tính
3.1 Kiểm tra trước phiên tớiGiá tham chiếu = giá đóng cửa cơ sở phiên trước; trần/sàn = ±7% làm tròn theo bước giá HOSE (10 đ dưới 10.000, 50 đ dưới 50.000, 100 đ từ 50.000). Định giá CW tại sàn · giá chọn · trần với IV tham chiếu. Nhập giá chào của TCPH khác thì suy ra IV ngầm và dãy sàn/trần tương ứng
3.2 Tín hiệu IVΔIV = IV hôm nay − hôm qua (điểm vol). Ngưỡng nhiễu = max(IV_JUMP_PTS, bước giá / vega). |ΔIV| < ngưỡng → Normal; giảm → IV Cut, tăng → IV Increase; cùng chiều ≥ 5 phiên và tổng ≥ 2 × ngưỡng → Persistent IV Decay/Expansion. Ngày không đủ tin cậy (không có IV ngày, vega ≤ 0, giá trị thời gian quá nhỏ) → Low Reliability
Phân vị IVTrung vị IV các CW tin cậy của cùng mã cơ sở hôm nay so với chính nó trong tối đa 252 phiên gần nhất. Không bị méo bởi sự kiện quyền hay mức IV lúc niêm yết
3.3 Lịch sử IVĐường IV theo ngày từng CW, giá cơ sở trục phải; ngắt nét ở ngày thiếu dữ liệu
3.4 IV theo TCPHCác CW cùng mã cơ sở, so IV của từng TCPH theo DTE

10.4 Tab 4 · Risk & Events

4.1 Rủi ro sổ CW của TCPH nhà. Tính cho mọi CW còn lưu hành, kể cả CW đã qua ngày giao dịch cuối nhưng chưa đáo hạn. OI = lượng lưu hành (số niêm yết − tồn kho, hoặc ước tính từ tự doanh). σ = IV; dùng HV nếu CW ITM sâu (moneyness > 15%), giá trị thời gian < 5% giá CW, hoặc không có IV; không có cả hai và ITM thì delta = 1/CR.

Chỉ sốCông thức (đơn vị đồng)
Giá trị thị trường CW lưu hành (khoản phải trả)OI × W, tách thành nội tại = OI × max(S − K, 0)/CR và giá trị thời gian = phần còn lại
Delta CW−OI × N(d1)/CR × S
Delta ExposureDelta CW + số cổ phiếu phòng hộ × S
Gamma (1%)½ × (−OI × Γ/CR) × (S × 1%)², Γ = n(d1) / (S·σ·√T): lãi lỗ bậc hai khi cơ sở biến động 1%
VegaOI × S·n(d1)·√T / 100 / CR: giá trị nghĩa vụ tăng thêm khi IV +1 điểm
Theta−OI × Θ/CR, Θ = [−S·n(d1)·σ/(2√T) − rK·e−rT·N(d2)] / 365: TCPH hưởng mỗi ngày lịch
Kịch bản ±7%Chưa phòng hộ: −OI × [W(S × 1,07) − W(S)]; đã phòng hộ: cộng thêm OI × Δ/CR × (S × 0,07)

Ví dụ tiếp mục 6.1 với OI = 2.000.000 CW: khoản phải trả 1,80 tỷ (toàn bộ là giá trị thời gian) · Delta CW −7,82 tỷ (cần khoảng 260.500 cổ phiếu để phòng hộ) · Gamma (1%) −0,86 triệu · Vega 34,3 triệu mỗi điểm IV · Theta +9,77 triệu/ngày · cơ sở +7%: chưa phòng hộ −588 triệu, đã phòng hộ −41 triệu.

4.2 Lịch sự kiện. CW đáo hạn trong 30/45/90 ngày và giá trị thanh toán dự kiến; CW mới niêm yết 30 ngày; sự kiện quyền của mã cơ sở được phát hiện từ dữ liệu giá, không cần lịch ngoài: hệ số = giá điều chỉnh (SSI) / giá chưa điều chỉnh (LiveDragon) mỗi ngày, lấy trung vị trượt 3 ngày; hệ số đổi hơn 0,5% → ngày giao dịch không hưởng quyền, tỷ lệ = hệ số trước / hệ số sau.

4.3 Chất lượng tạo lập thị trường. Tính theo thời gian trên toàn phiên liên tục (9:15–11:30, 13:00–14:30, bỏ 5 phút đầu mỗi nửa phiên), không dùng một ảnh chụp cuối ngày. Mỗi trạng thái bảng giá có trọng số bằng số giây nó tồn tại. Loại các giây không thể chào hai chiều: cổ phiếu cơ sở trắng một bên (đứng trần/sàn), hoặc CW chào bán ở giá sàn 10 đ.

Chỉ sốCông thức (cộng dồn trên mọi CW-ngày của nhóm)
% thời gian chào hai chiềuΣ giây có Bid > 0 và Ask > Bid / Σ giây hợp lệ
% thời gian đạt chuẩnΣ giây hai chiều có chênh lệch ≤ N bước giá và khối lượng mỗi bên ≥ X CW / Σ giây hợp lệ (N, X đặt trong cấu hình)
Chênh lệch bình quânΣ (Ask − Bid)/bước giá × giây / Σ giây hai chiều; và theo % giá giữa
% thời gian cách 1 bướcΣ giây chênh lệch đúng 1 bước / Σ giây hai chiều
Khối lượng tại giá tốt nhấtΣ (BidVol1 + OfferVol1)/2 × giây / Σ giây hai chiều
Chênh lệch hiệu dụngΣ khối lượng khớp × 2|giá khớp − giá giữa ảnh chụp trước| / bước giá ÷ Σ khối lượng khớp
TCPH nhà so với TCPH khácTrên cùng mã cơ sở: % đạt chuẩn của TCPH nhà − % đạt chuẩn của các TCPH khác gộp lại (điểm %); kèm TCPH tốt nhất
Lưu dữ liệu chào giá dạng tổng (giây, giây × chênh lệch…) thay vì tỷ lệ là chi tiết quan trọng: cộng tổng của nhiều CW, nhiều ngày rồi mới chia thì kết quả đúng trọng số thời gian. Lưu sẵn một lưới ngưỡng (1–5 bước × 0/500/1.000/2.000/5.000/10.000 CW) để đổi ngưỡng “đạt chuẩn” mà không phải tải lại.

11. Bảng tham số

Mọi tham số nằm trong một file config/api_config.py, chia mục [A]–[I]. Code đọc bằng getattr(config, "TÊN", mặc_định), nên thiếu dòng nào thì dùng mặc định, và bản cũ của file cấu hình vẫn chạy với code mới.

Tham sốÝ nghĩaMặc địnhSau khi đổi
[A] CW_API_URL…Địa chỉ các API ở mục 4có sẵnRun
API_TIMEOUTSố giây chờ mỗi lần gọi30Run
[B] RISK_FREE_RATEr trong Black-Scholes, một mức cho mọi CW0.07Run
DIVIDEND_YIELD, TRADING_DAYSTỷ suất cổ tức q; số phiên/năm0 · 252Run
[C] KAFI_ISSUER_KEYWORDS, ISSUER_ALIASESNhận diện TCPH nhà; gộp tên khác nhau của cùng TCPHcó sẵnRebuild
KAFI_BATCHES, KAFI_DEFAULT_BATCHDanh sách lô phát hành và các mã thuộc lô—Rebuild
[D] KAFI_INVENTORY_FILE, KAFI_INVENTORY_UNTIL, KAFI_INVENTORY_BRIDGEFile tồn kho nội bộ; dùng đến ngày nào; có nối tiếp bằng tự doanh khôngNone · None · TrueRebuild
KAFI_HEDGE_SHARES, KAFI_HEDGE_DATECổ phiếu phòng hộ đang nắm (nhập tay) và ngày của số liệu{} · NoneRebuild
[E] REALTIME_SNAPSHOT, REFRESH_ALL, GARCH_BACKTESTChụp phiên mới nhất; bỏ cache; chạy backtestTrue · False · FalseRun
[F] IV_HISTORY_DAYS, IV_WINDOW_SESSIONSSố ngày lịch sử giá CW; số phiên hiển thị200 · 60Run / Rebuild
IV_JUMP_PTS, IV_MIN_VEGANgưỡng nhiễu tín hiệu IV; vega tối thiểu1.0 · 10Rebuild
QUOTES_DAYS, QUOTES_WORKERSSố ngày tải bù giá chào; số luồng song song100 · 4Run
MM_MAX_TICKS, MM_MIN_VOL, MM_SKIP_MIN, MM_SESSIONSNgưỡng “đạt chuẩn” (bước giá, CW mỗi bên); phút bỏ đầu nửa phiên; số phiên hiển thị3 · 1000 · 5 · 20Rebuild (MM_SKIP_MIN: xoá data/quotes_mm rồi Run)
[G] IV_SOURCE, IV_DB_FILE, IV_MIN_SCANSNguồn IV hằng ngày: auto / db / local; file IV quét; số lần quét tối thiểuauto · None · 3Rebuild
[H] MARKET_CLOSE, MAX_STEP_BACKGiờ chốt; số ngày được lùi15:00 · 7Run
MIN_HV_RETURNS, GARCH_WINDOW, GARCH_HORIZONS, GARCH_MAX_PERSISTENCE, GARCH_MAX_ABS_RETURN_PCTTham số HV và GARCH (mục 7)20 · 750 · [21…315] · 0.99 · 7.5Run, REFRESH_ALL một lần
[I] LIVE_EVERY_MINSố phút giữa hai lần cập nhật ở chế độ Live10Chạy lại Live

12. Dựng lại từ đầu: lộ trình 8 chặng

Thứ tự dưới đây đi từ phần có giá trị ngay đến phần nâng cao. Mỗi chặng có một phép kiểm tra; qua được mới làm chặng sau. Làm một mình mất vài tuần; làm cùng trợ lý AI thì mỗi chặng thường gói gọn trong một buổi.

ChặngLàm gìKiểm tra xong khi
1. Lấy bảng giáGọi API 1 và 2, tách tỷ lệ chuyển đổi, đổi ngày, ghi CSVSố CW khớp với bảng giá trên web; tỷ lệ là số
2. Định giáViết Black-Scholes, giải IV, delta, các cột ở mục 6Ví dụ mục 6.1 ra đúng IV 60,3%, đòn bẩy hiệu dụng 4,34x
3. Một ngày as-of + cacheQuy tắc mục 5, lưu kết quả từng bước theo ngàyChạy 2 lần trong ngày, lần 2 không gọi lại API; chạy 10:00 ra ngày hôm trước
4. Lịch sử và biến độngAPI 3 và 5: HV, Yang-Zhang theo kỳ hạn gốc, ADV; sau đó GARCHHV của một mã khớp với tính tay trong Excel trên cùng dữ liệu
5. Tự doanh và phân phốiAPI 6: luỹ kế và theo ngày, Net sold, % phân phốiTổng Net sold của một CW khớp với cộng tay trên trang dstock
6. ExcelGhi Horizon theo tên cột qua xlwings, sao lưu trước khi ghiMở Excel thấy đủ 35 cột, định dạng khuôn còn nguyên
7. Dashboard tab 1–2Module JSON + khuôn HTML + build.py (mục 9)Mở file không mạng vẫn hiện đủ; KPI khớp tổng trong Excel
8. Tab 3–4, LiveAPI 7 và lưu giá chào hằng ngày; IV hằng ngày, tín hiệu, Greeks, sự kiện, chất lượng chào giá; vòng lặp LiveTín hiệu không bật trên ngày có sự kiện quyền; Greeks khớp ví dụ mục 10.4

12.1 Mẫu yêu cầu khi làm cùng trợ lý AI

Dán bài viết này vào cuộc trò chuyện, rồi yêu cầu từng chặng một. Ví dụ cho chặng 2:

Dựa trên mục 6 của tài liệu đính kèm, viết file option_pricing.py gồm:
- black_scholes_call(S, K, T, r, sigma, CR) trả giá MỘT CW (đã chia CR)
- implied_volatility(W, S, K, T, r, CR): Brent trong [0.0001, 5]; không có nghiệm thì trả NaN
- call_delta(S, K, T, r, sigma) trả N(d1)
Viết kèm test: S=30000, K=32000, CR=4, W=900, T=120/365, r=0.07 phải ra IV ≈ 0.603,
N(d1) ≈ 0.521. Chỉ dùng numpy, scipy.

Ba nguyên tắc giúp mỗi chặng ra đúng ngay:

  • Luôn nêu đơn vị (đồng hay nghìn đồng, ngày lịch hay phiên) và dấu (ai bán, ai mua).
  • Yêu cầu kèm một phép kiểm tra bằng số cụ thể như cột thứ ba ở bảng trên.
  • Giữ tên cột của các file trung gian ở mục 8, để các chặng sau ghép vào không phải sửa lại.

13. Vận hành và lỗi thường gặp

Bạn muốnBấmGhi chú
Số liệu cuối ngàyRun CW Market Overview.batSau 15:00. Đọc log: DATA CHECK toàn OK, không có WARNING
Theo dõi trong phiênRun Live.batĐể cửa sổ mở; trang tự tải lại
Chỉ đổi giao diện / tham số hiển thịRebuild Dashboard.batKhông tải lại dữ liệu
Hiện tượngNguyên nhânXử lý
Log báo lùi ngày as-ofMột nguồn chưa có số hôm nay (thường là tự doanh)Bình thường; chạy lại sau 15:30
DASHBOARD NOT BUILT · date mismatchWorkbook và CSV khác ngàyChạy Run, không dùng Rebuild
Dashboard trống sau RebuildChưa chạy Run lần nàoChạy Run
Timeout, HTTP 403Mạng chậm hoặc gọi quá dàyTăng API_TIMEOUT, giảm QUOTES_WORKERS
IV một mã nhảy bất thường vài tuầnSự kiện quyền làm lệch giá cơ sở với giá chàoKiểm tra mục 4.2; hệ số điều chỉnh phải được áp vào giá cơ sở
Tab 4.3 hiện bảng giá chào cuối ngàyChưa có dữ liệu data/quotes_mmChạy Run sau 15:00; lần đầu tải lại khoảng 3 tháng, 30–40 phút
SyntaxError trong api_configThiếu dấu ngoặc kép hoặc dấu phẩyXem số dòng được báo, sửa hoặc khôi phục bản sao
Số liệu lạ sau khi sửa codeCache cũĐặt REFRESH_ALL = True một lần

14. Dữ liệu nội bộ, bản quyền và miễn trừ

  • Tồn kho, tiểu khoản, số cổ phiếu phòng hộ và đường dẫn thư mục nội bộ là dữ liệu của tổ chức. Không đưa vào bài viết, không đăng dashboard có các số này ra ngoài; chỉ chia sẻ trong nội bộ theo quy định của đơn vị.
  • Dữ liệu thị trường thuộc SSI, VNDIRECT, VDSC và Sở Giao dịch Chứng khoán TP.HCM; chỉ dùng trong phạm vi điều khoản của từng nơi.
  • Ví dụ số trong bài (CW 30.000/32.000, OI 2 triệu CW) là giả định, không phản ánh vị thế của tổ chức nào.
  • Mô hình Black-Scholes (Black & Scholes, 1973), GARCH (Bollerslev, 1986), GJR-GARCH (Glosten, Jagannathan & Runkle, 1993), Yang-Zhang (Yang & Zhang, 2000) là kiến thức công khai. Thư viện dùng kèm: pandas, numpy, scipy (BSD), arch (NCSA), xlwings (BSD), openpyxl (MIT), requests (Apache 2.0).
  • Bài viết là chia sẻ kỹ thuật, không phải khuyến nghị đầu tư. Kiểm tra kỹ số liệu trước khi dùng cho báo cáo chính thức.

Tags: ,

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments