Vnstock Logo

Dùng trong Python

Thử nghiệmvnstock_oapi v0.1.0rc1

Mục lục

Bản thử nghiệm, chưa phát hành chính thức

Trang này viết cho vnstock_oapi v0.1.0rc1, bản thử nghiệm. Tên hàm, tham số và cột dữ liệu có thể còn đổi trước ngày phát hành; khi cài, ghi rõ số phiên bản như ở trang Cài đặt.

Nguồn của bạn

Chọn nguồn bạn có khoá, mã trên trang sẽ điền theo. Chưa chọn thì mã giữ chỗ trống <nguồn>. Nguồn xếp theo bảng chữ cái, không phải khuyến nghị.

Chọn nguồn bạn đã có khoá ở thanh đầu trang (cột source= ở bảng nguồn): mã ví dụ điền tên nguồn và một mã hợp với nguồn đó. Đổi mã thành mã bạn cần.

Gọi dữ liệu

Python
import vnstock_oapi as oapi

src = oapi.source("<nguồn>")                 # hoặc gọi tắt: oapi.<nguồn> (như oapi.ssi, oapi.dnse,...)
bars = src.ohlc("<mã>", start="2026-10-01", end="2026-10-30", interval="1D")

bars[0].body              # dữ liệu nguồn trả về, giữ nguyên
bars[0].operation         # thao tác đã gọi
bars.summary()            # mỗi bản ghi một dòng: thao tác, mã HTTP, mã băm, dung lượng
bars.save("nen.jsonl")    # mỗi dòng một bản ghi

Hàm chung: ohlc, trades, quote, index, foreign, symbols, calendar, events, cùng tham số với dòng lệnh. Mỗi hàm trả Envelopes, một danh sách bản ghi; nguồn chia trang thì mỗi trang một bản ghi.

Python
oapi.sources()                       # các nguồn có trong bản này
oapi.status()                        # khoá lấy từ đâu, phiên còn hạn không; không gọi mạng
print(oapi.terms("<nguồn>"))         # tóm tắt điều khoản, kèm đường dẫn văn bản gốc

src.ops                              # hàm và thao tác gốc nguồn hỗ trợ
src.preview("ohlc", "<mã>")          # request sẽ gửi, chưa gửi; khoá đã được che
src.raw("<thao-tác>", <khoá>="<giá_trị>")   # thao tác gốc, tham số đúng như tài liệu của nguồn

Nguồn mở phiên bằng OTP thì mở phiên trước. Đừng gõ OTP vào mã:

Python
import getpass

src.authenticate(getpass.getpass("OTP: "))
src.clear_auth()                     # xoá phiên đang giữ

Bản ghi kết quả

Mỗi lần gọi cho ra một bản ghi (Envelope): dữ liệu gốc giữ nguyên, kèm thông tin để biết nó đến từ đâu, lấy lúc nào, và đối chiếu lại được về sau.

TrườngNội dung
envelope_versionPhiên bản định dạng, hiện là "1"
source, operation, api_versionNguồn, thao tác đã gọi, phiên bản API
requestTham số đã gửi. Không bao giờ chứa khoá, chữ ký, token hay header
fetched_at, http_statusThời điểm lấy, mã HTTP
bodyDữ liệu nguồn trả về, giữ nguyên. Không phải JSON thì nằm ở body_base64
body_sha256Mã băm SHA-256 của dữ liệu gốc, để kiểm dữ liệu có bị sửa không
producerPhần mềm đã tạo bản ghi
transportTên miền, giao thức, độ trễ, số request đã gửi

Đọc lại tệp đã lưu bằng oapi.load("nen.jsonl"). vnstock 6 đọc thẳng các bản ghi này để dựng bảng chuẩn hoá.

Đã lấy dữ liệu bằng SDK của nguồn hay bằng mã của riêng bạn thì vẫn đóng gói được về cùng định dạng:

Python
env = oapi.wrap("<nguồn>", "<thao-tác>", body=my_json, request={"symbol": "<mã>"})

Xử lý lỗi

Mọi lỗi kế thừa vnstock_oapi.errors.OapiError. So khớp theo lớp lỗi, không so khớp câu chữ của thông báo.

Python
from vnstock_oapi import errors

try:
    bars = oapi.source("<nguồn>").ohlc("<mã>", start="2026-10-01")
except errors.CredentialError as exc:
    print(exc)          # thiếu khoá: thông báo ghi đúng tên biến môi trường cần đặt
except errors.OapiError as exc:
    print(type(exc).__name__, exc)
LớpKhi nàoLàm gì
InputErrorTham số sai, hoặc nguồn không có khung thời gian bạn chọnSửa tham số; xem ops <nguồn>
CredentialErrorMáy chưa có khoá của nguồn, hoặc khoá sai dạngCất khoá (Cài đặt)
AuthErrorNguồn từ chối khoá (401, 403). Không gọi lạivnstock-oapi check <nguồn>; tạo lại khoá nếu cần
LoginRequiredError, OtpRequiredErrorChưa có phiên, hoặc phiên hết hạn và nguồn cần OTP mớivnstock-oapi auth <nguồn>
RateLimitErrorVẫn bị giới hạn tần suất sau một lần chờChờ rồi gọi lại; giảm số lần gọi
ClockSkewErrorĐồng hồ máy lệch quá mức nguồn cho phép khi ký requestĐồng bộ lại giờ hệ thống
NetworkErrorHết thời gian chờ, mất kết nối, lỗi TLSKiểm mạng rồi gọi lại
SourceErrorNguồn lỗi (5xx), chuyển hướng, hoặc trả nội dung khác tài liệuGọi lại sau; nguồn có thể vừa đổi định dạng
UnsupportedErrorNguồn không có hàm hay thao tác nàyXem ops <nguồn>, hoặc chọn nguồn khác
PolicyErrorRequest vi phạm sàn an toàn của thư viện: tên miền lạ, không phải GET, khoá nằm trong requestGọi qua hàm của thư viện, không tự ghép request

Khi keys set báo NoKeyringError, máy không có keyring. Xem Máy không có keyring.

Thêm nguồn của riêng bạn

Khai báo một nguồn trong gói của riêng bạn bằng oapi.register(...), không phải sửa thư viện. Nguồn đó chạy dưới cùng sàn an toàn (chỉ https, chỉ tên miền đã khai, chỉ đọc dữ liệu thị trường), và bản ghi kết quả ghi tên gói của bạn:

Python
import vnstock_oapi as oapi
from vnstock_oapi import ext

SPEC = ext.SourceSpec(
    name="demo",
    title="Demo API",
    base_url="https://api.example.com/v1",
    hosts=frozenset({"api.example.com"}),
    credentials=(ext.CredentialField("api_key", "API_KEY"),),
    auth=lambda source: ext.ApiKeyHeaderAuth(source, header="X-Api-Key"),
    ops={"bars": ext.Op("bars", "/bars/{symbol}", doc="https://example.com/docs/bars")},
    verbs={"ohlc": lambda symbol, **kw: ext.Plan("bars", {"symbol": ext.symbol("demo", symbol), **kw})},
)

TERMS = ext.Terms(
    source="demo",
    title="Demo API",
    terms_url="https://example.com/terms",
    docs_url="https://example.com/docs",
    checked_at="2026-11-01",
    summary=("Chỉ dùng cho cá nhân.", "Không phân phối lại dữ liệu."),
)

oapi.register(SPEC, terms=TERMS, producer=("my-package", "0.1.0"))

Sau khi import gói của bạn, nguồn mới có thể gọi trực tiếp qua oapi.demo hoặc oapi.source("demo"). Chi tiết xem tại hướng dẫn viết nguồn trên GitHub.