PYX

API Reference

Complete reference for the pyx module available in scripts.

Trading

pyx.buy(token_id, condition_id, price, size, post_only, snap_direction, market_order, slippage_bps, metadata)

Enqueue a buy order. By default this is a limit order; set market_order = true for market execution.

pyx.buy("abc123", "0xcondition", 0.45, 5.0, false, "up")

-- Market buy with 0.5% slippage tolerance (50 bps)
pyx.buy("abc123", "0xcondition", 0.45, 5.0, nil, nil, true, 50)

-- Limit buy with metadata attached to this order
pyx.buy("abc123", "0xcondition", 0.45, 5.0, false, "down", false, nil, {
    strategy_id = "mr_v2",
    run_id = "2026-04-10-a",
    tags = {"entry", "risk_on"},
    leg = 1,
})
ParamTypeDescription
token_idstringThe token to buy
condition_idstringThe market condition
pricenumberFor market orders, treated as the worst-possible price before slippage
sizenumberQuantity in contracts
post_onlyboolean?If true, reject orders that would cross the spread instead of executing them
snap_directionstring? ("up" or "down")If "up", round fractional prices up, making them more aggressive
market_orderboolean?If true, submits a market order. Defaults to false (limit order behavior)
slippage_bpsnumber?Optional slippage tolerance in basis points (50 = 0.5%, 1000 = 10%). Only applies to market orders
metadatatable?Optional Lua table stored with this order and replayed on order lifecycle events

Order mode rules:

  • Limit order: market_order is omitted/false, price is required and limit-order price.
  • Market order: market_order = true, price is worst-possible before slippage.
  • slippage_bps only applies to market orders, 500bps = 5% slippage.

Orders are enqueued, not executed inline. They're submitted to the exchange after your callback returns. This keeps the Luau VM non-blocking.

If the order queue is full (256 pending), this throws a Lua error "order queue full". If you need higher limits, please reach out to us.

Metadata behavior:

  • metadata is stored per order ID.
  • The same metadata is replayed on on_placed, on_fill (including partial fills), and on_cancelled.
  • pyx.get_active_orders() and pyx.get_pending_orders() include a metadata field per row.
  • Order WebSocket events order_update and fill_insert include metadata.
  • Position updates are unchanged (no metadata added).

pyx.sell(token_id, condition_id, price, size, post_only, snap_direction, market_order, slippage_bps, metadata)

Enqueue a sell order. Same signature and behavior as pyx.buy.

pyx.sell("abc123", "0xcondition", 0.55, 0.10)

pyx.cancel_all()

Request cancellation of all active orders. Takes effect after your callback returns.

function on_tick(ctx)
    if some_exit_condition then
        pyx.cancel_all()
    end
end

pyx.cancel(order_id)

Request cancellation of one active order by exchange order ID.

local orders = pyx.get_active_orders()
if #orders > 0 then
    local ok = pyx.cancel(orders[1].order_id)
    if ok then
        pyx.log("Cancel requested for " .. orders[1].order_id)
    end
end
ParamTypeDescription
order_idstringExchange order ID to cancel

Returns boolean.

  • true: cancel request was accepted by the runtime and queued for execution
  • false: order is unknown (not active/pending) or request queue is unavailable

Positions

pyx.get_position(token_id)

Get the current position for a specific token.

local pos = pyx.get_position("abc123")
if pos then
    pyx.log(string.format("qty=%.4f avg=%.4f pnl=%.4f",
        pos.qty, pos.avg_cost, pos.realized_pnl))
end

Returns a table or nil if no position exists:

FieldTypeDescription
qtynumberCurrent quantity (positive = long)
avg_costnumberWeighted average cost basis
realized_pnlnumberRealized P&L from closed portions

pyx.get_positions()

Get all positions as a table keyed by token ID.

local positions = pyx.get_positions()
for token_id, pos in positions do
    pyx.log(token_id .. ": " .. pos.qty)
end

Returns a table { [token_id] = position } where each position has:

FieldTypeDescription
qtynumberCurrent quantity
avg_costnumberWeighted average cost
realized_pnlnumberRealized P&L
total_bought_qtynumberTotal bought quantity (lifetime)
total_sold_qtynumberTotal sold quantity (lifetime)

pyx.split(condition_id, amount)

Request a split for a market condition. The split is processed asynchronously by the runtime.

pyx.split("0xcondition", 5.0)
ParamTypeDescription
condition_idstringThe market condition ID to split
amountnumberAmount to split

Completion is reported via on_split_complete(ctx).

If the split/merge queue is full, this throws a Lua error "split merge queue full".

pyx.merge(condition_id, amount)

Request a merge for a market condition. The merge is processed asynchronously by the runtime. To be able to merge, you need equal amounts of both Yes and No tokens

pyx.merge("0xcondition", 2.5)
ParamTypeDescription
condition_idstringThe market condition ID to merge
amountnumberThe number of FULL sets to merge

Completion is reported via on_merge_complete(ctx).

If the split/merge queue is full, this throws a Lua error "split merge queue full".


Orders

pyx.active_orders(token_id?)

Count of active orders (confirmed on book).

local total = pyx.active_orders()          -- all tokens
local for_token = pyx.active_orders("abc") -- specific token

Returns number.

pyx.pending_orders(token_id?)

Count of pending orders (submitted but not yet confirmed on book).

local total = pyx.pending_orders()

Returns number.

pyx.get_active_orders(token_id?)

Get full details of all active orders.

local orders = pyx.get_active_orders("abc123")
for _, order in ipairs(orders) do
    pyx.log(string.format("%s %s %.4f @ %.4f",
        order.side, order.token_id, order.size, order.price))
end

Returns an array of tables:

FieldTypeDescription
order_idstringExchange order ID
token_idstringToken
sidestring"buy" or "sell"
pricenumberLimit price
sizenumberOrder size
placed_atnumberTimestamp (ms since epoch)
metadatatable?Metadata attached when the order was created

pyx.get_pending_orders(token_id?)

Get full details of all pending orders.

local pending = pyx.get_pending_orders()
for _, order in ipairs(pending) do
    pyx.log("Pending: " .. order.client_id)
end

Returns an array of tables:

FieldTypeDescription
client_idstringInternal tracking ID
order_idstringExchange order ID (may be empty if not yet assigned)
token_idstringToken
sidestring"buy" or "sell"
pricenumberLimit price
sizenumberOrder size
metadatatable?Metadata attached when the order was created

Account

pyx.get_balance()

Current USDC wallet balance.

local bal = pyx.get_balance()
pyx.log(string.format("Balance: $%.2f", bal))

Returns number.

pyx.get_spend()

Total capital committed to outstanding buy orders and unsold positions.

local spend = pyx.get_spend()
local remaining = pyx.get_balance() - spend

Returns number.


Spot Prices

pyx.subscribe_spot(symbols)

Subscribe to Binance spot price updates for the given symbols.

pyx.subscribe_spot({"BTC", "ETH"})
ParamTypeDescription
symbols{string}Array of symbols to subscribe to

Supported symbols: "BTC", "ETH", "SOL", "XRP", "BNB", "DOGE"

Subscriptions are additive - calling this multiple times adds new symbols without removing existing ones. Once subscribed, prices will be streamed to your script via on_spot_price(ctx).

pyx.get_spot_price(symbol)

Returns the latest BBO snapshot for a symbol, or nil if not yet available. Case-insensitive.

local btc = pyx.get_spot_price("BTC")
if btc then
    pyx.log("BTC mid=" .. btc.mid .. " spread=" .. (btc.ask - btc.bid))
end
ParamTypeDescription
symbolstringSymbol name (e.g. "BTC")

Supported symbols: "BTC", "ETH", "SOL", "XRP", "BNB", "DOGE"

Returns a table or nil:

FieldTypeDescription
symbolstringSymbol name
bidnumberBest bid price
asknumberBest ask price
bid_qtynumberBest bid size
ask_qtynumberBest ask size
midnumberMidpoint (bid + ask) / 2
timestampnumberReceipt time (ms since epoch)

Liquidations

pyx.subscribe_liquidations(exchanges)

Subscribe to liquidation events from one or more exchanges.

pyx.subscribe_liquidations({"binance", "okx", "bybit"})
ParamTypeDescription
exchanges{string}Array of exchange ids to subscribe to

Supported exchanges: "binance", "bybit", "okx", "hyperliquid"

Supported symbols: "BTC", "ETH", "SOL", "XRP", "BNB", "DOGE", "HYPE"

Subscriptions are additive - calling this multiple times adds new exchanges without removing existing ones. Once subscribed, liquidation events will be streamed to your script via on_liquidation(ctx).


pyx.subscribe_chainlink(symbols)

Subscribe to Chainlink oracle price updates for the given symbols.

pyx.subscribe_chainlink({"BTC", "ETH", "HYPE"})
ParamTypeDescription
symbols{string}Array of symbols to subscribe to

Supported symbols: "BTC", "ETH", "SOL", "XRP", "BNB", "DOGE", "HYPE"

Subscriptions are additive - calling this multiple times adds new symbols without removing existing ones. Once subscribed, prices will be streamed to your script via on_chainlink_price(ctx).

Returns a Chainlink oracle price for a symbol. If timestamp_ms is provided, returns the closest price at or before that time. If omitted, returns the latest price. Historical lookups are available immediately for recent markets. New prices are added continuously. Symbol matching is case-insensitive and also accepts slash pairs like "bnb/usd".

-- Latest price
local btc = pyx.get_chainlink_price("BTC")
if btc then
    pyx.log(string.format("BTC: $%.2f", btc.price))
end

-- Price at a specific time (e.g. market start)
local start_ms = 1772143200000
local btc_at_start = pyx.get_chainlink_price("BTC", start_ms)
if btc_at_start then
    pyx.log(string.format("BTC at start: $%.2f", btc_at_start.price))
end
ParamTypeDescription
symbolstringAsset symbol
timestamp_msnumber?Optional timestamp (ms since epoch). If omitted, returns latest price

Supported symbols: "BTC", "ETH", "SOL", "XRP", "BNB", "DOGE", "HYPE"

Returns a table or nil if no price is available:

FieldTypeDescription
pricenumberUSD price from Chainlink oracle
timestampnumberPrice timestamp (ms since epoch)

Chainlink prices are sourced from Polygon on-chain oracle contracts and update roughly every 27 seconds. These are the same price feeds used by Polymarket to determine market outcomes.


Funding Rates

pyx.get_funding_rate_history(symbol)

Returns recent perpetual funding rate history for a symbol. Symbol matching is case-insensitive. Returns nil when the symbol is unknown or when no funding history is available yet. Data is sourced from Binance funding history.

Binance funding rates change and settle every eight hours.

local history = pyx.get_funding_rate_history("BTC")
if history then
    local latest = history[#history]
    pyx.log(string.format(
        "%s funding=%.8f mark=%.2f at %d",
        latest.symbol,
        latest.funding_rate,
        latest.mark_price,
        latest.funding_time
    ))
end
ParamTypeDescription
symbolstringAsset symbol

Supported symbols: "BTC", "ETH", "SOL", "XRP", "BNB", "DOGE", "HYPE"

Returns an array of tables or nil:

FieldTypeDescription
symbolstringSymbol
funding_ratenumberFunding rate value for the interval
mark_pricenumberMark price for the interval
timestampnumberFunding event timestamp (ms since epoch)

Utility

pyx.clock_ms()

Returns the current wall-clock time in milliseconds since Unix epoch.

-- Instrument your hot path to catch slow callbacks
function on_price(ctx)
    local t0 = pyx.clock_ms()

    -- ... your strategy logic ...

    local elapsed = pyx.clock_ms() - t0
    if elapsed > 2 then
        pyx.log(string.format("on_price slow: %.1fms", elapsed))
    end
end
-- Rate-limit expensive operations
local last_rebalance_ms = 0
local REBALANCE_COOLDOWN_MS = 5000

function on_price(ctx)
    local now = pyx.clock_ms()
    if (now - last_rebalance_ms) < REBALANCE_COOLDOWN_MS then return end
    last_rebalance_ms = now

    -- ... expensive rebalance logic ...
end

Returns number.

pyx.log(message)

pyx.warn(message)

pyx.error(message)

Write a log entry. Visible in the task's log stream on the dashboard.

pyx.log("Strategy initialized")
pyx.log(string.format("Spread: %.4f", ctx.spread))
ParamTypeDescription
messagestringLog message

Logs are rate-limited. Avoid logging on every price update in production - use it for meaningful events.

On this page