Skip to main content

Python SDK for Limitless Exchange

Project description

Limitless Exchange Python SDK

A minimalistic, async Python SDK for interacting with the Limitless Exchange API.

Features

  • 🔐 Ethereum wallet authentication - EIP-712 message signing with EOA support
  • 📈 Market data access - Markets, orderbooks, and historical data
  • 📋 Order management - GTC and FOK orders with automatic signing
  • 💼 Portfolio tracking - Positions and trading history
  • 🔄 Automatic retries - Configurable retry logic with session re-authentication
  • 🌐 WebSocket support - Real-time orderbook updates
  • 🛡️ Custom headers - Global and per-request header configuration
  • Async/await support - Modern async Python with aiohttp

Installation

pip install limitless-sdk

Quick Start

import asyncio
import os
from eth_account import Account
from limitless_sdk.api import HttpClient
from limitless_sdk.auth import MessageSigner, Authenticator
from limitless_sdk.markets import MarketFetcher
from limitless_sdk.portfolio import PortfolioFetcher
from limitless_sdk.types import LoginOptions

async def main():
    # Setup
    account = Account.from_key(os.getenv("PRIVATE_KEY"))
    http_client = HttpClient(base_url="https://api.limitless.exchange")

    try:
        # Authenticate
        signer = MessageSigner(account)
        authenticator = Authenticator(http_client, signer)
        result = await authenticator.authenticate(LoginOptions(client="eoa"))

        print(f"Authenticated: {result.profile.account}")

        # Get markets
        market_fetcher = MarketFetcher(http_client)
        markets = await market_fetcher.get_markets()
        print(f"Found {markets['totalCount']} markets")

        # Get positions
        portfolio_fetcher = PortfolioFetcher(http_client)
        positions = await portfolio_fetcher.get_positions()
        print(f"CLOB positions: {len(positions['clob'])}")

    finally:
        await http_client.close()

if __name__ == "__main__":
    asyncio.run(main())

Authentication

The SDK uses EIP-712 message signing for authentication with EOA (Externally Owned Account) wallets.

Basic Authentication

from eth_account import Account
from limitless_sdk.api import HttpClient
from limitless_sdk.auth import MessageSigner, Authenticator
from limitless_sdk.types import LoginOptions

# Create account from private key
account = Account.from_key("0x...")

# Initialize HTTP client
http_client = HttpClient(base_url="https://api.limitless.exchange")

# Authenticate
signer = MessageSigner(account)
authenticator = Authenticator(http_client, signer)
result = await authenticator.authenticate(LoginOptions(client="eoa"))

# Access session
print(f"User ID: {result.profile.id}")
print(f"Session: {result.session_cookie[:32]}...")

Custom HTTP Headers

You can configure custom headers globally (applied to ALL requests) or per-request:

# Global headers (rate limiting bypass, custom auth, etc.)
http_client = HttpClient(
    base_url="https://api.limitless.exchange",
    additional_headers={
        "X-Rate-Limit-Bypass": "your-secret-token",
        "X-API-Version": "v1"
    }
)

# Per-request headers (request ID, tracing, etc.)
response = await http_client.get("/endpoint", headers={"X-Request-ID": "123"})

Auto-Retry on Session Expiration

The AuthenticatedClient wrapper automatically re-authenticates when sessions expire:

from limitless_sdk.auth import AuthenticatedClient

auth_client = AuthenticatedClient(
    http_client=http_client,
    authenticator=authenticator
)

# Automatically handles 401/403 errors with re-authentication
response = await auth_client.with_retry(
    lambda: portfolio_fetcher.get_positions()
)

Market Data

Get Markets

from limitless_sdk.markets import MarketFetcher

market_fetcher = MarketFetcher(http_client)

# Get all markets (paginated)
markets = await market_fetcher.get_markets(page=1, limit=50)
print(f"Total: {markets['totalCount']}")
print(f"Markets: {len(markets['data'])}")

# Get specific market
market = await market_fetcher.get_market("market-slug")
print(f"Title: {market.title}")
print(f"YES Token: {market.tokens.yes}")
print(f"NO Token: {market.tokens.no}")

Get Orderbook

orderbook = await market_fetcher.get_orderbook("market-slug")

# Access bids/asks
for order in orderbook.get('orders', []):
    print(f"Price: {order['price']}, Size: {order['size']}")

Order Management

The SDK supports two order types:

  • GTC (Good-Till-Cancelled): Uses price + size parameters
  • FOK (Fill-Or-Kill): Uses maker_amount (total USDC to spend/receive)

Create GTC Orders

from limitless_sdk.orders import OrderClient
from limitless_sdk.types import Side, OrderType, MarketType, UserData

# Setup order client
user_data = UserData(
    user_id=auth_result.profile.id,
    fee_rate_bps=auth_result.profile.fee_rate_bps
)

order_client = OrderClient(
    http_client=http_client,
    wallet=account,
    user_data=user_data,
    market_type=MarketType.CLOB
)

# Get token ID from market
token_id = str(market.tokens.yes)  # or market.tokens.no

# Create BUY GTC order
order = await order_client.create_order(
    token_id=token_id,
    price=0.50,      # Minimum acceptable price
    size=5.0,        # Number of shares
    side=Side.BUY,
    order_type=OrderType.GTC,
    market_slug=market.slug
)

print(f"Order ID: {order.order.id}")
print(f"Status: {order.order.status}")

Create FOK Orders

# FOK orders use maker_amount instead of price/size
order = await order_client.create_order(
    token_id=token_id,
    maker_amount=10.0,   # Total USDC to spend
    side=Side.BUY,
    order_type=OrderType.FOK,
    market_slug=market.slug
)

# Check if filled
if order.maker_matches and len(order.maker_matches) > 0:
    print(f"FILLED: {len(order.maker_matches)} matches")
else:
    print("NOT FILLED (cancelled)")

Cancel Orders

# Cancel single order by ID
await order_client.cancel(order_id)

# Cancel all orders for a market
await order_client.cancel_all(market_slug)

Portfolio

Get Positions

from limitless_sdk.portfolio import PortfolioFetcher

portfolio_fetcher = PortfolioFetcher(http_client)

# Get positions
positions = await portfolio_fetcher.get_positions()

# Access CLOB positions
clob_positions = positions['clob']
for position in clob_positions:
    print(f"Market: {position['market']['title']}")
    print(f"Size: {position['size']}")

# Access points
print(f"Points: {positions['accumulativePoints']}")

WebSocket Support

Subscribe to real-time orderbook updates:

from limitless_sdk.websocket import WebSocketClient, WebSocketConfig

# Setup WebSocket
config = WebSocketConfig(
    url="wss://ws.limitless.exchange",
    auto_reconnect=True,
    reconnect_delay=1.0
)
ws_client = WebSocketClient(config=config)

# Event handlers
@ws_client.on('connect')
async def on_connect():
    print("Connected")

@ws_client.on('orderbookUpdate')
async def on_orderbook_update(data):
    orderbook = data.get('orderbook', data)
    best_bid = orderbook['bids'][0]['price']
    best_ask = orderbook['asks'][0]['price']
    print(f"Bid: {best_bid:.4f} | Ask: {best_ask:.4f}")

# Connect and subscribe
await ws_client.connect()
await ws_client.subscribe('subscribe_market_prices', {'marketSlugs': [market_slug]})

Error Handling

The SDK provides APIError for all API-related errors:

from limitless_sdk.api import APIError

try:
    order = await order_client.create_order(...)
except APIError as e:
    print(f"Status: {e.status_code}")
    print(f"Error: {e}")  # Prints raw API response JSON

Retry Mechanism

Use the @retry_on_errors decorator for custom retry logic:

from limitless_sdk.api import retry_on_errors

@retry_on_errors(
    status_codes={500, 429},
    max_retries=3,
    delays=[1, 2, 3],
    on_retry=lambda attempt, error, delay: print(f"Retry {attempt+1}/3")
)
async def fetch_data():
    return await http_client.get("/endpoint")

Logging

Enable debug logging to see request headers and details:

from limitless_sdk.types import ConsoleLogger, LogLevel

logger = ConsoleLogger(level=LogLevel.DEBUG)
http_client = HttpClient(base_url="...", logger=logger)

Architecture

The SDK is organized into modular components:

Core Components

  • HttpClient: Low-level HTTP client with retry logic and custom headers
  • MessageSigner: EIP-712 message signing for authentication
  • Authenticator: Handles EOA authentication flow
  • AuthenticatedClient: Auto-retry wrapper with session management

Domain Components

  • MarketFetcher: Market data retrieval (markets, orderbooks)
  • OrderClient: Order creation/cancellation with automatic signing
  • PortfolioFetcher: Portfolio and positions data
  • WebSocketClient: Real-time orderbook updates

Type System

The SDK uses Pydantic models for type safety:

  • LoginOptions: Authentication configuration
  • UserData: User profile data
  • Side: BUY / SELL enum
  • OrderType: GTC / FOK enum
  • MarketType: CLOB enum
  • LogLevel: DEBUG / INFO / WARN / ERROR enum

Examples

See the examples/ directory for complete working examples:

  • 01_authentication.py - EOA authentication with custom headers
  • 02_create_buy_gtc_order.py - Create BUY GTC order
  • 03_cancel_gtc_order.py - Cancel orders (single or all)
  • 04_create_sell_gtc_order.py - Create SELL GTC order
  • 05_create_buy_fok_order.py - Create BUY FOK order
  • 06_create_sell_fok_order.py - Create SELL FOK order
  • 06_retry_handling.py - Custom retry logic with @retry_on_errors
  • 07_auto_retry_second_sample.py - Auto-retry with AuthenticatedClient
  • 08_websocket_events.py - Real-time orderbook updates

Development

Setup

git clone https://github.com/limitless-labs-group/limitless-exchange-ts-sdk.git
cd limitless-sdk
pip install -e ".[dev]"

Testing

pytest

Linting

ruff check .
mypy limitless_sdk/

License

MIT License - see LICENSE file for details.

Support

For questions or issues:

Key Features

Token ID Extraction

CLOB markets use a tokens object for YES/NO positions:

# Get YES token ID
token_id = str(market.tokens.yes)

# Get NO token ID
token_id = str(market.tokens.no)

Raw API Responses

The SDK returns raw API responses without heavy parsing, allowing direct access to all fields:

# Markets response
markets = await market_fetcher.get_markets()
total = markets['totalCount']
data = markets['data']

# Positions response
positions = await portfolio_fetcher.get_positions()
clob = positions['clob']
points = positions['accumulativePoints']

Order Type Parameters

  • GTC orders: price + size

    price=0.50,  # Minimum acceptable price
    size=5.0     # Number of shares
    
  • FOK orders: maker_amount

    maker_amount=10.0  # Total USDC to spend/receive
    

Changelog

v0.3.0

  • Architecture: Refactored to modular component structure
    • HttpClient with connection pooling via aiohttp
    • OrderClient for order management with automatic signing
    • MarketFetcher for market data operations
    • PortfolioFetcher for portfolio/positions queries
  • WebSocket Support: Real-time orderbook updates via WebSocketClient
    • Event-based subscription system with decorators
    • Auto-reconnect functionality with configurable delays
    • Typed event handlers for orderbook updates
  • Authentication: Enhanced authentication system
    • MessageSigner for EIP-712 message signing
    • Authenticator for EOA authentication flow
    • AuthenticatedClient wrapper for automatic session re-authentication
  • HTTP Client: Structured HTTP client with advanced features
    • Connection pooling and session management
    • Global and per-request custom headers
    • Configurable logging with ConsoleLogger and log levels
    • Retry decorator (@retry_on_errors) with customizable delays
  • Order System: Improved order handling
    • Support for GTC (Good-Till-Cancelled) orders with price + size
    • Support for FOK (Fill-Or-Kill) orders with maker_amount
    • Automatic order signing and submission
    • Order cancellation (single and batch)
  • Documentation: Comprehensive examples directory with 9 working examples
  • README: Updated to reflect actual implementation patterns

v0.2.0

  • Added additional_headers parameter to HttpClient
  • Global and per-request header configuration
  • AuthenticatedClient for auto-retry on session expiration
  • WebSocket support for real-time updates
  • Retry decorator (@retry_on_errors)
  • Comprehensive examples directory
  • Fixed license configuration in pyproject.toml

v0.1.0

  • Initial release
  • EOA authentication with EIP-712 signing
  • Market data access
  • GTC and FOK order support
  • Portfolio tracking

Project details


Download files

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

Source Distribution

limitless_sdk-0.3.0.tar.gz (54.5 kB view details)

Uploaded Source

Built Distribution

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

limitless_sdk-0.3.0-py3-none-any.whl (61.8 kB view details)

Uploaded Python 3

File details

Details for the file limitless_sdk-0.3.0.tar.gz.

File metadata

  • Download URL: limitless_sdk-0.3.0.tar.gz
  • Upload date:
  • Size: 54.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.0

File hashes

Hashes for limitless_sdk-0.3.0.tar.gz
Algorithm Hash digest
SHA256 4cd3d1712d34363022afa362d4142a60b94b85f2660e590cf9afdad2321a25ca
MD5 115cfcf590472fce024f632e75e1090f
BLAKE2b-256 83337c58b5ea1ec093a01a51215f538c40a68b04f7559dbbe655cd59679b26f5

See more details on using hashes here.

File details

Details for the file limitless_sdk-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: limitless_sdk-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 61.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.0

File hashes

Hashes for limitless_sdk-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 74e78fec801ca2004e50f6d0563e7c3dc51ac3d99b91643c94666af080e146db
MD5 5d9f17175cbc9675b0a3f03164d163ba
BLAKE2b-256 0f95c617a5ff613eca72a0010eaae3b440ef2fc1e8b691c4cc3259cce4d2a7c9

See more details on using hashes here.

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