Skip to main content

Trading

Place orders on Polymarket with local credential custody and builder attribution. Supports both the current exchange and the Polymarket V2 exchange. See also: PolyUSD Guide for V2 collateral wrapping. Requires the trading extras:
pip install polynode[trading]

Generate a Wallet

import asyncio
from polynode.trading import PolyNodeTrader

async def main():
    wallet = await PolyNodeTrader.generate_wallet()
    print(f"Address: {wallet.address}")
    print(f"Private key: {wallet.private_key}")
    # BACK UP THE PRIVATE KEY — it cannot be recovered

asyncio.run(main())

One-Call Onboarding

from polynode.trading import PolyNodeTrader, TraderConfig

trader = PolyNodeTrader(TraderConfig(polynode_key="pn_live_..."))

# Auto-detects wallet type, deploys Safe if needed, sets approvals, creates CLOB credentials
status = await trader.ensure_ready("0xYourPrivateKey...")
print(f"Wallet: {status.wallet}")
print(f"Funder: {status.funder_address}")
print(f"Type: {status.signature_type.name}")  # POLY_GNOSIS_SAFE
print(f"Actions: {status.actions}")

Place Orders

from polynode.trading import OrderParams

result = await trader.order(OrderParams(
    token_id="51037625779056581606819614184446816710505006861008496087735536016411882582167",
    side="BUY",
    price=0.55,
    size=100,
))
print(f"Success: {result.success}, Order ID: {result.order_id}")

Cancel Orders

# Cancel one
cancel = await trader.cancel_order("order-id-here")

# Cancel all
cancel = await trader.cancel_all()

# Cancel all in a market
cancel = await trader.cancel_all(market="condition-id")

Open Orders

orders = await trader.get_open_orders()
for o in orders:
    print(f"{o.side} {o.original_size} @ {o.price}{o.status}")

Pre-Trade Checks

# Check token approvals
approvals = await trader.check_approvals()
print(f"All approved: {approvals.all_approved}")

# Check balances
balance = await trader.check_balance()
print(f"USDC: {balance.usdc}, MATIC: {balance.matic}")

Wallet Management

# Link existing credentials (no signing needed)
trader.link_credentials(
    wallet="0x...",
    api_key="...",
    api_secret="...",
    api_passphrase="...",
)

# Export for backup
exported = trader.export_wallet()
# Import on another machine
trader.import_wallet(exported)

# List all linked wallets
wallets = trader.get_linked_wallets()

Address Derivation

from polynode.trading import derive_safe_address, derive_proxy_address

eoa = "0xacd89cFCB82Ae1f843467D56b58796bb928C9E1A"
safe = derive_safe_address(eoa)    # 0xf75564cEe0ed847463E18D20B5005c9db245c374
proxy = derive_proxy_address(eoa)  # 0x65FA7F1aFB344A3F78a62D662798A32d850738c8

Polymarket V2 Exchange

To trade on the Polymarket V2 exchange, set exchange_version on your TraderConfig:
from polynode.trading import TraderConfig, ExchangeVersion

config = TraderConfig(
    polynode_key="pn_live_...",
    exchange_version=ExchangeVersion.V2,
)
trader = PolyNodeTrader(config)
V2 uses PolyUSD (a 1:1 USDC.e wrapper) as collateral. You must wrap USDC.e into PolyUSD before placing orders:
# Wrap USDC.e → PolyUSD
result = await trader.wrap_to_polyusd(100.0)

# Unwrap PolyUSD → USDC.e
result = await trader.unwrap_from_polyusd(50.0)

# Check balances
polyusd = await trader.get_polyusd_balance()
usdce = await trader.get_usdce_balance()
print(f"PolyUSD: {polyusd}, USDC.e: {usdce}")
See the V2 Migration Guide for details on the Polymarket V2 exchange upgrade.

Fee Escrow

Charge per-order fees with on-chain escrow. Fees are pulled before the order, distributed on fill, and refunded on cancel. See the Fee Escrow Guide for the full architecture and security model.
from polynode.trading import PolyNodeTrader, TraderConfig, FeeConfig

trader = PolyNodeTrader(TraderConfig(
    polynode_key="pn_live_...",
    fee_config=FeeConfig(fee_bps=50),  # 0.5% fee on every order
))

result = await trader.order(OrderParams(
    token_id="...",
    side="BUY",
    price=0.55,
    size=100,
))

print(f"Fee TX: {result.fee_escrow_tx_hash}")  # on-chain pullFee TX
print(f"Fee: {result.fee_amount} USDC")        # fee amount charged

# Cancel → fee is automatically refunded
await trader.cancel_order(result.order_id)
Set fee_bps=0 or omit fee_config to skip the escrow entirely. Per-order overrides:
result = await trader.order(OrderParams(
    token_id="...",
    side="BUY",
    price=0.55,
    size=100,
    fee_config=FeeConfig(
        fee_bps=100,                             # 1% for this order
        affiliate="0xPartnerWallet...",           # partner address
        affiliate_share_bps=5000,                 # 50/50 split
    ),
))

Configuration

from polynode.trading import TraderConfig, SignatureType, ExchangeVersion, FeeConfig

config = TraderConfig(
    polynode_key="pn_live_...",                          # for builder attribution
    db_path="./polynode-trading.db",                     # local SQLite storage
    cosigner_url="https://trade.polynode.dev",           # co-signer proxy
    fallback_direct=True,                                 # direct CLOB if co-signer down
    default_signature_type=SignatureType.POLY_GNOSIS_SAFE,  # Safe (2), Proxy (1), or EOA (0)
    rpc_url="https://polygon-bor-rpc.publicnode.com",    # for on-chain reads
    exchange_version=ExchangeVersion.V1,                  # default; set to V2 for the Polymarket V2 exchange
    fee_config=FeeConfig(fee_bps=50),                     # optional: 0.5% fee on every order
)

trader = PolyNodeTrader(config)

Signature Types

TypeValueDescription
SignatureType.EOA0Direct EOA signing (user pays gas for approvals)
SignatureType.POLY_PROXY1Legacy Polymarket proxy wallet
SignatureType.POLY_GNOSIS_SAFE2Gnosis Safe (default, gasless onboarding)

Privy Signer (Server-Side Wallets)

Use Privy-managed wallets for headless server-side trading. No private key needed — signing is done through Privy’s wallet API:
from polynode.trading import PolyNodeTrader, TraderConfig
from polynode.trading.privy import PrivySigner, PrivyConfig

signer = PrivySigner(
    PrivyConfig(
        app_id="your-privy-app-id",
        app_secret="your-privy-app-secret",
        authorization_key="wallet-auth:your-authorization-key",
    ),
    wallet_id="your-privy-wallet-id",
    wallet_address="0xYourWalletAddress",
)

trader = PolyNodeTrader(TraderConfig(polynode_key="pn_live_..."))
status = await trader.ensure_ready(signer)
result = await trader.order(OrderParams(token_id="...", side="BUY", price=0.50, size=100))
The Privy signer implements the same RouterSigner interface and works with all trading methods (ensure_ready, order, cancel_all, etc.). Gnosis Safe wallets (type 2) are fully gasless.

Cleanup

trader.close()  # closes SQLite, clears active signer