Skip to content

Configuration

ClientConfig holds connection, credential, timeout, retry, and rate-limit settings. Build it directly or with ClientConfig.from_env().

stonepy.ClientConfig dataclass

ClientConfig(
    base_url: str,
    app_key: str = "",
    username: str = "",
    password: str = "",
    app_version: str = "stonepy",
    connect_timeout: float = 10.0,
    read_timeout: float = 30.0,
    write_timeout: float = 30.0,
    pool_timeout: float = 5.0,
    max_connections: int = 20,
    verify_tls: bool = True,
    proxy: str | None = None,
    user_agent: str = _DEFAULT_USER_AGENT,
    max_retries: int = 3,
    retry_budget_seconds: float = 30.0,
    rate_limit_max: int = 500,
    rate_limit_window_seconds: float = 5.0,
    proactive_refresh_seconds: float = 1080.0,
    status_decoder: StatusDecoder
    | LegacyStatusDecoder
    | None = default_status_decoder,
)

Configuration for StoneX clients.

base_url is required and points at the CIAPI root. app_key, username, and password enable automatic session refresh. Timeout, retry, rate-limit, TLS, proxy, and status-decoder fields tune transport behavior. A custom status_decoder fully replaces stonepy's top-level numeric logic for instruction- and order-domain endpoint specs; it receives (status, status_reason, *, domain); legacy two-argument callables also work. SaveOrder's text status and nested order statuses retain stonepy's built-in checks. Passing None disables all business-status checks. Use from_env() to read the STONEX_* environment variables with optional keyword overrides.

status_decoder class-attribute instance-attribute

status_decoder: (
    StatusDecoder | LegacyStatusDecoder | None
) = default_status_decoder

Optional replacement for top-level numeric instruction/order status decoding.

from_env classmethod

from_env(
    **overrides: Unpack[ClientConfigOverrides],
) -> ClientConfig

Build a config from STONEX_* environment variables, with keyword overrides.

Reads STONEX_BASE_URL, STONEX_APP_KEY, STONEX_USERNAME, and STONEX_PASSWORD. Any field may be overridden by keyword. For most fields an override of None is ignored in favor of the environment value or default; the exception is status_decoder, where passing None is honored to disable status decoding. base_url is required.

Parameters:

Name Type Description Default
**overrides Unpack[ClientConfigOverrides]

Field values that take precedence over the environment.

{}

Returns:

Type Description
ClientConfig

A populated ClientConfig.

Raises:

Type Description
TypeError

If an override names a field that does not exist.

ValueError

If no base_url is provided via override or environment.

Source code in src/stonepy/_core/config.py
@classmethod
def from_env(cls, **overrides: Unpack[ClientConfigOverrides]) -> ClientConfig:
    """Build a config from ``STONEX_*`` environment variables, with keyword overrides.

    Reads ``STONEX_BASE_URL``, ``STONEX_APP_KEY``, ``STONEX_USERNAME``, and
    ``STONEX_PASSWORD``. Any field may be overridden by keyword. For most fields an
    override of ``None`` is ignored in favor of the environment value or default; the
    exception is ``status_decoder``, where passing ``None`` is honored to disable status
    decoding. ``base_url`` is required.

    Args:
        **overrides: Field values that take precedence over the environment.

    Returns:
        A populated ``ClientConfig``.

    Raises:
        TypeError: If an override names a field that does not exist.
        ValueError: If no ``base_url`` is provided via override or environment.
    """

    known_fields = {f.name for f in fields(cls) if f.init}
    unknown_fields = set(overrides) - known_fields
    if unknown_fields:
        unknown = sorted(unknown_fields)[0]
        raise TypeError(f"unexpected ClientConfig override: {unknown}")

    kwargs: dict[str, Any] = {}
    for name, var in (
        ("base_url", "STONEX_BASE_URL"),
        ("app_key", "STONEX_APP_KEY"),
        ("username", "STONEX_USERNAME"),
        ("password", "STONEX_PASSWORD"),
    ):
        if os.environ.get(var):
            kwargs[name] = os.environ[var]
    for name, value in overrides.items():
        if value is not None or name == "status_decoder":
            kwargs[name] = value
    base_url = kwargs.get("base_url", "")
    if isinstance(base_url, str) and not base_url.strip():
        raise ValueError("base_url is required: set STONEX_BASE_URL or pass base_url=...")
    return cls(**kwargs)