Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

fugle-marketdata

Fugle market data REST and WebSocket client for Python, powered by a Rust core through PyO3.

Installation

pip install --pre fugle-marketdata   # 3.x pre-release

Wheels are published for CPython 3.8+ (abi3) on Linux glibc (x86_64, aarch64), macOS (x86_64, arm64) and Windows x64.

Development Build

# Create virtual environment
python -m venv .venv
source .venv/bin/activate

# Install maturin
pip install maturin

# Build and install in development mode
cd py
maturin develop

Release Build From Source

maturin build --release
pip install target/wheels/fugle_marketdata-*.whl

Quick Start

REST API

from fugle_marketdata import RestClient, MarketDataError

# Create client with API key
client = RestClient(api_key="your-api-key")

# Get stock quote
quote = client.stock.intraday.quote("2330")
print(f"TSMC Price: {quote['closePrice']}")
print(f"Change: {quote['change']}")
print(f"Volume: {quote['total']['tradeVolume']}")

# Get stock ticker info
ticker = client.stock.intraday.ticker("2330")
print(f"Name: {ticker['name']}")

# Get intraday candles (5-minute)
candles = client.stock.intraday.candles("2330", timeframe="5")
for candle in candles['data'][:3]:
    print(f"  {candle['time']}: O={candle['open']} H={candle['high']} L={candle['low']} C={candle['close']}")

# Get recent trades
trades = client.stock.intraday.trades("2330")
for trade in trades['data'][:5]:
    print(f"  Price: {trade['price']}, Size: {trade['size']}")

# FutOpt (futures/options) data
futopt_quote = client.futopt.intraday.quote("TXFC4")
print(f"Futures Price: {futopt_quote['closePrice']}")

WebSocket Streaming

from fugle_marketdata import WebSocketClient
import time

# Create WebSocket client
ws = WebSocketClient(api_key="your-api-key")

# --- Callback Mode ---

def on_message(msg):
    """Handle incoming messages"""
    if msg.get('event') == 'data':
        channel = msg.get('channel')
        symbol = msg.get('symbol')
        data = msg.get('data', {})
        print(f"[{channel}] {symbol}: {data}")

def on_connect():
    print("Connected!")

def on_disconnect(code, reason):
    print(f"Disconnected: {code} - {reason}")

def on_error(message, code):
    print(f"Error [{code}]: {message}")

# Register callbacks
stock = ws.stock
stock.on("message", on_message)
stock.on("connect", on_connect)
stock.on("disconnect", on_disconnect)
stock.on("error", on_error)

# Connect and subscribe
stock.connect()
stock.subscribe("trades", "2330")
stock.subscribe("books", "2330")

# Keep running for 10 seconds
time.sleep(10)

# Disconnect
stock.disconnect()

# --- Iterator Mode ---

ws2 = WebSocketClient(api_key="your-api-key")
stock2 = ws2.stock
stock2.connect()
stock2.subscribe("trades", "2330")

# Iterate over messages
for msg in stock2.messages():
    print(msg)
    # Add break condition as needed

Authentication

Three authentication methods are supported:

from fugle_marketdata import RestClient

# 1. API Key (most common)
client = RestClient(api_key="your-api-key")

# 2. Bearer Token
client = RestClient(bearer_token="your-bearer-token")

# 3. SDK Token
client = RestClient(sdk_token="your-sdk-token")

Configuration

Reconnection Config

Control WebSocket automatic reconnection behavior:

from fugle_marketdata import WebSocketClient, ReconnectConfig

# Create custom reconnect configuration
reconnect = ReconnectConfig(
    enabled=True,
    max_attempts=10,
    initial_delay_ms=2000,
    max_delay_ms=120000
)

ws = WebSocketClient(api_key="your-key", reconnect=reconnect)

ReconnectConfig Options:

  • enabled (bool): Whether auto-reconnect is enabled (default: True)
  • max_attempts (int): Maximum reconnection attempts (default: 5, min: 1)
  • initial_delay_ms (int): Initial delay for exponential backoff (default: 1000ms, min: 100ms)
  • max_delay_ms (int): Maximum delay cap (default: 60000ms)

Health Check Config

Control WebSocket health check (ping-pong) behavior:

from fugle_marketdata import WebSocketClient, HealthCheckConfig

# Create custom health check configuration
health_check = HealthCheckConfig(
    enabled=True,
    interval_ms=15000,
    max_missed_pongs=3
)

ws = WebSocketClient(api_key="your-key", health_check=health_check)

HealthCheckConfig Options:

  • enabled (bool): Whether health check is enabled (default: False)
  • interval_ms (int): Ping interval in milliseconds (default: 30000ms, min: 5000ms)
  • max_missed_pongs (int): Maximum missed pongs before considering connection stale (default: 2, min: 1)

Combined Configuration

from fugle_marketdata import WebSocketClient, ReconnectConfig, HealthCheckConfig

reconnect = ReconnectConfig(max_attempts=10, initial_delay_ms=2000)
health_check = HealthCheckConfig(enabled=True, interval_ms=15000)

ws = WebSocketClient(
    api_key="your-key",
    reconnect=reconnect,
    health_check=health_check
)

API Reference

RestClient

Stock Intraday Methods

client.stock.intraday.quote(symbol)        # Real-time quote
client.stock.intraday.ticker(symbol)       # Symbol information
client.stock.intraday.candles(symbol, timeframe="1")  # OHLCV candles
client.stock.intraday.trades(symbol)       # Trade history
client.stock.intraday.volumes(symbol)      # Volume by price

FutOpt Intraday Methods

client.futopt.intraday.quote(symbol)       # Real-time quote
client.futopt.intraday.ticker(symbol)      # Contract information
client.futopt.intraday.candles(symbol, timeframe="1")  # OHLCV candles
client.futopt.intraday.trades(symbol)      # Trade history
client.futopt.intraday.volumes(symbol)     # Volume by price
client.futopt.intraday.products(type)      # Product listing ("F" or "O")

WebSocketClient

Properties

ws.stock    # Access StockWebSocketClient
ws.futopt   # Access FutOptWebSocketClient

StockWebSocketClient / FutOptWebSocketClient Methods

client.connect()                           # Connect to server
client.disconnect()                        # Disconnect from server
client.is_connected()                      # Check connection status
client.is_closed()                         # Check if client is closed

client.subscribe(channel, symbol)          # Subscribe to channel
client.unsubscribe(subscription_id)        # Unsubscribe by ID
client.subscriptions()                     # List active subscriptions

client.on(event, callback)                 # Register event callback
client.off(event)                          # Unregister callback

client.messages()                          # Get message iterator

Event Types

Event Callback Signature Description
message fn(msg: dict) Incoming data message
connect fn() Connection established
disconnect fn(code: int, reason: str) Connection closed
error fn(message: str, code: int) Error occurred

Channels

Channel Description
trades Real-time trade executions
candles Candlestick updates
books Order book (5 levels)
aggregates Aggregated market data
indices Index values (stock only)

MessageIterator

# Get iterator from connected client
messages = stock.messages()

# Iterate (blocking)
for msg in messages:
    print(msg)

# Manual iteration
msg = next(messages)          # Blocking
msg = messages.try_recv()     # Non-blocking, returns None if no message
msg = messages.recv_timeout(5.0)  # Timeout in seconds

Error Handling

All API errors raise MarketDataError:

from fugle_marketdata import RestClient, MarketDataError

client = RestClient(api_key="invalid-key")

try:
    quote = client.stock.intraday.quote("2330")
except MarketDataError as e:
    message = e.args[0]
    error_code = e.args[1]
    print(f"Error [{error_code}]: {message}")

Error Codes

Code Error Type Description
1001 InvalidSymbol Invalid or unsupported symbol
1002 DeserializationError JSON parsing failed
1003 RuntimeError Internal runtime error
1004 ConfigError Configuration error
2001 ConnectionError Network connection failed
2002 AuthError Authentication failed
2003 ApiError API returned error response
2010 ClientClosed Client has been closed
3001 TimeoutError Operation timed out
3002 WebSocketError WebSocket protocol error
9999 Other Unexpected error

Examples

Full REST Example

from fugle_marketdata import RestClient, MarketDataError
import os

def main():
    api_key = os.environ.get("FUGLE_API_KEY")
    if not api_key:
        print("Set FUGLE_API_KEY environment variable")
        return

    client = RestClient(api_key=api_key)

    try:
        # Stock data
        print("=== Stock Market Data ===")
        quote = client.stock.intraday.quote("2330")
        print(f"TSMC Quote: {quote['closePrice']}")

        ticker = client.stock.intraday.ticker("2330")
        print(f"Ticker: {ticker['name']}")

        candles = client.stock.intraday.candles("2330", timeframe="5")
        print(f"Candles: {len(candles['data'])} entries")

        # FutOpt data
        print("\n=== FutOpt Market Data ===")
        products = client.futopt.intraday.products("F")
        print(f"Futures products: {len(products['data'])}")

    except MarketDataError as e:
        print(f"Error [{e.args[1]}]: {e.args[0]}")

if __name__ == "__main__":
    main()

Full WebSocket Example

from fugle_marketdata import WebSocketClient, MarketDataError
import os
import time

def main():
    api_key = os.environ.get("FUGLE_API_KEY")
    if not api_key:
        print("Set FUGLE_API_KEY environment variable")
        return

    ws = WebSocketClient(api_key=api_key)
    stock = ws.stock

    message_count = 0

    def on_message(msg):
        nonlocal message_count
        message_count += 1
        if msg.get('event') == 'data':
            print(f"[{message_count}] {msg.get('channel')}: {msg.get('symbol')}")

    def on_connect():
        print("Connected!")

    def on_error(message, code):
        print(f"Error [{code}]: {message}")

    stock.on("message", on_message)
    stock.on("connect", on_connect)
    stock.on("error", on_error)

    try:
        stock.connect()
        stock.subscribe("trades", "2330")
        stock.subscribe("books", "2330")

        print("Listening for 10 seconds...")
        time.sleep(10)

        print(f"\nReceived {message_count} messages")
        print(f"Subscriptions: {stock.subscriptions()}")

    except MarketDataError as e:
        print(f"Error [{e.args[1]}]: {e.args[0]}")
    finally:
        if stock.is_connected():
            stock.disconnect()
        print("Done")

if __name__ == "__main__":
    main()

Requirements

  • Python 3.8+
  • Rust toolchain (for building from source)
  • maturin (for development builds)

License

MIT

Metadata

Release files for fugle-marketdata 3.0.0rc2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for fugle-marketdata 3.0.0rc2
File Actions
fugle_marketdata-3.0.0rc2-cp38-abi3-win_amd64.whl CPython 3.8 abi3 Windows x86-64 Details for fugle_marketdata-3.0.0rc2-cp38-abi3-win_amd64.whl
fugle_marketdata-3.0.0rc2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.8 abi3 Linux glibc 2.17+ x86-64 Details for fugle_marketdata-3.0.0rc2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
fugle_marketdata-3.0.0rc2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.8 abi3 Linux glibc 2.17+ ARM64 Details for fugle_marketdata-3.0.0rc2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
fugle_marketdata-3.0.0rc2-cp38-abi3-macosx_11_0_arm64.whl CPython 3.8 abi3 macOS 11.0+ ARM64 Details for fugle_marketdata-3.0.0rc2-cp38-abi3-macosx_11_0_arm64.whl
fugle_marketdata-3.0.0rc2-cp38-abi3-macosx_10_12_x86_64.whl CPython 3.8 abi3 macOS 10.12+ x86-64 Details for fugle_marketdata-3.0.0rc2-cp38-abi3-macosx_10_12_x86_64.whl

Total release size: 15.0 MB

Release files / fugle_marketdata-3.0.0rc2-cp38-abi3-win_amd64.whl

Download URL fugle_marketdata-3.0.0rc2-cp38-abi3-win_amd64.whl
Size 2.7 MB
Tags CPython 3.8 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
a77ff5d05cf2ccc6e91bb5933911302a74c024c519ffb1addd5dd04b01532e0f
BLAKE2b-256 checksum
How to use checksums
86015547337afc160ec96cd081379c1de9c467780ea281cbce882482bc50b83c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 16, 2026.

Transparency log

Release files / fugle_marketdata-3.0.0rc2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL fugle_marketdata-3.0.0rc2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 3.1 MB
Tags CPython 3.8 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
ba309e09d512af1da759e07e4adf0aafcf2a158d50d5354b826a6b3d88dc5402
BLAKE2b-256 checksum
How to use checksums
27f66d2fb6711ba10ab5091e15a69b06421e781b805958bbe27de020b2197212
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 16, 2026.

Transparency log

Release files / fugle_marketdata-3.0.0rc2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL fugle_marketdata-3.0.0rc2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 3.4 MB
Tags CPython 3.8 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
b878c9af50bf63c743de689a77d87379f53038e9ff3854121efa094ea5a9362b
BLAKE2b-256 checksum
How to use checksums
819a67f450176f589ba17b71d7f2ce075cc9c4d305753a245670e10999d4499e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 16, 2026.

Transparency log

Release files / fugle_marketdata-3.0.0rc2-cp38-abi3-macosx_11_0_arm64.whl

Download URL fugle_marketdata-3.0.0rc2-cp38-abi3-macosx_11_0_arm64.whl
Size 2.9 MB
Tags CPython 3.8 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
246cbe96cb3fc1d89d999206fa380dbad0e67d09adc1a5fa78424d437552b024
BLAKE2b-256 checksum
How to use checksums
e1e3e0c005177ff031d715004a28ccb429c32c5e2a142e5c9574283d493eb539
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 16, 2026.

Transparency log

Release files / fugle_marketdata-3.0.0rc2-cp38-abi3-macosx_10_12_x86_64.whl

Download URL fugle_marketdata-3.0.0rc2-cp38-abi3-macosx_10_12_x86_64.whl
Size 2.9 MB
Tags CPython 3.8 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
498767c13d9064605cedae16ce059986b2fa634dad511b65f4996f2fb70c35f5
BLAKE2b-256 checksum
How to use checksums
9896c6a899374a641462bd5090f145fff1d855c4b7a66f6e9621aa1cd29df4cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 16, 2026.

Transparency log

Security for fugle-marketdata 3.0.0rc2

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.

Full provenance

All 5 files in this release have been uploaded with provenance metadata.

Select from 5 files

Attestation for fugle_marketdata-3.0.0rc2-cp38-abi3-win_amd64.whl

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 Sep 16, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page