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")| Param | Type | Description |
|---|---|---|
token_id | string | The token to buy |
condition_id | string | The market condition |
price | number | Limit price (0–1 for binary markets) |
size | number | Quantity in contracts |
post_only | boolean? | If true, reject orders that would cross the spread instead of executing them |
snap_direction | string? ("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
endpyx.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| Param | Type | Description |
|---|---|---|
order_id | string | Exchange order ID to cancel |
Returns boolean.
true: cancel request was accepted by the runtime and queued for executionfalse: 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))
endReturns a table or nil if no position exists:
| Field | Type | Description |
|---|---|---|
qty | number | Current quantity (positive = long) |
avg_cost | number | Weighted average cost basis |
realized_pnl | number | Realized 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)
endReturns a table { [token_id] = position } where each position has:
| Field | Type | Description |
|---|---|---|
qty | number | Current quantity |
avg_cost | number | Weighted average cost |
realized_pnl | number | Realized P&L |
total_bought_qty | number | Total bought quantity (lifetime) |
total_sold_qty | number | Total 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)| Param | Type | Description |
|---|---|---|
condition_id | string | The market condition ID to split |
amount | number | Amount 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)| Param | Type | Description |
|---|---|---|
condition_id | string | The market condition ID to merge |
amount | number | The 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 tokenReturns 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))
endReturns an array of tables:
| Field | Type | Description |
|---|---|---|
order_id | string | Exchange order ID |
token_id | string | Token |
side | string | "buy" or "sell" |
price | number | Limit price |
size | number | Order size |
placed_at | number | Timestamp (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)
endReturns an array of tables:
| Field | Type | Description |
|---|---|---|
client_id | string | Internal tracking ID |
order_id | string | Exchange order ID (may be empty if not yet assigned) |
token_id | string | Token |
side | string | "buy" or "sell" |
price | number | Limit price |
size | number | Order 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() - spendReturns number.
Spot Prices
pyx.subscribe_spot(symbols)
Subscribe to Binance spot price updates for the given symbols.
pyx.subscribe_spot({"BTC", "ETH"})| Param | Type | Description |
|---|---|---|
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| Param | Type | Description |
|---|---|---|
symbol | string | Symbol name (e.g. "BTC") |
Returns a table or nil:
| Field | Type | Description |
|---|---|---|
symbol | string | Symbol name |
bid | number | Best bid price |
ask | number | Best ask price |
bid_qty | number | Best bid size |
ask_qty | number | Best ask size |
mid | number | Midpoint (bid + ask) / 2 |
timestamp | number | Receipt time (ms since epoch) |
Chainlink Prices
pyx.get_chainlink_price(symbol, timestamp_ms?)
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| Param | Type | Description |
|---|---|---|
symbol | string | Asset symbol |
timestamp_ms | number? | 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:
| Field | Type | Description |
|---|---|---|
price | number | USD price from Chainlink oracle |
timestamp | number | Price 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 ...
endReturns 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))| Param | Type | Description |
|---|---|---|
message | string | Log message |
Logs are rate-limited. Avoid logging on every price update in production - use it for meaningful events.