Skip to main content

Python SDK

The SDK wraps /v2 and returns tables that convert to pandas, polars or Arrow. It needs Python 3.10 or newer.

Install​

pip install "veinmesh[all] @ https://data.cyberun.cloud/docs/sdk/veinmesh-0.2.0-py3-none-any.whl"

Choose only what you need: veinmesh[pandas], veinmesh[polars], veinmesh[arrow], veinmesh[live], or [all]. The base package only needs httpx.

import veinmesh

client = veinmesh.Client() # VEINMESH_API_KEY

Client(key=..., base_url=..., timeout=120, pending_timeout=3600, retries=3). pending_timeout is how long the client waits for trading days that are being prepared; None waits forever. Busy answers and network failures are retried.

Use it as a context manager to close the connection pool:

with veinmesh.Client() as client:
venues = client.venues()

Catalog​

client.venues()
client.products(venue="SHFE")
client.instruments(venue="SHFE", product="SHFE.rb", kind="future")
client.instrument("SHFE.rb2701") # specification and datasets
client.datasets(venue="SHFE")
client.calendar("SHFE", "2026-10-19", "2026-10-23", product="SHFE.rb")
client.schemas()

instruments() follows every page and returns the full list. instrument() returns the specification with its datasets attached.

Data​

t = client.data("book.snapshot", ["SHFE.rb2701"], trading_day="2026-10-20")
t = client.data("book.snapshot", "SHFE.rb2701", from_day="2026-10-01", to_day="2026-10-20",
fields=["last", "volume"], start=None, end=None)

data() splits long ranges and long symbol lists into requests the API accepts, follows next_cursor, and returns one table ordered by instrument, then time. Pass catalog_version to pin a version. See Limits for the request window and symbol count.

Bars​

daily = client.bars("SHFE.rb.main", "1d", from_day="2025-01-02", to_day="2026-10-20",
adjust="diff")
eighteen = client.bars("SHFE.rb2701", 1080, trading_day="2026-10-20")

interval is seconds (60, 1080) or timedelta, or 1d, 1w, 1mo, 1q, 1y. Other keys follow /v2/bars: type, anchor, adjust, transform, fill, dataset, catalog_version. Continuous contracts accept diff and ratio.

Tables​

data() and bars() return a Table:

len(t) # rows
t.columns # field names
t[0] # one row as a dict
t.to_pandas() # decimals become floats by default
t.to_polars()
t.to_arrow()
t.catalog_version

to_pandas(exact=True) (and the same option on polars and Arrow) keeps exact Decimal values instead of floats.

Live​

for message in client.stream("SHFE.rb2701"):
for row in message.rows:
print(row["ts"], row["last"])

client.stream(..., bars={"interval": 60}) yields bars; message.bar and message.complete describe the bar. start begins from an RFC 3339 instant on the current day. The SDK reconnects and resumes after the last row it received. It needs the websockets extra.

Exports​

job = client.export("book.snapshot", ["SHFE.rb2701", "SHFE.rb2705"],
from_day="2026-09-01", to_day="2026-10-20", format="parquet")
df = job.wait().to_pandas()
files = job.download("./data")

job.wait(poll=10, timeout=None) polls until done; download() writes the files; to_pandas(), to_polars() and to_arrow() download and combine them. client.get_export(id) reopens a job.

Errors​

  • APIError carries status and the problem dict; code is the stable part.
  • PendingTimeout means the client waited pending_timeout for data that was still being prepared.
  • ExportFailed means an export job ended in failed; its message includes the job and the problem.

See Errors for the codes and what to retry.