Vnstock Logo

Nâng cấp mảng Quỹ mở từ vnstock 4.x

Cộng đồng

Mục lục

Trang dùng chung với v5.0.0

Nội dung trang này giữ nguyên từ bản v5.0.0, chưa viết riêng cho free: ví dụ chạy được nếu tên hàm không đổi. Bản gốc: /docs/vnstock/chuyen-doi/nang-cap-quy-mo-fund.

Trang này dành riêng cho việc chuyển đổi mã nguồn xử lý dữ liệu quỹ mở (Fund) viết cho vnstock 4.x (hoặc vnstock_data 3.x) sang vnstock thế hệ 5.

Bước sang thế hệ 5, mảng dữ liệu quỹ mở có sự thay đổi căn bản về nguồn dữ liệu, cơ chế định danh, quy mô dữ liệu, phương thức truy xuất và cấp quyền truy cập.


1. Bối cảnh tuân thủ và chính sách cấp quyền

  • Loại bỏ hoàn toàn nguồn Fmarket: Thư viện đã chủ động gỡ bỏ nguồn Fmarket nhằm tuân thủ "Điều khoản sử dụng" được công bố trên website của đơn vị này (địa chỉ tham chiếu: fmarket.vn/legal?tab=terms). Người dùng đang sử dụng mã nguồn ở các phiên bản cũ hoặc kịch bản còn kết nối tới nguồn này cần chủ động rà soát và gỡ bỏ để đảm bảo tuân thủ đầy đủ quy định. Nếu gọi source="fmarket" trên thế hệ 5, thư viện trả về lỗi UnsupportedError (mã VNSTOCK_FEATURE_REMOVED) kèm hướng dẫn đổi sang source="cafef" hoặc source="digiinvest".
  • Chính sách cấp quyền từ Bronze trở lên: Bản 4.x từng mở Fund() tự do cho mọi người dùng. Ở thế hệ 5, dữ liệu quỹ mở được chuyển sang hai nguồn công khai là CafeF và DigiInvest, và chỉ mở cho tài khoản từ cấp tài trợ Bronze trở lên. Việc giới hạn này nhằm bảo vệ hạ tầng máy chủ công khai khỏi nguy cơ quá tải khi lượng người dùng bản Cộng đồng tăng cao. Tài khoản cấp Khách hoặc Cộng đồng khi gọi sẽ nhận lỗi EntitlementError (mã VNSTOCK_TIER_SOURCE hoặc VNSTOCK_TIER_ROUTE) ngay trên máy khách mà không gửi truy vấn ra ngoài.
  • Thời hạn tương thích chuyển tiếp: Nhằm giúp mã nguồn cũ không bị gãy đột ngột, lớp Fund() tại gốc gói và các phương thức cũ trên Reference().fund / Market().fund vẫn được duy trì hoạt động đến hết ngày 06/04/2027 (kèm cảnh báo FutureWarning). Sau mốc thời gian này, các tên cũ sẽ chính thức ngừng hoạt động.

2. So sánh quy mô và đặc tính nguồn dữ liệu

Sự thay đổi nguồn dẫn tới những khác biệt đáng chú ý về số lượng quỹ, cách định danh và độ sâu dữ liệu:

Tiêu chíFmarket (bản 4.x cũ)CafeF (thế hệ 5, mặc định)DigiInvest (thế hệ 5, bổ sung)
Quy mô danh mục~68–69 quỹ43 quỹ (24 cổ phiếu, 15 trái phiếu, 4 cân bằng)33 quỹ
Định danh quỹMã số nguyên fundId (ví dụ 23)Mã ticker chuỗi (ví dụ "DCDS")Mã ticker chuỗi (ví dụ "DCDS")
Quy ước mã tickerViết liền (ví dụ SSISCA)Một số mã có dấu gạch ngang (ví dụ SSI-SCA)Viết liền hoặc theo đăng ký quỹ
Độ sâu lịch sử NAVNgắn hơn hoặc ngắt quãngRất sâu (DCDS từ 11/03/2005, hơn 2.800 điểm)Sâu nhất (DCDS từ 01/06/2004, hơn 3.300 điểm)
Độ chính xác NAVLàm tròn tới đồngChi tiết tới 0,01 đồngLàm tròn tới đồng
Danh mục nắm giữTop 10 + trái phiếu, có ngày cụ thểTop 10 (báo cáo tháng, lấy ngày cuối tháng)Không có qua API công khai
Phân bổ tài sản & ngànhCó, nhãn tiếng ViệtCó, chuẩn hoá mã tiếng AnhKhông có qua API công khai
Cổ tức tiền mặtKhông hỗ trợKhông cóCó (Market().fund(s).dividends())
Hồ sơ & biểu phíKhông có hàm chuẩnCó (profile(), fee_structure(), reports())Có tên quỹ, phí quản lý trong danh mục
Lưu ý về quy mô quỹ và mã định danh
  • Số lượng quỹ ít hơn: Một số quỹ nhỏ trước đây có mặt trên Fmarket nhưng không có trên CafeF hoặc DigiInvest sẽ không còn truy xuất được. Bạn cần kiểm tra danh sách quỹ hiện hành bằng Reference().fund.list().
  • Tuyệt đối không dùng mã số fundId: CafeF và DigiInvest không sử dụng mã số nội bộ của Fmarket. Nếu truyền số nguyên (như fundId=23), thư viện sẽ báo lỗi InputError mã VNSTOCK_INPUT_SYMBOL.
  • Cách viết mã quỹ: Danh mục CafeF định danh quỹ SSI là SSI-SCA (có gạch ngang), thay vì SSISCA như bản cũ. Nếu gọi Market().fund("SSISCA") bị lỗi không tìm thấy, hãy kiểm tra mã chuẩn trong bảng danh mục.

3. Bảng đối chiếu phương thức 4.x vs 5.x

Bảng dưới đây tổng hợp chi tiết việc chuyển đổi từ các phương thức cũ sang giao diện hợp nhất thế hệ 5:

Tính năngPhương thức 4.xTên mới chuẩn (5.x)Tên cũ chuyển tiếp (hạn 06/04/2027)Ghi chú chuyển đổi
Danh mục quỹFund().listing(fund_type="")Reference().fund.list(fund_type, symbol=..., source=...)Fund().listing(fund_type)Tên cũ trả đủ 21 cột (10 cột đặc thù Fmarket để trống). Tên mới trả 8 cột chuẩn
Lọc tìm mã quỹFund().filter(symbol="")Reference().fund.list(symbol=...)Fund().filter(symbol)Bản 4.x trả cột id là số nguyên; thế hệ 5 trả id là mã ticker chuỗi để tương thích
Lịch sử NAVFund().nav_report(fundId)Market().fund(symbol).history(source=...)Fund().nav_report(symbol) hoặc Market().fund(s).nav()Bản 4.x nhận fundId số (bỏ trống tự lấy 23); thế hệ 5 bắt buộc truyền mã ticker chuỗi
Top khoản nắm giữFund().top_holding(fundId)Market().fund(symbol).holdings()Fund().top_holding(symbol) hoặc Market().fund(s).top_holding()Tên cũ trả cột stock_code, type_asset, update_at, fundId (cột fundId để trống)
Phân bổ ngànhFund().industry_holding(fundId)Market().fund(symbol).industry_allocation()Fund().industry_holding(symbol) hoặc Market().fund(s).industry_holding()Giữ nguyên ý nghĩa tỷ trọng ngành
Phân bổ tài sảnFund().asset_holding(fundId)Market().fund(symbol).asset_allocation()Fund().asset_holding(symbol) hoặc Market().fund(s).asset_holding()Bản 4.x trả tiếng Việt; thế hệ 5 trả mã chuẩn (equity, bond, cash_and_equivalents, others)
Chi tiết quỹFund().details (thuộc tính)Reference().fund(symbol).profile()Bị LOẠI BỎ hoàn toànGọi thuộc tính cũ nhận AttributeError
Danh sách quỹFund().fund_list (thuộc tính)Reference().fund.list()Bị LOẠI BỎ hoàn toànGọi thuộc tính cũ nhận AttributeError
Mặc định quỹ 23Gọi hàm không truyền mãBị LOẠI BỎ hoàn toànBị LOẠI BỎ hoàn toànBắt buộc truyền rõ mã quỹ, ví dụ Market().fund("DCDS")

Các tính năng mới chỉ có ở thế hệ 5

Bên cạnh việc thay thế các hàm cũ, thế hệ 5 bổ sung nhiều năng lực chuyên sâu mà bản 4.x trước đây chưa từng hỗ trợ:

  • Market().fund(symbol).performance(): Lợi nhuận qua các giai đoạn (ytd, 3y, 5y), kèm cờ annualized xác định lợi nhuận kép bình quân năm.
  • Market().fund(symbol).dividends(): Lịch sử chi trả cổ tức bằng tiền mặt trên mỗi chứng chỉ quỹ (nguồn DigiInvest).
  • Reference().fund(symbol).profile(): Hồ sơ chi tiết (tổng tài sản, mức đầu tư tối thiểu, ngày giao dịch, đại lý phân phối, chỉ số tham chiếu, website).
  • Reference().fund(symbol).fee_structure(): Biểu phí chi tiết chia theo từng bậc (phí mua, phí bán lại theo thời gian nắm giữ, phí chuyển đổi).
  • Reference().fund(symbol).reports(): Danh sách liên kết tải bản cáo bạch, điều lệ quỹ và các báo cáo định kỳ chính thức.

4. Đối chiếu Schema và thay đổi cột dữ liệu

Nếu mã nguồn của bạn đang xử lý kết quả trả về bằng cách truy cập tên cột cụ thể, hãy lưu ý bảng chuyển đổi cấu trúc cột sau:

Nghiệp vụCột ở bản 4.x (Fmarket)Cột ở thế hệ 5 (Chuẩn hoá)Lưu ý chuyển đổi
Danh mục quỹshort_name, name, fund_type, fund_owner_name, management_fee, inception_date, nav, nav_update_at + 10 cột nav_change_*, fund_id_fmarket, fund_code, vsd_fee_idticker, organ_name, organ_short_name, fund_type, management_fee, inception_date, nav, nav_update_atCột short_name đổi thành ticker. Cột fund_owner_name đổi thành organ_short_name. 10 cột đặc thù của Fmarket bị loại bỏ ở tên mới (để trống ở tên cũ)
Lịch sử NAVdate (chuỗi "YYYY-MM-DD"), nav_per_unit, short_nametime (datetime64[ns, Asia/Ho_Chi_Minh]), navCột date đổi thành time và đã có sẵn kiểu thời gian có múi giờ, không cần pd.to_datetime(). Cột nav_per_unit đổi thành nav
Nắm giữ lớn nhấtstock_code, industry, net_asset_percent, type_asset, update_at, fundIdupdate_at, ticker, industry, net_asset_percent, asset_typeCột stock_code đổi thành ticker. Cột type_asset (STOCK/BOND) đổi thành asset_type (equity/bond). Cột update_at đổi sang datetime64. Cột fundId bị loại bỏ
Phân bổ tài sảnasset_percent, asset_type, short_name (giá trị: "Cổ phiếu", "Trái phiếu"…)asset_type, asset_percent (giá trị: equity, bond, cash_and_equivalents, others)Giá trị phân loại chuyển từ chuỗi tiếng Việt sang mã chuẩn tiếng Anh
Phân bổ ngànhindustry, net_asset_percent, short_nameindustry, net_asset_percentBỏ cột phụ short_name ở tên mới

5. Hướng dẫn chuyển đổi mã nguồn thực tế

Dưới đây là 4 tình huống nâng cấp mã nguồn phổ biến nhất:

Tình huống 1: Lấy danh mục quỹ và tra cứu theo loại quỹ

Python
# ==========================================
# CÁCH CŨ (vnstock 4.x)
# ==========================================
from vnstock import Fund

fund = Fund()
# Lấy danh sách quỹ cổ phiếu (21 cột Fmarket)
df_funds = fund.listing(fund_type="STOCK")
# Tìm mã số nội bộ của quỹ
dcds_id = fund.filter("DCDS")["id"].iloc[0]   # trả về số nguyên, ví dụ 23

# ==========================================
# CÁCH MỚI (vnstock thế hệ 5)
# ==========================================
from vnstock import Reference

ref = Reference()
# Lấy danh sách quỹ cổ phiếu chuẩn hoá (8 cột)
df_funds = ref.fund.list("equity_fund")       # nhận cả "STOCK" để tương thích

# Tra cứu quỹ trực tiếp theo mã hoặc từ khoá
dcds_info = ref.fund.list(symbol="DCDS")
ticker = dcds_info["ticker"].iloc[0]          # mã ticker dạng chuỗi "DCDS"

Tình huống 2: Truy xuất lịch sử NAV và xử lý chuỗi thời gian

Python
# ==========================================
# CÁCH CŨ (vnstock 4.x)
# ==========================================
from vnstock import Fund
import pandas as pd

fund = Fund()
# Bắt buộc truyền fundId dạng số; ngày là chuỗi text
df_nav = fund.nav_report(fundId=23)
df_nav["date"] = pd.to_datetime(df_nav["date"])
latest_nav = df_nav["nav_per_unit"].iloc[-1]

# ==========================================
# CÁCH MỚI (vnstock thế hệ 5)
# ==========================================
from vnstock import Market

mkt = Market()
# Truyền mã ticker chuỗi; cột time đã có sẵn kiểu datetime có múi giờ
df_nav = mkt.fund("DCDS").history()
latest_nav = df_nav["nav"].iloc[-1]

# Lọc dữ liệu theo thời gian chuẩn xác
recent_nav = df_nav[df_nav["time"] >= "2026-01-01"]

Tình huống 3: Phân tích danh mục nắm giữ và cơ cấu phân bổ

Python
# ==========================================
# CÁCH CŨ (vnstock 4.x)
# ==========================================
from vnstock import Fund

fund = Fund()
# Gọi qua fundId số nguyên
top10 = fund.top_holding(fundId=23)
# Đọc cột stock_code và type_asset ("STOCK"/"BOND")
top_stocks = top10[top10["type_asset"] == "STOCK"]

# Phân bổ tài sản bằng nhãn tiếng Việt
assets = fund.asset_holding(fundId=23)
equity_pct = assets[assets["asset_type"] == "Cổ phiếu"]["asset_percent"].iloc[0]

# ==========================================
# CÁCH MỚI (vnstock thế hệ 5)
# ==========================================
from vnstock import Market

dcds = Market().fund("DCDS")
# Đọc danh mục nắm giữ với cột ticker và asset_type chuẩn ("equity"/"bond")
top10 = dcds.holdings()
top_stocks = top10[top10["asset_type"] == "equity"]

# Phân bổ tài sản với mã chuẩn tiếng Anh
assets = dcds.asset_allocation()
equity_pct = assets[assets["asset_type"] == "equity"]["asset_percent"].iloc[0]

Tình huống 4: Khai thác các tính năng mới chuyên sâu

Python
from vnstock import Market, Reference

symbol = "DCDS"

# 1. Xem hiệu suất lợi nhuận qua các giai đoạn (YTD, 3 năm, 5 năm)
perf = Market().fund(symbol).performance()
print(perf[["period", "period_label", "return_percent", "annualized"]])

# 2. Xem lịch sử chia cổ tức tiền mặt (đối với quỹ có chi trả, nguồn DigiInvest)
divs = Market().fund("DCDE").dividends()
print(divs.head())

# 3. Tra cứu biểu phí mua, bán lại theo bậc thời gian nắm giữ
fees = Reference().fund(symbol).fee_structure()
print(fees[["fee_type", "range", "fee", "unit"]])

# 4. Lấy link tải tài liệu, bản cáo bạch chính thức của quỹ
docs = Reference().fund(symbol).reports()
print(docs[["title", "period", "url"]])

6. Xử lý các sự cố và lỗi thường gặp khi nâng cấp

Ngoại lệMã lỗi (code)Nguyên nhânCách xử lý
EntitlementErrorVNSTOCK_TIER_SOURCE hoặc VNSTOCK_TIER_ROUTEĐang chạy ở cấp Khách (chưa đăng nhập) hoặc cấp Cộng đồngNhóm hàm quỹ mở yêu cầu khoá API từ cấp tài trợ Bronze trở lên. Đăng nhập bằng vnstock login <API_KEY>
InputErrorVNSTOCK_INPUT_SYMBOLTruyền fundId dạng số nguyên (như 23) hoặc không truyền mã quỹThay số nguyên bằng mã ticker chuỗi, ví dụ symbol="DCDS"
InputErrorVNSTOCK_PROVIDER_NOT_FOUNDQuỹ không có trên nguồn hoặc viết sai định dạng mãKiểm tra lại danh mục bằng Reference().fund.list(). Lưu ý một số mã có gạch nối như SSI-SCA
UnsupportedErrorVNSTOCK_FEATURE_REMOVEDGọi tham số source="fmarket"Bỏ tham số source để dùng mặc định "cafef", hoặc chuyển sang source="digiinvest"
AttributeErrorN/ATruy cập thuộc tính cũ Fund().details hoặc Fund().fund_listĐổi sang dùng Reference().fund(symbol).profile() hoặc Reference().fund.list()

Trong trường hợp bạn đang vận hành hệ thống lớn và cần thời gian để tái cấu trúc mã nguồn, bạn có thể tạm thời lọc bỏ cảnh báo FutureWarning bằng cấu hình sau:

Python
import warnings
# Chỉ tắt cảnh báo của các tên quỹ cũ chuyển tiếp (hạn 06/04/2027)
warnings.filterwarnings("ignore", category=FutureWarning, message=".*06/04/2027")