Metadata-Version: 2.4
Name: vnbond
Version: 0.1.0
Summary: Dữ liệu thị trường trái phiếu và tiền tệ Việt Nam, lấy thẳng từ nguồn công khai
License-Expression: MIT
Project-URL: Homepage, https://github.com/KhoaSampleTown/vnbond
Project-URL: Issues, https://github.com/KhoaSampleTown/vnbond/issues
Keywords: vietnam,bonds,fixed-income,market-data,hnx,sbv,vbma
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Office/Business :: Financial :: Investment
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pandas>=2.0
Requires-Dist: numpy>=1.24
Requires-Dist: requests>=2.31
Requires-Dist: pyarrow>=14.0
Provides-Extra: dotenv
Requires-Dist: python-dotenv>=1.0; extra == "dotenv"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Dynamic: license-file

# vnbond

Dữ liệu thị trường trái phiếu và tiền tệ Việt Nam, lấy thẳng từ nguồn công khai.

```bash
pip install vnbond
```

```python
import vnbond as vm

vm.hnx.auctions("2020-01-01")     # đấu thầu TPCP — chuỗi dài nhất, từ 2009
vm.hnx.secondary("2026-08-01")    # giao dịch thứ cấp theo ngày
vm.hnx.bond_list()                # danh mục, có ngày đáo hạn thật từng mã
vm.sbv.omo()                      # đấu thầu thị trường mở
vm.vira.omo("2026-01-01")         # lịch sử OMO từ bản tin VIRA
vm.cbonds.issuance_by_year()      # phát hành trái phiếu doanh nghiệp
```

---

## Không cần máy chủ

Thư viện chạy **trên máy bạn** và gọi trực tiếp endpoint công khai của các sở,
hiệp hội. Không có API trung gian, không cần thuê hạ tầng, không ai giới hạn bạn
ngoài chính các nguồn. Dữ liệu tải về nằm trong kho parquet cục bộ — mặc định
`~/.vnbond` — và lần chạy sau chỉ tải phần còn thiếu.

```bash
vnbond fetch hnx.auctions --from 2020-01-01
vnbond status
vnbond where
```

---

## Có gì

| Nguồn | Bảng | Từ | Đăng nhập |
|---|---|---|---|
| **HNX** | đấu thầu TPCP | 2009 | không |
| | giao dịch thứ cấp | 2018 | không |
| | danh mục trái phiếu, ngày đáo hạn thật | — | không |
| | thống kê theo nhà đầu tư (PDF) | 2017 | không |
| **cbonds** | phát hành TPDN theo năm | 2021 | không |
| | vùng lãi suất theo kỳ hạn | năm hiện hành | không |
| | phiên giao dịch, mã mới ĐKGD | phiên gần nhất | không |
| | danh mục TPDN từng mã | — | CSV kết xuất |
| **SBV** | đấu thầu thị trường mở | phiên gần nhất | không |
| **VIRA** | lịch sử OMO từ bản tin | ~2 năm | không |
| **VBMA** | fixing lợi suất · FX swap · VNIBOR | — | **có** |

---

## Ba giới hạn phải biết trước

**SBV và cbonds chỉ công bố phiên gần nhất.** Không có phân trang, không có kho
lưu trữ, không có API lịch sử. Chuỗi thời gian chỉ tích luỹ được bằng cách chạy
hằng ngày rồi nối vào kho. Gọi lần đầu cho đúng một phiên.

Muốn lịch sử OMO ngay thì dùng `vm.vira.omo()` — bản tin VIRA lưu theo URL có
ngày nên lùi lại được hơn hai năm. Đổi lại, số nằm trong lời văn nên phải bóc
bằng regex; ngày nào không khớp mẫu thì trả `None` chứ không đoán.

**Danh mục TPDN cần CSV kết xuất.** Endpoint danh mục của cbonds đòi đăng nhập.
Thư viện không tìm cách vòng qua. Mở cổng bằng trình duyệt, đăng nhập, kết xuất
CSV, rồi:

```python
vm.cbonds.corporate_bonds("danh-muc.csv")
```

**Endpoint sẽ đổi.** Đây là các trang web, không phải API có hợp đồng. HNX đổi
giao diện là thư viện gãy. Bộ test trong `tests/` chạy offline để bắt lỗi phân
tích cú pháp, nhưng không bắt được việc nguồn đổi địa chỉ.

---

## Cấu hình

Bốn nguồn HNX, cbonds, SBV và VIRA chạy được ngay sau khi cài, không cần cấu
hình gì.

VBMA là nguồn dành cho thành viên nên cần phiên đăng nhập. Sao `.env.example`
thành `.env` rồi điền `VBMA_USERNAME` và `VBMA_PASSWORD` của bạn — gói không kèm
thông tin đăng nhập, và `.env` đã nằm trong `.gitignore`. Không đặt thì các hàm
`vm.vbma.*` ném `MissingCredentials`, phần còn lại vẫn chạy.

```python
vm.vbma.government_bond_yield()
vm.vbma.fx_swap_curve()
vm.vbma.short_term_rate()
```

Đổi chỗ lưu kho bằng `VNBOND_HOME`.

---

## Lịch sự với nguồn

Nhịp gọi tối thiểu được **ép ở tầng `vnbond.http`**, không phải tuỳ chọn:

| Host | Giãn cách tối thiểu |
|---|---|
| `www.hnx.vn` | 0,4 s |
| `cbonds.hnx.vn` | 0,8 s |
| `vbma.org.vn` | 1,0 s |
| `sbv.gov.vn` | **6,0 s** |

Sáu giây cho SBV đến từ thực nghiệm, không phải phỏng đoán: họ đứng sau WAF (F5)
trả trang *"Request Rejected"* kèm **mã 200** khi bị gọi dồn. Thư viện nhận diện
trang đó và ném `BlockedError` thay vì parse nhầm thành "không có dữ liệu" — sai
âm thầm còn tệ hơn lỗi ném ra.

Đây là hạ tầng công dùng chung. Đừng hạ nhịp, đừng chạy song song nhiều luồng.

---

## Bốn cái bẫy đã sập một lần

Bốn lỗi dưới đây **không ném exception** — chúng chỉ cho ra số sai. Mỗi cái đều
có test riêng trong `tests/test_parsing.py`.

**1. Số kiểu Việt Nam.** Dấu chấm ngăn nghìn, dấu phẩy thập phân. `1.225.073` tỷ
đồng mà đọc dấu chấm thành thập phân thì ra `1.2` — sai sáu bậc.

**2. Dấu tiếng Việt trong so khớp.** `'ngay' in 'ngày'.lower()` là `False`. Cột
ngày không được nhận → mọi dòng bị gán ngày hôm nay → khử trùng gom cả lịch sử
về một ngày. Mọi so khớp tên cột đều bỏ dấu trước.

**3. Ô lãi suất của cbonds.** Giá trị `0` không phải lãi suất bằng không mà là
trái phiếu thả nổi; vài mã ghi bằng **điểm cơ bản** (`550` = 5,5%). Khoảng
30–100 trong dữ liệu hoàn toàn trống nên ngưỡng 100 tách được dứt khoát.

**4. Phân trang của HNX.** Phản hồi AJAX không kèm khối phân trang nên hàm đếm
trang gần như luôn trả 1 — dựa vào nó là âm thầm mất dữ liệu. Đã gặp: phiên
27/08/2026 có 75 giao dịch nhưng chỉ lấy được 50. Mọi hàm ở đây đặt số bản ghi
mỗi trang rất lớn để lấy trọn một lần.

---

## Một chi tiết đáng giá: ảnh chụp thành chuỗi thời gian

Danh mục trái phiếu là ảnh chụp một ngày, nhưng mỗi dòng có **ngày phát hành** và
**ngày đáo hạn**. Hai cột đó đủ để dựng lại dư nợ tại bất kỳ mốc quá khứ nào —
không cần chụp lại hằng ngày:

```python
vm.cbonds.corporate_bonds("danh-muc.csv")
vm.cbonds.outstanding_path(freq="QE")     # dư nợ theo quý, suy từ ảnh chụp
```

Với trái phiếu chính phủ, `vm.hnx.bond_list()` mặc định lấy **cả mã đã huỷ niêm
yết**. Bắt buộc: mã đã đáo hạn rời khỏi bảng "đang niêm yết", nên nếu chỉ lấy mã
đang niêm yết thì nhìn từ một ngày quá khứ mọi khoản đáo hạn đều bằng 0.

---

## Kho cục bộ

```python
vm.cache.status()                    # bảng nào, bao nhiêu dòng, cập nhật lúc nào
vm.cache.read("hnx_auctions")        # đọc thẳng
vm.cache.home()                      # đường dẫn kho
```

Đổi chỗ lưu bằng `VNBOND_HOME`, hoặc tham số `cache_dir` của từng hàm. Mọi hàm
`fetch` là idempotent: chạy lại cho cùng kết quả, khử trùng theo khoá, giữ bản
mới nhất để nguồn công bố lại số đã chỉnh thì kho cập nhật theo.

---

## Dữ liệu vĩ mô

GDP, CPI, thu chi ngân sách, thương mại song phương, cán cân thanh toán — từ
Tổng cục Thống kê và IMF — nằm ở gói riêng
[`vnmacro`](https://github.com/KhoaSampleTown/vnmacro), phát hành độc lập.

---

## Đóng góp

```bash
git clone https://github.com/KhoaSampleTown/vnbond
cd vnbond
pip install -e ".[dev]"
python -m pytest tests/ -q
```

Test chạy offline, không gọi mạng, không cần tài khoản.

Nếu một nguồn đổi giao diện và thư viện gãy, mở issue kèm HTML trả về — parser
sửa được nhanh khi có mẫu thật.

---

## Tuyên bố miễn trừ

Đọc phần này trước khi dùng.

**Thư viện lấy dữ liệu, không cấp quyền truy cập.** `vnbond` chỉ tự động hoá
những lời gọi mà trình duyệt của bạn vẫn thực hiện khi bạn vào các trang này.
Nó không vượt qua bất kỳ lớp kiểm soát nào, không giải CAPTCHA, không tìm cách
đi vòng qua yêu cầu đăng nhập. Quyền truy cập đến từ quan hệ giữa **bạn** và
nguồn, không đến từ gói này.

**Bạn chịu trách nhiệm tuân thủ điều khoản của từng nguồn.** HNX, cbonds, SBV,
VIRA và VBMA mỗi bên có quy định riêng về việc sử dụng, lưu trữ và phân phối lại
dữ liệu, và các quy định đó thay đổi được mà không báo trước. Hãy tự kiểm tra —
đặc biệt nếu bạn dùng cho mục đích thương mại, phân phối lại cho bên thứ ba, hay
đưa vào sản phẩm bán ra. Tác giả gói không rà soát và không bảo đảm việc bạn
dùng là hợp lệ.

**Dữ liệu không thuộc giấy phép MIT của gói.** Giấy phép MIT áp cho *mã nguồn*.
Dữ liệu bạn tải về thuộc về đơn vị công bố. Repo này không chứa và sẽ không chứa
file dữ liệu nào.

**Nhịp gọi có trong gói là mức tối thiểu, không phải mức khuyến nghị.** Các
nguồn ở đây là hạ tầng công phục vụ cả thị trường. Đừng hạ giãn cách, đừng chạy
song song nhiều luồng, đừng quét lại toàn bộ lịch sử mỗi ngày trong khi kho cục
bộ đã có sẵn. Gây tải nặng lên nguồn không chỉ khiến IP của bạn bị chặn mà còn
làm hỏng cho những người dùng khác.

**Không bảo đảm tính chính xác.** Dữ liệu được bóc từ HTML, CSV và lời văn của
các trang web; định dạng đổi là kết quả sai hoặc thiếu. Phần `Bốn cái bẫy đã sập
một lần` ở trên là những lỗi *đã biết và đã sửa* — gần như chắc chắn còn lỗi
chưa biết. Kiểm tra lại số trước khi dùng cho bất kỳ quyết định nào.

**Không phải tư vấn đầu tư.** Gói cung cấp dữ liệu thô, không đưa ra khuyến nghị.
Mọi quyết định đầu tư là của bạn.

**Cung cấp nguyên trạng.** Không bảo hành dưới bất kỳ hình thức nào. Tác giả
không chịu trách nhiệm cho thiệt hại phát sinh từ việc sử dụng gói này, bao gồm
nhưng không giới hạn ở tổn thất tài chính, mất quyền truy cập nguồn, hay hậu quả
pháp lý từ việc vi phạm điều khoản của bên thứ ba.

---

## Giấy phép

Mã nguồn: MIT — xem `LICENSE`. Dữ liệu: xem phần Tuyên bố miễn trừ ở trên.
