accueil

Premiers pas

SDK pour Python et Rust

SDK officiels de Seeryx pour Python et Rust : données de marché, Sign-In With Solana, ordres signés, dépôts et retraits vérifiés avant signature, WebSocket.

Vue d’ensemble

Les SDK officiels encapsulent l’API de ces pages pour Python et Rust, avec les mêmes notions et les mêmes noms dans les deux langages. Ils sont open source, sous licence MIT : github.com/Seeryx/seeryx-python et github.com/Seeryx/seeryx-rust.

  • Données de marché : marchés, manches en cours et passées, carnets d’ordres, transactions, volume, frais, statistiques, classement, profils et marchés d’événements, sans compte.
  • Sign-In With Solana avec la paire de clés de votre portefeuille ; quand le jeton expire, le SDK se reconnecte de lui-même.
  • Trading : une session de trading ouverte d’une seule signature du portefeuille, puis des ordres à cours limité, au marché et post-only, des lots de 15 ordres au plus, des annulations, des scissions et des fusions, le tout signé sur votre machine.
  • Fonds : dépôts depuis votre portefeuille, retraits vers votre propre portefeuille et retraits différés ; chaque transaction est vérifiée avant d’être signée.
  • En direct : des flux WebSocket d’une manche et de votre compte, qui se reconnectent d’eux-mêmes.
  • Utilitaires : la grille de prix, les frais, les slugs et les horaires des manches.

Installer

Python 3.9 ou plus récent (un Client bloquant et un AsyncClient asyncio aux mêmes méthodes), ou Rust 1.88 ou plus récent (asynchrone, sur tokio). Les deux s’installent depuis GitHub :

# Python 3.9 or newer
pip install "git+https://github.com/Seeryx/seeryx-python"

Lire un marché

Les données de marché ne demandent aucun compte. Les prix sont en cents ; les niveaux d’un carnet sont [prix, parts], les meilleurs en premier.

quickstart.py
"""The live BTC 5-minute round, its order book and its last trades. No account needed.

    python quickstart.py
"""
from seeryx import Client

with Client() as client:
    rnd = client.current_round("BTC", "5m")
    book = client.order_book(rnd["slug"], "up")  # levels are [cents, shares], best first
    trades = client.trades(rnd["slug"])

    bid = book["bids"][0][0] if book["bids"] else None
    ask = book["asks"][0][0] if book["asks"] else None
    print(rnd["slug"], "opened at", rnd["open"], "ends at", rnd["end"])
    print("Up bid", bid, "ask", ask, "chance of Up", f"{(bid + ask) / 2}%" if bid and ask else "no quotes yet")
    print("last trade", trades[0] if trades else "none yet")
    print("taker fee", client.fees()["rateBps"] / 100, "% of p x (1 - p) per share")

Se connecter

Chargez votre portefeuille depuis un fichier de paire de clés de la CLI Solana ou une clé secrète en base58 ; il ne quitte jamais votre processus. Avant que le portefeuille signe le texte de connexion, le SDK vérifie qu’il désigne ce site, ce portefeuille et le nonce tout juste émis, puis conserve le jeton valable 7 jours.

Lorsque GET /api/funds indique onChainTrading, une seule signature du portefeuille ouvre une session de trading ; sa clé, créée sur votre machine, signe ensuite chaque ordre. Avec un chemin, la session est enregistrée (lisible par vous seul) et réutilisée au lancement suivant ; sans chemin, elle reste en mémoire.

from seeryx import Client, Keypair

client = Client()  # https://seeryx.com
wallet = Keypair.from_file("wallet.json")  # a solana-keygen file; it never leaves this process
client.sign_in(wallet)  # checks the sign-in text, signs it, keeps the 7-day token
if client.funds().get("onChainTrading"):
    # one wallet signature; the session key then signs every order. Saved with mode 0600 and reused next time
    session = client.open_session(wallet, path="session.json")
    print("session key", session.address, "until", session.expires_at)

Passer un ordre

Les prix sont en cents (en dixièmes là où le marché les accepte), les tailles en parts, les montants en USDC. Le SDK choisit la forme signée (PMO2, PMO3 ou PMO4), l’id de l’ordre et son expiration ; un ordre au marché a besoin de cap, le pire prix que vous acceptez.

limit_order.py
"""Sign in, rest a small post-only buy below the market, list it, then cancel it.

    SEERYX_WALLET=~/.config/solana/id.json python limit_order.py
"""
import os

from seeryx import Client, Keypair

wallet = Keypair.from_file(os.path.expanduser(os.environ.get("SEERYX_WALLET", "wallet.json")))

with Client() as client:
    client.sign_in(wallet)
    if client.funds().get("onChainTrading"):
        # one wallet signature opens a trading session; its key then signs every order. Saved (mode 0600) so the
        # next run reuses it; leave out `path` to keep the key in memory only.
        client.open_session(wallet, path="session.json")

    rnd = client.current_round("BTC", "5m")
    book = client.order_book(rnd["slug"], "up")
    bid = book["bids"][0][0] if book["bids"] else 10
    limit = max(1, int(bid) - 5)  # 5c under the best bid: it rests in the book
    placed = client.buy(rnd["slug"], "up", shares=5, limit=limit, post_only=True)  # post_only: never trades at once
    print("resting order", placed["order"], "at", limit, "c")

    print("open orders", client.open_orders())
    if placed["order"]:
        print(client.cancel_order(placed["order"]))
market_buy.py
"""Spend up to $5 on Up now, paying at most 2c over the best ask. What the book cannot fill is dropped.

    SEERYX_WALLET=~/.config/solana/id.json python market_buy.py
"""
import os

from seeryx import Client, Keypair

wallet = Keypair.from_file(os.path.expanduser(os.environ.get("SEERYX_WALLET", "wallet.json")))

with Client() as client:
    client.sign_in(wallet)
    if client.funds().get("onChainTrading"):
        client.open_session(wallet, path="session.json")
    slug = client.current_round("BTC", "5m")["slug"]
    cap = client.market_cap(slug, "up", "buy", slippage=2)  # the worst price you accept, on the price grid
    result = client.market_buy(slug, "up", amount=5, cap=cap)
    print(result["status"], "filled", result["filled"], "shares for", result["spent"], "USDC, average", result.get("avgPrice"))

Mises à jour en direct

Un flux suit une manche ou un marché d’événement (les deux carnets, les transactions, le volume) et, une fois connecté, votre compte. Il se reconnecte avec un délai croissant et se réabonne ; quand une manche se termine, suivez la suivante sur la même connexion.

stream.py
"""Live books and trades of the BTC 5-minute rounds, and your account, over the WebSocket. Reconnects by itself.

    python stream.py                                           # market data only
    SEERYX_WALLET=~/.config/solana/id.json python stream.py    # and your account
"""
import asyncio
import os
import time

from seeryx import AsyncClient, Keypair


async def main() -> None:
    async with AsyncClient() as client:
        path = os.environ.get("SEERYX_WALLET")
        if path:
            await client.sign_in(Keypair.from_file(os.path.expanduser(path)))
        rnd = await client.current_round("BTC", "5m")
        async with client.stream(rnd["slug"], account=bool(path)) as stream:
            while True:
                # a message comes only when something changed: wait at most until the round ends
                message = await stream.next(timeout=max(1.0, rnd["end"] - time.time()))
                if message is None or time.time() >= rnd["end"]:
                    rnd = await client.current_round("BTC", "5m")  # follow the next round, same connection
                    await stream.watch_round(rnd["slug"])
                    continue
                if message["type"] == "round":
                    up = message["up"]
                    print(message["slug"], "bid", up["bids"][:1], "ask", up["asks"][:1], "volume", message["volume"])
                elif message["type"] == "account":
                    print("cash", message["balance"]["available"], "open orders", len(message["orders"]))
                else:
                    print("error", message["error"])


asyncio.run(main())

Déposer et retirer

La plateforme prépare chaque transaction et paie ses frais de réseau : votre portefeuille n’a besoin d’aucun SOL. Le SDK la compare exactement à ce que vous avez demandé et ne signe rien d’autre. Un retrait est signé par la clé de session lorsque sessionWithdraw est activé (au moins 1 USDC, uniquement vers votre propre portefeuille), sinon par votre portefeuille.

withdraw.py
"""Deposit USDC from your wallet, then withdraw some of it to the same wallet. The exchange pays every network fee:
the wallet needs no SOL. Every transaction is inspected before it is signed.

    SEERYX_WALLET=~/.config/solana/id.json python withdraw.py
"""
import os

from seeryx import Client, Keypair

wallet = Keypair.from_file(os.path.expanduser(os.environ.get("SEERYX_WALLET", "wallet.json")))

with Client(before_sign=lambda review: print("signing:", review.headline) or True) as client:
    client.sign_in(wallet)
    print("wallet", client.wallet_funds())  # USDC in the wallet; "account" is None until the first deposit

    print("deposit", client.deposit(wallet, 10))  # the first deposit is at least 1 USDC
    print("balance", client.balance())

    # signed by the trading session key when one is open and the server allows it, else by the wallet;
    # max_fee refuses a withdrawal fee above 1 USDC
    if client.funds().get("onChainTrading"):
        client.open_session(wallet, path="session.json")
    print("withdrawal", client.withdraw(4, wallet=wallet, max_fee=1))
    print("balance", client.balance())

Erreurs et nouvelles tentatives

Un refus arrive sous forme d’erreur avec le statut, le texte du serveur et son code ; les codes de la liste des erreurs ont leurs propres types. Les réponses 429 et 503 sont réessayées comme l’indique Retry-After, et les écritures gardent leur Idempotency-Key à chaque nouvelle tentative : rien n’est passé deux fois.

from seeryx import ApiError, BelowMinimum, WouldTake

try:
    client.buy(slug, "up", shares=5, limit=60, post_only=True)
except WouldTake:
    print("it would trade at once: post only refused it")
except BelowMinimum as e:
    print("the smallest order is", e.minimum, "shares")
except ApiError as e:
    print(e.status, e.code, e.message)  # 429 and 503 were already retried as Retry-After said

Clés et vérifications

  • La clé de votre portefeuille et la clé de session ne quittent jamais votre processus : seules des clés publiques et des signatures sont envoyées.
  • Chaque transaction préparée est décodée et doit être l’instruction propre au programme Seeryx, avec vos comptes et vos montants : une autorisation de dépense, un transfert, un autre signataire ou un autre programme est refusé.
  • Sur seeryx.com, le programme, le mint USDC et le cluster Solana sont figés, quoi que le serveur annonce.
  • Rien de ce qui contient un secret n’est affiché ni journalisé, et un fichier de session enregistré n’est lisible que par son propriétaire.

Exemples

Les deux langages ont les mêmes programmes dans leurs dossiers examples :

ExempleCe qu’il fait
quickstartLa manche BTC de 5 minutes en cours, son carnet et ses dernières transactions, sans compte
limit_orderSe connecter, placer un achat post-only sous le marché, l’afficher puis l’annuler
market_buyDépenser jusqu’à 5 $ immédiatement, en payant au plus 2¢ au-dessus de la meilleure offre
streamCarnets, transactions et votre compte en direct via le WebSocket
market_makerUne petite boucle de cotation des deux côtés, avec des ordres post-only et des fusions
withdrawDéposer depuis votre portefeuille, puis retirer vers celui-ci

Code source, toutes les méthodes, les tests et le journal des modifications : github.com/Seeryx/seeryx-python et github.com/Seeryx/seeryx-rust.