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)

Enqueue a limit buy order.

pyx.buy("abc123", "0xcondition", 0.45, 0.10, false, "up")
ParamTypeDescription
token_idstringThe token to buy
condition_idstringThe market condition
pricenumberLimit price (0–1 for binary markets)
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

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.

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

Enqueue a limit 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)

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

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"

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")

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)

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.

-- 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"

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.


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