Skip to main content

Rust implementation of Shioaji trading API for Taiwan financial markets

Project description

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

rshioaji-1.5.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (35.9 MB view details)

Uploaded CPython 3.14tmanylinux: glibc 2.17+ x86-64

rshioaji-1.5.4-cp314-cp314t-macosx_11_0_arm64.whl (31.5 MB view details)

Uploaded CPython 3.14tmacOS 11.0+ ARM64

rshioaji-1.5.4-cp37-abi3-win_amd64.whl (37.7 MB view details)

Uploaded CPython 3.7+Windows x86-64

rshioaji-1.5.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (35.9 MB view details)

Uploaded CPython 3.7+manylinux: glibc 2.17+ x86-64

rshioaji-1.5.4-cp37-abi3-macosx_11_0_arm64.whl (31.5 MB view details)

Uploaded CPython 3.7+macOS 11.0+ ARM64

File details

Details for the file rshioaji-1.5.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for rshioaji-1.5.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 091eaa3184bc65b440b740eb14a13a46c67efa15c95562c4ccf0cab203c2e1b4
MD5 4e3574d0d48e4b12035ef79b66ab727b
BLAKE2b-256 9c99ca7e98ad5f36ce4d7db21eed5a32a769171f6f0569169d41b80bfeb4662b

See more details on using hashes here.

Provenance

The following attestation bundles were made for rshioaji-1.5.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on Sinotrade/rshioaji

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rshioaji-1.5.4-cp314-cp314t-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rshioaji-1.5.4-cp314-cp314t-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 cf55cadc22e0b37128e9509b85d2d4a5a93076d77a445a6a744b15107fb695fd
MD5 246300a8a1c2380af2e9495ca85e7efe
BLAKE2b-256 1f48d1a4e0392c741db07fddc75ff7067143e785a0d326277c5b74d8eae7c0b7

See more details on using hashes here.

Provenance

The following attestation bundles were made for rshioaji-1.5.4-cp314-cp314t-macosx_11_0_arm64.whl:

Publisher: release.yml on Sinotrade/rshioaji

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rshioaji-1.5.4-cp37-abi3-win_amd64.whl.

File metadata

  • Download URL: rshioaji-1.5.4-cp37-abi3-win_amd64.whl
  • Upload date:
  • Size: 37.7 MB
  • Tags: CPython 3.7+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rshioaji-1.5.4-cp37-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 94009df86265fee9d40c04a02cfca5ccf768fd37e769f46d6e5a496b275ade0c
MD5 67370cb3b0ed55ffd62c9afae8d6f9d1
BLAKE2b-256 30c87e9dc60bfd42f83a84cb2190e2dab36949730a69b144a25802440a4380ff

See more details on using hashes here.

Provenance

The following attestation bundles were made for rshioaji-1.5.4-cp37-abi3-win_amd64.whl:

Publisher: release.yml on Sinotrade/rshioaji

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rshioaji-1.5.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for rshioaji-1.5.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f3c44c2156191b68e7b7d42b0cb6b07cad807ce9de0aac78b8c71dc08f84c0fe
MD5 2c218584389fd8ff415ef425f88dd7c2
BLAKE2b-256 d32f5af215a3d371f824964b473163074e1e9d93c0691af667488de7d0e304b9

See more details on using hashes here.

Provenance

The following attestation bundles were made for rshioaji-1.5.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on Sinotrade/rshioaji

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rshioaji-1.5.4-cp37-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rshioaji-1.5.4-cp37-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6c326c24e94214a8a527d285ac33c490c5d54e10f0173c75c042e8d77a0d3b71
MD5 9ff4c040f94848068becc54a4c2bb730
BLAKE2b-256 fc4eee248b0d164b9a797311e60b743bbeb9afb4294df768a76daf56706b69ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for rshioaji-1.5.4-cp37-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on Sinotrade/rshioaji

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page