Skip to main content

noether-sdk

Official Python SDK for Noether — a decentralized perpetual exchange on Stellar / Soroban.

Async-first (httpx + pydantic), typed, mirrors the public surface of the TypeScript SDK (noether-sdk on npm).

Install

pip install noether-sdk
# Required for API-key issuance (keys.create) and local Keypair signing:
pip install "noether-sdk[stellar]"

Quick start — public reads

import asyncio
from noether_sdk import NoetherClient

async def main():
    async with NoetherClient("https://api.noether.exchange") as client:
        markets = await client.markets.list()
        btc = await client.oracle.get_price("BTC")
        print("BTC oracle:", btc.price_float)

asyncio.run(main())

Authed: account info

from noether_sdk.transport import Credentials

async with NoetherClient(
    "https://api.noether.exchange",
    credentials=Credentials("nk_...", "..."),
) as client:
    me = await client.account.me()
    mine = await client.account.positions()  # mine.positions (open) + mine.events

Issue an API key (one-shot)

Requires the stellar extra. keys.create wraps the gateway challenge as a manageData op on a placeholder transaction and asks your signer for a signature over the transaction hash — the SDK never sees the secret.

from stellar_sdk import Keypair

kp = Keypair.from_secret(os.environ["STELLAR_SECRET"])
async with NoetherClient("https://api.noether.exchange") as client:
    issued = await client.keys.create(
        address=kp.public_key,
        signer=lambda data: kp.sign(data),
        label="mm-bot-1",
    )
    print(issued.key_id, issued.secret)  # store immediately

Place an order — execute_trade

Trading needs collateral: fund your wallet with testnet USDC from the Noether faucet (Friendbot only provides XLM) before placing orders.

from stellar_sdk import Network, TransactionBuilder

def sign_xdr(xdr: str) -> str:
    tx = TransactionBuilder.from_xdr(xdr, Network.TESTNET_NETWORK_PASSPHRASE)
    tx.sign(kp)
    return tx.to_xdr()

prepared, submitted = await authed.execute_trade(
    {
        "op": "open_position",
        "asset": "XLM",
        "collateral": 1_000 * 10_000_000,
        "leverage": 2,
        "direction": "Long",
    },
    sign_xdr,
)
print(submitted.hash, submitted.status)

execute_trade calls orders.prepare → asks your signer for the signed XDR → calls tx.submit and polls until SUCCESS / FAILED / timeout.

Sub-client cheatsheet

Call Auth
client.health.ping() no
client.markets.list() / get(asset) / stats() / candles(asset, ...) no
client.oracle.get_price(asset) / get_prices() / health() no
client.events.list(topic=, before_ts=, ...) no
client.trades.list(trader=, asset=, before_ts=, ...) no
client.adl.queue(asset, trader=...) no
client.keys.beta_status(address=...) no
client.keys.create(...) no
client.keys.list() / revoke(id) yes
client.account.me() / events() / positions() / orders() yes
client.account.volume(address) / shortfall(address) no
client.orders.prepare({op: ..., ...}) yes
client.positions.open(trader=...) no
client.tx.submit(signed_xdr=...) yes
client.execute_trade({...}, signer) yes
client.vaults.list() / get(id) / trades/deposits/withdraws/fee_claims(id) no
client.referral.lookup_code(code) / info(address) no
client.referral.me() / trades() / claims() yes

WebSocket

from noether_sdk.ws import WsClient

ws = WsClient("wss://api.noether.exchange/v1/ws")
await ws.connect()  # returns on server hello; raises on timeout/failure
await ws.subscribe("ticker.BTC", lambda data, ch: print(ch, data["priceFloat"]))

WsClient reconnects automatically with exponential backoff and replays your login + active subscriptions on every reconnect (account.* channels are re-sent after each login ack). connect() raises instead of hanging when the gateway is unreachable (connect_timeout, default 15s); subscription rejections and failed logins surface through the on_rejected / on_login callbacks.

Errors

from noether_sdk import (
    AuthError, RateLimitError, BadRequestError, ServerError,
)

try:
    await client.markets.get("DOGE")
except BadRequestError as err:
    print("bad request:", err.body)
except RateLimitError as err:
    print("retry in", err.retry_after_sec)

Examples

Dev

pip install -e ".[dev,stellar]"
pytest

Publish (maintainers)

# From sdk-py/ — do not put npm pack tarballs in dist/ (breaks twine).
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=pypi-...   # scope: entire account or project noether-sdk
./scripts/publish_pypi.sh

Status

REST surface complete + WS sub-client. Mirror of the TypeScript SDK shape so cross-language services can be written in either language without translation cost. See CHANGELOG.md.

Metadata

Release files for noether-sdk 0.1.2

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

Source distribution (sdist)

Source distribution for noether-sdk 0.1.2
File Size Uploaded Provenance
noether_sdk-0.1.2.tar.gz 26.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for noether-sdk 0.1.2
File Interpreter ABI Platform
noether_sdk-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 51.6 kB

Release files / noether_sdk-0.1.2.tar.gz

Download URL noether_sdk-0.1.2.tar.gz
Size 26.0 kB
Tags Source
SHA-256 checksum
How to use checksums
cec85b2768870b5bc7d6ddd4440e53f1f7ecd68418b5a8f5e066beb9996935f8
BLAKE2b-256 checksum
How to use checksums
6047030238e5908a35302e40d292e11f2a7dde59c89ca07f6d8f234c42096daf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / noether_sdk-0.1.2-py3-none-any.whl

Download URL noether_sdk-0.1.2-py3-none-any.whl
Size 25.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f57be15d6becefa0935f68991d0e6bfb6479b45c881cfa0af58e1bfd0367e802
BLAKE2b-256 checksum
How to use checksums
0e1abe8265d19cc9c38b77b347005c0fd64ae64ebafdcb0d6c4e864fa4ccd768
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Security for noether-sdk 0.1.2

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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.

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