Shioaji Python Bindings
Python bindings for the high-performance rshioaji Rust library - a next-generation client for Taiwan stock market data.
Features
- High Performance: Built on the Rust rshioaji core library for maximum throughput
- Type Safe: Full type annotations and comprehensive error handling
- Real-time Data: Support for stock ticks, bid/ask quotes, and futures/options data
- Multi-exchange: TSE, OTC, OES, and TAIFEX support
- Sync & Async: Both synchronous and asynchronous clients available
- Callback Support: Register callbacks for real-time data processing
Installation
Development Install (from source)
# Clone the repository
git clone <repository-url>
cd rshioaji/python
# Build and install with uv
uv build
uv run python examples/snapshot.py
Production Install (when published)
pip install shioaji
Quick Start
Sync Client
import shioaji
# Create client in simulation mode
api = shioaji.Shioaji(simulation=True)
# Login
api.login("your_api_key", "your_secret_key")
# Create a contract for Taiwan Semiconductor (2330)
contract = shioaji.BaseContract("STK", "TSE", "2330")
# Get snapshots
snapshots = api.snapshots([contract])
for snap in snapshots:
print(f"{snap.code}: {snap.close}")
# Subscribe to real-time tick data
api.subscribe(contract, "tick")
Async Client
import asyncio
import shioaji
async def main():
api = shioaji.ShioajiAsync(simulation=True)
await api.login("your_api_key", "your_secret_key")
contract = shioaji.BaseContract("STK", "TSE", "2330")
snapshots = await api.snapshots([contract])
await api.subscribe(contract, "tick")
asyncio.run(main())
API Reference
Shioaji (Sync Client)
class Shioaji:
def __init__(self, simulation: bool = False, proxy: str = None)
# Auth
def login(self, key: str, secret_key: str) -> List[Account]
def logout(self) -> None
def usage(self) -> UsageOut
def list_accounts(self) -> List[Account]
# Data
def snapshots(self, contracts: List[BaseContract], timeout: int = 30) -> List[Snapshot]
# Stream
def subscribe(self, contract: BaseContract, quote_type: str, intraday_odd: bool = False)
def get_tick_stk_v1_receiver(self) -> TickSTKv1Receiver
def get_bidask_stk_v1_receiver(self) -> BidAskSTKv1Receiver
def get_tick_fop_v1_receiver(self) -> TickFOPv1Receiver
def get_bidask_fop_v1_receiver(self) -> BidAskFOPv1Receiver
# Callbacks
def set_on_tick_stk_v1_callback(self, callback: Callable[[TickSTKv1], None])
def set_on_bidask_stk_v1_callback(self, callback: Callable[[BidAskSTKv1], None])
def set_on_tick_fop_v1_callback(self, callback: Callable[[TickFOPv1], None])
def set_on_bidask_fop_v1_callback(self, callback: Callable[[BidAskFOPv1], None])
def clear_on_tick_stk_v1_callback(self)
def clear_on_bidask_stk_v1_callback(self)
def clear_on_tick_fop_v1_callback(self)
def clear_on_bidask_fop_v1_callback(self)
ShioajiAsync (Async Client)
class ShioajiAsync:
def __init__(self, simulation: bool = False, proxy: str = None)
# Auth (all async)
async def login(self, key: str, secret_key: str) -> List[Account]
async def logout(self) -> None
async def usage(self) -> UsageOut
async def list_accounts(self) -> List[Account]
# Data (all async)
async def snapshots(self, contracts: List[BaseContract], timeout: int = 30) -> List[Snapshot]
# Stream (all async)
async def subscribe(self, contract: BaseContract, quote_type: str, intraday_odd: bool = False)
async def get_tick_stk_v1_receiver(self) -> TickSTKv1Receiver
async def get_bidask_stk_v1_receiver(self) -> BidAskSTKv1Receiver
BaseContract
class BaseContract:
def __init__(self, security_type: str, exchange: str, code: str, target_code: str = None)
# Properties
security_type: str # "STK", "FUT", "OPT", "IND"
exchange: str # "TSE", "OTC", "OES", "TAIFEX"
code: str # Security code (e.g., "2330")
target_code: str # Optional target code
Snapshot
class Snapshot:
ts: int # Timestamp
code: str # Security code
exchange: str # Exchange
open: float # Open price
high: float # High price
low: float # Low price
close: float # Close price
tick_type: TickType # Buy/Sell/None
change_price: float # Price change
change_rate: float # Change rate
change_type: ChangeType # LimitUp/Up/Unchanged/Down/LimitDown
volume: int # Volume
total_volume: int # Total volume
Stream Data Types
class TickSTKv1:
exchange: Exchange
code: str
date: tuple[int, int, int] # (year, month, day)
time: tuple[int, int, int, int] # (hour, minute, second, microsecond)
close: str
volume: int
tick_type: int
simtrade: bool
class BidAskSTKv1:
exchange: Exchange
code: str
bid_price: List[str]
bid_volume: List[int]
ask_price: List[str]
ask_volume: List[int]
Examples
Callback-based Real-time Data
import shioaji
api = shioaji.Shioaji(simulation=True)
api.login("api_key", "secret_key")
def on_tick(tick):
print(f"Tick: {tick.code} @ {tick.close}")
def on_bidask(bidask):
print(f"BidAsk: {bidask.code} Bid={bidask.bid_price[0]}")
api.set_on_tick_stk_v1_callback(on_tick)
api.set_on_bidask_stk_v1_callback(on_bidask)
contract = shioaji.BaseContract("STK", "TSE", "2330")
api.subscribe(contract, "tick")
api.subscribe(contract, "bid_ask")
# Callbacks run in background threads
import time
time.sleep(60)
Receiver-based Data Polling
import shioaji
api = shioaji.Shioaji(simulation=True)
api.login("api_key", "secret_key")
contract = shioaji.BaseContract("STK", "TSE", "2330")
api.subscribe(contract, "tick")
receiver = api.get_tick_stk_v1_receiver()
# Poll for data
while True:
tick = receiver.try_recv()
if tick:
print(f"Tick: {tick.code} @ {tick.close}")
Snapshots
import shioaji
api = shioaji.Shioaji(simulation=True)
api.login("api_key", "secret_key")
contracts = [
shioaji.BaseContract("STK", "TSE", "2330"), # TSMC
shioaji.BaseContract("STK", "TSE", "2317"), # Hon Hai
shioaji.BaseContract("FUT", "TAIFEX", "TXFB6"), # Futures
]
snapshots = api.snapshots(contracts)
for snap in snapshots:
print(f"{snap.code}: close={snap.close}, volume={snap.total_volume}")
Supported Markets
| Exchange | Description |
|---|---|
| TSE | Taiwan Stock Exchange |
| OTC | Over-the-Counter |
| OES | Order Entry System |
| TAIFEX | Taiwan Futures Exchange |
Quote Types
| Type | Description |
|---|---|
| tick | Real-time transaction data |
| bid_ask | Best bid/ask quotes |
Security Types
| Type | Description |
|---|---|
| STK | Stocks |
| FUT | Futures |
| OPT | Options |
| IND | Indices |
Performance Optimization
Latency Comparison
Based on our benchmarks (120s, ~88 FOP ticks):
| Method | P50 Latency | Notes |
|---|---|---|
try_recv() polling |
Fastest | Tight loop, highest CPU |
| Sync callback | ~5µs slower | Dedicated thread |
| Async + uvloop | ~6µs slower | Recommended for async |
| Async (default) | ~136µs slower | Default asyncio overhead |
Using uvloop (Recommended for Async)
For async users, we strongly recommend using uvloop to eliminate asyncio event loop overhead:
# Install uvloop
pip install uvloop
# or with uv
uv add uvloop
import asyncio
import uvloop
import shioaji
# Install uvloop before running async code
uvloop.install()
async def main():
api = shioaji.ShioajiAsync()
await api.login("api_key", "secret_key")
contract = shioaji.BaseContract("STK", "TSE", "2330")
await api.subscribe(contract, "tick")
receiver = await api.get_tick_stk_v1_receiver()
while True:
tick = await receiver.recv()
print(f"Tick: {tick.code} @ {tick.close}")
asyncio.run(main())
Low-Latency Options
For the lowest latency requirements:
Option 1: Sync Callback (Simple)
api = shioaji.Shioaji()
api.set_on_tick_stk_v1_callback(on_tick)
api.subscribe(contract, "tick")
Option 2: try_recv() Polling (Fastest)
receiver = await api.get_tick_stk_v1_receiver()
while True:
tick = receiver.try_recv() # Non-blocking, bypasses asyncio
if tick:
process(tick)
Latency Sources
Data Flow (Async recv):
Solace → Rust Parser → kanal channel → future_into_py → asyncio → Python
│
┌─────────┴─────────┐
│ Latency Source │
├───────────────────┤
│ call_soon_threadsafe (~50µs)
│ Python event loop scheduling (~50µs)
│ asyncio.Future callback (~20µs)
└───────────────────┘
│
uvloop optimizes this entire section
to ~5µs total
Development
Building from Source
cd python
# Build the package
uv build
# Run example
uv run python examples/snapshot.py
uv run python examples/callback.py
Architecture
The Python bindings are built using:
- PyO3: Rust-Python FFI bindings
- maturin: Build tool for Rust-based Python extensions
- Tokio: Async runtime for handling real-time data streams
- rshioaji: Core Rust library for market data processing
License
This project is licensed under the same terms as the main rshioaji project.
Metadata
Release files for rshioaji 1.5.13
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| rshioaji-1.5.13-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.14 | CPython 3.14 free-threading | Linux glibc 2.17+ x86-64 | Details |
| rshioaji-1.5.13-cp314-cp314t-macosx_11_0_arm64.whl | CPython 3.14 | CPython 3.14 free-threading | macOS 11.0+ ARM64 | Details |
| rshioaji-1.5.13-cp37-abi3-win_amd64.whl | CPython 3.7 | abi3 | Windows x86-64 | Details |
| rshioaji-1.5.13-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.7 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| rshioaji-1.5.13-cp37-abi3-macosx_11_0_arm64.whl | CPython 3.7 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 179.1 MB
Release files / rshioaji-1.5.13-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | rshioaji-1.5.13-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 37.2 MB |
| Tags | CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ x86-64 |
|
SHA-256 checksum How to use checksums |
72ed4232342f1251660c4352da54546b49cd3ff764b0c90c7af32da74d36c308
|
|
BLAKE2b-256 checksum How to use checksums |
051f841a03a738fced038967ad09843d47692d268929f56e304857593f6d4c56
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 15, 2026.
Transparency logRelease files / rshioaji-1.5.13-cp314-cp314t-macosx_11_0_arm64.whl
| Download URL | rshioaji-1.5.13-cp314-cp314t-macosx_11_0_arm64.whl |
|---|---|
| Size | 32.8 MB |
| Tags | CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
b95eec4e308b560217b6b32dc641322f458c2e826758e8e91bdcdd1c1ff185d5
|
|
BLAKE2b-256 checksum How to use checksums |
045c4602a1c307566e7207f21421330a11e60912c12b46823ab8e310600ee527
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 15, 2026.
Transparency logRelease files / rshioaji-1.5.13-cp37-abi3-win_amd64.whl
| Download URL | rshioaji-1.5.13-cp37-abi3-win_amd64.whl |
|---|---|
| Size | 39.1 MB |
| Tags | CPython 3.7 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
e5fae84b9f5882499788ea38e3dacff9245153d8d07917464f20406c8e614a15
|
|
BLAKE2b-256 checksum How to use checksums |
d8d6c5711e52c00073cd722c4cf34896b223cca1ef88726ecc6393ad56431cd6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 15, 2026.
Transparency logRelease files / rshioaji-1.5.13-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | rshioaji-1.5.13-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 37.2 MB |
| Tags | CPython 3.7 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
2f3faa0e2a1025b1e256d6407cf1a487c62ed87f06698fec4d4dafb36260b51a
|
|
BLAKE2b-256 checksum How to use checksums |
a6ebe2c05d9c6f012207a03c93d08e094beac4cc4452b1a1b148b99edbcbde3f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 15, 2026.
Transparency logRelease files / rshioaji-1.5.13-cp37-abi3-macosx_11_0_arm64.whl
| Download URL | rshioaji-1.5.13-cp37-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 32.8 MB |
| Tags | CPython 3.7 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
1cf4b8d28c51ffb2d636b8a65602421f010dc33a40e89c2eaeb4c11b982146c9
|
|
BLAKE2b-256 checksum How to use checksums |
0d0f119d34f405a58a31ce721ab66c27ad879750e618b642afc136c241dae037
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 15, 2026.
Transparency log