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
APIErrorcarriesstatusand the problemdict;codeis the stable part.PendingTimeoutmeans the client waitedpending_timeoutfor data that was still being prepared.ExportFailedmeans an export job ended infailed; its message includes the job and the problem.
See Errors for the codes and what to retry.