Skip to main content

decibel-python-sdk

PyPI PyPI - Python Version PyPI - Downloads CI License: MIT

Python SDK for interacting with Decibel, a fully on-chain trading engine built on Aptos.

📚 View Full Documentation →

Installation

pip install decibel-python-sdk

Or with uv:

uv add decibel-python-sdk

Configuration

Set the following environment variables:

# Required for write operations
export PRIVATE_KEY="your_private_key_hex"

# Optional: for better rate limits
export APTOS_NODE_API_KEY="your_aptos_node_api_key"

New to Decibel? Follow the Getting Started Guide to create your API Wallet and get your API key from Geomi.

Quick Start

Reading Market Data

import asyncio
from decibel import TESTNET_CONFIG
from decibel.read import DecibelReadDex

async def main():
    read = DecibelReadDex(TESTNET_CONFIG)

    # Get all markets
    markets = await read.markets.get_all()
    for market in markets:
        print(f"{market.market_name}: {market.max_leverage}x leverage")

    # Get market prices
    prices = await read.market_prices.get_all()
    for price in prices:
        print(f"{price.market}: ${price.mark_px}")

asyncio.run(main())

Placing Orders

import asyncio
import os
from aptos_sdk.account import Account
from aptos_sdk.ed25519 import PrivateKey
from decibel import (
    TESTNET_CONFIG,
    BaseSDKOptions,
    DecibelWriteDex,
    GasPriceManager,
    PlaceOrderSuccess,
    TimeInForce,
    amount_to_chain_units,
)
from decibel.read import DecibelReadDex

async def main():
    private_key = PrivateKey.from_hex(os.environ["PRIVATE_KEY"])
    account = Account.load_key(private_key.hex())

    gas = GasPriceManager(TESTNET_CONFIG)
    await gas.initialize()

    read = DecibelReadDex(TESTNET_CONFIG)
    markets = await read.markets.get_all()
    btc = next(m for m in markets if m.market_name == "BTC/USD")

    write = DecibelWriteDex(
        TESTNET_CONFIG,
        account,
        opts=BaseSDKOptions(gas_price_manager=gas),
    )

    result = await write.place_order(
        market_name="BTC/USD",
        price=amount_to_chain_units(100000.0, btc.px_decimals),
        size=amount_to_chain_units(0.001, btc.sz_decimals),
        is_buy=True,
        time_in_force=TimeInForce.GoodTillCanceled,
        is_reduce_only=False,
    )

    if isinstance(result, PlaceOrderSuccess):
        print(f"Order placed! ID: {result.order_id}")
    else:
        print(f"Order failed: {result.error}")

    await gas.destroy()

asyncio.run(main())

WebSocket Streaming

import asyncio
from decibel import TESTNET_CONFIG
from decibel.read import DecibelReadDex

async def main():
    read = DecibelReadDex(TESTNET_CONFIG)

    def on_price(msg):
        price = msg.price
        print(f"BTC/USD: ${price.mark_px}")

    unsubscribe = read.market_prices.subscribe_by_name("BTC/USD", on_price)

    await asyncio.sleep(30)
    unsubscribe()
    await read.ws.close()

asyncio.run(main())

Spot Trading

Decibel has two products: perpetual futures (perp) and spot. Everything shared between them — readers, order rows, trade rows — carries an asset_type discriminator. Perp is the default everywhere, so existing perp code keeps working unchanged.

import asyncio
from decibel import TESTNET_CONFIG, DecibelWriteDex, PlaceSpotOrderSuccess, TimeInForce
from decibel.read import AssetTypeName, DecibelReadDex

async def main():
    read = DecibelReadDex(TESTNET_CONFIG)

    # Spot market data
    contexts = await read.spot_asset_contexts.get_all()   # 24h stats per spot market
    spot_markets = await read.markets.get_all_spot()      # spot rows from /markets
    depth = await read.market_depth.get_by_name("APT/USDC", asset_type=AssetTypeName.SPOT)

    # Account data, filtered by product ("perp" | "spot" | "all")
    spot_orders = await read.user_open_orders.get_by_addr(sub_addr=sub_addr, asset_type="spot")
    everything = await read.user_trade_history.get_by_addr(sub_addr=sub_addr, asset_type="all")

    # Trading
    write = DecibelWriteDex(TESTNET_CONFIG, account, opts=opts)
    result = await write.place_spot_order(
        market_name="APT/USDC",
        price=price,
        size=size,
        is_buy=True,
        time_in_force=TimeInForce.GoodTillCanceled,
    )
    if isinstance(result, PlaceSpotOrderSuccess) and result.pending_cbs:
        # Committed, but queued behind a rate-limited CBS withdrawal instead of resting on
        # the book — poll the order endpoints for the real acknowledgment.
        print("order queued")

asyncio.run(main())

Notes:

  • asset_type="all" omits the query parameter rather than sending asset_type=all; rows that predate spot carry no asset_type and are treated as perp.
  • Market addresses encode their product, so *_by_addr readers and every WebSocket topic are product-agnostic and take no asset_type.
  • Spot market addresses derive from the deployment package (via the GlobalSpotEngine named object), not from perp_engine_global — use get_spot_market_addr(name, config.deployment.package) or get_market_addr_for_product(name, asset_type, config.deployment).
  • Spot rows in /markets reuse the perp row shape: sz_decimals is the base asset's decimals, px_decimals the quote's, and max_leverage / max_open_interest are always 0.
  • Spot writes need the spot Move modules. They ship in the bundled ABI; if a module is missing from it the SDK fetches the ABI from the fullnode on first use (one extra request, cached thereafter). On a network where the modules aren't deployed at all, writes raise Cannot build transaction: missing ABI for <fn>.

Examples

See the examples directory for complete working examples:

Market Maker Bot

The SDK includes a complete market maker bot example that demonstrates how to build a trading bot using Decibel. The bot:

  • Places bid/ask quotes around the mid-price with configurable spread
  • Manages inventory with skew adjustments to encourage mean-reversion
  • Monitors margin usage and pauses quoting when limits are exceeded
  • Supports both dry-run (simulation) and live trading modes
  • Includes configurable parameters: spread, order size, inventory limits, refresh interval, and more
  • Uses POST_ONLY orders for predictable fills

To run the bot, set environment variables and execute:

# Dry-run mode (no transactions)
export SUBACCOUNT_ADDRESS="0x..."
export NETWORK="testnet"
python examples/write/market_maker_bot.py --dry-run

# Live mode (requires PRIVATE_KEY as plain hex, no 0x prefix)
export PRIVATE_KEY="your_private_key_hex"
python examples/write/market_maker_bot.py \
  --market="BTC/USD" \
  --spread=0.001 \
  --order-size=0.001 \
  --max-inventory=0.01 \
  --max-margin-usage=0.5 \
  --refresh-interval=20

Use python examples/write/market_maker_bot.py --help to see all available options.

API Reference

Network Configs

from decibel import MAINNET_CONFIG, TESTNET_CONFIG

# MAINNET_CONFIG - Production network
# TESTNET_CONFIG - Test network

Read Client

from decibel.read import DecibelReadDex

read = DecibelReadDex(config, api_key=None)

# Market data (asset_type defaults to perp; *_by_addr variants are product-agnostic)
read.markets.get_all()
read.markets.get_all_spot()
read.spot_asset_contexts.get_all()
read.market_prices.get_all()
read.market_prices.get_by_name(market_name)
read.market_depth.get_by_name(market_name, limit=50, asset_type=AssetTypeName.PERP)
read.market_depth.get_by_addr(market_addr, limit=50)
read.market_trades.get_by_name(market_name, asset_type=AssetTypeName.PERP)
read.market_contexts.get_all()
read.candlesticks.get_by_name(market_name, interval=interval, start_time=start, end_time=end)

# User data (asset_type: "perp" | "spot" | "all")
read.account_overview.get_by_addr(sub_addr=sub_addr)
read.user_positions.get_by_addr(sub_addr=sub_addr)
read.user_open_orders.get_by_addr(sub_addr=sub_addr, asset_type="perp")
read.user_order_history.get_by_addr(sub_addr=sub_addr, asset_type="perp")
read.user_trade_history.get_by_addr(sub_addr=sub_addr, asset_type="perp")
read.user_bulk_orders.get_by_addr(sub_addr=sub_addr, asset_type="perp")
read.user_bulk_orders.get_status(sub_addr=sub_addr, market=market_addr, sequence_number=seq)
read.user_bulk_orders.get_fills(sub_addr=sub_addr, asset_type="perp")
read.user_orders.get_order(sub_addr=sub_addr, market=market_addr, order_id=order_id)
read.user_fees.get_by_addr(sub_addr)
read.user_subaccounts.get_by_addr(owner_addr=addr)
read.user_fund_history.get_by_addr(sub_addr=sub_addr)
read.user_funding_history.get_by_addr(sub_addr=sub_addr)
read.user_active_twaps.get_by_addr(sub_addr=sub_addr)
read.user_twap_history.get_by_addr(sub_addr=sub_addr)
read.withdraw_queue.get_by_addr(sub_addr=sub_addr)

# Points, campaigns & referrals
read.trading_points.get_by_owner(owner_addr=addr)
read.trading_amps.get_by_owner(owner_addr=addr)
read.tier.get_by_owner(owner_addr=addr)
read.global_points_stats.get()
read.points_leaderboard.get_points_leaderboard()
read.streaks.get_by_owner(owner_addr=addr)
read.campaigns.get_active()
read.campaigns.get_summary(account_address=addr)
read.referrals.get_account_referral(account=addr)
read.referrals.get_referrer_stats(account=addr)
read.referrals.get_affiliate_earnings(account=addr)
read.funded_first_trade.get_eligibility(account=addr)
read.funded_first_trade.get_active_trial(account=addr)

# Other
read.delegations.get_all(sub_addr=sub_addr)
read.leaderboard.get_leaderboard()
read.portfolio_chart.get_by_addr(sub_addr=sub_addr, time_range="7d", data_type="pnl")
read.vaults.get_vaults()

# On-chain view helpers
read.spot_market_assets(market_addr)
read.fungible_asset_metadata(asset_addr)

# WebSocket subscriptions (topics are keyed by market address, so product-agnostic)
read.market_prices.subscribe_by_name(market_name, callback)
read.market_prices.subscribe_all(callback)
read.market_prices.subscribe_all_spot_mids(callback)
read.market_depth.subscribe_by_name(market_name, aggregation_size, callback)
read.market_depth.subscribe_by_addr(market_addr, aggregation_size, callback)
read.market_trades.subscribe_by_name(market_name, callback)
read.candlesticks.subscribe_by_name(market_name, interval, callback)
read.account_overview.subscribe_by_addr(sub_addr, callback)
read.user_positions.subscribe_by_addr(sub_addr, callback)
read.user_open_orders.subscribe_by_addr(sub_addr, callback)
read.user_order_history.subscribe_by_addr(sub_addr, callback)
read.user_trade_history.subscribe_by_addr(sub_addr, callback)
read.user_bulk_orders.subscribe_by_addr(sub_addr, callback)
read.user_active_twaps.subscribe_by_addr(sub_addr, callback)
read.user_notifications.subscribe_by_addr(sub_addr, callback)
read.withdraw_queue.subscribe_by_addr(sub_addr, callback)
read.funded_first_trade.subscribe_by_addr(account, callback)

Write Client

from decibel import DecibelWriteDex, TimeInForce

write = DecibelWriteDex(config, account, opts)

# Perp orders
write.place_order(market_name=..., price=..., size=..., is_buy=..., time_in_force=..., is_reduce_only=...)
write.update_order(market_addr=..., order_id=..., price=..., size=..., is_buy=..., time_in_force=..., is_reduce_only=...)
write.cancel_order(order_id=..., market_name=...)
write.cancel_client_order(client_order_id=..., market_name=...)
write.place_bulk_orders(market_name=..., sequence_number=..., bid_prices=..., bid_sizes=..., ask_prices=..., ask_sizes=...)
write.cancel_bulk_order(market_name=...)

# Spot orders
write.place_spot_order(market_name=..., price=..., size=..., is_buy=..., time_in_force=...)
write.cancel_spot_order(order_id=..., market_name=...)
write.place_spot_bulk_order(market_name=..., sequence_number=..., bid_prices=..., bid_sizes=..., ask_prices=..., ask_sizes=...)
write.cancel_spot_bulk_order(market_name=...)
write.cancel_spot_bulk_order_at_price_level(market_name=..., price=..., is_buy=...)
write.set_hold_as_non_collateral(asset_addr=..., hold=...)
write.process_spot_pending_requests(market_name=..., max_fills=...)  # permissionless

# TP/SL
write.place_tp_sl_order_for_position(market_name=..., tp_price=..., sl_price=..., ...)
write.update_tp_order_for_position(market_name=..., order_id=..., new_trigger_price=..., ...)
write.update_sl_order_for_position(market_name=..., order_id=..., new_trigger_price=..., ...)

# TWAP
write.place_twap_order(market_name=..., size=..., is_buy=..., is_reduce_only=..., twap_frequency_seconds=..., twap_duration_seconds=...)
write.cancel_twap_order(market_addr=..., order_id=...)

# Collateral
write.deposit(amount)
write.withdraw(amount)                                # withdraws from cross collateral
write.withdraw_non_collateral(asset_addr, amount)     # non-collateral spot assets

# Campaigns & funded first trade
write.claim_campaign_reward(campaign_id)
write.open_fft_trial(owner=...)
write.claim_fft_unlock(lock_id=..., owner=...)
write.settle_fft_trial(trial_id=...)

# Vaults
write.deposit_to_vault(vault_address=..., amount=..., subaccount_addr=...)
write.withdraw_from_vault(vault_address=..., shares=...)

# Subaccounts
write.create_subaccount()
write.admin_create_subaccount(owner_address)
write.deactivate_subaccount(subaccount_addr=...)

# Builder fees
write.approve_max_spot_builder_fee(builder_addr=..., max_fee=...)
write.revoke_max_spot_builder_fee(builder_addr=...)

A synchronous DecibelWriteDexSync mirrors every method above. Protocol admin operations live on DecibelAdminDex (perp) and DecibelSpotAdminDex (spot), each with a *Sync variant.

Development

make setup                 # Install dependencies + pre-commit hooks
make                       # Run full quality pipeline (format, lint, typecheck, test)
make lint                  # Check for lint errors
make fix                   # Auto-fix lint and format issues
make typecheck             # Run pyright type checking
make test                  # Run tests

Generating ABI JSON Files

The SDK uses ABI JSON files to build on-chain transactions. These are fetched from the deployed smart contracts and stored in src/decibel/abi/json/. They should be regenerated whenever the on-chain contracts are updated.

# Generate ABIs for a specific network (default: mainnet)
make abi
make abi NETWORK=testnet
make abi NETWORK=mainnet

# Generate ABIs for all networks
make abi-all

Resources

License

This project is licensed under the MIT License - see the LICENSE file for details.

Download files

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

Source Distribution

decibel_python_sdk-0.3.0.tar.gz (106.1 kB view details)

Uploaded Source

Built Distribution

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

decibel_python_sdk-0.3.0-py3-none-any.whl (137.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: decibel_python_sdk-0.3.0.tar.gz
  • Upload date:
  • Size: 106.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for decibel_python_sdk-0.3.0.tar.gz
Algorithm Hash digest
SHA256 82417d53a204b72ceedc751e71b4216173b6422ec1ab2ed3e6eef5c58e006fdc
MD5 effebc3a0486c9993c75dd1a443bda7c
BLAKE2b-256 199a3c91b9c008cb8c0535286cbdfc08abe5aee85c1003566ffb375b22005db5

See more details on using hashes here.

Provenance

The following attestation bundles were made for decibel_python_sdk-0.3.0.tar.gz:

Publisher: pypi_publish.yml on decibeltrade/python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

File hashes

Hashes for decibel_python_sdk-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e8e317b49e4d738aa78bfc940f24246285e269a90ff3933fdba10df46b25c232
MD5 bf6b1bdc2c8b4916818d02153425329d
BLAKE2b-256 6f5093dcdab4b1fdc5661ee375ce99f98fee78941822f1e835abce29682564a8

See more details on using hashes here.

Provenance

The following attestation bundles were made for decibel_python_sdk-0.3.0-py3-none-any.whl:

Publisher: pypi_publish.yml on decibeltrade/python-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 files

0.2.1

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

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