# Price across a range of trade sizes Source: https://docs.ostium.com/api-reference/liquidity/price-across-a-range-of-trade-sizes /api-reference/openapi.json get /v1/depth/{pair} The same impact model as `/v1/depth/{pair}/quote`, walked into a ladder so it reads like an order book. `asks` is buying (long), `bids` is selling (short); both ascend in notional out to `maxNotionalUsd`. `cumSizeUsd` is **cumulative**: each level prices one trade of that full size, not an increment on the level below. Summing levels is meaningless. `maxNotionalUsd` is the pair's max open interest, or its current OI where that is larger — the same extent the trading UI's depth chart draws. `levels` only sets sampling density. The underlying curve is piecewise linear — flat until volume crosses the pair's threshold, then a straight line — so a higher count draws a smoother chart but adds almost no information. Some pairs return one repeated price, when their threshold exceeds their own OI cap. Either pair spelling is accepted, as with the quote route. Rate limit: 100 requests per 10 seconds per IP. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # Price for a given trade size Source: https://docs.ostium.com/api-reference/liquidity/price-for-a-given-trade-size /api-reference/openapi.json get /v1/depth/{pair}/quote Ostium has no central-limit order book. The price a trade actually gets comes from the **dynamic price-impact model**: quotes widen as net directional volume pushes past a per-pair threshold, and that volume decays over time. This prices a given size against the live model — the same one behind the trading UI's depth chart — so you can show a fill price before submitting. `sizeUsd` is **USD notional**, not collateral and not a quantity of the asset. There is no `direction` input: the model reads buy volume for a long and sell volume for a short, so the two sides can diverge after a large one-sided trade, and `availableNotionalUsd` differs between them at all times. Both are always returned. Either pair spelling is accepted (`US500-USD` or the legacy `SPX-USD`); the response always echoes the public one. A plain GET: read-only, idempotent, and safe to cache for a second or two. **A price is returned even when the size cannot fill.** The impact curve stays defined beyond the open-interest cap, so compare `sizeUsd` against that side's `availableNotionalUsd` before presenting a quote as executable. When a pair has no dynamic impact configured, or the size stays under the pair's volume threshold, `price` is exactly the top of book — the spread is the only cost. Rate limit: 100 requests per 10 seconds per IP. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # Markets Source: https://docs.ostium.com/api-reference/markets What is listed and when it trades. What is listed and when it trades. ### Pairs Every pair on Ostium. Use `id` wherever a request takes a `pairIndex`, and the symbol wherever one takes a `pair`. Do not infer the id from a row's position — read the column. A pair marked `not yet` in **Tradeable** is listed on chain but has no open-interest ceiling, so it cannot be traded and `GET /v1/depth/{pair}` answers `503` for it (the `/quote` sub-resource still prices it, with `availableNotionalUsd: 0`). It is shown rather than hidden so the ids either side of it stay right. Note `GET /v1/pairs` returns the subgraph's own spelling in `from`/`to`, which for renamed assets is the legacy one — `SPX` where this table says `US500`. The table uses the symbol the price and depth endpoints expect. | id | Pair | Tradeable | | - | - | - | | 0 | `BTC-USD` | yes | | 1 | `ETH-USD` | yes | | 2 | `EUR-USD` | yes | | 3 | `GBP-USD` | yes | | 4 | `USD-JPY` | yes | | 5 | `XAU-USD` | yes | | 6 | `XCU-USD` | yes | | 7 | `WTI-USD` | yes | | 8 | `XAG-USD` | yes | | 9 | `SOL-USD` | yes | | 10 | `US500-USD` | yes | | 11 | `US30-USD` | yes | | 12 | `US100-USD` | yes | | 13 | `JP225-JPY` | yes | | 14 | `UK100-GBP` | yes | | 15 | `GER40-EUR` | yes | | 16 | `USD-CAD` | yes | | 17 | `USD-MXN` | yes | | 18 | `NVDA-USD` | yes | | 19 | `GOOG-USD` | yes | | 20 | `AMZN-USD` | yes | | 21 | `META-USD` | yes | | 22 | `TSLA-USD` | yes | | 23 | `AAPL-USD` | yes | | 24 | `MSFT-USD` | yes | | 25 | `USD-CHF` | yes | | 26 | `AUD-USD` | yes | | 27 | `NZD-USD` | yes | | 28 | `XPD-USD` | yes | | 29 | `XPT-USD` | yes | | 30 | `HK50-HKD` | yes | | 31 | `COIN-USD` | yes | | 32 | `HOOD-USD` | yes | | 33 | `MSTR-USD` | yes | | 34 | `CRCL-USD` | yes | | 35 | `BMNR-USD` | yes | | 36 | `SBET-USD` | yes | | 37 | `GLXY-USD` | yes | | 38 | `BNB-USD` | yes | | 39 | `XRP-USD` | yes | | 40 | `TRX-USD` | yes | | 41 | `HYPE-USD` | yes | | 42 | `LINK-USD` | yes | | 43 | `ADA-USD` | yes | | 44 | `PLTR-USD` | yes | | 45 | `AMD-USD` | yes | | 46 | `NFLX-USD` | yes | | 47 | `ORCL-USD` | yes | | 48 | `RIVN-USD` | yes | | 49 | `COST-USD` | yes | | 50 | `XOM-USD` | yes | | 51 | `CVX-USD` | yes | | 52 | `URA-USD` | yes | | 53 | `USD-KRW` | not yet | | 54 | `KR2550-USD` | yes | | 55 | `BRENT-USD` | yes | | 56 | `GEV-USD` | yes | | 57 | `SHEL-USD` | yes | | 58 | `UNG-USD` | yes | | 59 | `XLE-USD` | yes | | 60 | `ARM-USD` | yes | | 61 | `ASML-USD` | yes | | 62 | `AVGO-USD` | yes | | 63 | `CAT-USD` | yes | | 64 | `INTC-USD` | yes | | 65 | `SMCI-USD` | yes | | 66 | `TSM-USD` | yes | | 67 | `MU-USD` | yes | | 68 | `SNDK-USD` | yes | | 69 | `HYG-USD` | yes | | 70 | `TLT-USD` | yes | | 71 | `MP-USD` | yes | | 72 | `DRAM-USD` | yes | | 73 | `REMX-USD` | yes | | 74 | `BB-USD` | yes | | 75 | `CRWV-USD` | yes | | 76 | `DELL-USD` | yes | | 77 | `MRNA-USD` | yes | | 78 | `MRVL-USD` | yes | | 79 | `NBIS-USD` | yes | | 80 | `LLY-USD` | yes | | 81 | `SKHY-USD` | yes | | 82 | `SPCX-USD` | yes | # Every listed pair and its live state Source: https://docs.ostium.com/api-reference/markets/every-listed-pair-and-its-live-state /api-reference/openapi.json get /v1/pairs What is tradeable, and the limits that apply to it. Use it to build a market list, or to check leverage bounds and remaining capacity before sending an order. **`id` is the `pairIndex`** an order intent signs — this endpoint is where you get it. Do not derive it by counting rows in a table. Two names per pair, deliberately. `from`/`to` are the subgraph's spelling, which for nine renamed instruments is the legacy one (`SPX`, `CL`, `HG`); `symbol` is what the price and depth endpoints expect (`US500-USD`, `WTI-USD`, `XCU-USD`). Join on `symbol`. This is the on-chain view. For the bid/mid/ask a trade would price against use `GET /v1/prices`; for what a given size actually costs use `GET /v1/depth/{pair}/quote`. ### Reading a pair ```json { "from": "BTC", "to": "USD", "maxLeverage": 100, "minLeverage": 1, "lastTradePrice": 78502.04, "longOIInUnits": 0.783, "maxOIInUsd": 6000000, "totalOpenTrades": "182" } ``` **Open interest and its cap are on different scales.** `longOIInUnits` and `shortOIInUnits` are quantities of the base asset; `maxOIInUsd` is a USD ceiling. To compare them, multiply the unit figures by `lastTradePrice` first — here 0.783 BTC is about $61k against a $6M cap. `maxLeverage` is the limit that actually applies to this pair: most pairs inherit their group's, and the few that are capped lower override it. `minLeverage` comes from the group. `from`/`to` are the subgraph's spelling, which for renamed assets is the legacy one — `SPX`, where every other endpoint says `US500`. Rate limit: 60 requests per 10 seconds per IP. This budget is **shared across `/v1/pairs`, `/v1/trades`, `/v1/limits` and `GET /v1/orders`**, not counted per path. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # When each market is open Source: https://docs.ostium.com/api-reference/markets/when-each-market-is-open /api-reference/openapi.json get /v1/market-hours When each market is tradeable. Returns `schedules` (unique schedule definitions keyed by numeric id), `markets` (pair symbol → schedule id), and `lastUpdated`. `markets` keys are unhyphenated and always the current pair name: look up `US500USD`, not `US500-USD` and not the legacy `SPXUSD`. Use it to show opening hours, day-trading windows and holidays without hard-coding session rules per asset class — equities, FX and crypto differ, and a schedule may be `alwaysOpen`. Several pairs usually share one schedule, hence the two-part shape: look the pair up in `markets`, then read that id from `schedules`. For whether a market is open *right now*, prefer the `isMarketOpen` and `isDayTradingClosed` fields on a price tick — this endpoint describes the calendar, not live state. Schedules change rarely, so cache the response and refresh periodically rather than per request. Rate limit: 100 requests per 10 seconds per IP. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # One-time onboarding (gasless) Source: https://docs.ostium.com/api-reference/orders/one-time-onboarding-gasless /api-reference/openapi.json post /v1/onboard A one-time setup step, done gaslessly. Sign two EIP-712 messages offline, post the signatures here, and we relay them on chain and pay for it — the partner never sends a transaction or needs ETH. Restricted to allowlisted partner addresses. Contact us before integrating. Send whichever parts you still need; at least one. They are relayed as a single atomic batch, so you are never left with an allowance but no delegate. The response reads both values back from chain, so `state.missing` reflects what is actually set rather than what we submitted. ### The two signatures **`delegation`** lets the OstiumAtomicTrading wrapper place trades for you. - Domain: `{ name: "Ostium", version: "1", chainId, verifyingContract: }` - Type: `OstiumDelegation(address delegator, address delegate, uint256 nonce, uint256 expiry)` - The verifying contract is **Trading**, but `delegate` is the **wrapper** — it is the contract that will call Trading for you, so it is what Trading checks. Sending anything else is rejected. **`permit`** grants the USDC allowance (ERC-2612). - Domain: `{ name, version, chainId, verifyingContract: }` - Type: `Permit(address owner, address spender, uint256 value, uint256 nonce, uint256 deadline)` - `spender` is **TradingStorage**, not Trading — different contracts. - Read `name` and `version` from the token itself; they differ between deployments and a wrong domain produces a signature that fails on chain. Both nonces come from the chain at signing time — `Trading.delegatableNonces(partner)` and `USDC.nonces(partner)`. ### Addresses | | Arbitrum (42161) | Arbitrum Sepolia (421614) | | --- | --- | --- | | Trading | `0x6D0bA1f9996DBD8885827e1b2e8f6593e7702411` | `0x2A9B9c988393f46a2537B0ff11E98c2C15a95afe` | | TradingStorage (permit spender) | `0xccd5891083a8acd2074690f65d3024e7d13d66e7` | `0x0b9F5243B29938668c9Cfbd7557A389EC7Ef88b8` | | USDC | `0xaf88d065e77c8cc2239327c5edb3a432268e5831` | `0xe73B11Fb1e3eeEe8AF2a23079A4410Fe1B370548` | | OstiumAtomicTrading (delegate) | `0x5eB3960C3fd3274cD81fE5972e0de01084bDa325` | `0x32C06a3eC2A40DABf6A8f645f29321cB7236DAA3` | ### Two cases where you send only one half **On Arbitrum Sepolia there is no permit.** The test token is a plain ERC-20 with no `permit` or `nonces`, so no permit signature exists for it. Send `approve(, )` from the wallet, then post `delegation` alone. Mainnet USDC does implement ERC-2612. **A contract wallet can permit but not delegate.** `setDelegateWithSignature` uses `ecrecover`, which no EIP-1271 signature satisfies. Call `Trading.setDelegate()` from the wallet, then post `permit` alone. ### Notes - **Keep `expiry` and `deadline` short** — 30 minutes is plenty. Until one passes, anyone holding the signature can relay it. They cannot redirect it: `delegate`, `spender` and `value` are all inside the signed bytes. - **Numbers are decimal strings**, never JSON numbers. A uint256 nonce or a max allowance exceeds `Number.MAX_SAFE_INTEGER`, and a rounded value no longer matches what you signed. Rate limit: 10 requests per 10 seconds per IP. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # Submit an order Source: https://docs.ostium.com/api-reference/orders/submit-an-order /api-reference/openapi.json post /v1/orders One endpoint, three actions. `type` picks between opening a position, closing one (fully or partially), and withdrawing collateral from one. Pick the variant in the request body below to see the fields each needs. ### Reading the response **`status` is the answer, not the HTTP code.** A `200` means the order was submitted and settled; `status` says how it settled: | `status` | What happened | | --- | --- | | `filled` | It executed. `execution` carries the `tradeId` and the resulting amounts. | | `reverted` | It reached the chain and changed nothing. `reason` says why. | ### Signing Every intent is an EIP-712 signature under this domain: ```json { "name": "OstiumAtomicTrading", "version": "1", "chainId": 42161, "verifyingContract": "0x5eB3960C3fd3274cD81fE5972e0de01084bDa325" } ``` On Arbitrum Sepolia (`421614`) it is a different contract, so the domain differs too: ```json { "name": "OstiumAtomicTrading", "version": "1", "chainId": 421614, "verifyingContract": "0x32C06a3eC2A40DABf6A8f645f29321cB7236DAA3" } ``` The struct you sign is the `intent` object itself, and its `primaryType` is named after the `type` you send: | `type` | `primaryType` | | --- | --- | | `open` | `OpenIntent` | | `close` | `CloseIntent` | | `removeCollateral` | `RemoveCollateralIntent` | Declare the fields in the order the request body lists them, **and with exactly these solidity widths**. EIP-712 hashes the field names AND types into a single typehash, so a different order — or `uint256` where the contract says `uint192` — is a different type: the digest changes and the contract cannot match your signature. The JSON schema below shows `string` and `integer`, which cannot express the widths, so take them from here: ``` OpenIntent(uint256 collateral,uint192 openPrice,uint192 tp,uint192 sl,address trader, uint32 leverage,uint16 pairIndex,bool buy,bool isDayTrade,address builder, uint32 builderFee,uint256 slippageP,uint256 nonce,uint256 deadline) CloseIntent(address trader,uint16 pairIndex,uint8 index,uint256 tradeId, uint16 closePercentage,uint192 marketPrice,uint32 slippageP,uint256 nonce, uint256 deadline) RemoveCollateralIntent(address trader,uint16 pairIndex,uint8 index,uint256 tradeId, uint256 removeAmount,uint256 nonce,uint256 deadline) ``` (Line breaks above are for reading only — the canonical type string has none.) As a viem `signTypedData` call: ```ts await account.signTypedData({ domain, // the OstiumAtomicTrading domain above primaryType: 'OpenIntent', types: { OpenIntent: [ { name: 'collateral', type: 'uint256' }, { name: 'openPrice', type: 'uint192' }, { name: 'tp', type: 'uint192' }, { name: 'sl', type: 'uint192' }, { name: 'trader', type: 'address' }, { name: 'leverage', type: 'uint32' }, { name: 'pairIndex', type: 'uint16' }, { name: 'buy', type: 'bool' }, { name: 'isDayTrade', type: 'bool' }, { name: 'builder', type: 'address' }, { name: 'builderFee', type: 'uint32' }, { name: 'slippageP', type: 'uint256' }, { name: 'nonce', type: 'uint256' }, { name: 'deadline', type: 'uint256' }, ], }, message: intent, }); ``` To check your work without spending anything, the wrapper exposes `hashOpenIntent`, `hashCloseIntent` and `hashRemoveCollateralIntent` as view functions — a local digest that matches those is a signature the contract will accept. Sign as `trader`: an EOA, or a contract wallet that answers EIP-1271. **One trap the schema cannot warn you about.** `slippageP` is a `uint256` on `OpenIntent` but a `uint32` on `CloseIntent`. The contract types them differently, and signing the wrong width silently changes the digest. ### Limits Checked before anything is submitted, and tighter than the contract itself — an intent the contract would accept can still be refused here: | Field | Allowed | Meaning | | --- | --- | --- | | `slippageP` | `0 < slippageP ≤ 100` | scaled by 10000, so `100` is 1% — the most you can tolerate | | `closePercentage` | `0 < closePercentage ≤ 10000` | scaled by 10000, so `10000` is 100% and `5000` is half | | `deadline` | `now < deadline ≤ now + 60s` | unix seconds | Both percentages use the same base of **10000**. Neither may be `0`: a zero `slippageP` cannot fill, and the protocol reads a zero `closePercentage` as a *full* close. ### Before your first order The trader must be an allowlisted partner, and onboarded once per chain through `POST /v1/onboard`. Without the delegation an order reaches the chain and reverts as `NotDelegate`. ### Field notes - **Send amounts as strings of plain digits** — `"50000000"`, not `5e7` or `50000000`. They are too large for a JSON number, and rounding one changes the digest. - **Addresses can be any casing.** Checksummed, lowercase or uppercase all work. - **Every field is signed**, `builder` and `builderFee` included. Nothing can be added or altered between you and the contract. Rate limit: 30 requests per 10 seconds per IP. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # Overview Source: https://docs.ostium.com/api-reference/overview Ostium Builder API: endpoints, rate limits, errors, and the full market list. REST API for the Ostium Builder SDK and integrating partners: live prices, depth, OHLC, and market hours. ## Authentication **None required today.** ## Quick start 1. **Snapshot** — `GET /v1/prices` (or `GET /v1/prices/{pair}`) for an initial board. 2. **Stream** — connect to `WS /v1/prices/stream` for live ticks — see the **Price Stream** section. 3. **Candles** — `POST /v1/ohlc` for historical OHLC. 4. **Sessions** — `GET /v1/market-hours` for calendars (cache it; use tick flags for “open right now”). The pair list is under **Markets**. 5. **Depth** — `GET /v1/depth/{pair}/quote` for the price a given size actually gets. 6. **Status** — `GET /v1/status` to check the price feed is live before relying on quotes. Typed clients: use `@ostium/builder-sdk`, or generate one from this document with any OpenAPI 3.1 client generator. ## Rate limits Applied per IP. Most limits are per route; where a group of endpoints shares one budget the endpoint's own description says so. Every rate-limited response carries `x-ratelimit-limit`, `x-ratelimit-remaining`, and `x-ratelimit-reset`; 429s add `retry-after`. **Read the headers** — do not hard-code the documented figures. ## Errors Two envelopes: * **Framework** — `{ "error": "", "message": "..." }` (optional `issues` / `details`). * **Upstream proxy** — `{ "error": "" }` from OHLC failures. `error` means different things across the two shapes — do not switch on it alone until a future major version unifies them. Every response carries `x-request-id`. Quote it when reporting a problem. ## Hosts Each chain is served by exactly one host, because an environment's oracle publishers are only registered against its own chain's verifier. Sending a chain to the other host is refused with a 400 naming the one that works. * Production (Arbitrum One, `chainId` 42161): `https://builder.prod.bedrock.ostium.io` * Staging (Arbitrum Sepolia, `chainId` 421614): `https://builder.stage.bedrock.ostium.io` Read endpoints — `/v1/pairs`, `/v1/trades`, `/v1/prices`, depth — have no publisher dependency and serve both chains from either host. Only `/v1/orders` is pinned. # Limit/stop orders for a wallet Source: https://docs.ostium.com/api-reference/portfolio/limitstop-orders-for-a-wallet /api-reference/openapi.json get /v1/limits Orders the wallet has placed that have not filled or been cancelled — its resting book. **Nothing here has executed.** These are not positions: when one fills it becomes a position in `GET /v1/trades` and a fill in `GET /v1/orders`, and leaves this list. ### Reading a resting order ```json { "limitType": "STOP", "isBuy": false, "openPrice": 1.16064, "collateral": 302.77, "leverage": 50, "pair": { "id": "2", "from": "EUR", "to": "USD" } } ``` A short on EUR-USD waiting to trigger at 1.16064, which will open with 302.77 USDC at 50x. | `limitType` | Triggers | | --- | --- | | `LIMIT` | When price reaches `openPrice` from the favourable side | | `STOP` | When price breaks through `openPrice` | `stopLossPrice` and `takeProfitPrice` are the exits that will be attached to the position once it opens, and are `0` when unset. Rate limit: 60 requests per 10 seconds per IP. This budget is **shared across `/v1/pairs`, `/v1/trades`, `/v1/limits` and `GET /v1/orders`**, not counted per path. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # Open positions for a wallet Source: https://docs.ostium.com/api-reference/portfolio/open-positions-for-a-wallet /api-reference/openapi.json get /v1/trades What the wallet is holding right now, newest first. A position appears the moment it fills and disappears the moment it closes — its closing fill then shows up in `GET /v1/orders`. ### Reading a position ```json { "tradeID": "151146", "isBuy": true, "openPrice": 77498.43, "collateral": 49.2, "notionalInUsd": 492, "notionalInUnits": 0.00634851, "leverage": 10, "openingFee": 0.8, "pair": { "id": "0", "from": "BTC", "to": "USD" } } ``` A 10x long on BTC-USD: 49.2 USDC of margin controlling 492 USD of exposure, which at an entry of 77,498.43 is 0.00634851 BTC. It cost 0.80 USDC to open. | Field | Means | | --- | --- | | `notionalInUsd` | Position size in USD — `collateral × leverage` | | `notionalInUnits` | The same size as a quantity of the base asset | | `openingFee` | Total charged at open, in USDC | | `builder` / `builderFee` | The builder code the trade was opened with, and its fee | | `isDayTrade` | Opened under day-trade margin, which closes at session end | `tradeID` is the handle you pass back to `POST /v1/orders` to close it. ### Unrealized PnL Each position is also valued against the live mid price: | Field | Means | | --- | --- | | `markPrice` | Mid price the position was valued at | | `unrealizedPnl` | Price PnL, in USDC — capped at +900% / -100% of collateral | | `fundingFee` | Funding accrued so far. Positive is owed by the position | | `rolloverFee` | Rollover accrued so far. Positive is owed by the position | | `netPnl` | `unrealizedPnl - fundingFee - rolloverFee` | | `netPnlPercent` | `netPnl` over collateral, floored at -100% | | `netPnlAfterOpeningFee` | `netPnl - openingFee` | | `netPnlPercentAfterOpeningFee` | Over collateral, not floored | | `netValue` | `collateral + netPnl` | | `liquidationPrice` | Price at which the position liquidates, `null` if underivable | `collateral` is already net of `openingFee`, so use `netPnl` to measure the trade and `netPnlAfterOpeningFee` to measure the deposit. **Funding and rollover are reported as of the pair's last on-chain update** when that update is more than ~50,000 blocks old (roughly 3.5 hours). On a pair that quiet the two fees stop accruing in this response and step forward when the next trade on that pair lands — a close still settles the full amount. This matches what the Ostium UI shows. **Not a close quote.** `markPrice` is the feed mid, not either side of the book, and `netValue` deducts neither the spread nor the closing fee. Price a real close with `GET /v1/depth/{pair}/quote`. **The block may be absent.** When a position cannot be priced — no live price for the pair, or pair data briefly unavailable — all ten fields are omitted rather than returned as `0`, so test for `netPnl` instead of reading a missing block as flat. The position itself is always returned. A closed market still prices, from the last quote before close. Within a present block, `liquidationPrice` is the one field that can independently be `null` (a pair with no leverage cap configured). It is never `0` for that case, because on a long that would read as "only liquidates if the market goes to zero". Rate limit: 60 requests per 10 seconds per IP. This budget is **shared across `/v1/pairs`, `/v1/trades`, `/v1/limits` and `GET /v1/orders`**, not counted per path. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # Order history for a wallet Source: https://docs.ostium.com/api-reference/portfolio/order-history-for-a-wallet /api-reference/openapi.json get /v1/orders Everything that has already happened, newest first: fills of every kind and the orders that were cancelled. Pending orders are excluded — they have not happened yet. ### Narrowing the log | Want | Send | | --- | --- | | Fills only | `isCancelled=false` | | Cancellations only | `isCancelled=true` | | Both | omit `isCancelled` | | One kind of event | `orderAction=Open` | | The last 7 days | `since=` | `orderAction` is one of `Open`, `Close`, `TakeProfit`, `StopLoss`, `Liquidation`, `RemoveCollateral`, `CloseDayTrade`. Bounding by `since` rather than paging by `skip` is the better way through a long history — it is indexed on execution time. ### Reading a fill ```json { "orderAction": "Liquidation", "price": 4511.41, "collateral": 9.4, "leverage": 50, "closePercent": 100, "profitPercent": -73.93, "totalProfitPercent": -100, "amountSentToTrader": 0, "liquidationFee": 2.327023, "pair": { "id": "5", "from": "XAU", "to": "USD" } } ``` A liquidated XAU-USD position: the whole position closed, the trader got nothing back, and 2.33 USDC went to the liquidator. | Field | Means | | --- | --- | | `closePercent` | How much of the position this fill closed — `50` is half, `100` is all | | `profitPercent` | PnL on this fill, as a percentage | | `totalProfitPercent` | PnL on the position as a whole; a liquidation reads `-100` | | `amountSentToTrader` | USDC actually returned to the wallet | | `priceImpactP` | How far the fill moved from mid, as a percentage | Those four are populated on closing fills; on an `Open` they are `0`. Fee fields (`fundingFee`, `rolloverFee`, `closeFee`, `liquidationFee`, `devFee`, `vaultFee`, `oracleFee`) are USDC amounts settled by this fill. Rate limit: 60 requests per 10 seconds per IP. This budget is **shared across `/v1/pairs`, `/v1/trades`, `/v1/limits` and `GET /v1/orders`**, not counted per path. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # Price Stream Source: https://docs.ostium.com/api-reference/price-stream Live prices over a WebSocket. Live prices over a WebSocket. This section is the contract — everything below is what the server actually sends. ### Connecting ``` wss://builder.prod.bedrock.ostium.io/v1/prices/stream?pairs=BTC-USD,ETH-USD ``` `?pairs=` is optional; omit it to receive every asset. No authentication, though the handshake is capped — see **Limits**. Browser clients are subject to an origin allowlist; a rejected upgrade is closed with a bare `403`. ### Server messages One snapshot on connect, carrying the `seq` baseline for every asset: ```json theme={null} { "type": "snapshot", "seq": { "BTC-USD": 41 }, "data": [{ "pair": "BTC-USD", "bid": 1, "mid": 1, "ask": 1 }] } ``` Then one frame per tick: ```json theme={null} { "type": "tick", "seq": 42, "data": { "pair": "BTC-USD", "bid": 1, "mid": 1, "ask": 1 } } ``` `data` is byte-identical to a row from `GET /v1/prices` — `seq` sits on the frame, not inside it, so the tick payload stays the same shape as REST. | `type` | Sent when | | - | - | | `snapshot` | Once, on connect | | `tick` | A price updates | | `gap` | Ticks were dropped for you — precedes the next frame you receive | | `ack` | Your `subscribe`/`unsubscribe` was applied | | `error` | Your message was rejected; the filter is unchanged | ### Client messages ```json theme={null} { "type": "subscribe", "pairs": ["EUR-USD"] } { "type": "unsubscribe", "pairs": ["EUR-USD"] } ``` Every message gets exactly one reply — an `ack` carrying `pairCount` (the number of assets you now receive; `null` is all of them, `0` is none), or an `error` carrying a `code` of `malformed`, `unknown_type`, `invalid_pairs`, `no_filter` or `rate_limited`. ```json theme={null} { "type": "ack", "for": "subscribe", "pairCount": 2 } { "type": "error", "code": "no_filter", "message": "..." } ``` Filters only widen. `subscribe` on an unfiltered connection is a no-op acked with `"pairCount": null` — to narrow, reconnect with `?pairs=`. `unsubscribe` needs a filtered connection and is rejected with `no_filter` otherwise. Unsubscribing your last asset leaves you receiving nothing (`"pairCount": 0`), which `subscribe` recovers without reconnecting. ### Detecting loss Delivery is best effort, but loss is **detectable**. If more than 1 MB is buffered for a slow client, ticks are dropped rather than queued — and you are told: ```json theme={null} { "type": "gap", "dropped": 17 } ``` `seq` is a per-asset counter, so a jump between consecutive `tick` frames for one asset means you missed that many. Baseline each asset from the `snapshot`, then compare. Two limits on what `seq` can tell you. It is **per connection** — process-wide, not global, so it does not survive a reconnect and is not comparable across replicas. And there is **no replay**: the stream tells you that you fell behind, not what you missed, so recover by re-reading `GET /v1/prices`. Assets with no trading schedule are omitted entirely, from the snapshot and from ticks. A missing asset is not a signal that its market is closed. ### Limits Per pod, so the effective ceiling scales with replica count. Read the headers on a rejected upgrade rather than hard-coding these. | Limit | Default | Rejected with | | - | - | - | | Connections per IP | 20 | `429` | | Connections in total | 500 | `503` | | Upgrades per IP per minute | 60 | `429` | | Client messages per socket per minute | 120 | `error`, `code: "rate_limited"` | Rejected upgrades carry `Retry-After`. ### Heartbeat The server pings every 30 seconds and terminates a connection that has not ponged since the previous ping. Browsers pong automatically; other clients need a library that does. On shutdown the server closes with `1001 going away` after draining. # Latest price for every pair Source: https://docs.ostium.com/api-reference/prices/latest-price-for-every-pair /api-reference/openapi.json get /v1/prices A point-in-time snapshot of the most recent bid/mid/ask for every pair. Each entry is the last price received for that pair, so a quiet market returns an older timestamp rather than no price at all. Use it to paint an initial view, to reconcile after a gap, or where a persistent connection is impractical. For continuous updates prefer the WebSocket stream (`/v1/prices/stream`) — polling this endpoint adds latency and burns rate-limit budget for data that is pushed for free. Each tick carries its own `timestampSeconds`; check it per pair rather than relying on the top-level `stale` flag, which reflects the feed as a whole. A `503` means the feed has not delivered any ticks yet — retry rather than fail. Rate limit: 100 requests per 10 seconds per IP. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # Latest price for one pair Source: https://docs.ostium.com/api-reference/prices/latest-price-for-one-pair /api-reference/openapi.json get /v1/prices/{pair} The most recent bid/mid/ask for a single pair, given as `BASE-QUOTE` (e.g. `BTC-USD`). Identical to `/v1/prices` but scoped to one symbol — use it for a single-market view, or for a quick quote before submitting an order, rather than fetching every pair and discarding the rest. A `404` means no price is available for that pair: either the symbol is wrong, or it has not traded since the service started. Check `timestampSeconds` on the tick to judge how fresh the quote is. Rate limit: 100 requests per 10 seconds per IP. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # OHLC candles Source: https://docs.ostium.com/api-reference/prices/ohlc-candles /api-reference/openapi.json post /v1/ohlc Historical candles for one pair over a time range — chart history, and the backfill to sit behind the live stream. `pair` is `BASE-QUOTE` (e.g. `FTSE-GBP`). `resolution` is a candle width in minutes, or `1D` / `1W`. Candle `time` is the open time in Unix **milliseconds**, while the request range is in seconds. Rate limit: 100 requests per 10 seconds per IP. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # Service status Source: https://docs.ostium.com/api-reference/status/service-status /api-reference/openapi.json get /v1/status Whether the API can answer usefully right now — not merely whether it is running. `status` is `ok` while the price feed is delivering ticks; `degraded` when none have arrived yet or the feed has gone quiet past its staleness window. Market data endpoints are unreliable while degraded, and quotes should not be trusted. It is a feed-wide verdict: one actively trading pair keeps it `ok`, so for a single market still check `timestampSeconds` on that pair's tick. Always answers `200`, including when degraded — read `status`, not the HTTP code. Poll it for a health widget or before a batch job; it is not a substitute for checking `timestampSeconds` on the tick you actually trade on. Rate limit: 60 requests per 10 seconds per IP. Read `x-ratelimit-*` for the live budget rather than assuming this figure. # GET /v1/prices Source: https://docs.ostium.com/developer/builder-api/get-prices Fetch the current Ostium live price snapshot directly from the Builder API. ```bash theme={null} curl https://builder.prod.bedrock.ostium.io/v1/prices ``` The response includes: * `feed_id` * `pair` * `from` * `to` * `bid` * `mid` * `ask` * `isMarketOpen` * `isDayTradingClosed` * `secondsToToggleIsDayTradingClosed` * `timestampSeconds` * `schedule` SDK equivalent: ```ts theme={null} const { prices } = await client.getAllPrices(); ``` ## Response schema ```ts theme={null} interface PairSchedule { id: number; alwaysOpen?: boolean; timezone?: string; openingHours?: string[]; } interface Response { prices: Array<{ feed_id: string; pair: string; from: string; to: string; bid: number; mid: number; ask: number; isMarketOpen: boolean; isDayTradingClosed: boolean; secondsToToggleIsDayTradingClosed: number; timestampSeconds: number; schedule?: PairSchedule; }>; stale: boolean; generatedAt: number; } ``` # Builder API Overview Source: https://docs.ostium.com/developer/builder-api/overview Use the Builder API directly for live prices, candles, and streaming, or consume the same data through the Builder SDK. Base URL: ```text theme={null} https://builder.prod.bedrock.ostium.io ``` Market-data endpoints: * `GET /v1/prices` * `POST /v1/ohlc` * `WS /v1/prices/stream` SDK-managed endpoints: * `POST /v1/trade` for fire-and-forget trade attribution * `/v1/subgraph/gn` as the default mainnet GraphQL subgraph endpoint * `POST /v1/pimlico/sponsor?chainId=42161` for mainnet gasless UserOperation sponsorship * `POST /v1/pimlico/sponsor?chainId=421614` for testnet gasless UserOperation sponsorship SDK wrappers: * `getAllPrices()` * `getCandles()` * `streamPrices()` * `getPairs()`, `getOrders()`, `getBuilderOrders()`, and other read methods through the default subgraph * `openTrade()`, `closeTrade()`, and other Trading-contract submissions report to `POST /v1/trade` in the background # POST /v1/pimlico/sponsor Source: https://docs.ostium.com/developer/builder-api/pimlico-sponsor Default Pimlico-compatible sponsorship endpoints used by SDK gasless modes. Gasless SDK modes use a Pimlico-compatible bundler/paymaster endpoint by default. Mainnet: ```text theme={null} https://builder.prod.bedrock.ostium.io/v1/pimlico/sponsor?chainId=42161 ``` Testnet: ```text theme={null} https://builder.prod.bedrock.ostium.io/v1/pimlico/sponsor?chainId=421614 ``` ## SDK usage The default is applied when you create a gasless client without a custom `pimlicoUrl`. ```ts theme={null} const client = await OstiumClient.createDelegatedAndGasless({ delegatePrivateKey: process.env.DELEGATE_PRIVATE_KEY as `0x${string}`, traderAddress: '0xTraderAddress', }); ``` Override it when you want to use a different ERC-4337 bundler/paymaster endpoint. ```ts theme={null} const client = await OstiumClient.createSelfAndGasless({ traderPrivateKey: process.env.TRADER_PRIVATE_KEY as `0x${string}`, pimlicoUrl: 'https://your-bundler.example.com', }); ``` This endpoint is used internally by the SDK submitter for gasless UserOperations. Non-gasless modes do not call it. # POST /v1/ohlc Source: https://docs.ostium.com/developer/builder-api/post-ohlc Fetch OHLC candles directly from the Builder API. ```bash theme={null} curl https://builder.prod.bedrock.ostium.io/v1/ohlc \ -H 'Content-Type: application/json' \ -d '{ "pair": "BTC-USD", "fromTimestampSeconds": 1711929600, "toTimestampSeconds": 1714521600, "resolution": "1D" }' ``` SDK equivalent: ```ts theme={null} const candles = await client.getCandles({ pairId: 0, from: Date.now() - 30 * 24 * 60 * 60 * 1000, resolution: '1D', sets: 3, }); ``` `sets` is SDK-side pagination. The direct Builder API response includes `lastRequestTimestamp`; the SDK handles repeated requests and returns one flattened candle array. ## Request schema ```ts theme={null} interface Request { pair: string; fromTimestampSeconds: number; toTimestampSeconds: number; resolution: '1' | '5' | '15' | '60' | '240' | '1D'; } ``` ## Response schema ```ts theme={null} interface Response { data: Array<{ from: string; to: string; time: number; open: number; high: number; low: number; close: number; }>; lastRequestTimestamp: number | null; } ``` # POST /v1/trade Source: https://docs.ostium.com/developer/builder-api/post-trade Report an Ostium trading transaction hash to the Builder API for SDK usage attribution. The SDK sends this request in the background after any successful submission that targets the Ostium Trading contract. ```bash theme={null} curl https://builder.prod.bedrock.ostium.io/v1/trade \ -H 'Content-Type: application/json' \ -d '{ "hash": "0xTransactionHash" }' ``` ## Request schema ```ts theme={null} interface Request { hash: `0x${string}`; } ``` ## SDK behavior `OstiumClient` sends this as a fire-and-forget attribution request. The SDK does not wait for the response, does not inspect the response body, and swallows failures so attribution can never block or change trading behavior. # /v1/subgraph/gn Source: https://docs.ostium.com/developer/builder-api/subgraph Default mainnet GraphQL subgraph endpoint used by @ostium/builder-sdk read methods. The SDK uses this as the default mainnet subgraph endpoint: ```text theme={null} https://builder.prod.bedrock.ostium.io/v1/subgraph/gn ``` It backs read methods such as: * `getPairs()` * `getOpenPositions()` * `getOpenOrders()` * `getOrders()` * `getBuilderOrders()` * `getFills()` * `getFillsByTime()` * `getSimSlippage()` * `getSimOrderbook()` ## SDK configuration Override the endpoint with `subgraphUrl` when creating the client. ```ts theme={null} const client = await OstiumClient.createReadOnly({ subgraphUrl: 'https://your-subgraph.example.com/graphql', }); ``` For direct GraphQL usage, use the SDK reference pages as the response-shape source of truth for each read method. # WS /v1/prices/stream Source: https://docs.ostium.com/developer/builder-api/ws-prices-stream Subscribe to live Ostium price updates directly through the Builder API WebSocket feed. Connect to: ```text theme={null} wss://builder.prod.bedrock.ostium.io/v1/prices/stream ``` Subscribe: ```json theme={null} { "type": "subscribe", "pairs": ["BTC-USD", "ETH-USD"] } ``` SDK equivalent: ```ts theme={null} const stream = client.streamPrices([0, 1]); ``` ## Message schemas Subscribe: ```ts theme={null} interface SubscribeMessage { type: 'subscribe'; pairs: string[]; } ``` Unsubscribe: ```ts theme={null} interface UnsubscribeMessage { type: 'unsubscribe'; pairs: string[]; } ``` Snapshot: ```ts theme={null} interface SnapshotMessage { type: 'snapshot'; data: PriceTick[]; } ``` Tick: ```ts theme={null} interface TickMessage { type: 'tick'; data: PriceTick; } interface PairSchedule { id: number; alwaysOpen?: boolean; timezone?: string; openingHours?: string[]; } interface PriceTick { feed_id: string; pair: string; from: string; to: string; bid: number; mid: number; ask: number; isMarketOpen: boolean; isDayTradingClosed: boolean; secondsToToggleIsDayTradingClosed: number; timestampSeconds: number; schedule?: PairSchedule; } ``` # Getting keys from the App Source: https://docs.ostium.com/developer/builders/getting-keys-from-the-app Use the Ostium app to generate a delegated gasless SDK account and export the delegate private key for Builder SDK integrations. Use the Ostium app export flow here: [app.ostium.com/sdk-export](https://app.ostium.com/sdk-export) That page creates a delegated gasless SDK setup in the browser: * it generates a fresh delegate private key locally in the browser * it asks the trader to approve USDC once * it registers the derived Safe as the trader's on-chain delegate After that, the integration can use `createDelegatedAndGasless()`. ## What the app page gives you The export flow shows: * the trader address * the derived smart-account address * the registration status and timestamp * a ready-to-copy Builder SDK snippet ## SDK snippet ```ts theme={null} import { OstiumClient } from '@ostium/builder-sdk'; const client = await OstiumClient.createDelegatedAndGasless({ delegatePrivateKey: '0xYourDelegateKey', // paste the key you saved in step 2 traderAddress: '0xa02fa4da932f616975f258ce0a9077f8ed3564', // pimlicoUrl is optional — defaults to Ostium's sponsored Pimlico bundler on Arbitrum One // pimlicoUrl: 'https://builder.prod.bedrock.ostium.io/v1/pimlico/sponsor?chainId=42161', // testnet: true, // Arbitrum Sepolia — uses the 421614 sponsor URL when pimlicoUrl is omitted // sponsorshipPolicyId: '...', // optional Pimlico sponsorship policy id // rpcUrl: 'https://arb-mainnet.g.alchemy.com/v2/...', // optional; public Arbitrum RPC for reads if omitted }); ``` The snippet uses a placeholder for the private key. Paste the saved key there and never commit it to source control. ## Flow in the app ### 1. Trader address This is the connected EOA that holds the user's USDC and positions. ### 2. Generate delegate key Ostium generates a fresh private key in the browser. The user must save it because it cannot be recovered later. ### 3. Approve USDC The trader completes a one-time approval so `TradingStorage` can move their USDC for SDK trades. ### 4. Register delegate The app registers the derived Safe smart-account address as the trader's on-chain delegate. ## Why this mode is useful This flow sets the user up for [Delegated + Gasless](/developer/client-modes/delegated-and-gasless): * trades are signed by the delegate * transactions are submitted as sponsored ERC-4337 user operations * the SDK can use Ostium's default Pimlico-compatible sponsor URL when `pimlicoUrl` is omitted Read the [SDK Overview](/developer/sdk/overview) before integrating if you need the full mode model, helper methods, and trading examples. # Builder Set Up Source: https://docs.ostium.com/developer/builders/overview Set up an Ostium builder integration, configure builder fees, and choose the right client mode for your application. This page is the starting point for builder integrations. Builders typically care about two things first: * how to attach builder fees to trades * which client mode matches the way their product handles signing and submission ## Builder fees Builder fees are configured once at client creation and then applied automatically to opening trades sent through that client. * `builder.address` is where your fee share is routed * `builder.feeBps` is the fee amount in basis points * the allowed range is `0` to `50` bps * builder fees apply on open, not on close ```ts theme={null} const client = await OstiumClient.createSelfAndSelf({ traderPrivateKey: userPrivateKey, rpcUrl: process.env.ARB_RPC_URL!, builder: { address: '0xYourBuilderAddress', feeBps: 20, }, }); ``` If you do not want to charge builder fees, omit the `builder` config entirely. You can also override builder settings on a single `openTrade()` call: ```ts theme={null} await client.openTrade({ pairId: 0, buy: true, price: '65000', collateral: '100', leverage: '10', type: OrderType.Market, builder: { address: '0xYourBuilderAddress', feeBps: 10, }, }); ``` For builder-routed order history, use [getBuilderOrders](/developer/reference/get-builder-orders). It includes sibling close, TP, and SL orders on positions opened through the builder. ## Which client mode to use ### Wallet-driven frontend Use `self-self` when the user signs and pays gas in their own wallet. Use `self-gasless` when the user should still own the account but you want gasless trading after one-time setup. This is usually the right fit for: * React apps * embedded trading widgets * client-side wallet integrations ### Backend execution on behalf of users Use `delegated-self` when your backend should sign and submit using a delegate EOA that pays gas. Use `delegated-gasless` when your backend should sign but submit through a Safe user operation. This is usually the right fit for: * managed execution products * server-side order routing * apps that want users to keep custody while your backend handles execution ### Read-only market data Use `createReadOnly()` when you only need prices, pairs, positions, candles, or order history in your app and you do not need transaction building or submission. ## Recommended path * Start with [SDK Overview](/developer/sdk/overview) for the current API surface. * Use [Client Modes](/developer/client-modes/overview) to choose the right mode for your integration. * Use [Getting keys from the App](/developer/builders/getting-keys-from-the-app) if you want users to export a delegated gasless SDK account from `app.ostium.com/sdk-export`. * Use [React Example](/developer/builders/react-quickstart) if your app needs wallet-driven transaction building and live position updates. ## Legacy note If you are maintaining an older Python integration, the old docs are preserved under [Legacy](/developer/legacy/overview), but new integrations should use the current TypeScript SDK. # React Example Source: https://docs.ostium.com/developer/builders/react-quickstart Example React integration using Ostium transaction builders, order polling, and live position updates. This example focuses on a client-side application where your UI builds transactions and the connected wallet signs them. ## Build transaction data for the wallet Create a build-only client using addresses instead of private keys. This lets your app use the SDK to construct the correct calldata without submitting through the SDK. ```ts theme={null} import { OrderType, OstiumClient } from '@ostium/builder-sdk'; const client = await OstiumClient.createSelfAndSelf({ traderAddress: '0xTraderAddress', builder: { address: '0xYourBuilderAddress', feeBps: 20, }, }); ``` Build the trade request: ```ts theme={null} const tx = client.getOpenTradeTx({ pairId: 0, buy: true, price: '65000', collateral: '100', leverage: '5', type: OrderType.Market, }); ``` If `tx.kind === 'eoa'`, pass it to the wallet: ```ts theme={null} await window.ethereum.request({ method: 'eth_sendTransaction', params: [ { from: tx.from, to: tx.to, data: tx.data, value: `0x${tx.value.toString(16)}`, }, ], }); ``` The same pattern works for `getCloseTradeTx()`, `getModifyOrderTx()`, `getCancelOrderTx()`, and `getUpdateCollateralTx()`. ## Stream live position updates Fetch the current positions once, then stream price-driven updates over WebSocket. ```ts theme={null} const positions = await client.getOpenPositions({ user: '0xTraderAddress' }); const stream = client.streamPositionUpdates(positions); stream.onUpdate(next => { renderMarginSummary(next.marginSummary); renderPositions(next.pairPositions); }); stream.onError(error => { console.error('position stream error', error); }); ``` The stream only subscribes to the unique `pairId` values present in the current positions response, so it is usually lighter than subscribing to the full price feed. ## Poll trade status after wallet submission Once a wallet sends the transaction, poll `getOrders()` by `initiatedTxHashes` until the order leaves the pending state. ```ts theme={null} async function pollTrade(txHash: `0x${string}`) { while (true) { const orders = await client.getOrders({ initiatedTxHashes: [txHash] }); const order = orders[0]; if (order && !order.isPending) { return order; } await new Promise(resolve => setTimeout(resolve, 2000)); } } ``` This is the usual pattern for showing submitted, filled, or cancelled state in the UI after a wallet signature flow. # Client Configuration Source: https://docs.ostium.com/developer/client-modes/configuration Every parameter you can pass when initializing an Ostium SDK client — shared options, per-mode fields, and build-only variants. This page is the complete reference for the parameters accepted by the `OstiumClient` factory methods. Every factory returns a `Promise` and is `async`, so always `await` it. ```ts theme={null} import { OstiumClient } from '@ostium/builder-sdk'; const client = await OstiumClient.createSelfAndSelf({ traderPrivateKey: process.env.TRADER_PRIVATE_KEY as `0x${string}`, rpcUrl: process.env.ARB_RPC_URL!, // shared options below are accepted by every write mode testnet: false, slippageBps: 25, builder: { address: '0xBuilderAddress', feeBps: 10 }, alchemyApiKey: process.env.ALCHEMY_API_KEY!, }); ``` ## Shared options (all write modes) These optional fields are accepted by `createSelfAndSelf`, `createSelfAndGasless`, `createDelegatedAndSelf`, and `createDelegatedAndGasless`. | Option | Type | Default | Description | | - | - | - | - | | `testnet` | `boolean` | `false` | Use Arbitrum Sepolia. Switches the contracts, subgraph endpoint, builder API endpoint, and the default Pimlico sponsor URL. See [Testnet](/developer/client-modes/testnet). | | `slippageBps` | `number` | `25` | Default slippage tolerance in basis points (`25` = 0.25%). Used when a call does not pass its own slippage. | | `builder` | `{ address: string; feeBps: number }` | — | Builder fee sharing. `feeBps` is in basis points, range `0`–`50` (0%–0.5%), in steps of `0.01` bps. Can be overridden per `openTrade()` call. | | `subgraphUrl` | `string` | mainnet/testnet subgraph | Override the Ostium subgraph endpoint used by read methods (`getPairs`, `getOpenPositions`, …). Mainnet default is `https://builder.prod.bedrock.ostium.io/v1/subgraph/gn`. | | `builderApiUrl` | `string` | `https://builder.prod.bedrock.ostium.io` | Override the builder API base URL used for live prices, OHLC candles, and the WebSocket price stream. | | `rpcWsUrl` | `string` | — | WebSocket Arbitrum RPC endpoint for [`streamAccountUpdates()`](/developer/reference/stream-account-updates)'s contract-log subscription. Can also be passed per stream call. | | `rpcHttpUrl` | `string` | see below | HTTP RPC endpoint for the account stream's missed-event sweep and block reads. Set it only to send those reads somewhere other than where they go by default. | | `alchemyApiKey` | `string` | — | Alchemy API key for the same stream. Still fully supported — it just builds the Alchemy WebSocket and HTTP URLs for you. | These three are only needed for `streamAccountUpdates()`. Set them at client creation or per stream call, where the per-call value wins. When `rpcHttpUrl` is not set, the sweep and block reads go to the first of these that exists: the Alchemy URL (when `alchemyApiKey` is set), then `rpcUrl`, then the public Arbitrum RPC. Prefer `rpcWsUrl`: the stream makes only standard JSON-RPC calls, so any Arbitrum node works, and no vendor key needs to reach a browser bundle. With neither `rpcWsUrl` nor `alchemyApiKey`, the stream throws `INVALID_CONFIG`. Factories do not pre-fetch the pair list during construction. Pair metadata is loaded lazily by read methods and streams when they need it. Submit-capable gasless factories still derive the Safe address with one `eth_call` unless you pass a known `safeAddress`. ## Submit-capable vs build-only Every write mode can be created two ways: * **Submit-capable** — pass a private key; the SDK signs and submits. * **Build-only** — pass addresses only; use `get*Tx()` to return unsigned transaction data for your own wallet or Safe flow. No key ever touches the SDK. The fields below differ between the two variants of each mode. ## `createSelfAndSelf` The trader EOA owns funds, signs, and pays gas. See [Self + Self](/developer/client-modes/self-and-self). **Submit-capable** | Field | Type | Required | Description | | - | - | - | - | | `traderPrivateKey` | `0x${string}` | Yes | Private key of the trader EOA. Holds USDC, owns positions, pays gas. | | `rpcUrl` | `string` | Yes | Arbitrum One (or Sepolia) RPC URL. | **Build-only** | Field | Type | Required | Description | | - | - | - | - | | `traderAddress` | `0x${string}` | Yes | Trader EOA address. Used to build unsigned EOA transactions. | | `rpcUrl` | `string` | No | RPC URL for reads/simulation. Defaults to the chain's public RPC. | ## `createSelfAndGasless` The trader EOA owns funds and signs; a Safe derived from the key submits gaslessly. See [Self + Gasless](/developer/client-modes/self-and-gasless). **Submit-capable** | Field | Type | Required | Description | | - | - | - | - | | `traderPrivateKey` | `0x${string}` | Yes | Private key of the trader EOA. A Safe is derived from this key to relay trades gaslessly. | | `safeAddress` | `0x${string}` | No | Known Safe smart-account address for this key. Use the value from `client.getSmartAccountAddress()` to skip the derivation call during construction. Deterministic per key and chain. | | `pimlicoUrl` | `string` | No | Pimlico-compatible bundler/paymaster RPC URL. Defaults to the Ostium sponsor URL (`…/v1/pimlico/sponsor?chainId=42161`, or the Sepolia variant on testnet). | | `rpcUrl` | `string` | No | RPC URL for reads/simulation. Defaults to the public Arbitrum RPC. | | `sponsorshipPolicyId` | `string` | No | Pimlico sponsorship policy ID. | **Build-only** | Field | Type | Required | Description | | - | - | - | - | | `traderAddress` | `0x${string}` | Yes | Trader EOA that owns USDC and positions. | | `safeAddress` | `0x${string}` | Yes | Safe smart-account address that will submit delegated calls. | | `rpcUrl` | `string` | No | RPC URL for reads/simulation. Defaults to the chain's public RPC. | ## `createDelegatedAndSelf` A delegate EOA signs and pays gas on behalf of a separate trader. See [Delegated + Self](/developer/client-modes/delegated-and-self). **Submit-capable** | Field | Type | Required | Description | | - | - | - | - | | `delegatePrivateKey` | `0x${string}` | Yes | Private key of the delegate EOA. Signs and pays gas for all transactions. | | `traderAddress` | `0x${string}` | Yes | Trader this delegate acts for. The trader must have called `setDelegate(delegateAddress)`. | | `rpcUrl` | `string` | Yes | Arbitrum One (or Sepolia) RPC URL. | **Build-only** | Field | Type | Required | Description | | - | - | - | - | | `traderAddress` | `0x${string}` | Yes | Trader this delegate acts for. | | `delegateAddress` | `0x${string}` | Yes | Delegate EOA that will submit the transaction. | | `rpcUrl` | `string` | No | RPC URL for reads/simulation. Defaults to the chain's public RPC. | ## `createDelegatedAndGasless` A Safe derived from the delegate key submits sponsored user operations on behalf of the trader. See [Delegated + Gasless](/developer/client-modes/delegated-and-gasless). **Submit-capable** | Field | Type | Required | Description | | - | - | - | - | | `delegatePrivateKey` | `0x${string}` | Yes | Private key of the delegate EOA. A Safe is derived from this key and submits user operations via Pimlico. | | `safeAddress` | `0x${string}` | No | Known Safe smart-account address for the delegate key. Use the value from `client.getSmartAccountAddress()` to skip the derivation call during construction. Deterministic per key and chain. | | `traderAddress` | `0x${string}` | Yes | Trader this delegate acts for. The trader must have called `setDelegate(safeAddress)`, where `safeAddress` is the Safe derived from the delegate key (`client.getSmartAccountAddress()`). | | `pimlicoUrl` | `string` | No | Pimlico bundler/paymaster RPC URL. Defaults to the Ostium sponsor URL (chain-aware). | | `rpcUrl` | `string` | No | RPC URL for reads/simulation. Defaults to the public Arbitrum RPC. | | `sponsorshipPolicyId` | `string` | No | Pimlico sponsorship policy ID. | **Build-only** | Field | Type | Required | Description | | - | - | - | - | | `traderAddress` | `0x${string}` | Yes | Trader this delegate acts for. | | `delegateAddress` | `0x${string}` | Yes | Delegate EOA that owns the Safe. | | `safeAddress` | `0x${string}` | Yes | Safe smart-account address that will submit delegated calls. | | `rpcUrl` | `string` | No | RPC URL for reads/simulation. Defaults to the chain's public RPC. | ## `createReadOnly` No signer, no submitter, no private key. All read methods work; write methods throw `INVALID_CONFIG`. See [Read-only](/developer/client-modes/read-only). | Field | Type | Required | Description | | - | - | - | - | | `rpcUrl` | `string` | No | Arbitrum RPC URL. Defaults to the chain's public RPC. | | `testnet` | `boolean` | No | Use Arbitrum Sepolia. Defaults to `false`. | | `subgraphUrl` | `string` | No | Override the subgraph endpoint. | | `builderApiUrl` | `string` | No | Override the builder API base URL. | | `alchemyApiKey` | `string` | No | Alchemy API key for [`streamAccountUpdates()`](/developer/reference/stream-account-updates). | Read-only clients do not accept `slippageBps` or `builder` — those only apply to write modes that submit or build trades. ## Notes * All factories are `async` — `await` them. * Client creation does not fetch pair metadata from the subgraph. Reads and streams populate that cache lazily. * Mode is inferred from the fields you pass; you don't set `mode` directly. * Builder fee defaults (`builder` at client creation) can be overridden per `openTrade()` call via `builder.address` / `builder.feeBps`. * On `testnet: true`, omitted `pimlicoUrl`, `subgraphUrl`, and `builderApiUrl` resolve to their Sepolia defaults — you can still override any of them. # Delegated + Gasless Source: https://docs.ostium.com/developer/client-modes/delegated-and-gasless Backend-controlled delegated execution with Safe-based gasless submission in the Ostium SDK. `createDelegatedAndGasless()` is the most operationally advanced mode. * the trader EOA owns USDC and positions * a delegate EOA signs the delegated action * the delegate's Safe submits it as a sponsored user operation ## When to use it * backend-driven products that want custody separation and gasless submission * high-volume builder integrations * systems that already operate a Safe or Pimlico flow ## One-time trader setup The trader must approve USDC and register the delegate Safe, not the delegate EOA: ```ts theme={null} await traderClient.approveUsdc('max'); await traderClient.setDelegate('0xDelegateSafeAddress'); ``` You can get that Safe address from `client.getSmartAccountAddress()`. ## Submit-capable client ```ts theme={null} const client = await OstiumClient.createDelegatedAndGasless({ delegatePrivateKey: process.env.DELEGATE_PRIVATE_KEY as `0x${string}`, traderAddress: '0xTraderAddress', pimlicoUrl: 'https://builder.prod.bedrock.ostium.io/v1/pimlico/sponsor?chainId=42161', }); ``` If you already know the Safe address for this delegate key and chain, pass `safeAddress` to skip the SDK's smart-account derivation call during construction: ```ts theme={null} const client = await OstiumClient.createDelegatedAndGasless({ delegatePrivateKey: process.env.DELEGATE_PRIVATE_KEY as `0x${string}`, traderAddress: '0xTraderAddress', safeAddress: '0xDelegateSafeAddress', }); ``` ## Build-only client ```ts theme={null} const client = await OstiumClient.createDelegatedAndGasless({ traderAddress: '0xTraderAddress', delegateAddress: '0xDelegateAddress', safeAddress: '0xDelegateSafeAddress', }); ``` In build-only mode, `get*Tx()` returns a Safe-style request whose call data is already wrapped for delegated execution. ## Parameters | Field | Type | Required | Notes | | - | - | - | - | | `delegatePrivateKey` | `0x${string}` | Submit-capable | Delegate EOA key. A Safe is derived from it and submits via Pimlico. | | `traderAddress` | `0x${string}` | Yes | Trader the delegate acts for. Must have called `setDelegate(safeAddress)` with the derived Safe (`client.getSmartAccountAddress()`). | | `delegateAddress` | `0x${string}` | Build-only | Delegate EOA that owns the Safe. | | `safeAddress` | `0x${string}` | Build-only; optional submit-capable | Required for build-only. Optional with `delegatePrivateKey` when you already know the deterministic Safe address and want to skip derivation. | | `pimlicoUrl` | `string` | Optional | Bundler/paymaster URL. Defaults to the Ostium sponsor URL (chain-aware). | | `rpcUrl` | `string` | Optional | RPC URL for reads/simulation. Defaults to the public RPC. | | `sponsorshipPolicyId` | `string` | Optional | Pimlico sponsorship policy ID. | Plus the shared options (`testnet`, `slippageBps`, `builder`, `subgraphUrl`, `builderApiUrl`, `alchemyApiKey`). See [Client Configuration](/developer/client-modes/configuration). # Delegated + Self Source: https://docs.ostium.com/developer/client-modes/delegated-and-self Backend-controlled delegated execution where a delegate EOA signs and pays gas on behalf of a trader. `createDelegatedAndSelf()` separates the trader from the executor. * the trader EOA owns USDC and positions * a delegate EOA signs each action * the delegate EOA submits the transaction and pays gas ## When to use it * backend systems trading on behalf of users * managed execution products * integrations where users keep custody but your server handles submission ## One-time trader setup Before this mode can trade, the trader must: ```ts theme={null} await traderClient.approveUsdc('max'); await traderClient.setDelegate('0xDelegateAddress'); ``` ## Submit-capable client ```ts theme={null} const client = await OstiumClient.createDelegatedAndSelf({ delegatePrivateKey: process.env.DELEGATE_PRIVATE_KEY as `0x${string}`, traderAddress: '0xTraderAddress', rpcUrl: process.env.ARB_RPC_URL!, }); ``` ## Build-only client ```ts theme={null} const client = await OstiumClient.createDelegatedAndSelf({ traderAddress: '0xTraderAddress', delegateAddress: '0xDelegateAddress', }); ``` In build-only mode, `get*Tx()` returns an EOA request whose calldata is already wrapped for delegated execution. ## Parameters | Field | Type | Required | Notes | | - | - | - | - | | `delegatePrivateKey` | `0x${string}` | Submit-capable | Delegate EOA key. Signs and pays gas. | | `traderAddress` | `0x${string}` | Yes | Trader the delegate acts for. Must have called `setDelegate(delegateAddress)`. | | `delegateAddress` | `0x${string}` | Build-only | Delegate EOA that will submit the transaction. | | `rpcUrl` | `string` | Submit-capable; optional for build-only | Arbitrum RPC URL. Build-only defaults to the public RPC. | Plus the shared options (`testnet`, `slippageBps`, `builder`, `subgraphUrl`, `builderApiUrl`, `alchemyApiKey`). See [Client Configuration](/developer/client-modes/configuration). # Client Modes Source: https://docs.ostium.com/developer/client-modes/overview Choose the correct Ostium SDK mode based on who owns funds, who signs, and whether your app submits transactions or only builds them. The SDK exposes four write-enabled execution modes plus a read-only mode. Each mode answers three questions: * whose address owns the USDC and positions * who signs the transaction payload * whether submission happens as a normal EOA transaction or a gasless Safe user operation ## Mode matrix | Mode | Trader funds live in | Signer | Submitter | Typical use | | - | - | - | - | - | | `self-self` | trader EOA | trader EOA | trader EOA | wallet-driven apps, bots, simple scripts | | `self-gasless` | trader EOA | trader EOA | trader Safe | client apps that want gasless trading after one-time setup | | `delegated-self` | trader EOA | delegate EOA | delegate EOA | backend execution on behalf of users | | `delegated-gasless` | trader EOA | delegate EOA | delegate Safe | gasless backend execution on behalf of users | | `read-only` | n/a | none | none | dashboards, analytics, price and account views | ## Build-only vs submit-capable clients Every mode can be created in two ways: * submit-capable: pass a private key and let the SDK sign and submit * build-only: pass addresses only and use `get*Tx()` to return unsigned transaction data for your own wallet or Safe flow ## Configuration All modes share a common set of optional settings — `testnet`, `slippageBps`, `builder`, `subgraphUrl`, `builderApiUrl`, and `alchemyApiKey` (required for [`streamAccountUpdates()`](/developer/reference/stream-account-updates)). See [Client Configuration](/developer/client-modes/configuration) for the complete parameter reference across every mode, including required fields and build-only variants. ## Choose the right mode * Use [Self + Self](/developer/client-modes/self-and-self) when the trader signs and pays gas directly. * Use [Self + Gasless](/developer/client-modes/self-and-gasless) when the trader still owns the account but you want a gasless UX after setup. * Use [Delegated + Self](/developer/client-modes/delegated-and-self) when your backend executes for users and a delegate EOA pays gas. * Use [Delegated + Gasless](/developer/client-modes/delegated-and-gasless) when your backend executes for users but you want sponsored Safe submission. * Use [Read-only](/developer/client-modes/read-only) when your app only needs data. ## Related * [Client Configuration](/developer/client-modes/configuration) — every parameter accepted by the factory methods. * [Testnet](/developer/client-modes/testnet) explains how `testnet: true` changes the SDK defaults. # Read-only Source: https://docs.ostium.com/developer/client-modes/read-only Use createReadOnly when your app only needs market or account data and does not need to build or submit transactions. `createReadOnly()` is the no-signing, no-submission mode. * no private key * no signer * no transaction building * all read methods available ## When to use it * price widgets * charts and dashboards * analytics tools * account views that display positions, orders, fills, or candles ## Example ```ts theme={null} const client = await OstiumClient.createReadOnly(); const { pairs } = await client.getPairs(); const { prices } = await client.getAllPrices(); const positions = await client.getOpenPositions({ user: '0xTraderAddress' }); ``` For low-latency account snapshots, pass `user` and an Alchemy key: ```ts theme={null} const stream = client.streamAccountUpdates({ user: ['0xTraderAddress'], alchemyApiKey: process.env.ALCHEMY_API_KEY!, }); ``` Write methods throw `INVALID_CONFIG` in this mode. ## Parameters All fields are optional. | Field | Type | Default | Notes | | - | - | - | - | | `rpcUrl` | `string` | public RPC | Arbitrum RPC URL for reads/simulation. | | `testnet` | `boolean` | `false` | Use Arbitrum Sepolia. | | `subgraphUrl` | `string` | mainnet/testnet subgraph | Override the subgraph endpoint. | | `builderApiUrl` | `string` | `https://builder.prod.bedrock.ostium.io` | Override the builder API base URL. | | `alchemyApiKey` | `string` | — | Required only to start [`streamAccountUpdates()`](/developer/reference/stream-account-updates). | Read-only clients do not accept `slippageBps` or `builder`. See [Client Configuration](/developer/client-modes/configuration) for the full reference. # Self + Gasless Source: https://docs.ostium.com/developer/client-modes/self-and-gasless Trader-owned positions with trader signatures and Safe-based gasless submission in the Ostium SDK. `createSelfAndGasless()` keeps custody with the trader EOA but submits trades through a Safe smart account. * the trader EOA owns USDC and positions * the trader EOA signs the underlying trade action * the trader's Safe submits the transaction as a sponsored user operation ## When to use it * consumer apps that want a gasless UX * embedded trading flows where the user should not need ETH after setup * client-side apps that already have a Safe execution path ## One-time setup The trader must do two EOA-signed transactions once: ```ts theme={null} await client.approveUsdc('max'); await client.setupGaslessDelegation(); ``` After that, trading calls can be sent gaslessly through the Safe. ## Submit-capable client ```ts theme={null} const client = await OstiumClient.createSelfAndGasless({ traderPrivateKey: process.env.TRADER_PRIVATE_KEY as `0x${string}`, pimlicoUrl: 'https://builder.prod.bedrock.ostium.io/v1/pimlico/sponsor?chainId=42161', }); ``` If you already know the Safe address for this trader key and chain, pass `safeAddress` to skip the SDK's smart-account derivation call during construction: ```ts theme={null} const client = await OstiumClient.createSelfAndGasless({ traderPrivateKey: process.env.TRADER_PRIVATE_KEY as `0x${string}`, safeAddress: '0xSafeAddress', }); ``` ## Build-only client ```ts theme={null} const client = await OstiumClient.createSelfAndGasless({ traderAddress: '0xTraderAddress', safeAddress: '0xSafeAddress', }); const tx = client.getOpenTradeTx({ pairId: 0, buy: true, price: '65000', collateral: '100', leverage: '5', type: OrderType.Market, }); ``` In build-only mode, `get*Tx()` returns a Safe-style request with `safeAddress` and `calls`. ## Parameters | Field | Type | Required | Notes | | - | - | - | - | | `traderPrivateKey` | `0x${string}` | Submit-capable | Trader EOA key. A Safe is derived from it to relay trades gaslessly. | | `traderAddress` | `0x${string}` | Build-only | Trader EOA address. | | `safeAddress` | `0x${string}` | Build-only; optional submit-capable | Required for build-only. Optional with `traderPrivateKey` when you already know the deterministic Safe address and want to skip derivation. | | `pimlicoUrl` | `string` | Optional | Bundler/paymaster URL. Defaults to the Ostium sponsor URL (chain-aware). | | `rpcUrl` | `string` | Optional | RPC URL for reads/simulation. Defaults to the public RPC. | | `sponsorshipPolicyId` | `string` | Optional | Pimlico sponsorship policy ID. | Plus the shared options (`testnet`, `slippageBps`, `builder`, `subgraphUrl`, `builderApiUrl`, `alchemyApiKey`). See [Client Configuration](/developer/client-modes/configuration). # Self + Self Source: https://docs.ostium.com/developer/client-modes/self-and-self Trader-owned, trader-signed, directly submitted transactions with the Ostium SDK. `createSelfAndSelf()` is the simplest mode. * the trader EOA owns USDC and positions * the same trader EOA signs transactions * transactions are submitted directly on Arbitrum and the trader pays gas ## When to use it * bots and scripts * server-side systems trading a house account * wallet-driven apps where the user is comfortable paying gas * client-side apps that only need unsigned EOA transaction payloads ## Submit-capable client ```ts theme={null} const client = await OstiumClient.createSelfAndSelf({ traderPrivateKey: process.env.TRADER_PRIVATE_KEY as `0x${string}`, rpcUrl: process.env.ARB_RPC_URL!, }); ``` ## Build-only client ```ts theme={null} const client = await OstiumClient.createSelfAndSelf({ traderAddress: '0xTraderAddress', }); const tx = client.getOpenTradeTx({ pairId: 0, buy: true, price: '65000', collateral: '100', leverage: '5', type: OrderType.Market, }); ``` In build-only mode, `get*Tx()` returns an EOA request with `from`, `to`, `data`, and `value` so your app can pass it to a wallet for signing. ## Parameters | Field | Type | Required | Notes | | - | - | - | - | | `traderPrivateKey` | `0x${string}` | Submit-capable | Trader EOA key. Holds USDC, owns positions, pays gas. | | `traderAddress` | `0x${string}` | Build-only | Trader EOA address (no key). | | `rpcUrl` | `string` | Submit-capable; optional for build-only | Arbitrum RPC URL. Build-only defaults to the public RPC. | Plus the shared options (`testnet`, `slippageBps`, `builder`, `subgraphUrl`, `builderApiUrl`, `alchemyApiKey`). See [Client Configuration](/developer/client-modes/configuration). # Testnet Source: https://docs.ostium.com/developer/client-modes/testnet Use the Ostium SDK on Arbitrum Sepolia by enabling the testnet option on any client mode. All client modes support `testnet: true`. When enabled, the SDK switches to Arbitrum Sepolia defaults for: * contracts * subgraph endpoint * builder API endpoint * default Pimlico sponsor URL ## Example ```ts theme={null} const client = await OstiumClient.createDelegatedAndGasless({ delegatePrivateKey: process.env.DELEGATE_PRIVATE_KEY as `0x${string}`, traderAddress: '0xTraderAddress', testnet: true, }); ``` ## Notes * if you omit `pimlicoUrl` in gasless modes, the SDK uses the default Sepolia sponsor URL when `testnet: true` * you can still override `rpcUrl`, `subgraphUrl`, `builderApiUrl`, or `pimlicoUrl` manually * make sure the trader account, approvals, and delegation setup all happen on the same network See [Client Configuration](/developer/client-modes/configuration) for the full list of parameters every mode accepts. # approveUsdc Source: https://docs.ostium.com/developer/reference/approve-usdc Approve TradingStorage to spend trader USDC through the Ostium Builder SDK. ```ts theme={null} await client.approveUsdc('max'); ``` Or approve a fixed amount: ```ts theme={null} await client.approveUsdc('1000'); ``` ## Important behavior * available in self modes * unavailable in delegated modes * required before `openTrade()` and some `updateCollateral()` top-ups ## Response schema ```ts theme={null} interface Response { txHash: `0x${string}`; smartAccountAddress?: `0x${string}`; } ``` # cancelOrder Source: https://docs.ostium.com/developer/reference/cancel-order Cancel pending limit, market open, or market close orders with the Ostium Builder SDK. ```ts theme={null} await client.cancelOrder({ type: CancelOrderType.Limit, pairId, idx, }); ``` ```ts theme={null} await client.cancelOrder({ type: CancelOrderType.PendingOpen, orderId: 123, }); ``` ```ts theme={null} await client.cancelOrder({ type: CancelOrderType.PendingClose, orderId: 123, retry: true, }); ``` ## Response schema ```ts theme={null} interface Response { txHash: `0x${string}`; smartAccountAddress?: `0x${string}`; } ``` # checkUsdcAllowance Source: https://docs.ostium.com/developer/reference/check-usdc-allowance Check whether the connected trader has enough USDC allowance for a required amount. ```ts theme={null} const allowance = await client.checkUsdcAllowance('100'); ``` ## Returns * `current` * `required` * `sufficient` ## Use when * validating a trade before `openTrade()` * validating a top-up before `updateCollateral()` This helper uses the connected trader address and is not for read-only clients. ## Response schema ```ts theme={null} interface Response { current: bigint; required: bigint; sufficient: boolean; } ``` # closeTrade Source: https://docs.ostium.com/developer/reference/close-trade Fully or partially close an Ostium position with the Builder SDK. ```ts theme={null} await client.closeTrade({ pairId, idx, price: '66000', closePercent: 100, }); ``` For a partial close: ```ts theme={null} await client.closeTrade({ pairId, idx, price: '66000', closePercent: 50, }); ``` ## Response schema ```ts theme={null} interface Response { txHash: `0x${string}`; smartAccountAddress?: `0x${string}`; } ``` # createStore Source: https://docs.ostium.com/developer/reference/create-store One subscribable object holding Ostium pairs, live prices, and a trader's positions — kept current for you. `createStore(params?)` returns a single object holding pairs, live prices and the trader's positions, and keeps all three current — replacing the price socket, polls and recompute loop most integrations write by hand. ```ts theme={null} const store = client.createStore(); const unsubscribe = store.subscribe(({ ready, positions, marginSummary }) => { if (!ready) return; render(positions, marginSummary); // PnL and liquidation price already current }); await client.openTrade({ /* … */ }); await store.refresh(); // pick the new position up at once unsubscribe(); store.close(); ``` Each input moves at its own cadence: | Input | Source | Default cadence | | - | - | - | | Prices | WebSocket | live | | Pairs | `getPairs()` | 60s | | Positions | `getOpenPositions()` | 15s | PnL, liquidation price and accrued rollover are recomputed locally on every tick, using the same [math helpers](/developer/reference/math-helpers) you could call yourself — so a price tick costs no network request. ## Parameters | Parameter | Type | Default | Description | | - | - | - | - | | `user` | `Address` | connected wallet | Trader to follow. Throws `INVALID_CONFIG` if there is none — a read-only client must pass one. | | `pairPollMs` | `number` | `60000` | How often to re-read pairs, for rollover accumulators. | | `positionPollMs` | `number` | `15000` | How often to re-read positions, for membership changes. | | `throttleMs` | `number` | `250` | Minimum gap between emissions. Ticks arriving faster are coalesced, newest wins. Set `0` to emit on every tick. | ## Store interface ```ts theme={null} interface OstiumStore { getState(): OstiumStoreState; subscribe(listener: (state: OstiumStoreState) => void): () => void; // fires immediately, then on each update refresh(): Promise; // re-read pairs and positions now close(): void; // stop polling and close the socket } ``` ## State schema ```ts theme={null} interface OstiumStoreState { ready: boolean; // pairs, prices and positions have all arrived once positions: Array; marginSummary: MarginSummary; // same shape getOpenPositions() returns pairs: Record; // empty until the first fetch lands pairMeta: Record; // available immediately — see below prices: Record; blockNumber?: string; // block the rollover figures are current as of lastError?: string; // last failed poll, if any } ``` ## Rendering before the first fetch `pairMeta` is populated **synchronously** from a snapshot shipped with the package, so a market list renders on the first `getState()` instead of after a round trip. Live data replaces it once `getPairs()` resolves. ```ts theme={null} const store = client.createStore(); selectMarkets(store.getState()); // already populated — no await ``` It carries pair names, category, leverage caps and minimum notional only — never prices, open interest or rollover data, which are always fetched live. The same snapshot is exported as `PAIR_SNAPSHOT` if you want it without a store. ## Selectors Plain functions of state, for the lookups every UI writes by hand: ```ts theme={null} import { selectPosition, selectPositionsForPair, selectPrice, selectPair, selectPairMeta, selectMarkets, selectPositionsNearLiquidation, memoSelector, } from '@ostium/builder-sdk'; const state = store.getState(); // pairId accepts the numeric string or a number — these are the same pair. selectPosition(state, '0', 0); // one position, by pair and index selectPositionsForPair(state, '0'); // every position on a pair selectPrice(state, '0'); // latest tick selectPair(state, '0'); // live pair state selectPairMeta(state, '0'); // available before the first fetch selectMarkets(state); // tradeable pairs, sorted by symbol selectPositionsNearLiquidation(state, 10); // within 10% of liquidation ``` ## Using it in React `subscribe` and `getState` already match the contract of React's `useSyncExternalStore`, so there is nothing to wire up and React is not an SDK dependency: ```tsx theme={null} const selectBtc = memoSelector(s => selectPositionsForPair(s, '0')); function BtcPositions() { const positions = useSyncExternalStore(store.subscribe, () => selectBtc(store.getState())); return ; } ``` `memoSelector` is required here: `useSyncExternalStore` needs `getSnapshot` to return a stable reference, and a selector that builds a fresh array on every call makes React loop. It does not suppress re-renders on unrelated ticks — the store emits a new state whenever any watched price moves. To keep a component still while another pair moves, select a primitive, or compare by content first. ## Errors A failed poll leaves a stale field, not a dead store: the store keeps running and reports the message on `lastError`. ## Exported types `OstiumStore`, `OstiumStoreState` and `StorePosition` are the shapes above. `CreateStoreParams` is the parameter object. `PairSnapshotEntry` is one entry of `pairMeta`. `StoreBackend` is the narrow interface the store reads through — `subgraph`, `streamPrices` and `getBlockNumber`. `client.createStore()` supplies it for you; it is exported so a test can hand the store a fake instead of a network. ## Related * [Math helpers](/developer/reference/math-helpers) — the same numbers, without a store * [streamPositionUpdates](/developer/reference/stream-position-updates) — re-price a payload you already have * [streamAccountUpdates](/developer/reference/stream-account-updates) — low-latency confirmations # getAllPrices Source: https://docs.ostium.com/developer/reference/get-all-prices Fetch current mid, bid, and ask prices for all Ostium pairs. ```ts theme={null} const { prices } = await client.getAllPrices(); ``` The response is keyed by `pairId`: ```ts theme={null} console.log(prices['0']); ``` Use this when you need quotes without the full `getPairs()` payload. ## Response schema ```ts theme={null} interface Response { prices: Record; } ``` # getBalances Source: https://docs.ostium.com/developer/reference/get-balances Fetch USDC balance, ETH balance, and USDC allowance for an Ostium trader. ```ts theme={null} const balances = await client.getBalances(); ``` In read-only mode: ```ts theme={null} await client.getBalances('0xTraderAddress'); ``` The response contains: * `usdc` * `eth` * `allowance` ## Response schema ```ts theme={null} interface Response { usdc: string; eth: string; allowance: string; } ``` # getBuilderOrders Source: https://docs.ostium.com/developer/reference/get-builder-orders Fetch orders routed through a builder, including sibling close, TP, and SL orders on the same positions. `getBuilderOrders(builder, params?)` returns builder-tagged orders plus related sibling orders for the same positions. ```ts theme={null} const orders = await client.getBuilderOrders('0xBuilderAddress', { start: 1765411200, end: 1765497599, pairIds: [0, 1], limit: 100, }); ``` ## How it works The subgraph stores `builder` on open orders. The SDK first fetches orders tagged with the builder address, then fetches sibling close, take-profit, and stop-loss orders matched by `pid`. `limit` caps the first builder-tagged phase only. Sibling orders from the second phase are appended without a cap, so the final array can contain more than `limit` rows. ## Parameters ```ts theme={null} type GetBuilderOrdersParams = Omit< GetOrdersParams, 'builder' | 'orderIds' | 'initiatedTxHashes' >; ``` Supported filters: | Parameter | Type | Description | | - | - | - | | `user` | `Address \| 'ALL'` | Scope to one trader or all traders. | | `isPending` | `boolean` | Filter by pending status. | | `isCanceled` | `boolean` | Filter by cancelled status. | | `isCancelled` | `boolean` | Alias for `isCanceled`. | | `pairIds` | `Array` | Filter by pair ids. | | `start` | `number` | Inclusive lower bound on execution time, as Unix seconds UTC. | | `end` | `number` | Inclusive upper bound on execution time, as Unix seconds UTC. | | `limit` | `number` | Cap for the first builder-tagged query. Defaults to `100`. | ## Response schema Same `Order[]` schema as [getOrders](/developer/reference/get-orders). # getCandles Source: https://docs.ostium.com/developer/reference/get-candles Fetch OHLC candle data for an Ostium pair. ```ts theme={null} const candles = await client.getCandles({ pairId: 0, from: Date.now() - 30 * 24 * 60 * 60 * 1000, resolution: '1D', sets: 3, }); ``` `sets` controls how many candle pages the SDK requests. It defaults to `1`; when greater than `1`, the SDK uses the previous page's last candle timestamp as the next request cursor and returns one flattened array. Supported resolutions: * `"1"` * `"5"` * `"15"` * `"60"` * `"240"` * `"1D"` ## Parameters ```ts theme={null} interface GetCandlesParams { pairId: string | number; from: number; to?: number; resolution: '1' | '5' | '15' | '60' | '240' | '1D'; sets?: number; } ``` ## Response schema ```ts theme={null} type Response = Array<{ pairFrom: string; pairTo: string; time: number; open: number; high: number; low: number; close: number; }>; ``` # getFills Source: https://docs.ostium.com/developer/reference/get-fills Fetch executed Ostium fills for one trader or across all traders. ```ts theme={null} const fills = await client.getFills({ limit: 100 }); ``` Filter by pair: ```ts theme={null} const fills = await client.getFills({ pairId: 0, limit: 100 }); ``` Across all traders: ```ts theme={null} const fills = await client.getFills({ user: 'ALL', pairId: 0 }); ``` ## Parameters ```ts theme={null} interface GetFillsParams { user?: `0x${string}` | 'ALL'; pairId?: string | number; limit?: number; } ``` On `OstiumClient`, `user` defaults to the connected trader. Pass `user: 'ALL'` to remove the trader filter. `oid` is the on-chain keeper order id formatted as a base-10 numeric string. It uses the same id space as `Order.oid` and the value returned by `extractOrderIdFromReceipt()`. ## Response schema ```ts theme={null} type Response = Array<{ pairTo: string; pairFrom: string; pairId: string; oid: string; pid: string; trader: string; side: 'B' | 'S'; action: 'Open' | 'Close' | 'Liquidation' | 'StopLoss' | 'TakeProfit' | 'RemoveCollateral' | 'CloseDayTrade'; type: 'Market' | 'Limit' | 'REMOVE_COLLATERAL'; px: string; szi: string; ntl: string; collateralUsed: string; builder: string; fees: { opening: string; rollover: string; liquidation: string; builder: string; priceImpact: string; }; closedPnl: string; hash: string; time: number; timestamp: number; }>; ``` # getFillsByTime Source: https://docs.ostium.com/developer/reference/get-fills-by-time Fetch executed Ostium fills within a time range. ```ts theme={null} const fills = await client.getFillsByTime({ startTime: Date.now() - 7 * 24 * 60 * 60 * 1000, endTime: Date.now(), }); ``` This method supports the same user and pair filters as `getFills()`. `startTime` and `endTime` are Unix milliseconds. `endTime` defaults to `Date.now()`. `oid` is the on-chain keeper order id formatted as a base-10 numeric string. It uses the same id space as `Order.oid` and the value returned by `extractOrderIdFromReceipt()`. ## Parameters ```ts theme={null} interface GetFillsByTimeParams { user?: `0x${string}` | 'ALL'; pairId?: string | number; limit?: number; startTime: number; endTime?: number; } ``` ## Response schema ```ts theme={null} type Response = Array<{ pairTo: string; pairFrom: string; pairId: string; oid: string; pid: string; trader: string; side: 'B' | 'S'; action: 'Open' | 'Close' | 'Liquidation' | 'StopLoss' | 'TakeProfit' | 'RemoveCollateral' | 'CloseDayTrade'; type: 'Market' | 'Limit' | 'REMOVE_COLLATERAL'; px: string; szi: string; ntl: string; collateralUsed: string; builder: string; fees: { opening: string; rollover: string; liquidation: string; builder: string; priceImpact: string; }; closedPnl: string; hash: string; time: number; timestamp: number; }>; ``` # getMaxCollateral Source: https://docs.ostium.com/developer/reference/get-max-collateral The largest collateral an Ostium trade can use, and which limit is stopping it going higher. `getMaxCollateral(params)` returns what a **Max** button should fill in, and which limit stopped it there — so a UI can explain why, rather than showing a number that refuses to grow. ```ts theme={null} const { max, bound, limits } = await client.getMaxCollateral({ pairId: 0, isLong: true, leverage: 10, }); console.log(max); // "13204.51" — fill this into the collateral field console.log(bound); // "openInterest" — why it stopped here console.log(limits); // every ceiling considered ``` The connected trader's wallet balance and USDC allowance are included automatically. Call it on `OstiumSubgraphClient` for the protocol-side limits only. ## Parameters | Parameter | Type | Default | Description | | - | - | - | - | | `pairId` | `string \| number` | — | Pair the trade would open on. | | `isLong` | `boolean` | — | Direction — each side has its own open-interest headroom. | | `leverage` | `number` | — | Leverage the trade would use. Open-interest headroom depends on it. | | `user` | `Address` | connected wallet | Trader whose balance and allowance to fold in. | ## Response schema ```ts theme={null} interface MaxCollateralResult { max: string; // the binding value — what a Max button fills in bound: 'openInterest' | 'groupCollateral' | 'perTradeMax' | 'balance' | 'allowance' | 'none'; limits: { openInterest: string; // headroom under this side's OI cap, at this leverage groupCollateral: string; // headroom under the group's share of vault liquidity perTradeMax: string; // MAX_COLLATERAL_USD balance?: string; // trader's USDC balance — only when a trader was resolved allowance?: string; // USDC allowance to TradingStorage — same }; } ``` `groupCollateral` can come back as `"unknown"` when the vault balance could not be read. `max` then reflects only the limits that were checked. `max` is point-in-time. The open-interest cap is denominated in USD, so it moves with the price — a value sitting exactly on the boundary can be rejected moments later. Re-run [`previewOpenTrade()`](/developer/reference/preview-open-trade) before enabling submit, or apply your own margin. ## Related * [previewOpenTrade](/developer/reference/preview-open-trade) * [getBalances](/developer/reference/get-balances) # getOnboardingStatus Source: https://docs.ostium.com/developer/reference/get-onboarding-status What still stands between a trader and their first Ostium trade, with the transaction that clears each step. `getOnboardingStatus(params?)` reports everything outstanding before a trader can open a position — USDC approval, delegate registration, gasless setup — and hands you the transaction that clears each one, in the order they should be submitted. It replaces hand-rolling that sequence across three separate transaction builders, and it is mode-aware: a self-submit client is never told to set up gasless delegation. ```ts theme={null} const status = await client.getOnboardingStatus({ requiredUsd: '100' }); if (status.ready) { // nothing outstanding — the trader can open a position } for (const step of status.steps) { console.log(step.kind, step.description); await wallet.sendTransaction(step.tx); // the trader signs from their own account } if (status.needsFunding) { // no transaction can fix this — the trader has to fund the account } ``` ## Parameters | Parameter | Type | Default | Description | | - | - | - | - | | `requiredUsd` | `string` | `"1"` | Collateral the trader intends to trade with — balance and allowance are checked against it. The default is enough to prove an approval exists at all. | ## Response schema ```ts theme={null} interface OnboardingStatus { ready: boolean; // nothing outstanding needsApproval: boolean; // USDC allowance below requiredUsd needsFunding: boolean; // USDC balance below requiredUsd — no tx can fix this needsDelegate: boolean; // no delegate registered, or a different one needsGaslessSetup: boolean; // Self + Gasless only — smart account not yet authorised steps: Array<{ kind: 'approveUsdc' | 'setDelegate' | 'setupGaslessDelegation'; description: string; tx: BuiltTxRequest; // always sent from the trader's own account }>; allowance: string; // current USDC allowance to TradingStorage usdcBalance: string; ethBalance: string; // needed for gas in self-submit modes currentDelegate?: Address; // undefined when none is set } ``` `needsFunding` produces no step — there is no transaction that funds an account — but it does keep `ready` false. Every step's `tx` is sent from the trader's own account. A delegate cannot approve USDC or register itself on the trader's behalf. ## Related * [approveUsdc](/developer/reference/approve-usdc) * [setDelegate](/developer/reference/set-delegate) * [setupGaslessDelegation](/developer/reference/setup-gasless-delegation) * [Approvals and first trade](/developer/traders/approvals-and-first-trade) # getOpenOrders Source: https://docs.ostium.com/developer/reference/get-open-orders Fetch active Ostium limit orders for a trader. ```ts theme={null} const orders = await client.getOpenOrders(); ``` In read-only mode: ```ts theme={null} await client.getOpenOrders({ user: '0xTraderAddress' }); ``` Use `pairId` and `idx` from this response with `modifyOrder()` and `cancelOrder()`. `idx` is the on-chain limit-order slot index within the trader and pair, not the global order id from the subgraph. Pass it directly with `pairId` when cancelling or modifying a limit or stop order. ## Response schema ```ts theme={null} type Response = Array<{ pairTo: string; pairFrom: string; pairId: string; trader: string; idx: number; side: 'B' | 'S'; limitPx: string; szi: string; orderType: string; tpPx?: string; slPx?: string; timestamp: number; }>; ``` # getOpenPositions Source: https://docs.ostium.com/developer/reference/get-open-positions Fetch live Ostium positions, margin summary, and withdrawable collateral. ```ts theme={null} // Connected wallet (default) const { pairPositions, marginSummary } = await client.getOpenPositions(); // Specific trader (read-only mode) await client.getOpenPositions({ user: '0xTraderAddress' }); // All traders — no user filter await client.getOpenPositions({ user: 'ALL' }); // Paginated — first page of 50 await client.getOpenPositions({ user: 'ALL', limit: 50, skip: 0 }); // Paginated — second page await client.getOpenPositions({ user: 'ALL', limit: 50, skip: 50 }); ``` The returned `pairId` and `idx` values are used by position-management methods. `maxWithdrawable` is the largest collateral removable from the position — the smallest of the three limits the contract checks: the leverage cap (removing collateral raises leverage), liquidation safety (what remains must cover accrued fees and any unrealised loss), and profit protection. It is price-dependent, so it is only current as of the read that produced it. `rolloverSnapshot` is the pair's rollover accumulator when the position opened. With `Pair.rollover` from [`getPairs()`](/developer/reference/get-pairs), it lets you advance accrued rollover locally between polls — see [`rolloverFee()`](/developer/reference/math-helpers). ## Parameters | Parameter | Type | Default | Description | | - | - | - | - | | `user` | `Address \| 'ALL'` | connected wallet | Trader address to scope results to. Pass `'ALL'` to fetch open positions across every trader (no trader filter applied). | | `blockNumber` | `bigint` | current block | Arbitrum block number used for live PnL projection. Auto-fetched when using `OstiumClient`. | | `limit` | `number` | `Infinity` | Maximum number of positions to return. | | `skip` | `number` | `0` | Number of positions to skip — use with `limit` to paginate. | ## Response schema ```ts theme={null} interface Response { pairPositions: Array<{ position: { pairTo: string; pairFrom: string; pairId: string; pid: string; trader: string; idx: number; side: 'B' | 'S'; szi: string; entryPx: string; leverage: string; ntl: string; unrealizedPnl: string; returnOnEquity: string; liquidationPx: string; collateralUsed: string; cumRollover: string; rolloverSnapshot: string; tpPx?: string; slPx?: string; openTimestamp: number; isDayTrade: boolean; maxLeverage: string; highestLeverage: string; maxWithdrawable: string; confirmationStatus?: 'optimistic' | 'initiated' | 'executed' | 'indexed'; orderId?: string; initiatedTx?: string; initiatedBlock?: string; }; }>; marginSummary: { accountValue: string; totalCollateralUsed: string; totalNtlPos: string; totalRawPnlUsd: string; totalCumRollover: string; totalWithdrawable: string; }; time: number; } ``` # getOrders Source: https://docs.ostium.com/developer/reference/get-orders Fetch pending, executed, or cancelled Ostium orders by hash, id, or recent trader activity. ## Poll by transaction hash ```ts theme={null} const orders = await client.getOrders({ initiatedTxHashes: [txHash], }); ``` ## Query by order id ```ts theme={null} const orders = await client.getOrders({ orderIds: [123] }); ``` `orderIds` are on-chain keeper order ids. In the response, `oid` is the same id formatted as a base-10 numeric string, so it can be compared directly with the value returned by `extractOrderIdFromReceipt()`. ## Filter order history Without filters, `OstiumClient.getOrders()` returns recent orders for the connected trader. Pass `user: 'ALL'` to remove the trader filter and fetch global orders. When `builder` is provided without `user`, the SDK does not add the connected-trader default. ```ts theme={null} const globalOrders = await client.getOrders({ user: 'ALL' }); const builderOrders = await client.getOrders({ builder: '0xBuilderAddress', }); const pendingBtcOrders = await client.getOrders({ isPending: true, pairIds: ['0'], }); const ordersExecutedToday = await client.getOrders({ user: 'ALL', start: 1765411200, end: 1765497599, }); const cancelledBuilderOrders = await client.getOrders({ user: 'ALL', builder: '0xBuilderAddress', isCanceled: true, }); ``` `orderIds` and `initiatedTxHashes` are mutually exclusive. The other filters can be combined. `start` and `end` filter by execution time (`executedAt`) as Unix seconds UTC with inclusive bounds. Pending orders do not have execution time, so combining `start` or `end` with `isPending: true` returns no executed-time matches. For builder analytics that should include sibling close, TP, and SL orders on the same positions, use [getBuilderOrders](/developer/reference/get-builder-orders). ## Parameters ```ts theme={null} interface GetOrdersParams { orderIds?: Array; initiatedTxHashes?: readonly `0x${string}`[]; user?: `0x${string}` | 'ALL'; builder?: string; isPending?: boolean; isCanceled?: boolean; isCancelled?: boolean; pairIds?: Array; start?: number; end?: number; limit?: number; } ``` ## Response schema ```ts theme={null} type Response = Array<{ pairTo: string; pairFrom: string; pairId: string; oid: string; pid: string; trader: string; side: 'B' | 'S'; action: 'Open' | 'Close' | 'Liquidation' | 'StopLoss' | 'TakeProfit' | 'RemoveCollateral' | 'CloseDayTrade'; type: 'Market' | 'Limit' | 'REMOVE_COLLATERAL'; px: string; szi: string; ntl: string; collateralUsed: string; builder: string; fees: { opening: string; rollover: string; liquidation: string; builder: string; priceImpact: string; }; closedPnl: string; hash: string; time: number; timestamp: number; initiatedTx: string; initiatedTime: number; isPending: boolean; isCancelled: boolean; cancelReason?: string; initiatedBlock?: string; }>; ``` # getPairs Source: https://docs.ostium.com/developer/reference/get-pairs Fetch all Ostium pairs, leverage limits, live prices, and market-state fields. ## What it does Returns the current pair list with market metadata and live price fields. ## Example ```ts theme={null} const { pairs } = await client.getPairs(); ``` Filter by pair: ```ts theme={null} const { pairs } = await client.getPairs({ pairIds: [0, 1] }); ``` Include a builder fee in the computed `openFee` values: ```ts theme={null} const { pairs } = await client.getPairs({ builderFeeBps: 20 }); ``` On `OstiumClient`, `builderFeeBps` defaults to the configured `builder.feeBps` when omitted. ## Use it for * pair pickers * market tables * reading pair and overnight leverage limits before `openTrade()` * pairId discovery before `openTrade()` ## Parameters ```ts theme={null} interface GetPairsParams { pairIds?: Array; builderFeeBps?: number; } ``` ## Response schema ```ts theme={null} interface PairSchedule { id: number; alwaysOpen?: boolean; timezone?: string; openingHours?: string[]; } interface Response { pairs: Array<{ pairId: string; pairTo: string; pairFrom: string; minSz: string; maxBSz: string; maxSSz: string; minNtl: string; maxLeverage: number; minLeverage: number; overnightMaxLeverage: number; rolloverFeePerBlock: string; rollover: { accLong: string; // long-side rollover accumulator accShort: string; // short-side rollover accumulator lastBlock: string; // block the accumulators were last updated at perBlockPure: string; // per-block rate, before the broker premium brokerPremium: string; negativeAllowed: boolean; // whether traders can earn rollover on this pair }; openInterest: string; buyOpenInterest: string; sellOpenInterest: string; maxOpenInterest: string; category: string; rolloverRate: { long: string; short: string }; midPx: string; askPx: string; bidPx: string; isMarketOpen: boolean; isDayTradingClosed: boolean; secondsToToggleIsDayTradingClosed: number; schedule?: PairSchedule; openFee: number; closeFee: number; }>; } ``` `openFee` is the pair taker fee plus the configured builder fee, in basis points. `closeFee` is currently always `0`. ## Rollover accumulators `rollover` carries the accumulators the contracts use to charge rollover. They are global per pair, so one poll covers every position. Pass them with a position's `rolloverSnapshot` to [`rolloverFee()`](/developer/reference/math-helpers) to advance accrued rollover — and therefore PnL and liquidation price — without re-fetching positions. # getSimOrderbook Source: https://docs.ostium.com/developer/reference/get-sim-orderbook Fetch a synthetic bid/ask orderbook for an Ostium pair. ```ts theme={null} const book = await client.getSimOrderbook({ pairId: 0, levels: 20, }); ``` Use this for depth views and execution visualizations. ## Response schema ```ts theme={null} interface Response { pairId: string; pairFrom: string; pairTo: string; levels: [ Array<{ px: string; sz: string; n: number }>, Array<{ px: string; sz: string; n: number }> ]; time: number; } ``` # getSimSlippage Source: https://docs.ostium.com/developer/reference/get-sim-slippage Fetch simulated long and short slippage for Ostium pairs at different notionals. ```ts theme={null} const slippage = await client.getSimSlippage({ pairIds: [0, 1], ntls: ['10000', '100000'], }); ``` Use this for pre-trade execution previews. ## Response schema ```ts theme={null} type Response = Record; short: Array<{ ntl: string; slippage: string }>; }>; ``` # getSmartAccountAddress Source: https://docs.ostium.com/developer/reference/get-smart-account-address Return the Safe smart-account address used by gasless Ostium client modes. ```ts theme={null} const address = client.getSmartAccountAddress(); ``` ## Returns * Safe address in gasless modes * `undefined` in non-gasless modes Use this when: * registering the Safe delegate * inspecting the effective gasless sender ## Response schema ```ts theme={null} type Response = `0x${string}` | undefined; ``` # getTraderAddress Source: https://docs.ostium.com/developer/reference/get-trader-address Return the connected trader address for a write-enabled Ostium client. ```ts theme={null} const trader = client.getTraderAddress(); ``` ## Returns The on-chain trader address that owns funds and positions for the connected client. ## Important behavior This is not available in read-only mode. ## Response schema ```ts theme={null} type Response = `0x${string}`; ``` # getVaultBalance Source: https://docs.ostium.com/developer/reference/get-vault-balance Protocol vault balance in USDC — the liquidity backing trader PnL on Ostium. `getVaultBalance()` returns the protocol vault balance in USDC: the liquidity backing trader PnL. It is the input to the exposure-limit check, which is why the SDK exposes it. ```ts theme={null} const vault = await client.getVaultBalance(); console.log(vault); // 12_480_331.42 ``` The value is cached for 60 seconds, so calling it per-keystroke in an order ticket costs nothing after the first read. ## Response `Promise` — USDC, as a plain number. ## Why it matters A pair group can only hold a share of vault liquidity as collateral. That ceiling is what `withinExposureLimit` on [`previewOpenTrade()`](/developer/reference/preview-open-trade) and `limits.groupCollateral` on [`getMaxCollateral()`](/developer/reference/get-max-collateral) are measured against. Both read the vault for you — call this directly only if you are computing exposure yourself. # isReadOnly Source: https://docs.ostium.com/developer/reference/is-read-only Check whether an Ostium client was created in read-only mode. ```ts theme={null} const readOnly = client.isReadOnly(); ``` Returns `true` for clients created with `createReadOnly()`. ## Response schema ```ts theme={null} type Response = boolean; ``` # Math helpers Source: https://docs.ostium.com/developer/reference/math-helpers Ostium liquidation price, PnL, and rollover fee as pure functions — no client, no network. `liquidationPrice()`, `pnl()` and `rolloverFee()` are standalone functions over plain numbers — no client, no network. For bots, backtesters and risk dashboards. All three run `@ostium/formulae`, the same math the contracts use. ```ts theme={null} import { liquidationPrice, pnl, rolloverFee, maxWithdrawable, maxAddCollateral, } from '@ostium/builder-sdk'; ``` ## liquidationPrice ```ts theme={null} liquidationPrice({ entryPx: 100_000, isLong: true, collateral: 1000, leverage: 10, maxLeverage: 100, }); // → 90_250 ``` | Parameter | Type | Default | Description | | - | - | - | - | | `entryPx` | `number` | — | Price the position opened at. | | `isLong` | `boolean` | — | Direction. | | `collateral` | `number` | — | Collateral backing the position, in USDC. | | `leverage` | `number` | — | Position leverage. | | `maxLeverage` | `number` | — | Max leverage allowed for the pair — this sets the maintenance margin. | | `rollover` | `number` | `0` | Rollover accrued so far, in USDC. | | `funding` | `number` | `0` | Funding accrued so far, in USDC. | Accrued fees push the liquidation price toward the entry price, so a long-held position liquidates sooner than it did at open. Pass `rollover` for the current figure. ## pnl ```ts theme={null} pnl({ entryPx: 100_000, markPx: 105_000, isLong: true, collateral: 1000, leverage: 10 }); // → { netPnl: 500, netPnlPercent: 50, netValue: 1500 } ``` | Parameter | Type | Default | Description | | - | - | - | - | | `entryPx` | `number` | — | Price the position opened at. | | `markPx` | `number` | — | Current mark price. | | `isLong` | `boolean` | — | Direction. | | `collateral` | `number` | — | Collateral backing the position, in USDC. | | `leverage` | `number` | — | Position leverage. | | `highestLeverage` | `number` | `leverage` | Highest leverage the position has ever run at. Only differs after collateral has been added or removed. | | `rollover` | `number` | `0` | Rollover accrued, in USDC. | | `funding` | `number` | `0` | Funding accrued, in USDC. | Returns `netPnl` (USDC, after rollover and funding), `netPnlPercent` (as a percentage of collateral) and `netValue` (`collateral + netPnl` — what the position is worth if closed now). ## rolloverFee ```ts theme={null} const { pairs } = await client.getPairs(); const { pairPositions } = await client.getOpenPositions({ user }); const { position } = pairPositions[0]; const pair = pairs.find(p => p.pairId === position.pairId)!; const accrued = rolloverFee({ rollover: pair.rollover, isLong: position.side === 'B', snapshot: position.rolloverSnapshot, collateral: Number(position.collateralUsed), leverage: Number(position.leverage), blockNumber: await publicClient.getBlockNumber(), // your own viem client }); const liq = liquidationPrice({ entryPx: Number(position.entryPx), isLong: position.side === 'B', collateral: Number(position.collateralUsed), leverage: Number(position.leverage), maxLeverage: Number(position.maxLeverage), rollover: accrued, }); ``` | Parameter | Type | Description | | - | - | - | | `rollover` | `PairRollover` | The pair's raw accumulators, from `Pair.rollover`. | | `isLong` | `boolean` | `true` for a long position. | | `snapshot` | `string` | The position's `rolloverSnapshot` — the accumulator when it opened. | | `collateral` | `number` | Collateral backing the position, in USDC. | | `leverage` | `number` | Position leverage. | | `blockNumber` | `bigint \| number \| string` | Current chain block. Rollover accrues per block, so this sets the clock. | Positive means the trader pays. Rollover accumulators are global per pair, not per position, so one [`getPairs()`](/developer/reference/get-pairs) poll plus a block number lets you keep liquidation price and PnL current for any number of positions locally — no per-position read, and no re-fetching positions. [`createStore()`](/developer/reference/create-store) does this for you. ## maxWithdrawable / maxAddCollateral The two collateral-edit limits, for a ticket that has to bound its own input. ```ts theme={null} maxWithdrawable({ collateral: 1000, leverage: 10, maxLeverage: 100, notional: 10_000, entryPx: 100_000, exitPx: 100_000, isLong: true, pnl: -300, }); // → 675 maxAddCollateral({ collateral: 1000, leverage: 10, minLeverage: 2 }); // → 4000 ``` Removing collateral raises leverage, so it is bounded by three limits at once and `maxWithdrawable` returns the smallest: the leverage cap, liquidation safety (accrued fees and unrealised loss), and profit protection. The leverage cap alone overstates the answer on a losing position — 900 in the example above. Adding collateral lowers leverage, so that direction is bounded by the pair group's minimum, `Pair.minLeverage`. `Position.maxWithdrawable` is this number, already computed for an open position. ## Related * [createStore](/developer/reference/create-store) * [getPairs](/developer/reference/get-pairs) # modifyOrder Source: https://docs.ostium.com/developer/reference/modify-order Update take profit, stop loss, or limit-order price on Ostium with the Builder SDK. ## Update TP ```ts theme={null} await client.modifyOrder({ pairId, idx, takeProfit: '72000' }); ``` ## Update SL ```ts theme={null} await client.modifyOrder({ pairId, idx, stopLoss: '62000' }); ``` ## Reprice a limit order ```ts theme={null} await client.modifyOrder({ pairId, idx, price: '64500' }); ``` ## Response schema ```ts theme={null} interface Response { txHash: `0x${string}`; smartAccountAddress?: `0x${string}`; } ``` # openTrade Source: https://docs.ostium.com/developer/reference/open-trade Open market, limit, or stop trades on Ostium with the Builder SDK. ```ts theme={null} const result = await client.openTrade({ pairId: 0, buy: true, price: '65000', collateral: '100', leverage: '10', type: OrderType.Market, }); ``` Override the client-level builder fee for one trade: ```ts theme={null} const result = await client.openTrade({ pairId: 0, buy: true, price: '65000', collateral: '100', leverage: '10', type: OrderType.Market, builder: { address: '0xBuilderAddress', feeBps: 20, }, }); ``` ## Important behavior * `pairId` comes from `getPairs()` * collateral has a fixed minimum open size of `MIN_OPEN_SIZE_USD` (`5`) * market orders respect slippage * limit and stop orders do not use slippage * the SDK does not cap leverage locally; contract-side limits are authoritative * `isDayTrade` may be required when leverage exceeds a pair's overnight limit * `builder.address` and `builder.feeBps` can be overridden per trade; omitted fields fall back to the client builder config * successful SDK submissions to the Trading contract report `{ hash }` to `POST /v1/trade` in the background for attribution ## Parameters ```ts theme={null} interface OpenTradeParams { pairId: string | number; buy: boolean; price: string; collateral: string; leverage: string; type: OrderType; takeProfit?: string; stopLoss?: string; slippage?: number; isDayTrade?: boolean; builder?: { address?: `0x${string}`; feeBps?: number; }; } ``` ## Response schema ```ts theme={null} interface Response { txHash: `0x${string}`; smartAccountAddress?: `0x${string}`; } ``` # previewCloseTrade Source: https://docs.ostium.com/developer/reference/preview-close-trade What closing all or part of an Ostium position would return: exit price, rollover settled, net PnL, and proceeds. `previewCloseTrade(params)` is the exit mirror of [`previewOpenTrade`](/developer/reference/preview-open-trade). It reports what a full or partial close would return at the live price, including the rollover the close settles. ```ts theme={null} // Full close const p = await client.previewCloseTrade({ pairId: 0, idx: 0 }); // Half the position const half = await client.previewCloseTrade({ pairId: 0, idx: 0, closePercent: 50 }); console.log(half.exitPx); // after spread — closing takes the other side of the book console.log(half.rollover); // settled in proportion to the share being closed console.log(half.received); // collateral released + net PnL ``` `pairId` and `idx` come from [`getOpenPositions()`](/developer/reference/get-open-positions). ## Parameters | Parameter | Type | Default | Description | | - | - | - | - | | `pairId` | `string \| number` | — | Pair the position is on. | | `idx` | `number` | — | Position index within the pair — `Position.idx`. | | `closePercent` | `number` | `100` | Percentage to close, 1–100. The chain carries this at two decimals, so anything finer is rejected. | | `user` | `Address` | connected wallet | Trader who owns the position. | | `blockNumber` | `bigint` | current block | Block used for rollover accrual. Fetched automatically on `OstiumClient`. | ## Response schema ```ts theme={null} interface PreviewCloseTradeResult { pairId: string; pairFrom: string; pairTo: string; idx: number; isLong: boolean; closePercent: string; midPx: string; exitPx: string; // expected execution price, after dynamic spread priceImpactP: string; // differs from the open-side figure: closing takes the other side sizeClosing: string; // in base-asset units collateralClosing: string; // collateral being released, in USDC leverage: string; grossPnl: string; // PnL at the exit price, before rollover spreadCost: string; // PnL at exit minus PnL at mid — usually negative rollover: string; // settled by this close; positive means the trader pays funding: string; // always "0" — funding is excluded throughout the SDK oracleFee: string; // flat deposit the wallet must hold; refunded on execution netPnl: string; // grossPnl after rollover netPnlPercent: string; // as a percentage of the collateral being closed received: string; // collateral released + net PnL isFullClose: boolean; warnings: Array<{ code: string; message: string }>; } ``` ## Partial closes Size, collateral, PnL and rollover all scale with `closePercent`: closing 25% releases a quarter of the collateral and settles a quarter of the accrued rollover. `oracleFee` is a flat deposit the wallet must hold to submit the close. It is refunded on execution, so it is not deducted from `received` — but a ticket should show it, and block submission when the wallet cannot cover it. ## Related * [closeTrade](/developer/reference/close-trade) * [getOpenPositions](/developer/reference/get-open-positions) # previewOpenTrade Source: https://docs.ostium.com/developer/reference/preview-open-trade Everything an Ostium order ticket shows before a trade is signed: execution price, fees, liquidation price, and preflight warnings. `previewOpenTrade(params)` returns the numbers an order ticket displays before submission — execution price after dynamic spread, the fee breakdown, collateral left backing the position, resulting liquidation price, and the checks that should disable the submit button. Every value derives from `@ostium/formulae`, the same math the contracts run. ```ts theme={null} const preview = await client.previewOpenTrade({ pairId: 0, isLong: true, collateral: 100, leverage: 10, }); console.log(preview.entryPx); // price after dynamic spread console.log(preview.fees.total); // deducted from collateral at open console.log(preview.liquidationPx); if (!preview.isValid) { console.warn(preview.warnings.map(w => w.code)); } ``` `builderFeeBps` defaults to the fee configured on the client, so the ticket quotes the fee the trade will actually pay. Pass `0` to preview without one. The preview takes numbers and `isLong`; `openTrade()` takes decimal strings and `buy`. ## Parameters | Parameter | Type | Default | Description | | - | - | - | - | | `pairId` | `string \| number` | — | Pair to preview. | | `isLong` | `boolean` | — | Direction. | | `collateral` | `number` | — | Gross collateral in USDC, before fees. | | `leverage` | `number` | — | Leverage the trade would use. | | `limitPrice` | `number` | live bid/ask | Trigger price for a limit or stop order. Omit for a market order, which prices off the live book and pays the dynamic spread. | | `isDayTrade` | `boolean` | `false` | Day trades get the pair's higher intraday leverage cap. | | `builderFeeBps` | `number` | client config | Builder fee in basis points to include in the quote. | ## Response schema ```ts theme={null} interface PreviewOpenTradeResult { pairId: string; pairFrom: string; pairTo: string; isLong: boolean; midPx: string; // live mid price refPx: string; // the side's bid/ask, or the limit price entryPx: string; // expected execution price, after spread priceImpactP: string; // dynamic spread applied, as a percentage spreadDecaySeconds: number; // until the current imbalance spread decays to zero fees: { openFee: string; // protocol opening fee oracleFee: string; // flat price-retrieval fee builderFee: string; // charged on notional; "0" with no builder builderFeeBps: string; total: string; // deducted from collateral at open openFeePercent: string; // blended rate actually applied takerFeePercent: string; makerFeePercent: string; takerNotional: string; makerNotional: string; }; collateral: string; // gross, as supplied collateralAtOpen: string; // what actually backs the position, after fees exposure: string; // collateralAtOpen × leverage positionSize: string; // in base-asset units leverage: string; liquidationPx: string; effectiveMaxLeverage: string; // accounts for the day-trade cap minLeverage: string; minPositionSize: string; isDayTrade: boolean; withinExposureLimit?: boolean; // undefined when the vault balance could not be read isValid: boolean; // true when warnings is empty warnings: Array<{ code: string; message: string }>; } ``` ## Warnings `warnings` covers the preflight conditions a ticket should surface, and `isValid` is simply `warnings.length === 0`. | Code | Meaning | | - | - | | `BELOW_MIN_COLLATERAL` | Collateral is under `MIN_COLLATERAL_USD`. | | `ABOVE_MAX_COLLATERAL` | Collateral is over `MAX_COLLATERAL_USD`. | | `LEVERAGE_ABOVE_MAX` | Above the pair's effective max leverage. | | `LEVERAGE_BELOW_MIN` | Below the group's minimum leverage. | | `BELOW_MIN_POSITION_SIZE` | Notional is under the pair's minimum. | | `FEES_EXCEED_COLLATERAL` | Fees would consume the whole position. | | `ABOVE_EXPOSURE_LIMIT` | Breaches the pair's open-interest or the group's collateral cap. | | `MARKET_CLOSED` | The market is closed. | | `DAY_TRADING_CLOSED` | Intraday trading is closed for this pair. | The list is not exhaustive, and chain state moves between preview and submission — keep normal error handling around `openTrade()`. ## Related * [getMaxCollateral](/developer/reference/get-max-collateral) — what a Max button should fill in * [previewCloseTrade](/developer/reference/preview-close-trade) — the exit mirror * [openTrade](/developer/reference/open-trade) # removeDelegate Source: https://docs.ostium.com/developer/reference/remove-delegate Remove the currently registered delegate on Ostium through the Builder SDK. ```ts theme={null} await client.removeDelegate(); ``` This follows the same connected-client rules as `setDelegate()`. ## Response schema ```ts theme={null} interface Response { txHash: `0x${string}`; smartAccountAddress?: `0x${string}`; } ``` # setDelegate Source: https://docs.ostium.com/developer/reference/set-delegate Register a delegate address on Ostium through the Builder SDK. ```ts theme={null} await client.setDelegate('0xDelegateAddress'); ``` Use this to register: * a delegate EOA for delegated self mode * a Safe address for delegated gasless mode For self gasless mode, prefer `setupGaslessDelegation()`. ## Registering the first delegate `setDelegate()` submits through the current mode, so a delegated client sends it through its registered delegate — which cannot work before one exists. Build the transaction from the trader instead, and have them sign it: ```ts theme={null} const tx = client.getSetDelegateTx('0xDelegateAddress', { from: 'trader' }); ``` [`getOnboardingStatus()`](/developer/reference/get-onboarding-status) returns exactly this transaction as its `setDelegate` step. ## Who sends the transaction `getSetDelegateTx()` and `getRemoveDelegateTx()` take an optional `{ from }`: | `from` | Sent by | | - | - | | omitted | whoever the client's mode submits as — the trader on a self client, the registered delegate on a delegated one | | `'trader'` | the trader's own account, in every mode | | `'delegate'` | the registered delegate, wrapped in `delegatedAction` | Use `'trader'` for the first registration and for a revocation the trader wants to make themselves; `'delegate'` when an already-registered delegate rotates the delegation. ## Response schema ```ts theme={null} interface Response { txHash: `0x${string}`; smartAccountAddress?: `0x${string}`; } ``` # setupGaslessDelegation Source: https://docs.ostium.com/developer/reference/setup-gasless-delegation Register the Safe delegate required for self gasless Ostium trading. Use this once after creating a `createSelfAndGasless()` client. ```ts theme={null} await client.approveUsdc('max'); await client.setupGaslessDelegation(); ``` This registers the Safe returned by `getSmartAccountAddress()` as the delegate for the trader EOA. ## Response schema ```ts theme={null} interface Response { txHash: `0x${string}`; smartAccountAddress?: `0x${string}`; } ``` # streamAccountUpdates Source: https://docs.ostium.com/developer/reference/stream-account-updates Stream low-latency account confirmations, pending orders, active limits, and open trades. `streamAccountUpdates()` emits full account snapshots for one or more traders. It combines subgraph polling, contract-log overlays read over your RPC, and live price repricing so market opens and full closes can appear before subgraph indexing catches up. ```ts theme={null} const client = await OstiumClient.createSelfAndSelf({ traderPrivateKey: process.env.TRADER_PRIVATE_KEY as `0x${string}`, rpcUrl: process.env.ARB_RPC_URL!, rpcWsUrl: process.env.ARB_WS_URL!, // or alchemyApiKey — see RPC configuration }); const stream = client.streamAccountUpdates(); stream.onUpdate(snapshot => { const account = snapshot[client.getTraderAddress().toLowerCase()]; console.log(account.positions); console.log(account.orders); console.log(account.limits); }); stream.onError(error => console.error(error)); ``` Read-only clients and `OstiumSubgraphClient` require a `user` address array. ```ts theme={null} const stream = client.streamAccountUpdates({ user: ['0xTraderAddress'], rpcWsUrl: process.env.ARB_WS_URL!, pollIntervalMs: 3000, }); ``` ## Multiple addresses Pass one or more addresses in `user` to subscribe to accounts on a single stream. The stream uses one WebSocket, one poll loop, and one price feed regardless of how many addresses you watch — far cheaper than opening one stream per trader. ```ts theme={null} const stream = client.streamAccountUpdates({ user: ['0xTraderA', '0xTraderB', '0xTraderC'], rpcWsUrl: process.env.ARB_WS_URL!, }); stream.onUpdate(snapshot => { console.log(snapshot['0xtradera'].positions); console.log(snapshot['0xtraderb'].orders); }); ``` The snapshot is keyed by normalized trader address. Each trader bucket contains `positions`, `orders`, and `limits`. Duplicate addresses are de-duplicated, and `stream.users` returns the subscribed addresses. ## Optimistic opens For market opens, add an optimistic overlay immediately after submission and reconcile it once you know the on-chain order id. ```ts theme={null} import { extractOrderIdFromReceipt } from '@ostium/builder-sdk'; const result = await client.openTrade(params); const localId = stream.addOptimisticOpen(params, result); const receipt = await publicClient.waitForTransactionReceipt({ hash: result.txHash, }); const orderId = extractOrderIdFromReceipt(receipt); if (orderId) { stream.attachOrderId(localId, orderId, { initiatedTx: result.txHash, }); } ``` `extractOrderIdFromReceipt()` decodes the current Trading contract's market-open and market-close initiation events, plus older `PriceRequested` receipts. The returned id matches the base-10 `Order.oid` and `Fill.oid` format used by SDK reads. `addOptimisticOpen()` only supports market open orders. When streaming multiple addresses, pass the owning address as the third argument (`addOptimisticOpen(params, result, '0xTraderA')`); it is optional and defaults to the sole subscribed address when streaming one trader. ## Parameters ```ts theme={null} interface StreamAccountUpdatesParams { /** One or more addresses to stream on one connection. */ user?: `0x${string}`[]; /** WebSocket RPC endpoint for the contract-log subscription. Preferred. */ rpcWsUrl?: string; /** HTTP RPC endpoint for the missed-event sweep and block reads. */ rpcHttpUrl?: string; /** Alchemy API key. Still supported — it just builds the URLs for you. */ alchemyApiKey?: string; /** Reconciliation poll cadence. Defaults to 3000ms. */ pollIntervalMs?: number; } ``` ## RPC configuration The stream needs a **WebSocket** Arbitrum RPC endpoint. It makes only standard JSON-RPC calls, so any node works: ```ts theme={null} const stream = client.streamAccountUpdates({ user: ['0xTraderAddress'], rpcWsUrl: process.env.ARB_WS_URL!, // wss://… rpcHttpUrl: process.env.ARB_HTTP_URL, // optional; see the fallback order below }); ``` `alchemyApiKey` remains fully supported — it builds the Alchemy URLs for you: ```ts theme={null} const stream = client.streamAccountUpdates({ user: ['0xTraderAddress'], alchemyApiKey: process.env.ALCHEMY_API_KEY!, }); ``` Prefer `rpcWsUrl` in browser code — it keeps a vendor key out of your bundle. Either can be set when creating the client or per stream call, where the per-call value wins. With neither, the stream throws `OstiumSubgraphError` with code `INVALID_CONFIG`. `rpcHttpUrl` is optional. These reads resolve in order: `rpcHttpUrl`, then the Alchemy URL when `alchemyApiKey` is set, then `rpcUrl`, then the public Arbitrum RPC. `pollIntervalMs` defaults to `3000`. Sub-second open/close confirmations come from the Alchemy event watchers (which also trigger an immediate poll), so the timer poll only paces reconciliation of changes with no watcher — limit fills, partial closes, TP/SL edits, and liquidations. Pass a lower value to restore a faster cadence. All subscribed traders are fetched in a single batched subgraph query per poll. The contract-log WebSocket reconnects indefinitely with a 2-second delay. Fast-overlay positions seed rollover from the pair accumulator at the open block, so streamed PnL and liquidation estimates stay aligned with the eventual indexed position. ## Response schema ```ts theme={null} interface OstiumAccountUpdatesStream { /** Trader addresses this stream is subscribed to, in the order supplied. */ readonly users: `0x${string}`[]; onUpdate(handler: (snapshot: AccountUpdatesSnapshot) => void): () => void; onError(handler: (error: Error) => void): this; getCurrent(): AccountUpdatesSnapshot; addOptimisticOpen( params: OpenTradeParams, submission?: SubmissionResult, user?: `0x${string}`, ): string; attachOrderId( localId: string, orderId: string, metadata?: { initiatedTx?: string; initiatedBlock?: string }, ): void; close(): void; } interface AccountUpdatesForTrader { /** Open positions, formatted like getOpenPositions().pairPositions. */ positions: PairPosition[]; /** Pending market orders only. */ orders: Order[]; /** Active limit and stop orders. */ limits: OpenOrder[]; } type AccountUpdatesSnapshot = Record; ``` `positions`, `orders`, and `limits` use the same SDK-formatted objects returned by [getOpenPositions](/developer/reference/get-open-positions), [getOrders](/developer/reference/get-orders), and [getOpenOrders](/developer/reference/get-open-orders). # streamPositionUpdates Source: https://docs.ostium.com/developer/reference/stream-position-updates Subscribe to live price-driven changes for an existing open positions payload. `streamPositionUpdates(initial, priceStream?)` takes a previously fetched `getOpenPositions()` response and emits an updated payload whenever relevant prices change. ## Example ```ts theme={null} const positions = await client.getOpenPositions({ user: '0xTraderAddress' }); const stream = client.streamPositionUpdates(positions); stream.onUpdate(next => { console.log(next.marginSummary.totalRawPnlUsd); console.log(next.pairPositions[0]?.position.unrealizedPnl); }); stream.onError(err => console.error(err)); ``` ## How it works * the SDK extracts the unique `pairId` values from `initial.pairPositions` * it subscribes only to those pairs * on each price tick, it recalculates price-sensitive fields and emits the full updated `OpenPositionsResponse` ## Tracking a new position The stream re-prices the set it was given; it does not discover new trades. After a fill or a close, fetch again and pass the result to `refresh()`: ```ts theme={null} await client.openTrade({ /* … */ }); // …once the fill lands stream.refresh(await client.getOpenPositions({ user: '0xTraderAddress' })); ``` The new position starts being priced, a closed one stops, and the price subscription adjusts to match. A stream created for a trader with no open positions works the same way — it starts pricing when `refresh()` brings the first one in. A price stream you passed in stays yours: `refresh()` will not subscribe, unsubscribe or close it. For a stream that discovers trades on its own, use [`streamAccountUpdates()`](/developer/reference/stream-account-updates). ## Reusing an existing price stream If your app already owns a price WebSocket, pass it as the second argument to avoid opening another connection: ```ts theme={null} const priceStream = client.streamPrices([0, 1]); const positions = await client.getOpenPositions({ user: '0xTraderAddress' }); const stream = client.streamPositionUpdates(positions, priceStream); ``` ## Response schema ```ts theme={null} interface OstiumPositionUpdatesStream { onUpdate(handler: (positions: OpenPositionsResponse) => void): () => void; onOpen(handler: () => void): this; onError(handler: (event: Error) => void): this; onClose(handler: (code: number, reason: string) => void): this; getCurrent(): OpenPositionsResponse; refresh(next: OpenPositionsResponse): void; ingestTick(tick: PriceTick): void; ingestSnapshot(ticks: PriceTick[]): void; close(): void; } ``` # streamPrices Source: https://docs.ostium.com/developer/reference/stream-prices Open a live WebSocket price stream from the Ostium Builder SDK. ```ts theme={null} const stream = client.streamPrices([0, 1]); stream.onSnapshot(ticks => { console.log(ticks); }); stream.onTick(tick => { console.log(tick.pair, tick.mid); }); ``` You can update subscriptions dynamically: ```ts theme={null} stream.subscribe([2]); stream.unsubscribe([1]); ``` You can call `streamPrices(pairIds)` immediately after client creation. The SDK does not require a preloaded pair cache; if pair metadata is still loading, the stream connects and applies the pair filter once the metadata resolves. `subscribe()` and `unsubscribe()` calls made while the socket is still connecting are sent when the socket opens. ## Response schema ```ts theme={null} interface Response { onSnapshot(handler: (ticks: PriceTick[]) => void): () => void; onTick(handler: (tick: PriceTick) => void): () => void; onOpen(handler: () => void): this; onError(handler: (event: Error) => void): this; onClose(handler: (code: number, reason: string) => void): this; subscribe(pairIds: Array): this; unsubscribe(pairIds: Array): this; close(): void; readonly readyState: number; } interface PairSchedule { id: number; alwaysOpen?: boolean; timezone?: string; openingHours?: string[]; } interface PriceTick { pairId?: string; feedId: string; pair: string; from: string; to: string; bid: number; mid: number; ask: number; isMarketOpen: boolean; isDayTradingClosed: boolean; secondsToToggleIsDayTradingClosed: number; timestampSeconds: number; schedule?: PairSchedule; } ``` # transaction builders Source: https://docs.ostium.com/developer/reference/transaction-builders Build unsigned Ostium SDK transactions with the get*Tx helpers for EOA or Safe-based client applications. The SDK exposes `get*Tx()` helpers for every write action. Use them when your app wants the SDK to build the correct calldata, but your wallet or Safe flow will handle signing and submission. ## Available methods * `getSetupGaslessDelegationTx()` * `getApproveUsdcTx(amount)` * `getSetDelegateTx(delegateAddress, options?)` * `getRemoveDelegateTx(options?)` * `getOpenTradeTx(params)` * `getCloseTradeTx(params)` * `getCancelOrderTx(params)` * `getModifyOrderTx(params)` * `getUpdateCollateralTx(params)` ## Return shape Depending on the mode, the SDK returns one of two request types: ```ts theme={null} type BuiltTxRequest = | { kind: 'eoa'; to: `0x${string}`; data: `0x${string}`; value: bigint; from: `0x${string}`; traderAddress: `0x${string}`; } | { kind: 'safe'; safeAddress: `0x${string}`; traderAddress: `0x${string}`; calls: [ { to: `0x${string}`; data: `0x${string}`; value: bigint; }, ]; }; ``` ## Example ```ts theme={null} const client = await OstiumClient.createSelfAndSelf({ traderAddress: '0xTraderAddress', }); const tx = client.getOpenTradeTx({ pairId: 0, buy: true, price: '65000', collateral: '100', leverage: '5', type: OrderType.Market, }); ``` Use `createSelfAndSelf()` or `createDelegatedAndSelf()` for EOA-style build output, and use `createSelfAndGasless()` or `createDelegatedAndGasless()` for Safe-style build output. # updateCollateral Source: https://docs.ostium.com/developer/reference/update-collateral Add or remove collateral from an Ostium position with the Builder SDK. ```ts theme={null} await client.updateCollateral({ pairId, idx, amount: '50' }); await client.updateCollateral({ pairId, idx, amount: '-25' }); ``` Positive values top up collateral. Negative values remove collateral. ## Response schema ```ts theme={null} interface Response { txHash: `0x${string}`; smartAccountAddress?: `0x${string}`; } ``` # Changelog Source: https://docs.ostium.com/developer/sdk/changelog Versioned changes for @ostium/builder-sdk. # Changelog All notable changes to `@ostium/builder-sdk` will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## \[0.9.0] - 2026-09-23 Existing SDK calls and the values they read keep working untouched. Three things do change — see **Upgrading** below. ### Added * `createStore(params?)` — one subscribable object holding pairs, live prices and a trader's positions, kept current: prices over the WebSocket, pairs every 60s, positions every 15s. PnL, liquidation price and accrued rollover are recomputed locally on every tick. `getState()` and `subscribe()` match React's `useSyncExternalStore`. It follows one trader and throws `INVALID_CONFIG` when none can be resolved, so pass `user` on a read-only client. * `state.pairMeta` and the exported `PAIR_SNAPSHOT` — pair names, category, leverage caps and minimum notional for every listed pair, available synchronously so a market list renders before the first network call. No prices or rollover data: those are always fetched live. * Selectors over store state — `selectPosition`, `selectPositionsForPair`, `selectPrice`, `selectPair`, `selectPairMeta`, `selectMarkets`, `selectPositionsNearLiquidation` and `memoSelector`. Plain functions of state; React is not a dependency. * `previewCloseTrade(params)` — the exit mirror of `previewOpenTrade`: exit price after spread, rollover settled, net PnL and proceeds, for a full or partial close. * `getMaxCollateral(params)` — the largest collateral a trade can use, with `bound` naming the limit that stopped it (open interest, group collateral, per-trade cap, wallet balance or allowance). * `rolloverFee()` — accrued rollover as a pure function, alongside the existing `liquidationPrice()` and `pnl()`. * An optional `{ from }` on `getSetDelegateTx()` and `getRemoveDelegateTx()`. The default is unchanged — with no options the transaction still follows the client's mode. `{ from: 'trader' }` builds it from the trader's own account, which is what a first delegate registration needs, since the wrapped form asks a delegate that does not exist yet to authorise itself. `{ from: 'delegate' }` states the wrapped form explicitly. The `setDelegate` step from `getOnboardingStatus()` is the `{ from: 'trader' }` transaction. * `maxWithdrawable(params)` and `maxAddCollateral(params)` — the two collateral-edit limits as pure functions. `Pair.minLeverage` is returned too, since the add-side limit is measured against it. * `Position.highestLeverage` — the highest leverage a position has run at, which is what PnL is calculated against once collateral has been added or removed. * `Pair.rollover` and `Position.rolloverSnapshot` — the inputs `rolloverFee()` needs, so rollover can be advanced locally from one pairs poll instead of one read per position. * `rpcWsUrl` and `rpcHttpUrl` on the client and on `streamAccountUpdates()` — any Arbitrum RPC endpoint now works for the account stream's contract-log overlay. `alchemyApiKey` remains fully supported. * `OstiumPositionUpdatesStream.refresh(next)` — swap the watched position set without tearing the stream down. A stream created for a trader holding nothing opens its price socket on the first `refresh()` that brings a position in. ### Changed * `graphql` is now a declared dependency. It was always required at runtime by `graphql-request` and merely happened to resolve; a locked lockfile or a conflicting `graphql` version would have failed. Nothing to do unless your project pins a major version other than 16. ### Fixed * `Position.maxWithdrawable` was only the leverage cap, and overstated what a losing position can remove — 900 against a real limit of 675 on a 1,000 USDC position at 10x with a 300 loss. It now takes the smallest of the three limits the contract checks: the leverage cap, liquidation safety, and profit protection. * The live price stream now reconnects after a dropped connection, with backoff, and restores its subscriptions. Previously a drop left a stream that stayed silent. * `streamPositionUpdates()` no longer recomputes `maxWithdrawable` on a tick — it lacks the pair data to weigh all three limits, and was reporting the leverage cap against a price-adjusted leverage. The value from the last `getOpenPositions()` stands. * `streamPositionUpdates().close()` detaches its handlers from a price stream you supplied, instead of leaving them attached for the life of your socket. ### Upgrading Nothing to change, but three things behave differently: * **The price stream reconnects on its own now.** If you added your own reconnect on `onClose()` — the only option before — remove it, or you will end up with two sockets and duplicate ticks. * **`maxWithdrawable` can come back smaller**, and with it `marginSummary.totalWithdrawable`. Anything gating a "max" input on it gets stricter, never looser. * **TypeScript only:** `Position` gained `rolloverSnapshot` and `highestLeverage`, and `Pair` gained `rollover` and `minLeverage`, all required. Reading them is unaffected — the only code that stops compiling is code that *builds* a `Position` or `Pair` literal, typically a test fixture or a hand-assembled `OpenPositionsResponse` passed to `streamPositionUpdates()`. Add the new fields. ## \[0.8.0] - 2026-09-16 ### Added * `previewOpenTrade(params)` — everything an order ticket renders before a trade is signed: execution price after dynamic spread, the fee breakdown, collateral backing the position, position size, liquidation price, effective max leverage and the exposure-limit check. Derived from `@ostium/formulae`, the same math the contracts run. * `warnings[]` covers collateral and leverage bounds, minimum position size, fees exceeding collateral, exposure limits, and market or day-trading closure. `isValid` is `warnings.length === 0`. It is not exhaustive — chain state moves between preview and submission, so keep normal error handling around `openTrade()`. * The preview takes numbers and `isLong`; `openTrade()` takes decimal strings and `buy`. * `getOnboardingStatus(params?)` — what still stands between a trader and their first trade (USDC approval, delegate registration, gasless setup), each step carrying the transaction that clears it, plus `needsFunding` for the case no transaction can fix. * `getVaultBalance()` — protocol vault balance in USDC, cached for 60 seconds. * `liquidationPrice()` and `pnl()` — standalone trading math as pure functions over plain numbers. * `OstiumSubmissionPendingError` and `OstiumErrorCode.SUBMISSION_PENDING` — raised when an operation was submitted but its outcome is not yet known. Carries `userOpHash`. * `examples/` — three runnable programs, published with the package: an order ticket, a live positions view, and a complete trade loop. The first two need no credentials. * `llms.txt` and a Claude skill, both published with the package: flat API references written for AI coding agents. ### Changed * The default sponsorship endpoint is now `/v1/sponsor`. `DEFAULT_PIMLICO_URL` / `DEFAULT_PIMLICO_URL_TESTNET` still resolve, as deprecated aliases of `DEFAULT_SPONSOR_URL` / `DEFAULT_SPONSOR_URL_TESTNET`. * Gasless submissions are now confirmed against the UserOperation receipt rather than the transaction receipt. Setting `sponsorshipPolicyId`, or pointing `pimlicoUrl` at your own bundler, keeps the 0.7.x submission path. * A gasless receipt wait now times out after 120 seconds instead of waiting indefinitely. * `Fill.action` / `OrderAction` now include `'TopUpCollateral'`; `Fill.type` / fill `OrderType` now include `'TOP_UP_COLLATERAL'`. * Pair queries now request the fee and group fields the opening-fee and exposure-limit calculations need. ### Fixed * Gasless submissions no longer report a reverted trade as a success. A UserOperation whose inner call reverts still lands on-chain as a successful transaction, so a transaction hash was returned for a trade that never opened. Such a submission now raises `OstiumError` with code `CONTRACT_ERROR`, naming the contract error. * A gasless receipt timeout no longer looks like a failure. It raises `OstiumSubmissionPendingError` carrying `userOpHash`, so callers reconcile instead of resubmitting a trade that can still land. * Network errors carrying hex payloads are no longer misclassified as contract reverts. * `sponsorshipPolicyId` is no longer silently dropped. ### Upgrading No changes are required — every 0.7.1 export still resolves and all five constructors accept their existing arguments. Three things are worth knowing: * A gasless config with no `sponsorshipPolicyId` now submits through Ostium's sponsorship endpoint and is confirmed against the UserOperation receipt, so a trade that reverts on-chain raises `OstiumError` instead of returning a transaction hash. * A gasless receipt wait can now end in `OstiumSubmissionPendingError`. Do not resubmit on it — reconcile against `getOpenPositions()` or `getOrders()`. * If you override `subgraphUrl`, the endpoint must serve the pair fields added in this release; pair reads request them unconditionally. ## \[0.7.1] - 2026-08-12 ### Added * `extractOrderIdFromReceipt(receipt, trader?, action?)` accepts two optional filters for receipts that bundle several operations, such as an ERC-4337 `handleOps`. `trader` restricts matching to that address; `action` (`'any'` | `'open'` | `'close'`) scopes it to an open or close order id. Pre-V2 `PriceRequested` receipts carry no trader topic, so parsing those requires omitting `trader`. * `streamAccountUpdates()` snapshots now include `closeExecutions` per trader, surfacing close economics (`px`, `percentProfit`, `usdcSentToTrader`, `percentageClosed`, `isFullClose`). Each partial close of a trade appears as its own entry. * `OpenOrder` now includes `ntl`, `collateralUsed` and `leverage`. ### Changed * Pair-list and live-price reads share a 5-second in-flight cache, so concurrent `getPairs()`, `getAllPrices()`, `getOpenPositions()`, `getSimSlippage()` and `getSimOrderbook()` calls no longer duplicate upstream requests. * `streamAccountUpdates()` backs off after snapshot failures and respects upstream `Retry-After`. Live-price seeding errors now reach `onError` instead of being swallowed. ### Fixed * Stale pending market orders that no longer exist on-chain are no longer returned by `getOrders()`, `getBuilderOrders()` or `streamAccountUpdates()`. Cancelling one of them reverted. * Partial closes in `streamAccountUpdates()` are no longer treated as full closes. * Streamed positions keep `idx` at `-1` until the on-chain trade slot is known, instead of showing an order id that could not be used for close, TP/SL or collateral calls. ## \[0.7.0] - 2026-07-29 ### Changed * Gasless key-mode factories (`createSelfAndGasless`, `createDelegatedAndGasless`) accept an optional `safeAddress`. Use the smart-account address from a previous `client.getSmartAccountAddress()` call to skip the counterfactual-address derivation `eth_call` and make gasless construction network-free. The address is deterministic per key and chain. * Client construction no longer blocks on a subgraph pair-list fetch. Pair metadata loads lazily on first use, so build-only consumers and price streams can start without waiting for a full pair cache. * `streamPrices(pairIds)` can be called immediately after client creation. If the pair list is still loading, the stream connects and applies the pair filter once pair metadata resolves. ### Fixed * `OpenOrder.idx` from `getOpenOrders()` now carries the on-chain limit slot index, not the subgraph's global order id. Pass this value directly to `cancelOrder({ type: CancelOrderType.Limit })` and `modifyOrder()`. * `Fill.oid` and `Order.oid` are now documented and normalized as the on-chain keeper order id, formatted as a base-10 numeric string for both fast-overlay and subgraph-indexed entries. * `extractOrderIdFromReceipt()` now decodes order ids from the current `MarketOpenOrderInitiated`, `MarketCloseOrderInitiated`, and `MarketCloseOrderInitiatedV2` events, while still supporting older `PriceRequested` receipts. * Fast-overlay trades in `streamAccountUpdates()` seed their rollover baseline from the pair's rollover accumulator at the open block, keeping streamed PnL and liquidation estimates aligned with indexed positions. * `OstiumPriceStream.subscribe()` and `.unsubscribe()` no longer drop filter messages while the socket is still connecting; pending filter changes are sent on open. * The account-updates WebSocket retries reconnection indefinitely with a 2-second delay instead of stopping after viem's default retry limit. ## \[0.6.0] - 2026-07-23 ### Changed * **BREAKING**: Migrated the default builder API endpoints from `https://builder.ostium.io` to `https://builder.prod.bedrock.ostium.io` (subgraph, Pimlico sponsor, prices/OHLC, and WebSocket stream). `builder.ostium.io` is being deprecated; clients relying on the old default must upgrade. Consumers passing explicit URLs should update them accordingly. ### Fixed * **Ghost positions in `streamAccountUpdates()`**: a trade closed before its open was ever observed indexed, whose `MarketCloseExecutedV2` event was missed (e.g. during a WebSocket reconnect), previously lingered in the emitted snapshot forever. Three complementary fixes: * The account snapshot query now also fetches recently executed close/liquidation orders (15-minute lookback) and tombstones matching overlay entries, so the subgraph poll can clear a ghost even with a dead event socket. * New missed-event backfill: each poll sweeps `MarketOpenExecuted` / `MarketCloseExecutedV2` logs over HTTP from the last swept block, so events dropped during a WebSocket flap surface within roughly one poll interval instead of being lost. * `executed` overlay entries are no longer exempt from the overlay TTL; an executed trade the subgraph never confirms within the TTL now expires instead of ghosting indefinitely. ## \[0.5.0] - 2026-07-13 ### Changed * `streamAccountUpdates()` now fetches the account snapshot for all subscribed traders in **one batched subgraph query** per poll instead of one query per trader. If the shared 1000-row window saturates (any entity set returns a full page), the poll transparently falls back to per-user queries so a busy account still cannot starve the others. * Default `pollIntervalMs` raised from `700` to `3000`. Sub-second open/close confirmations come from the Alchemy event watchers (which also trigger an immediate poll), so the timer poll only paces reconciliation of changes with no watcher (limit fills, partial closes, TP/SL edits, liquidations). Pass `pollIntervalMs` to restore a faster cadence. * The per-poll Alchemy `eth_blockNumber` call is now served from a 30-second cache. Combined with the changes above, a 20-user stream drops from \~1,700 subgraph requests/minute to \~20, and steady-state Alchemy HTTP calls drop \~15×. ## \[0.4.1] - 2026-06-14 ### Added * `streamAccountUpdates()` now accepts `user` as an address array, allowing one or more trader addresses on a single stream (one WebSocket, one poll loop, one price feed). Emitted snapshots are keyed by normalized trader address with `{ positions, orders, limits }` per trader. * `OstiumAccountUpdatesStream.users` getter returning the subscribed trader addresses. * Optional `user` argument to `OstiumAccountUpdatesStream.addOptimisticOpen(params, submission?, user?)` to attribute an optimistic open to a specific subscribed address. Required when streaming multiple addresses; defaults to the sole subscribed address otherwise. ## \[0.4.0] - 2026-06-11 ### Added * Added this changelog. * Added `sets` pagination support to `getCandles()`. * Added `getOrders()` filters for global orders, builder address, status, pair ids, and execution time (`start` / `end` as Unix seconds UTC, inclusive bounds on `executedAt`). * Added `getBuilderOrders(builder, params?)` — fetches builder-tagged open orders plus sibling close/TP/SL orders on the same positions. `limit` caps phase-1 results only; phase-2 siblings are appended without a cap. * Added `builder` to returned `Fill` and `Order` objects. * Added `ntl` (USD notional) to returned `Fill` and `Order` objects. * Added `trader` to returned `Fill`, `Order`, `Position`, and `OpenOrder` objects. * Added `timestamp` (execution time, Unix seconds UTC — subgraph `executedAt`) to returned `Fill` and `Order` objects. * Added `MIN_OPEN_SIZE_USD` for the fixed \$5 minimum open size. * Added per-trade optional `builder.address` / `builder.feeBps` overrides on `openTrade()`; omitted fields fall back to client config. * Added `openFee` and `closeFee` (bps) to `Pair` — `openFee` is `takerFeeP / 10_000` plus the configured builder fee; `closeFee` is always `0` as there's no closing fees on Ostium currently. * Added `streamAccountUpdates()` for low-latency account confirmations using subgraph polling, Alchemy contract-log overlays, and live price repricing for open-trade PnL. * Added optimistic market-open overlays to `streamAccountUpdates()`, receipt `orderId` extraction via `extractOrderIdFromReceipt()`, and `attachOrderId()` reconciliation for lower-latency confirmations. * Added `alchemyApiKey` as a client option for account confirmation streams. * Added account update snapshots with SDK-formatted `Order`, `OpenOrder`, and `PairPosition` values. * Added `schedule` (market hours — `timezone`, `openingHours`, `alwaysOpen`) to `Pair` returned by `getPairs()`, and to `PriceData` / `PriceTick` from the live price feed. * Added background SDK usage attribution: submissions that target the Trading contract report their transaction hash to the builder API (`POST /v1/trade`) as a fire-and-forget request that never blocks or affects trading calls. ### Changed * Updated the default mainnet subgraph URL to `https://builder.ostium.io/v1/subgraph/gn`. ### Fixed * Removed the SDK-side `openTrade()` maximum leverage cap so contract-side validation is authoritative. * Removed the internal minimum-open-size config override path. ## \[0.3.1] * Current published package version when this changelog was introduced. # Errors Source: https://docs.ostium.com/developer/sdk/errors Reference for Ostium SDK error classes and error codes. The SDK exposes two error classes: * `OstiumError` for client creation, transaction building, signing, submission, and contract interaction * `OstiumSubgraphError` for subgraph reads, builder API reads, parsing, and stream-related data lookups ## OstiumError `OstiumError` is thrown by the main `OstiumClient` surface. ```ts theme={null} import { OstiumError, OstiumErrorCode } from '@ostium/builder-sdk'; try { await client.openTrade(params); } catch (error) { if (error instanceof OstiumError) { console.error(error.code, error.message); } } ``` ### Error codes | Code | Meaning | | - | - | | `INVALID_CONFIG` | The client was created with incompatible or missing configuration for the selected mode. | | `VALIDATION_FAILED` | Input parameters failed SDK validation before submission. | | `ALLOWANCE_INSUFFICIENT` | The trader does not have enough USDC allowance for the requested action. | | `SUBMISSION_FAILED` | Transaction or user operation submission failed. | | `DELEGATION_FAILED` | Delegation setup is missing or the requested delegated action is not allowed in the current mode. | | `CONTRACT_ERROR` | A contract read or write failed. | | `NETWORK_ERROR` | An RPC or network request failed. | | `SUBMISSION_PENDING` | The operation was submitted but its outcome is unknown. See below. | ### OstiumSubmissionPendingError `OstiumSubmissionPendingError` extends `OstiumError` with code `SUBMISSION_PENDING`. It is thrown when an operation reached the network but the SDK could not confirm how it ended — in practice, when waiting for a gasless UserOperation receipt times out after 120 seconds. This is not a failure: the operation was accepted and can still land, so retrying risks opening the position twice. Reconcile instead of resubmitting: ```ts theme={null} import { OstiumSubmissionPendingError } from '@ostium/builder-sdk'; try { await client.openTrade(params); } catch (error) { if (error instanceof OstiumSubmissionPendingError) { console.warn('still in flight:', error.userOpHash); // poll for the receipt, or reconcile against getOpenPositions() return; } throw error; } ``` A gasless trade that reverts on-chain raises `OstiumError` with code `CONTRACT_ERROR`, naming the contract error — it is never reported as a success. ## OstiumSubgraphError `OstiumSubgraphError` is thrown by read methods backed by the subgraph or builder API. ```ts theme={null} import { OstiumSubgraphError, OstiumSubgraphErrorCode } from '@ostium/builder-sdk'; try { const positions = await client.getOpenPositions({ user: '0xTraderAddress' }); } catch (error) { if (error instanceof OstiumSubgraphError) { console.error(error.code, error.message); } } ``` ### Error codes | Code | Meaning | | - | - | | `INVALID_CONFIG` | The read client was created with invalid endpoint or mode configuration. | | `INVALID_PARAMS` | The read method was called with invalid arguments. | | `FETCH_FAILED` | The subgraph or builder API request failed. | | `NOT_FOUND` | A requested entity or pair could not be found. | | `PARSE_ERROR` | The SDK received data but could not parse it into the expected shape. | ## Recommended handling * Catch `OstiumError` around trade setup and write methods. * Catch `OstiumSubgraphError` around read methods and streams. * Log both `error.code` and `error.message`. * If present, inspect `error.cause` for the underlying RPC, contract, or fetch error. # Examples Source: https://docs.ostium.com/developer/sdk/examples Runnable @ostium/builder-sdk programs shipped with the package: an order ticket, a live positions view, and a complete trade loop. Three runnable programs ship with the package, at `node_modules/@ostium/builder-sdk/examples/` after install. They import the SDK by package name, so they also run unchanged if you copy them into your own project. | File | What it shows | Needs a key? | | - | - | - | | `order-ticket.ts` | Preview a trade the way an order ticket would — execution price, fees, liquidation price, validity | No | | `positions.ts` | A trader's open positions, then live PnL over WebSocket | Snapshot no; streaming needs a WebSocket RPC | | `bot.ts` | A complete trade loop: onboard, preview, submit, watch, close | Yes | ## Running them ```bash theme={null} bun node_modules/@ostium/builder-sdk/examples/order-ticket.ts bun node_modules/@ostium/builder-sdk/examples/positions.ts 0xTraderAddress ARBITRUM_WS_URL=wss://... \ bun node_modules/@ostium/builder-sdk/examples/positions.ts 0xTraderAddress PRIVATE_KEY=0x... ARBITRUM_RPC_URL=https://... \ bun node_modules/@ostium/builder-sdk/examples/bot.ts ``` They are TypeScript — run them with `bun`, or compile them with `tsc` first. ## order-ticket.ts Resolves BTC/USD from [`getPairs()`](/developer/reference/get-pairs), then prints what [`previewOpenTrade()`](/developer/reference/preview-open-trade) returns: execution price, fees, liquidation price and any warnings. Read-only — no key, nothing submitted. ## positions.ts Prints a trader's open positions from [`getOpenPositions()`](/developer/reference/get-open-positions), then streams live updates via [`streamAccountUpdates()`](/developer/reference/stream-account-updates). The snapshot needs no credentials. Streaming needs a WebSocket Arbitrum RPC endpoint; without one the example prints the snapshot and skips streaming. `ALCHEMY_API_KEY` also works. ## bot.ts The full lifecycle: [`getOnboardingStatus()`](/developer/reference/get-onboarding-status), [`previewOpenTrade()`](/developer/reference/preview-open-trade), `openTrade()`, watching the position, then `closeTrade()` — including how to handle `OstiumError` and `OstiumSubmissionPendingError`. `bot.ts` spends funds. It defaults to testnet; `MAINNET=1` points it at real money. ## For AI coding agents The package also ships `llms.txt` and a Claude skill at `.claude/skills/ostium-builder-sdk/SKILL.md` — flat API references written for coding agents. Point your agent at one of them instead of pasting documentation pages. # Ostium API & SDK Source: https://docs.ostium.com/developer/sdk/overview The official Ostium TypeScript SDK and Builder API for reading market data, streaming prices, and placing trades programmatically on Ostium. The Ostium SDK is the current TypeScript client for reading Ostium market data, building mode-correct transactions, and submitting trading actions. Current package: `@ostium/builder-sdk@0.9.0`. See the [Changelog](/developer/sdk/changelog) for what it adds and the three behaviour changes to know about before upgrading. ## Install ```bash theme={null} npm install @ostium/builder-sdk viem ``` ## Core SDK surfaces * client creation methods for each execution mode * build-only transaction helpers for client-side signing * SDK-managed write methods for direct submission * read methods backed by the subgraph and builder API * live streams for prices, positions, and low-latency account confirmations * pre-trade previews for order and close tickets, derived from the same math the contracts run * a subscribable store that keeps pairs, prices and positions current for you Client construction is lazy: factories no longer pre-fetch the full pair list from the subgraph. Read methods populate market metadata on first use. Gasless submit-capable factories accept an optional known `safeAddress` to skip the smart-account derivation call during construction. ## Method index ### Client creation * `createSelfAndSelf` * `createSelfAndGasless` * `createDelegatedAndSelf` * `createDelegatedAndGasless` * `createReadOnly` See [Client Configuration](/developer/client-modes/configuration) for every parameter these factories accept. ### Previews and limits * `previewOpenTrade` * `previewCloseTrade` * `getMaxCollateral` * `getOnboardingStatus` * `getVaultBalance` Everything an order or close ticket needs before a trade is signed: execution price after spread, fees, resulting liquidation price, what a **Max** button should fill in, and what still stands between a trader and their first trade. ### Live state * `createStore` * `PAIR_SNAPSHOT` * `selectPosition`, `selectPositionsForPair`, `selectPrice`, `selectPair`, `selectPairMeta`, `selectMarkets`, `selectPositionsNearLiquidation`, `memoSelector` [`createStore()`](/developer/reference/create-store) holds pairs, live prices and positions in one subscribable object and keeps them current. Its `getState`/`subscribe` pair matches React's `useSyncExternalStore`. ### Standalone math * `liquidationPrice` * `pnl` * `rolloverFee` Pure functions over plain numbers, for bots and backtesters. See [Math helpers](/developer/reference/math-helpers). ### Helpers * `canBuildTransactions` * `canSubmitTransactions` * `getTraderAddress` * `isReadOnly` * `getSmartAccountAddress` * `checkUsdcAllowance` * `getBalances` * `extractOrderIdFromReceipt` ### Utilities and constants * `parseUsdc` * `parsePrice` * `parseLeverage` * `MIN_OPEN_SIZE_USD` * `MIN_COLLATERAL_USD` * `MAX_COLLATERAL_USD` ### Read methods * `getPairs` * `getAllPrices` * `getOpenPositions` * `getOpenOrders` * `getOrders` * `getBuilderOrders` * `getFills` * `getFillsByTime` * `getSimSlippage` * `getSimOrderbook` * `getCandles` * `getVaultBalance` * `streamPrices` * `streamPositionUpdates` * `streamAccountUpdates` ### Transaction builders * `getSetupGaslessDelegationTx` * `getApproveUsdcTx` * `getSetDelegateTx` * `getRemoveDelegateTx` * `getOpenTradeTx` * `getCloseTradeTx` * `getCancelOrderTx` * `getModifyOrderTx` * `getUpdateCollateralTx` ### Write methods * `approveUsdc` * `setupGaslessDelegation` * `setDelegate` * `removeDelegate` * `openTrade` * `closeTrade` * `modifyOrder` * `updateCollateral` * `cancelOrder` ## Build vs submit Every write action now has two SDK surfaces: * `get*Tx()` returns unsigned transaction data for wallet-driven or Safe-driven client applications * the write method (`openTrade`, `closeTrade`, `approveUsdc`, and so on) signs and submits through the configured mode when the client was created with credentials For example: ```ts theme={null} const client = await OstiumClient.createSelfAndSelf({ traderAddress: '0xTraderAddress', }); const tx = client.getOpenTradeTx({ pairId: 0, buy: true, price: '65000', collateral: '100', leverage: '5', type: OrderType.Market, }); ``` In gasless build-only modes, the same `get*Tx()` methods return a Safe-style request instead of an EOA request. ## Guides If you want implementation examples instead of method reference, use the guides section: * [Builder Set Up](/developer/builders/overview) * [React Example](/developer/builders/react-quickstart) * [Trader Quickstart](/developer/traders/approvals-and-first-trade) ## Examples Three runnable programs ship with the package: | File | What it shows | Needs a key? | | - | - | - | | `order-ticket.ts` | Preview a trade the way an order ticket would | No | | `positions.ts` | Open positions, then live PnL over WebSocket | Snapshot no; streaming needs a WebSocket RPC | | `bot.ts` | A complete trade loop: onboard, preview, submit, watch, close | Yes | See [Examples](/developer/sdk/examples) for what each one covers and how to run it. The same page lists the `llms.txt` and Claude skill files shipped for AI coding agents. ## Error handling See [Errors](/developer/sdk/errors) for the exported `OstiumError`, `OstiumSubgraphError`, `OstiumSubmissionPendingError`, and their error codes. ## Changelog See [Changelog](/developer/sdk/changelog) for the versioned SDK changes, including the `0.8.0` preview and gasless-submission work and the `0.9.0` store, rollover and reconnect additions. # Trader Quickstart Source: https://docs.ostium.com/developer/traders/approvals-and-first-trade Approve USDC and place a first Ostium trade with the Builder SDK. ## 1. Create a client ```ts theme={null} import { OrderType, OstiumClient } from '@ostium/builder-sdk'; const client = await OstiumClient.createSelfAndSelf({ traderPrivateKey: process.env.TRADER_PRIVATE_KEY as `0x${string}`, rpcUrl: process.env.ARB_RPC_URL!, }); ``` ## 2. Approve USDC ```ts theme={null} await client.approveUsdc('max'); ``` ## 3. Submit your first trade ```ts theme={null} const result = await client.openTrade({ pairId: 0, buy: true, price: '65000', collateral: '100', leverage: '10', type: OrderType.Market, }); ``` ## 4. Track status ```ts theme={null} const orders = await client.getOrders({ initiatedTxHashes: [result.txHash], }); ``` # Traders Overview Source: https://docs.ostium.com/developer/traders/overview Start here if you are using the Ostium Builder SDK to automate trading, run bots, or manage positions programmatically. The Trader track is for: * strategy developers * bots and automation scripts * desks running programmatic execution * power users who want direct control over positions and orders ## What traders usually do * discover pairs and market metadata * open market, limit, or stop orders * inspect open positions * update TP and SL * add or remove collateral * close positions * cancel timed-out or pending orders * fetch fills and execution history ## Start here * [Trader Modes](/developer/traders/trader-modes) * [Approvals and First Trade](/developer/traders/approvals-and-first-trade) * [Discover Pairs](/developer/traders/discover-pairs) ## Action pages * [Open a Market Trade](/developer/traders/open-market-trade) * [Open a Limit or Stop Order](/developer/traders/open-limit-or-stop-order) * [Manage Positions](/developer/traders/manage-positions) * [Modify TP / SL](/developer/traders/modify-tp-sl) * [Update Collateral](/developer/traders/update-collateral) * [Close a Trade](/developer/traders/close-a-trade) * [Cancel Orders](/developer/traders/cancel-orders) * [Track Fills and History](/developer/traders/track-fills-and-history) # How Ostium Works Source: https://docs.ostium.com/protocol/how-ostium-works A comprehensive explanation of the Ostium protocol: the onchain vault, the offchain hedge, how they settle daily, and the three core participants. *Last updated: July 22, 2026.* Ostium is an onchain perpetual instruments platform offering transparent, non-custodial leverage trading on Stocks, ETFs, Commodities, Indices, Forex, and Crypto with up to 200x leverage. Trades settle instantly in USDC on Arbitrum. Directional flow is hedged offchain through a network of institutional partners, including market makers (like Jump), prime brokers, and other major institutional partners, so pricing on every fill reflects the deepest underlying markets while collateral stays self-custodied onchain. ## What Ostium Does Ostium operates at the distribution layer of global markets. It offers onchain price exposure to 75 trading pairs across six asset classes and connects directional flow to the deepest underlying liquidity for each asset. The system has two layers that run side by side: * **Onchain settlement layer.** USDC collateral is held in audited smart contracts. Positions open, close, and liquidate onchain, and trade PnL settles to the user's wallet instantly. Oracle pricing from Ostium's in-house consensus oracle governs onchain price discovery for opens, closes, and liquidations. * **Offchain hedging layer.** Directional flow is hedged through a network of institutional partners: market makers (like Jump), prime brokers, and other major institutional partners. Partners supply pricing from the most liquid underlying markets and hedge the resulting flow, so execution on Ostium closely mirrors execution on those markets. ```mermaid theme={null} flowchart LR Trader[Trader
USDC, self-custody] --> Onchain[Onchain Settlement Layer
Smart contracts on Arbitrum] Onchain -->|net delta| Offchain[Offchain Hedging Layer
Institutional partners] Offchain --> Markets[Underlying Markets
FX, equities, commodities, indices, crypto] Onchain <-.->|daily settlement| Offchain ``` The two layers are reconciled by a **daily settlement run**. Once per day, USDC flows between the onchain vault and the offchain hedging book to rebalance the onchain buffer to its target size: * If traders net **win** during the day, the vault pays them onchain and the buffer shrinks. At settlement, the offchain book's matching gain is sent onchain to replenish the buffer. * If traders net **lose** during the day, the vault retains their losses and the buffer grows. At settlement, the excess is sent offchain to keep the hedging book funded. Between settlements, the protocol is net-flat across the two books. Only the *location* of the USDC changes intraday. Trader collateral remains self-custodied throughout, and every fill remains verifiable onchain. ## Three Pillars: Traders, Liquidity Providers, and Protocol Services Ostium has three core participants whose interactions make the protocol work. Traders open leveraged positions and pay opening fees. Liquidity providers deposit USDC into OLP and earn yield from those fees, sitting in the senior loss position for trading losses. Protocol services (oracle pricing, execution automation, settlement infrastructure, and the offchain hedging layer) power execution itself, run permissionlessly across third-party networks. Open leveraged long or short positions on 75 trading pairs. Pay opening fees, manage TP/SL, settle into self-custodied wallets. Deposit USDC into the OLP vault. Senior loss position for trading losses, protected by a junior buffer. Earn yield from 30% of opening fees. Four core services power execution: oracle pricing, automation, settlement infrastructure, and the hedging layer. ### Traders Traders open leveraged long or short positions on any of Ostium's 75 trading pairs. When entering a position, traders pay an opening fee and can set take-profit and stop-loss orders to manage risk. Position size is collateral × leverage; as the asset price moves, unrealized PnL fluctuates in real time. Traders pay rollover fees that reflect real-world carry costs, derived from the futures term structure or funding rates of the underlying asset, plus a carry premium. Either side of a trade can collect rollover rather than pay it, depending on whether the underlying sits in contango or backwardation. Positions are subject to liquidation if collateral falls below the maintenance margin threshold. Traders interact with the protocol entirely onchain; they are never locked into the interface and can exit or manage positions through any contract-enabled wallet. ### Liquidity Providers (LPs) Liquidity providers deposit USDC into the OLP vault and receive OLP tokens representing a pro-rata claim on vault capital and earned fees. **OLP sits in the senior loss position for trading losses.** A dedicated buffer of junior capital, posted by Ostium affiliates and strategic partners, absorbs trader PnL first, in full, before any trading loss can reach OLP. This is the same subordination structure used in CLOs and structured credit deals. The subordination covers trading losses and operational challenges with offchain hedging. OLP capital is held onchain in the protocol's vault, so a security event affecting onchain funds is borne first by onchain capital, including OLP. OLP deposits are not insured. OLP also functions as the working capital that settles winning trades onchain during the day, with balances restored at daily settlement from the offchain hedge. LPs earn yield from opening fees and can exit by burning OLP, subject to the vault's withdrawal window. See [Vault Overview](/vault/overview) for full deposit mechanics, yield breakdown, and settlement timing. ### Protocol Services Four core services power execution. Ostium's in-house consensus oracle supplies sub-second prices for both crypto and real-world assets. Prices are fetched on-demand when a trader opens a position. Automated keepers monitor price levels and execute liquidations, stop-losses, and take-profits in a decentralized, permissionless manner. Neither Ostium Labs nor the protocol controls execution. The OLP vault holds trader collateral, pays winning trades immediately onchain, accrues fees, and enforces maintenance margin. It is not a counterparty to directional flow. Institutional partners (market makers like Jump, prime brokers, and others) supply pricing from the most liquid underlying markets and hedge the directional flow offchain. The protocol nets internal offsets first; only the residual net delta is hedged. ## Protocol, Interface, and Labs Ostium separates protocol, interface, and team into three distinct components, so users always know which entity they're interacting with. The protocol (audited smart contracts on Arbitrum) is what handles trades and custodies user collateral. The interface (app.ostium.com) is just a frontend and can be replaced. Ostium Labs is the team developing both, but does not custody user funds. A suite of audited smart contracts deployed on Arbitrum that enable position opening, liquidation, fee accrual, and settlement. Source code is published. The web application at app.ostium.com. The interface is a frontend for interacting with the protocol and can be updated or retired without affecting the underlying contracts. The team developing the protocol and maintaining the interface. Labs does not custody user funds; collateral stays in audited smart contracts and traders interact with those contracts directly from self-custodied wallets. If the interface goes down, traders can still manage positions via direct contract interaction. ## Why Arbitrum? Ostium is deployed on Arbitrum because four properties together enable onchain leverage trading without compromising on speed, cost, or security. Sub-second finality lets liquidations execute tightly. Gas fees of approximately \$0.01 per trade keep leverage accessible. Ethereum's security guarantees are inherited through Arbitrum's fraud-proof mechanism. Circle supports USDC natively, simplifying collateral management. Arbitrum settles transactions in under one second, enabling tight liquidation execution and reliable price discovery. Network gas costs are approximately \$0.01 per trade, making leveraged trading accessible without prohibitive slippage or fees. Arbitrum inherits full Ethereum security through validator bonds and the fraud-proof mechanism. Users do not sacrifice decentralization or settlement guarantees. Circle supports USDC natively on Arbitrum with full composability, simplifying deposit and collateral management. ## Oracle System Prices come from Ostium's in-house oracle, a consensus pricing system built and operated by Ostium Labs. Built on sub-second market data, it publishes a consensus price onchain and governs every position open, close, and liquidation. **Crypto assets** (Bitcoin, Ethereum, etc.) are priced from live order book data across major exchanges and market data providers, normalized to a single reference price. **Real-world assets** (forex pairs, commodities, indices, and stocks) are priced from multiple market data providers. Prices update on roughly a sub-second basis. Multiple independent publishers each pull in the underlying market feeds and compute the price, then cryptographically sign it. Those signed prices are reconciled into a single agreed price, which is then published onchain. When a trader opens a position, the protocol immediately fetches the current oracle price and uses it as the entry price. ## Key Statistics * **\$50B+ cumulative volume** since launch across all 75 trading pairs * **\$300M+ peak open interest** * **26K+ traders** globally have opened positions on Ostium * **75 trading pairs** across six asset classes: Stocks, ETFs, Commodities, Indices, Forex, Crypto * **Up to 200x leverage** on select pairs, with per-pair caps visible on the [Markets](/traders/reference/markets) page ## FAQ The protocol continues to operate. Traders can still manage positions by calling smart contracts directly from their wallets. Liquidations and automations continue to execute. The interface is not a single point of failure. Perpetual instruments enable price exposure without owning the underlying asset, and let traders apply leverage without needing to borrow. Spot trading would require the protocol to hold actual assets offchain or mint synthetic tokens, introducing custodial risk. Ostium's perpetual instruments are fully collateralized in USDC, settle instantly onchain, and don't require the protocol to custody anything beyond user collateral. OLP sits in the senior loss position for trading losses: a junior buffer absorbs trader PnL first, in full, before any trading loss reaches OLP, the same subordination structure used in CLOs and structured credit deals. That protection covers trading losses and operational challenges with offchain hedging. Because OLP is held onchain, a security event affecting onchain funds is borne first by onchain capital, including OLP, and OLP deposits are not insured. See [Vault Overview](/vault/overview). The vault is the instant-settlement layer for every trade on Ostium. When traders close winning positions, the vault pays them immediately onchain, and those flows are mirrored by offchain hedges so the protocol stays balanced. Only the *location* of the USDC changes intraday. Once per day, a settlement run moves USDC between the two books to restore the buffer to its target size. This is operational cash flow, not loss. Trades settle instantly onchain through the OLP vault. Directional flow is hedged offchain through a network of institutional partners, across market makers (like Jump), prime brokers, and other major institutional partners. These partners supply pricing from the most liquid underlying markets, so fills on Ostium closely mirror the underlying exchange. No. Because directional flow is hedged offchain through institutional partners, no individual trader's PnL depends on the positioning of any other trader on Ostium. If a large cohort is long oil, that does not alter the cost or payoff of another long-oil position. No. Ostium uses request-for-quote (RFQ): the protocol solicits a live quote from its institutional partner network for each order, rather than matching against resting orders in a book. This is what lets Ostium inherit the depth of the underlying venues instead of rebuilding liquidity for each asset from scratch. ## What to Read Next Detailed audit summaries and contract verification. How the OLP settlement layer manages collateral and fees. Full list of trading pairs and asset classes. # Smart Contract Audits Source: https://docs.ostium.com/protocol/security/audits Comprehensive security audits of Ostium's smart contracts by Zellic, ThreeSigma, and Pashov ## Responsible Disclosure If you discover a security vulnerability in Ostium's smart contracts, please report it through [Ostium's Immunefi bug bounty program](https://immunefi.com/bug-bounty/ostium/). Do not publicly disclose the vulnerability before giving the team time to investigate and remediate. Do not attempt to exploit any vulnerability you discover. Responsible disclosure protects the entire community and may qualify you for a security reward. ## Audit Summaries ### Zellic **Who:** Zellic is a smart contract audit firm specializing in DeFi security reviews and vulnerability research. **Audits:** Two engagements. An initial audit in February 2024 covering the original Ostium architecture, and a follow-up audit in November 2025 reviewing the upgraded trading contracts ahead of the Jump Liquidity Upgrade. **Scope:** Both engagements covered core trading, vault, and liquidation contracts: trading execution, position settlement, fee calculations, and oracle price handling. The November 2025 review focused on the contract changes underpinning the post-JLU architecture. **Key Findings:** No critical vulnerabilities identified in either engagement. The reviews confirmed proper implementation of collateral management, fee accrual mechanics, and liquidation logic. Recommendations from the initial audit were addressed in subsequent contract updates. [Download Zellic Audit Report: November 2025 (PDF)](https://1263702948-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCEDPLHGTrrpP1i2dbe3d%2Fuploads%2F1NAt99nKJ1HesxyWjElF%2FZellic%20Nov%2025.pdf?alt=media\&token=3e34f62e-8909-41a7-888a-dda6d6fc481c) [Download Zellic Audit Report: February 2024 (PDF)](https://1263702948-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCEDPLHGTrrpP1i2dbe3d%2Fuploads%2FaMgw1k5iR4SvbYWRcs7q%2FOstium%20-%20Zellic%20Audit%20Report%20%281%29.pdf?alt=media\&token=771b25d4-be83-4a49-b1b5-8a9184d2b3f6) ### ThreeSigma **Who:** ThreeSigma is an independent security research firm focused on DeFi protocol audits and risk analysis. **Audit Period:** Conducted from February 19 to March 22, 2024. **Scope:** Secondary audit of trading contracts, OLP vault mechanics, rollover fee calculations, and position closure logic, complementing Zellic's earlier review. Included static analysis and dynamic testing across all major execution paths. **Key Findings:** No critical or high-severity vulnerabilities. ThreeSigma confirmed correct implementation of variable fee structures, proper handling of leverage constraints, and appropriate liquidation threshold enforcement. All recommendations have been addressed or are slated for future upgrades. [Download ThreeSigma Audit Report (PDF)](https://1263702948-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCEDPLHGTrrpP1i2dbe3d%2Fuploads%2FMpYIMzIusmebDMScUlYB%2FOstiumAudit.pdf?alt=media\&token=7043d99e-ba05-4ad1-8505-d3cf9e2a6415) ### Pashov Audit Group **Who:** Pashov Audit Group operates a network of 40+ vetted security researchers with deep experience in perpetual instrument protocols and oracle-driven pricing. **Audits:** Three security reviews: January 2025, April 2025, and January 2026. The January 2026 review specifically covered the post-JLU architecture (new vault settlement flow, daily reconciliation between onchain and offchain books, dynamic open-interest caps) ahead of the April 2026 mainnet upgrade. **Scope:** The January 2025 review covered core trading and vault contracts. The April 2025 review focused on oracle integration, price verification, and updates to liquidation automation following mainnet deployment feedback. The January 2026 review covered 13 core contracts (including OstiumVault, OstiumOpenPnl, OstiumTradingCallbacks, OstiumTrading, OstiumTradingStorage, OstiumPriceRouter, OstiumPairInfos, and related libraries) with five reviewers over a one-week engagement. **Key Findings:** All three reviews confirmed no critical vulnerabilities. The January 2026 review identified one high-severity finding affecting share-price accounting (operation ordering in the trade-close callback causing potential PnL double-counting between settlements) which was resolved before the JLU mainnet launch, plus two medium and eight low-severity findings, with eight resolved and three formally acknowledged. Pashov verified correct implementation of oracle price feeds, liquidation automation, and secure handling of collateral across all three engagements. Ostium's oracle relies on multiple independent publishers, and execution runs through external automation services, distributing critical functions across independent participants rather than relying on any single operator. [Download Pashov Security Review: January 2025 (PDF)](https://1263702948-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCEDPLHGTrrpP1i2dbe3d%2Fuploads%2FG0Of6YAPlrOIPs51aj16%2FOstium-security-review_2025-01-21.pdf?alt=media\&token=162c18f6-54fe-4dfe-be56-826ad040fff0) [Download Pashov Security Review: April 2025 (PDF)](https://1263702948-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCEDPLHGTrrpP1i2dbe3d%2Fuploads%2F7b08UITTgMLh1ej19d7I%2FOstium-security-review_2025-04-06.pdf?alt=media\&token=a61ab4ef-2245-4ec6-b865-e8069d40a332) [Download Pashov Security Review: January 2026 (PDF)](https://1263702948-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCEDPLHGTrrpP1i2dbe3d%2Fuploads%2F342r2xPX6yppDzAfPLVz%2FPashov%20Jan%2026.pdf?alt=media\&token=a212135d-79f4-4896-bc90-fb7e88058ea3) ## Mainnet Contract Addresses (Arbitrum) All contracts below are verified on Arbiscan and can be inspected at any time to confirm code integrity: | Contract | Address | Arbiscan Link | | - | - | - | | ProxyAdmin | 0x083F97BabF33D4abC03151B5DEc98170761f4025 | [View](https://arbiscan.io/address/0x083F97BabF33D4abC03151B5DEc98170761f4025) | | Registry | 0x799a139aE56e11F0476aCE2f6118CfcAed9608d2 | [View](https://arbiscan.io/address/0x799a139aE56e11F0476aCE2f6118CfcAed9608d2) | | Vault | 0x20D419a8e12C45f88fDA7c5760bb6923Cee27F98 | [View](https://arbiscan.io/address/0x20D419a8e12C45f88fDA7c5760bb6923Cee27F98) | | LockedDepositNft | 0xb4f1123BE58f5d69E1cf565ED8756C7fcf31c8D3 | [View](https://arbiscan.io/address/0xb4f1123BE58f5d69E1cf565ED8756C7fcf31c8D3) | | TradingStorage | 0xccd5891083a8acd2074690f65d3024e7d13d66e7 | [View](https://arbiscan.io/address/0xccd5891083a8acd2074690f65d3024e7d13d66e7) | | PairInfos | 0x3890243a8fc091c626ed26c087a028b46bc9d66c | [View](https://arbiscan.io/address/0x3890243a8fc091c626ed26c087a028b46bc9d66c) | | PairsStorage | 0x260E349F643f12797fDc6f8c9d3df211D5577823 | [View](https://arbiscan.io/address/0x260E349F643f12797fDc6f8c9d3df211D5577823) | | Trading | 0x6D0bA1f9996DBD8885827e1b2e8f6593e7702411 | [View](https://arbiscan.io/address/0x6D0bA1f9996DBD8885827e1b2e8f6593e7702411) | | TradingCallbacks | 0x7720fC8c8680bF4a1Af99d44c6c265a74e9742a9 | [View](https://arbiscan.io/address/0x7720fC8c8680bF4a1Af99d44c6c265a74e9742a9) | | OpenPnlFeed | 0xE607aC9FF58697c5978AfA1Fc1C5C437a6D1858c | [View](https://arbiscan.io/address/0xE607aC9FF58697c5978AfA1Fc1C5C437a6D1858c) | | TradesUpKeep | 0x959Da1452238F71F17f7DA5dbA2e9c04FEf57324 | [View](https://arbiscan.io/address/0x959Da1452238F71F17f7DA5dbA2e9c04FEf57324) | | PriceRouter | 0x4B0C3c77D398912491f192d265b237C8d4441AD7 | [View](https://arbiscan.io/address/0x4B0C3c77D398912491f192d265b237C8d4441AD7) | | PriceUpKeep | 0x52B2a78E12b09B66C6c8ce291D653D40bAb77f0c | [View](https://arbiscan.io/address/0x52B2a78E12b09B66C6c8ce291D653D40bAb77f0c) | | PrivatePriceUpKeep | 0xB71ec9eBD8145daCaCF6724363143cb5567A3d36 | [View](https://arbiscan.io/address/0xB71ec9eBD8145daCaCF6724363143cb5567A3d36) | | Verifier | 0xcCF233920e8cc9415ecF503b992881d69b6c47Ad | [View](https://arbiscan.io/address/0xcCF233920e8cc9415ecF503b992881d69b6c47Ad) | ## Testnet Contract Addresses (Arbitrum Sepolia) The following contracts are deployed on Arbitrum Sepolia for development and testing: | Contract | Address | Sepolia Explorer Link | | - | - | - | | Registry | 0xf86cff7679BA3E99d21255d774088E25FE0ec34a | [View](https://sepolia.arbiscan.io/address/0xf86cff7679BA3E99d21255d774088E25FE0ec34a) | | ProxyAdmin | 0xaB5583ebf187b926e48DeB9e9bb13418255c665C | [View](https://sepolia.arbiscan.io/address/0xaB5583ebf187b926e48DeB9e9bb13418255c665C) | | TimeLockOwner | 0xbc7B65D3Aa1C38B39AC63f131D5245C51b83acbc | [View](https://sepolia.arbiscan.io/address/0xbc7B65D3Aa1C38B39AC63f131D5245C51b83acbc) | | LockedDepositNft | 0xfFAd1f402030000C93152D38E384C202DD233445 | [View](https://sepolia.arbiscan.io/address/0xfFAd1f402030000C93152D38E384C202DD233445) | | Vault | 0x2fbf52c8769c5da05afee7853b12775461cD04d2 | [View](https://sepolia.arbiscan.io/address/0x2fbf52c8769c5da05afee7853b12775461cD04d2) | | Trading | 0x2A9B9c988393f46a2537B0ff11E98c2C15a95afe | [View](https://sepolia.arbiscan.io/address/0x2A9B9c988393f46a2537B0ff11E98c2C15a95afe) | | TradingStorage | 0x0b9F5243B29938668c9Cfbd7557A389EC7Ef88b8 | [View](https://sepolia.arbiscan.io/address/0x0b9F5243B29938668c9Cfbd7557A389EC7Ef88b8) | | PairInfos | 0xEF5D3fC8A4651B32D2DAB967E1D91a67eCfa953E | [View](https://sepolia.arbiscan.io/address/0xEF5D3fC8A4651B32D2DAB967E1D91a67eCfa953E) | | PairsStorage | 0x81e252CCF6BB99202220FDc0c5788bBd9e2473D0 | [View](https://sepolia.arbiscan.io/address/0x81e252CCF6BB99202220FDc0c5788bBd9e2473D0) | | TradingCallbacks | 0x83DC7c5dDeAD58f47230b70e6EF6bc44064BD814 | [View](https://sepolia.arbiscan.io/address/0x83DC7c5dDeAD58f47230b70e6EF6bc44064BD814) | | OpenPnlFeed | 0x27db8B73eC5cbaa17B4e7D3D3F07EBDb2eE3e154 | [View](https://sepolia.arbiscan.io/address/0x27db8B73eC5cbaa17B4e7D3D3F07EBDb2eE3e154) | | PriceRouter | 0x30DA14a620c9724C1Bb5d1f04049a29e2413d3aA | [View](https://sepolia.arbiscan.io/address/0x30DA14a620c9724C1Bb5d1f04049a29e2413d3aA) | | PriceUpKeep | 0x297775475E875025F58789dD46A9E2dcFCB0a1e1 | [View](https://sepolia.arbiscan.io/address/0x297775475E875025F58789dD46A9E2dcFCB0a1e1) | | PrivatePriceUpKeep | 0x5d3Af2Ab23a5F38c548151F507F6dded9979B328 | [View](https://sepolia.arbiscan.io/address/0x5d3Af2Ab23a5F38c548151F507F6dded9979B328) | | Verifier | 0x52C8c22BF47657C172e5D7a7FB2C1156916BAc46 | [View](https://sepolia.arbiscan.io/address/0x52C8c22BF47657C172e5D7a7FB2C1156916BAc46) | | TradesUpKeep | 0x9404A01D0546907e0bDCD0545146cB9781416E4c | [View](https://sepolia.arbiscan.io/address/0x9404A01D0546907e0bDCD0545146cB9781416E4c) | | MockUsdc | 0xe73B11Fb1e3eeEe8AF2a23079A4410Fe1B370548 | [View](https://sepolia.arbiscan.io/address/0xe73B11Fb1e3eeEe8AF2a23079A4410Fe1B370548) | | Gelato PairInfosManager | 0xad42c5da19b8d3f8c20847cb5a1a2deb502b5d46 | [View](https://sepolia.arbiscan.io/address/0xad42c5da19b8d3f8c20847cb5a1a2deb502b5d46) | ## Ongoing Monitoring All Ostium smart contracts are continuously monitored for anomalies in fund flows, liquidation execution, and oracle prices. Any unexpected behavior triggers immediate investigation and, if necessary, protocol safeguards. ## Verifying Contract Code All mainnet and testnet contracts are fully verified on Arbiscan and Arbitrum Sepolia Explorer. To verify a contract: 1. Navigate to the contract address on Arbiscan (mainnet) or Sepolia Explorer (testnet) 2. Click the "Code" tab 3. Compare the displayed source code against the [Ostium GitHub repository](https://github.com/ostium-protocol) 4. Confirm the compiler version and optimization settings match the audit reports This ensures transparency and allows anyone to independently audit the deployed code. ## FAQ All six audits cover the core trading and vault smart contracts: position opening and closing, liquidation logic, fee accrual, oracle pricing integration, and settlement flow. The post-JLU Pashov review (January 2026) specifically covered the new vault settlement architecture. Frontend code (the Ostium web app) and offchain hedging infrastructure are not in scope. The audits focus on the smart contracts where user funds are held. All contracts are verified on Arbiscan. Navigate to any contract address listed above, click "Code," and inspect the source. You can also clone the Ostium GitHub repository and compare the code directly. Ostium Labs monitors the protocol continuously and maintains relationships with top security researchers. If a vulnerability is discovered post-audit, the team will assess severity and implement a remediation plan (contract upgrade, market freeze, or emergency measures) depending on risk level. ## What to Read Next * [**How Ostium Works**](/protocol/how-ostium-works) — Two-layer architecture and the four core services that run the protocol. * [**Vault Overview**](/vault/overview) — Onchain settlement layer and two-tranche structure underpinning trader collateral. * [**Markets**](/traders/reference/markets) — All 75 trading pairs with leverage caps, fees, and trading hours. # Support & Community Source: https://docs.ostium.com/traders/community/support Where to get help, report issues, and stay connected as Ostium evolves Ostium's community runs across five surfaces: [Discord](https://discord.com/invite/ostiumlabs) for day-to-day support and discussion, [X](https://x.com/Ostium) for announcements and market commentary, the Ostium newsletter (posted on X and sent by email) for a regular wrap of markets and product updates, the [blog](https://www.ostium.com/blog) for long-form analysis, and [GitHub](https://github.com/ostium-labs) for open-source code. Discord is the primary support channel, monitored during active trading hours across US and European time zones. The routing table below maps each type of issue to the right channel. ## Where to Get Help Different issues route to different channels. Trading questions and UX feedback go to Discord. Security vulnerabilities go through [Ostium's Immunefi bug bounty program](https://immunefi.com/bug-bounty/ostium/) before any public disclosure. Privacy requests go to [privacy@ostium.io](mailto:privacy@ostium.io). Legal, partnership, and general inquiries go to [team@ostium.io](mailto:team@ostium.io). Using the right channel produces the fastest response and keeps sensitive matters off public timelines. | Issue | Route To | | - | - | | General trading question | Discord | | A trade did not execute as expected | Discord (include wallet address and transaction hash) | | Deposit or withdrawal issue | Check [Deposit](/vault/getting-started/deposit) or [Withdraw](/vault/getting-started/withdraw), then Discord | | UI bug | Discord or [team@ostium.io](mailto:team@ostium.io) | | Security vulnerability | [Ostium's Immunefi program](https://immunefi.com/bug-bounty/ostium/) (never post publicly) | | Privacy request | [privacy@ostium.io](mailto:privacy@ostium.io) | | Partnership or institutional inquiry | [team@ostium.io](mailto:team@ostium.io) | | Legal or terms question | [team@ostium.io](mailto:team@ostium.io) | ## Reporting Security Issues Report security vulnerabilities in Ostium smart contracts or infrastructure through [Ostium's Immunefi bug bounty program](https://immunefi.com/bug-bounty/ostium/) before any public disclosure. Public disclosure before reporting disqualifies the reporter from any security reward and can enable attacks against live user funds. Full scope, disclosure criteria, and reward details (up to \$200K USDC on Arbitrum) are on the Immunefi page; cross-referenced from the [Smart Contract Audits](/protocol/security/audits) page. ## Staying Informed Protocol changes, new market listings, and product upgrades are announced on X ([@Ostium](https://x.com/Ostium)) and the [blog](https://www.ostium.com/blog). X carries real-time announcements and market commentary; the blog hosts long-form analysis. For a packaged recap, the Ostium newsletter goes out on a regular cadence, published as an X post and sent by email; subscribe at the blog URL above. ## FAQ Ostium's primary community channel is Discord. A Telegram trading bot exists for placing trades directly from Telegram (see the [Terms of Use](/legal/terms-of-use) for details), but general community discussion, feature requests, and support happen in Discord. There is no official Ostium-run community Telegram group. No. Ostium is non-custodial: the team cannot access your wallet, move your funds, or reverse transactions. If tokens are sent to the wrong chain or address, the team cannot recover them. Always verify the recipient address and network before sending. The [Fund Your Account](/traders/getting-started/fund-account) page covers safe bridging practices. Functional bugs (UI glitches, display errors, unexpected behavior that does not expose user funds) go to Discord or [team@ostium.io](mailto:team@ostium.io). Security issues (smart contract vulnerabilities, access control flaws, anything that could compromise user funds) go through [Ostium's Immunefi bug bounty program](https://immunefi.com/bug-bounty/ostium/) privately. When in doubt, treat it as a security issue and use the Immunefi channel. ## What to Read Next Set up a wallet and start trading. Independent security reviews and the full responsible disclosure process. Two-layer architecture, settlement and hedging, and the four core services that run the protocol. # Connect Your Account Source: https://docs.ostium.com/traders/getting-started/connect-account Get started on Ostium with email login or Web3 wallet. Choose your preferred connection method and enable 1-click trading. ## Overview Ostium offers two ways to connect: email login (smart account) or Web3 wallet. Both methods are non-custodial. Trading is settled on Arbitrum. | Feature | Email Login | Web3 Wallet | | - | - | - | | Setup time | \~30 seconds | \~1 minute | | Gas fees | Platform-sponsored (no ETH needed) | You pay gas in ETH | | Custody | Smart account on Arbitrum | Your own wallet | | 1-click trading | Built-in | Enable separately | ## How to Connect Email login creates a smart account on Arbitrum, managed by you but with gasless transactions. Your funds remain under your control; Privy manages the account infrastructure without accessing your keys. Open [app.ostium.com](https://app.ostium.com) and click "Connect." Choose the "Email" option. Type your email address. Look for a code from [no-reply@privy.io](mailto:no-reply@privy.io). Check spam if it doesn't arrive within a minute. Copy the code and paste it back into Ostium. Your smart account is created and ready to fund. Your address appears in your profile. Smart accounts deduct 2 USDC from your balance to ensure you can always withdraw. This covers gas fees for future withdrawal transactions. Web3 wallet connection gives you full self-custody via your own Arbitrum-compatible wallet (MetaMask, Rabby, Coinbase Wallet, etc.). Open [app.ostium.com](https://app.ostium.com) and click "Connect." Choose "Continue with a wallet." Select MetaMask, Coinbase, Rabby, or another supported wallet. Approve the connection request in your wallet. If your wallet is on a different network, switch to Arbitrum when prompted. Your wallet address appears in the app. You're ready to fund. Your funds stay in your wallet at all times. The Ostium smart contracts are permitted to interact with them only for trades you authorize. ## Enable 1-Click Trading 1-click trading pre-approves transactions so Ostium can execute trades faster without requiring manual approval for each order. Open your profile settings page. Find "1-Click Trading" and click to enable. Follow the module steps and approve in your wallet. Requires a small amount of ETH for gas. Once enabled, future trades execute without additional prompts. Disable anytime from your profile. 1-click trading is built into your smart account and enabled by default. No setup needed. Trades are pre-approved automatically, with no gas costs. ## Security & Non-Custody Both connection methods are non-custodial. With email login, Privy manages the smart account infrastructure but cannot access your funds; only you can authorize transactions. With Web3 wallet login, you hold your private keys and full control. In both cases, Ostium never stores or accesses your authentication credentials or keys. Only send Arbitrum USDC to your account address. Sending other tokens or using a different chain risks permanent loss of funds. ## Troubleshooting **Email verification code not arriving?** Check your spam folder. If still missing, wait 5 minutes and request a new code. Privy support is available at [Privy Help](https://privy.io). **Wallet connection fails?** Ensure your wallet is on Arbitrum network. Try disconnecting and reconnecting. If issues persist, clear your browser cache and try a different wallet or browser. **Not enough ETH for gas?** Web3 wallet users need a small amount of ETH on Arbitrum to approve transactions and execute trades. If your transactions are failing, check your ETH balance. You can bridge ETH to Arbitrum using the [Arbitrum Bridge](https://bridge.arbitrum.io/) or buy ETH directly on Arbitrum through an exchange that supports Arbitrum withdrawals. Gas fees are typically under \$0.01 per transaction, so even a few dollars of ETH will last a long time. ## FAQ Email login requires no gas fees and includes built-in 1-click trading. Web3 wallet provides full self-custody. No. Email and Web3 wallet logins create separate accounts. You cannot merge them. If you want to use a different method, create a new account. Yes, if you use the same login method (same email or same wallet). Your balance and positions sync across all devices automatically. With email login, no; all gas fees are covered. With Web3 wallet, you pay small gas fees in ETH for transactions (approval, trades). Arbitrum gas is typically under \$0.01 per transaction. ## What to Read Next * **[Fund Your Account](/traders/getting-started/fund-account)** — Deposit USDC on Arbitrum. * **[Opening a Trade](/traders/trading/opening-a-trade)** — Execute your first order. # Fund Your Account Source: https://docs.ostium.com/traders/getting-started/fund-account Get USDC on Arbitrum to start trading. Your funds stay in your wallet; the Ostium smart contracts lock margin when you open a trade and return it when you close. ## Overview Trading on Ostium requires USDC on Arbitrum in your connected wallet. There is no separate Ostium balance or deposit step; your USDC sits in your wallet until you open a trade. When you open a trade, the Ostium smart contracts lock the required margin. When you close that trade, the margin (plus or minus your PnL) is returned to your wallet. If you already have USDC on Arbitrum, you're ready to trade. If not, there are several ways to get it there. | Method | Speed | Fees | Best for | | - | - | - | - | | Built-in on-ramp (Fun.xyz) | \~1 minute | Small gas + swap fee | New users, multi-chain assets | | Send USDC on Arbitrum | Instant | Arbitrum gas only | Already on Arbitrum | | CEX withdrawal | 5–30 minutes | Exchange fee | Binance, Coinbase users | | Bridge from Ethereum | 1–10 minutes | Gas + bridge fee | Existing ETH mainnet holders | ## Built-In On-Ramp The Ostium app integrates a built-in on-ramp **provided by third-party Fun.xyz** that lets you swap tokens from any supported chain (Ethereum, Base, Polygon, Solana, etc.) into USDC on Arbitrum. Fun.xyz handles the swap and bridge automatically; Ostium itself does not operate any on-ramp service. Open the Ostium app and click the Fund Account button. Choose the token you want to convert (ETH, USDT, USDC on another chain, etc.) and the chain it's on. The interface generates a one-time deposit address. Copy it. Transfer from your external wallet to the copied address. Within 1–2 minutes, USDC lands in your Arbitrum wallet. You're ready to trade. The credited amount reflects your deposit minus swap and bridge fees. Onchain gas fees apply on your source network; check the estimate before sending. Each transaction generates a unique address. Do not reuse addresses across multiple transactions. Always copy the fresh address shown. ## Send USDC Directly If you already hold USDC on Arbitrum in another wallet, send it to your connected wallet address. This is the fastest option with the lowest fees. Find your wallet address in the Ostium app or your wallet extension. Initiate a USDC transfer on Arbitrum from your other wallet. Once the transaction confirms onchain, your wallet balance reflects the new USDC. Ostium reads your wallet balance directly. ## CEX Withdrawal (Binance, Coinbase, etc.) Most major exchanges support USDC withdrawal directly to Arbitrum. Go to the withdraw or send section for USDC. Choose Arbitrum from the network dropdown. This is critical; do not select Ethereum or another chain. Enter your connected wallet address and complete the withdrawal. Exchange processing takes 5–30 minutes depending on the platform. Exchange fees vary but are typically 0–5 USDC. ## Bridge from Ethereum Mainnet If you hold USDC on Ethereum, bridge it to Arbitrum using Stargate, Across, or another bridge provider. Go to a bridge like [Stargate](https://stargate.finance), [Across](https://across.to), or another provider. Set USDC as the token, Ethereum as the source, and Arbitrum as the destination. Enter your wallet address as the recipient. Confirm the transaction in your wallet. Allow 1–10 minutes for the bridge to finalize. Once complete, your Arbitrum wallet balance updates and you're ready to trade. Bridge fees vary by provider, typically \$1–10. ## Troubleshooting **USDC not showing in Ostium after transfer?** Check the transaction on [Arbiscan](https://arbiscan.io) using your wallet address. If the transfer confirmed onchain, refresh the Ostium app or wait a few minutes for the UI to sync. **Sent tokens to the wrong chain?** Funds sent to non-Arbitrum networks cannot be recovered through Ostium. Contact the bridge or exchange support for help. **How much USDC do I need?** There is no minimum; your required amount depends on the collateral you use per trade. Only send USDC on Arbitrum to your wallet. Sending other tokens (USDT, WETH, etc.) or using a different chain (Ethereum mainnet, Solana, etc.) may result in permanent loss of funds. Always verify the network before sending. ## FAQ Ostium is non-custodial. Your USDC sits in your connected wallet until you open a trade; margin is then locked in the protocol contracts for the duration of the position and returned (adjusted for PnL and fees) when you close. Keys and approvals remain under your control throughout. Yes, via the built-in on-ramp or a manual bridge. The on-ramp supports Ethereum, Base, Polygon, Solana, and others. For unsupported chains, bridge to Arbitrum first using a third-party provider. Direct USDC on Arbitrum: instant. Built-in on-ramp: 1–2 minutes. Bridges: 1–10 minutes. CEX withdrawals: 5–30 minutes depending on the exchange. Nothing. It sits in your wallet untouched. The Ostium smart contracts are permitted to interact with your USDC only when you open or close a trade. ## What to Read Next * **[Connect Your Account](/traders/getting-started/connect-account)** — Set up email or Web3 wallet login. * **[Opening a Trade](/traders/trading/opening-a-trade)** — Start trading with your funded wallet. # Fees Source: https://docs.ostium.com/traders/reference/fees Every cost you'll pay trading on Ostium: opening, oracle, rollover, and liquidation fees in one page. ## Overview Ostium has four explicit fees (opening, oracle, rollover, early-close) plus liquidation, which takes remaining collateral when your margin is wiped out. The early-close fee applies only to profitable positions closed within 15 seconds of opening and is capped at the position's realized profit. | Fee Type | When Charged | Rate | | - | - | - | | Opening fee | Position entry | 3–10 bps (varies by asset) | | Oracle fee | Price request | \$0.10 USDC flat | | Rollover fee | Continuous (all pairs) | Variable, derived from underlying carry cost | | Early-close fee | Profitable close within 15s of open | 0–40 bps of notional, capped at profit | | Liquidation | Position liquidated | Remaining collateral | Opening, rollover, and liquidation proceeds flow into the Ostium Vault. 30% of opening fees accrues to OLP holders at each daily settlement. See [Vault Overview](/vault/overview) for how fees translate into OLP yield. **Coming from crypto perps?** Ostium does not use a zero-sum funding-rate payment between longs and shorts. All pairs, including crypto, use rollover fees anchored to real-world carry costs — derived from funding rates and futures term structure for the underlying asset. See [Rollover vs. Funding Rates](#rollover-vs-funding-rates) below for the comparison. *** ## Opening Fee The opening fee is a one-time charge deducted from your collateral when you enter a position. Rates vary by pair; the table below loads live values from the protocol subgraph. **Example:** 5x long on EUR/USD, 2,000 USDC collateral. Notional: 10,000 USDC. Fee: 10,000 × 3 bps = **3 USDC**. Effective collateral: 1,997 USDC. ### Where Opening Fees Go Opening fees split between two destinations: 30% flows to OLP holders at each daily settlement, and the remainder funds protocol operations and development. The OLP allocation is a tunable protocol parameter. *** ## Oracle Fee The oracle fee is a flat \$0.10 USDC charge each time the protocol fetches an onchain price. It covers oracle infrastructure and automation costs. The fee is refunded when you close your full position successfully, but not on partial closes or failed transactions. | Action | Fee | Refunded? | | - | - | - | | Open a market order | \$0.10 | No | | Place a limit or stop order | \$0.10 | No | | Cancel a limit or stop order | \$0.10 | No | | Partial close | \$0.10 | No | | Full close (successful) | \$0.10 | **Yes** | | Remove collateral | \$0.10 | No | If a market open fails due to slippage, your collateral is returned but the \$0.10 oracle fee is still consumed. The interface blocks most failure cases, so slippage is the most common reason you'd see a failed open with the fee charged. **Fee cap:** Oracle fees in a single transaction cannot exceed 10 USDC. *** ## Rollover Fee The rollover fee is the cost of holding any position over time. It reflects the real-world carry cost of the underlying asset — derived from the futures term structure or funding rates of the underlying — plus a carry premium from Ostium. Rates update daily via Gelato keepers; the fee itself accrues continuously per block. Both the fee and the rate display under the **Net Rate (L/S)** label in the trading interface. ### Two-Sided Rollover On every pair, rollover is two-sided: one side can collect rather than pay, depending on whether the underlying sits in contango or backwardation. The formula is symmetric: * **Long rollover** = underlyingCarry + brokerPremium * **Short rollover** = −underlyingCarry + brokerPremium Where `underlyingCarry` is derived from the futures curve or funding-rate market of the underlying asset, and `brokerPremium` is Ostium's markup (typically 1–2% annualized). If `underlyingCarry` is strongly negative (backwardation), longs may end up with a net negative rate — collecting rollover — while shorts pay more. The reverse is true in contango. ### Example: Crude Oil (WTI/USD) WTI/USD underlying term structure: −40% annualized (deep backwardation). * **Long:** −40% + 2% = −38% → **negative**, so longs collect a rollover credit on this pair (\~38% annualized) * **Short:** 40% + 2% = **42%** annualized (\~0.115% daily) A 1,000 USDC short position accrues roughly \$1.15/day in rollover fees, deducted from collateral. A long position on this pair would collect rollover, in this example around 38% annualized. ### Positive Rollover (Earning While Holding) On any pair, the rollover rate can be positive for one side of the trade — meaning traders on that side collect rather than pay. This is a structural property of how rollover is derived: when the underlying carry is asymmetric, one side receives the spread. Oil pairs are a common example given the depth of backwardation in energy futures, but the same dynamic applies across all asset classes when the underlying curve supports it. ### By Asset Type * **Commodities & Forex:** Derived from the futures term structure of the underlying. Contango means longs pay more; backwardation means shorts pay more. The opposing side can collect when the curve is steep enough. * **Stocks, ETFs & Indices:** Derived from SOFR plus carry premium. * **Crypto:** Derived from funding rates and futures term structure of the underlying market, plus carry premium. Rollover on crypto is two-sided like every other asset class; it is not a zero-sum long-vs-short funding payment. **Term Structure (Commodities, Forex, Crypto)** Ostium pulls settlement prices from consecutive contract months (M1, M2, M3+). Rather than using the raw basis `(M2 − M1) / M1`, which spikes at contract rolls, Ostium applies Gaussian weighting across contract months: ``` w_i = exp(-0.5 × ((i - current_month) / σ)²) smoothed_rate = Σ(w_i × rate_i) / Σ(w_i) ``` The smoothed result becomes the `underlyingCarry` component. Crypto pairs additionally incorporate funding-rate information from the underlying market to reflect the cost of carry observed by institutional market-makers. **SOFR (Stocks, ETFs & Indices)** Ostium uses the published SOFR rate plus carry premium. Updated daily by Gelato keepers at 00:00 UTC. **Carry Premium** A flat 1–2% annualized markup applied to all pairs. *** ## Rollover vs. Funding Rates If you're coming from other crypto perpetual platforms, you're likely familiar with funding rates: periodic payments between longs and shorts that keep perp prices anchored to spot. Ostium takes a different approach. | | Funding Rates (Typical Perp Platforms) | Rollover Fees (Ostium) | | - | - | - | | **What drives the rate** | Long/short OI imbalance | Real-world carry costs (SOFR, futures term structure, funding rates) | | **Who pays whom** | Dominant side pays minority side (zero-sum) | Traders pay the vault (or collect on enabled pairs) | | **Rate behavior** | Flips positive/negative based on market sentiment | Reflects underlying interest rates and term structure | | **Typical update frequency** | Every 1–8 hours | Rates update daily; fee accrues continuously per block | Funding rates are driven by trader positioning, so they can spike or flip direction when one side of the market gets crowded. Rollover fees are anchored to real-world borrowing costs and term structure, so rates move gradually and in line with broader macroeconomic conditions. Holding costs can be estimated before entering a position from the underlying carry plus carry premium. *** ## Liquidation There is no separate liquidation fee charged to the trader. When a position is liquidated, remaining collateral is retained by the protocol as part of settlement. The keeper bot (Gelato Functions) that executes the liquidation is paid by the protocol. You are not charged gas. For details on when and how liquidation triggers, see [Liquidation](/traders/trading/liquidation). *** ## Early-Close Fee A small fee applies to profitable positions closed within the first 15 seconds of opening. The fee is capped at the position's realized profit, so it cannot make a trade net-negative. Losing or breakeven closes pay no fee. Closes after 15 seconds pay no fee. The fee rate decays linearly from 40 bps at the moment of open to 0 bps at 15 seconds, applied to the position's notional size (collateral × leverage). The realized profit serves as the cap on the fee amount. ``` Fee rate (bps) = 40 × (15 - t) / 15, where t = seconds since open Fee amount = min(Fee rate × notional, realized profit) ``` ### Worked Example A trader opens a 10x long on BTC/USD with 1,000 USDC collateral (10,000 USDC notional). The position closes 10 seconds later with 30 USDC of realized profit. 1. Fee rate at t = 10s: 40 × (15 − 10) / 15 = **13.33 bps** 2. Fee on notional: 13.33 bps × 10,000 = **13.33 USDC** 3. Cap: realized profit is 30 USDC, so the full 13.33 USDC stands 4. Trader receives: 1,000 + 30 − 13.33 = **1,016.67 USDC** If the same position closes at breakeven or a loss, the fee is zero. If it closes at t ≥ 15 seconds, the fee is zero regardless of profit. *** ## FAQ Opening and oracle fees are one-time. Rollover fees accrue continuously per block on all pairs and reduce your effective collateral over time (unless you're on the receiving side of a positive rollover). Factor holding costs into any multi-day position. Opening fees, rollover, and liquidation proceeds flow into the Ostium Vault. 30% of opening fees accrues to OLP holders as yield at each daily settlement; the remainder funds protocol operations and development. Oracle fees cover oracle and automation infrastructure costs. See [Vault Overview](/vault/overview) for how these flows translate into LP yield. The order is rejected. Opening and oracle fees are deducted from collateral at submission. If the fee exceeds your available balance, the transaction won't execute. Reduce leverage, choose a lower-fee pair, or deposit more USDC. *** ## What to Read Next * **[Markets](/traders/reference/markets)** — All 75 trading pairs with leverage caps, fee rates, and trading hours. * **[Opening a Trade](/traders/trading/opening-a-trade)** — Step-by-step from collateral deposit to order confirmation. * **[Managing Positions](/traders/trading/managing-positions)** — Adjust TP/SL and collateral while a position is open. # Glossary Source: https://docs.ostium.com/traders/reference/glossary Key terms and definitions used throughout the Ostium protocol documentation A reference of terms used across Ostium documentation. Organized alphabetically with cross-references to related concepts. ## A ### Arbitrum Arbitrum is a Layer 2 Ethereum scaling network that executes transactions off-chain and settles them on Ethereum mainnet, reducing gas costs to approximately \$0.01 per trade while maintaining full Ethereum security. Ostium deploys exclusively on Arbitrum. ### Ask Price Ask price is the current market price at which you can buy an asset. Longs open at the ask and shorts close at the ask. On Ostium, the ask is derived from the oracle feed plus any applicable spread or price impact. ### Auto-Close Auto-close is the automatic closure of stock positions held above the overnight leverage cap at 3:45 PM ET, 15 minutes before regular market close. Positions at or below the overnight cap can be held across market sessions. See [Stocks: Day Trading](/traders/trading/stocks-day-trading). ## B ### Backwardation Backwardation occurs when the underlying asset's futures curve slopes downward: distant contracts trade below near-term contracts or spot. On Ostium, backwardation in the underlying lowers the long-side rollover rate and raises the short-side rate; longs may collect rollover on deeply backwardated pairs (see Contango, Rollover Fee). ### Bid Price Bid price is the current market price at which you can sell an asset. Shorts open at the bid and longs close at the bid. On Ostium, the bid is derived from the oracle feed minus any applicable spread or price impact. ### Buffer The buffer is the junior tranche of the Ostium Vault: dedicated capital posted by Ostium affiliates and strategic partners that sits in the vault smart contract alongside OLP capital. The buffer absorbs trader PnL first, in full, before any loss can reach OLP. Rebalanced to its target size once per day at daily settlement. See [Vault Overview](/vault/overview). ### Builder Codes Builder codes are referral identifiers that allow affiliates and integrators to track referrals and earn commission on trading fees from referred users. ## C ### Carry Cost Carry cost is the economic cost of holding a position in an underlying asset, derived from interest rates, futures term structure, and funding-rate markets. Ostium's rollover fee reflects the carry cost of each asset class plus a carry premium. See [Fees](/traders/reference/fees). ### Carry Premium Carry premium is a flat 1–2% annualized markup added to the rollover fee on all pairs. The total rollover fee equals the underlying market carry rate plus the carry premium. See [Fees](/traders/reference/fees). ### Collateral Collateral is the USDC a trader commits to open a leveraged position. Position size equals collateral multiplied by leverage. If unrealized losses erode collateral below the liquidation threshold, the position is liquidated (see Liquidation). Collateral is locked in the protocol contracts while a position is open and returned (adjusted for PnL) on close; keys and approvals remain under the trader's control throughout. ### Contango Contango occurs when the underlying asset's futures curve slopes upward: distant contracts trade above near-term contracts or spot. On Ostium, contango in the underlying raises the long-side rollover rate; shorts may collect rollover on deeply contango pairs (see Backwardation, Rollover Fee). ### C-Ratio C-ratio (collateral ratio) is the ratio of total vault collateral to total open position notional value. A legacy metric from the pre-upgrade vault model where c-ratio determined Overcollateralized (OC) and Undercollateralized (UC) states. Post-upgrade, directional trader flow is hedged offchain and OLP sits in the senior loss position behind a dedicated buffer, so c-ratio is no longer the primary driver of LP yield or vault state. See [Vault Overview](/vault/overview). ## D ### Daily Settlement Daily settlement is the once-per-day reconciliation between the onchain Ostium Vault and the offchain hedging book. During the day, winning trades are paid onchain from the vault while their offchain hedges accrue equal and opposite gains; losing trades are retained onchain while their offchain hedges take the matching loss. At settlement, USDC flows between the two books to restore the buffer to its target size. OLP price recomputes at settlement. See [Vault Overview](/vault/overview). ### Day Trading Leverage Day trading leverage is the higher leverage tier available on stocks during market hours (9:35 AM – 3:45 PM ET), up to 100x or the pair's maximum. Positions using day trading leverage auto-close at 3:45 PM ET. See [Stocks: Day Trading](/traders/trading/stocks-day-trading). ### Dynamic Spreads Dynamic spreads are variable bid-ask spreads that adjust based on short-term order flow imbalance. Currently enabled for all crypto and stock pairs on Ostium. Under balanced conditions, dynamic spreads apply zero spread; when order flow becomes one-sided, spreads widen to reflect the imbalance. Trades on pairs with dynamic spreads execute at a Price-After-Impact rather than the raw bid/ask (see Price-After-Impact). ## E ### Early-Close Fee A fee applied to profitable positions closed within 15 seconds of opening. The rate decays linearly from 40 bps at the moment of open to 0 bps at 15 seconds, applied to position notional (collateral × leverage), and capped at the position's realized profit. Losing and breakeven closes within 15 seconds pay no fee. See [Fees](/traders/reference/fees#early-close-fee). ### ETF An Exchange Traded Fund (ETF) is a basket of underlying assets that trades on an exchange. Ostium offers perpetual instruments on URA (uranium), KR2550 (Korean stock index), UNG (natural gas), and XLE (energy), with leverage up to 50x. See [Markets](/traders/reference/markets). ### Execution Model Execution model describes how Ostium executes trades. Prices are sourced from Ostium's in-house consensus oracle. Orders, liquidations, and automated TP/SL are executed by decentralized keepers, without a central operator. ## F ### Funding Fee (Deprecated) Funding fees were previously used on crypto pairs as a zero-sum payment between longs and shorts based on OI imbalance. This mechanism has been removed. All pairs now use rollover fees (see Rollover Fee). ## G ### Gas Gas is the transaction fee paid to execute onchain operations. On Arbitrum, gas costs are typically under \$0.01 per transaction. Web3 wallet users pay gas in ETH; email login users trade gas-free, as the platform sponsors their transactions. ### Gelato Functions Gelato Functions is a decentralized automation service that executes smart contract functions reliably and cost-efficiently. Ostium uses Gelato to execute liquidations, stop-losses, and take-profits without a central operator. ## H ### Hedging Partner An institutional counterparty that hedges the directional flow of trades opened on Ostium. When a trade opens onchain, it is mirrored offchain through a network of hedging partners, including market makers like Jump, as well as prime brokers and other major institutional partners. Partners supply pricing from the most liquid underlying markets. See [How Ostium Works](/protocol/how-ostium-works). ## J ### Junior Tranche In structured credit, the junior tranche absorbs losses first, protecting the senior tranche above it. On Ostium, the **buffer** is the junior tranche: it takes trader PnL in full before any loss can reach OLP (the senior tranche). See Buffer, Senior Tranche, and [Vault Overview](/vault/overview). ## K ### Keeper A keeper is an external service or bot that monitors trading conditions and executes transactions like liquidations or stop orders. On Ostium, keepers run as automated services without a central operator. ## L ### Leverage Leverage is a multiplier applied to collateral to determine position size. A trader with 100 USDC collateral and 10x leverage controls a 1,000 USDC notional position. Higher leverage amplifies both gains and losses. Ostium supports leverage from 1x up to 200x depending on the pair. ### Limit Order A limit order is an instruction to open a position at a specified price or better. The order executes automatically when the bid/ask reaches the limit price. Canceling a pending limit order incurs an oracle fee. See [Order Types](/traders/trading/order-types). ### Liquidation Liquidation is the automatic closure of a position when collateral falls below the liquidation threshold. Keeper bots execute liquidations onchain; the protocol pays the gas. All remaining collateral is retained by the protocol as part of settlement. There is no margin call. See [Liquidation](/traders/trading/liquidation). ## M ### Margin Margin is the collateral required to hold a position. Initial margin is the collateral needed to open. If unrealized losses bring collateral below the liquidation threshold, the position is liquidated. ### Market Order A market order executes immediately at the current bid (for shorts) or ask (for longs). Market orders are the standard way to enter or exit a position when you want to execute right away. ### Mid-Price Mid-price is the midpoint between the bid and ask. It is used as a reference for triggering stops, stop-losses, and liquidations, but trades never actually execute at the mid-price; execution always happens at the bid or ask. ## N ### Net Rate (L/S) Net Rate (L/S) is the label in the trading interface that displays the current rollover rate for both long and short positions on a pair. A positive rate means that side pays; a negative rate means that side collects. ### Non-Custodial Non-custodial means users retain full control of their keys and approvals at all times. Collateral moves into protocol smart contracts only when a position is opened and is returned (adjusted for PnL) on close; Ostium has no ability to move user funds outside that flow. ### Notional Notional is the total size of a leveraged position, equal to collateral multiplied by leverage. A 100 USDC position at 10x leverage has a notional of 1,000 USDC. Opening fees, rollover fees, and PnL scale with notional. Also called position size. ## O ### OI (Open Interest) Open interest is the total cumulative notional value of all open positions on a particular asset and side (long or short). High OI indicates liquidity and trader activity. ### OI Cap OI cap is the maximum notional open interest allowed for a pair, managing the protocol's risk envelope and the hedging layer's capacity. When the cap is reached, no new positions in that direction can be opened until existing positions are closed. ### OLP OLP (Ostium Liquidity Provider token) is the ERC-20 received by LPs who deposit USDC into the Ostium Vault. OLP holds the **senior loss position** of the protocol: a dedicated buffer of junior capital absorbs trader PnL first, in full, before any loss can reach OLP. OLP earns yield from 30% of opening fees. OLP price is recomputed once per day at settlement and does not update intraday. See [OLP Token](/vault/reference/olp-token). ### One-Click Trading (1-Click) One-click trading pre-approves transactions so trades execute without a wallet prompt for each order. Enabled by default on email (smart account) logins. Web3 wallet users can enable it in profile settings; doing so requires a one-time approval transaction. ### Opening Fee The opening fee is charged when a trader opens a position. Calculated on notional (collateral × leverage) and deducted from collateral. Rates range from 3 to 10 bps depending on asset class and pair. 30% of opening fees flows to OLP holders at daily settlement; the remainder funds protocol operations. See [Fees](/traders/reference/fees). ### Oracle An oracle is a service that supplies real-time price data for onchain use. Ostium uses its in-house consensus oracle, built and operated by Ostium Labs, for both crypto and real-world assets (stocks, commodities, forex, indices). ### Oracle Fee The oracle fee is a flat \$0.10 USDC charge each time the protocol fetches an onchain price. Charged at position open and refunded on a successful full close. Not charged on automated TP/SL executions. See [Fees](/traders/reference/fees). ### Overcollateralized (OC) — Deprecated Overcollateralized (OC) described a vault state from the pre-April 2026 model when c-ratio exceeded 100%. Retained here for historical reference only. Post-upgrade, OLP sits in the senior loss position behind a dedicated buffer, and the vault's state is described as Normal (buffer intact, OLP protected) or UC (buffer depleted). See [Vault Overview](/vault/overview). ### Overnight Leverage Overnight leverage is the lower leverage cap applied to stock positions held past market close (typically 5x–20x, varies by stock). Positions above the overnight cap auto-close at 3:45 PM ET. See [Stocks: Day Trading](/traders/trading/stocks-day-trading). ## P ### Partial Close A partial close exits a portion of an open position while keeping the rest active. Each partial close incurs an oracle fee (\$0.10). The remaining position must meet the pair's minimum trade size. ### Perpetual Instrument A perpetual instrument is a leveraged derivative that provides price exposure to an underlying asset without expiration, delivery, or ownership of the asset itself. Unlike traditional futures contracts, perpetual instruments have no expiry date and no physical or cash-settled delivery. Ostium's perpetual instruments are fully collateralized in USDC, settled onchain, and priced from oracle feeds on the underlying market. They are not futures contracts and are not regulated as such. ### Price-After-Impact Price-after-impact is the execution price on pairs with dynamic spreads enabled. It reflects short-term order flow imbalance: zero spread under balanced conditions, wider spread when flow becomes one-sided. See Dynamic Spreads. ### Privy Privy is the account infrastructure provider that powers Ostium's email login. Privy manages smart account creation and authentication without holding user funds or keys. ## R ### Rollover Fee Rollover fee is the cost of holding any position over time. Derived from the underlying asset's carry cost (SOFR for stocks, ETFs, and indices; futures term structure for commodities and forex; funding rates and futures term structure for crypto) plus a carry premium. Rollover is two-sided on every pair: depending on the shape of the underlying carry, one side can collect rollover rather than pay. Fees accrue continuously per block and are collected by the protocol. See [Fees](/traders/reference/fees) and [Vault Overview](/vault/overview) for how fees reconcile at daily settlement. ## S ### Senior Tranche In structured credit, the senior tranche is the safest layer of a capital stack. Losses must chew through the junior layers beneath it before any can reach senior capital. On Ostium, **OLP is the senior tranche** of the vault, protected by the buffer (the junior tranche). This is the same subordination architecture used in CLOs and clearinghouse default waterfalls. See Buffer, Junior Tranche, and [Vault Overview](/vault/overview). ### Settlement Settlement has two meanings on Ostium: **Position-level settlement** is the realization of PnL and return of collateral to the trader's wallet when a position closes. This happens instantly and onchain. **Daily settlement** is the once-per-day reconciliation between the onchain Ostium Vault and the offchain hedging book, at which point USDC flows between the two books to restore the buffer to its target size. OLP price recomputes at daily settlement. See [Vault Overview](/vault/overview). ### Slippage Slippage is the difference between the expected execution price and the actual execution price, caused by spreads and market movement between submission and execution. Traders can set slippage tolerance to limit unintended price movements. ### Smart Account A smart account is a programmable wallet managed onchain. Ostium's email login creates a smart account for each user, enabling gasless transactions and 1-click trading. The user retains full control; Privy provides the infrastructure without accessing keys. ### SOFR SOFR (Secured Overnight Financing Rate) is the benchmark interest rate published by the Federal Reserve reflecting overnight lending costs. Ostium uses SOFR plus carry premium to compute rollover for stocks, ETFs, and indices. Commodities and forex use futures term structure; crypto uses funding rates and futures term structure. ### Spread Spread is the difference between the bid and ask price. A wider spread means higher execution costs. On Ostium, spreads reflect underlying market liquidity; on pairs with dynamic spreads enabled, spreads also adjust with short-term order flow imbalance. ### Stop-Loss (SL) Stop-loss (SL) is an order that automatically closes a position when the mid-price crosses a specified level, limiting losses. Executes as a market close at the bid/ask. Free to set and adjust. No oracle fee on automated execution. ### Supported Assets Ostium supports 75 trading pairs across six asset classes: 35 stocks, 8 ETFs, 7 commodities, 7 indices, 9 forex, and 9 crypto. Each pair is a perpetual instrument with leverage from 1x up to 200x (varies by pair). See [Markets](/traders/reference/markets). ## T ### Take-Profit (TP) Take-profit (TP) is an order that automatically closes a position at a target price to lock in gains. Executes as a limit close at the TP price. Maximum TP is 900% above entry (entry × 10). Free to set and adjust. No oracle fee on automated execution. ### Term Structure Term structure refers to the relationship between spot prices and futures prices across different time horizons in the underlying market. For Ostium's perpetual instruments, the underlying term structure is reflected in rollover rates. Contango signals upward term structure; backwardation signals downward term structure. ## U ### Undercollateralized (UC) Post-upgrade, UC describes a state in which the vault's buffer has been fully depleted and additional trader PnL losses begin drawing on OLP capital. During UC, the vault automatically blocks new deposits as an accounting measure (pending-loss deposits would create share-pricing ambiguity). See [Vault Overview](/vault/overview). *Pre-upgrade, UC had a different meaning tied to c-ratio; that framing no longer applies.* ### USDC USDC is a fully-collateralized US dollar stablecoin issued by Circle. Ostium uses USDC as the sole collateral and settlement asset, allowing traders and LPs to maintain dollar-denominated exposure without conversion overhead. ## V ### Vault The Ostium Vault is the onchain settlement layer for every trade on the protocol. It holds two distinct pools of USDC: **OLP capital** (the senior tranche, deposited by LPs) and **buffer capital** (the junior tranche, posted by Ostium affiliates and strategic partners). Losses flow in strict order: the buffer absorbs trader PnL first, in full, before any loss can reach OLP. During the day, the vault pays winning trades immediately onchain; at daily settlement, USDC is rebalanced against the offchain hedging book to restore the buffer to its target size. See [Vault Overview](/vault/overview). *** ## Cross-Reference Summary **Position Management**: Leverage, Collateral, Margin, Notional, Position Size, Liquidation, Stop-Loss, Take-Profit, Limit Order, Market Order, Partial Close **Pricing & Execution**: Oracle, Ask Price, Bid Price, Mid-Price, Spread, Price-After-Impact, Slippage, Dynamic Spreads, Execution Model **Fees & Costs**: Opening Fee, Oracle Fee, Rollover Fee, Carry Premium, Net Rate (L/S) **Vault & Collateral**: Vault, Buffer, OLP, Senior Tranche, Junior Tranche, Daily Settlement, Settlement, Collateral, Undercollateralized (UC), Overcollateralized (deprecated), C-Ratio (deprecated) **Hedging & Carry**: Hedging Partner, Carry Cost, Rollover Fee, SOFR, Term Structure, Contango, Backwardation **Assets & Markets**: ETF, Perpetual Instrument, OI, OI Cap, Term Structure, Contango, Backwardation, Supported Assets **Stock Trading**: Day Trading Leverage, Overnight Leverage, Auto-Close **Accounts & Access**: Smart Account, Non-Custodial, Privy, One-Click Trading, Gas **Services & Integration**: Gelato Functions, Keeper, Builder Codes **Standards & Infrastructure**: Arbitrum, USDC, SOFR ## What to Read Next * **[Fees](/traders/reference/fees)** — Fee structure and calculations. * **[Markets](/traders/reference/markets)** — Trading pairs and asset availability. * **[Order Types](/traders/trading/order-types)** — All order types and execution mechanics. # Markets Source: https://docs.ostium.com/traders/reference/markets All 75 perpetual instrument trading pairs on Ostium across Stocks, ETFs, Commodities, Indices, Forex, and Crypto, with leverage caps, fees, and trading hours. ## Overview Ostium offers 75 perpetual instruments across 6 asset classes: Stocks, ETFs, Commodities, Indices, Forex, and Crypto. Leverage ranges from 5x to 200x depending on the pair, opening fees range from 3 to 10 bps, and all pairs execute on Bid/Ask pricing. Crypto trades 24/7; traditional assets follow their native market hours. *** ## Stocks 35 US-listed equities with leverage up to 100x and 6 bps opening fees. All use Bid/Ask execution. Rollover fees apply (SOFR-based). Market hours: Monday–Friday, 9:30 AM – 4:00 PM ET. Day-trading positions (above the overnight leverage cap) can be opened from 9:35 AM ET and auto-close at 3:45 PM ET. Outside hours, limit and stop orders queue; market orders are rejected. See [Stocks: Day Trading](/traders/trading/stocks-day-trading) for the full day-trading mechanics. | Pair | Max Leverage | Opening Fee | | - | - | - | | AAPL/USD | 100x | 6 bps | | AMD/USD | 100x | 6 bps | | AMZN/USD | 100x | 6 bps | | ARM/USD | 100x | 6 bps | | ASML/USD | 100x | 6 bps | | AVGO/USD | 100x | 6 bps | | BB/USD | 100x | 6 bps | | BMNR/USD | 100x | 6 bps | | CAT/USD | 100x | 6 bps | | COIN/USD | 100x | 6 bps | | COST/USD | 100x | 6 bps | | CRCL/USD | 100x | 6 bps | | CVX/USD | 100x | 6 bps | | GEV/USD | 100x | 6 bps | | GLXY/USD | 100x | 6 bps | | GOOG/USD | 100x | 6 bps | | HOOD/USD | 100x | 6 bps | | INTC/USD | 100x | 6 bps | | META/USD | 100x | 6 bps | | MP/USD | 100x | 6 bps | | MSFT/USD | 100x | 6 bps | | MSTR/USD | 100x | 6 bps | | MU/USD | 100x | 6 bps | | NFLX/USD | 100x | 6 bps | | NVDA/USD | 100x | 6 bps | | ORCL/USD | 100x | 6 bps | | PLTR/USD | 100x | 6 bps | | RIVN/USD | 100x | 6 bps | | SBET/USD | 100x | 6 bps | | SHEL/USD | 100x | 6 bps | | SMCI/USD | 100x | 6 bps | | SNDK/USD | 100x | 6 bps | | TSLA/USD | 100x | 6 bps | | TSM/USD | 100x | 6 bps | | XOM/USD | 100x | 6 bps | *** ## ETFs 8 ETFs with leverage up to 75x and 5 bps opening fees. Rollover fees apply (SOFR-based). Market hours follow the underlying exchange. KR2550 follows the Korean Stock Exchange schedule; the remaining ETFs trade US equity hours (9:30 AM – 4:00 PM ET). | Pair | Max Leverage | Opening Fee | | - | - | - | | DRAM/USD | 50x | 5 bps | | HYG/USD | 50x | 5 bps | | KR2550/USD | 10x | 5 bps | | REMX/USD | 50x | 5 bps | | TLT/USD | 75x | 5 bps | | UNG/USD | 5x | 5 bps | | URA/USD | 15x | 5 bps | | XLE/USD | 25x | 5 bps | *** ## Commodities 7 physical and energy commodities with leverage up to 50x and opening fees of 3 to 5 bps (gold 3 bps, all others 5 bps). Rollover fees apply (derived from futures term structure). Market hours generally follow CME/NYMEX futures: Sunday 6:00 PM ET – Friday 5:00 PM ET, with a daily settlement break. | Pair | Max Leverage | Opening Fee | | - | - | - | | XAU/USD (Gold) | 50x | 3 bps | | WTI/USD (Crude Oil) | 15x | 5 bps | | BRENT/USD | 15x | 5 bps | | XCU/USD (Copper Spot) | 50x | 5 bps | | XAG/USD (Silver) | 25x | 5 bps | | XPT/USD (Platinum) | 50x | 5 bps | | XPD/USD (Palladium) | 50x | 5 bps | *** ## Indices 7 major global indices with leverage ranging from 50x to 200x depending on the pair and 3 bps opening fees. Rollover fees apply (SOFR-based). US indices (US500, US100, US30) follow extended futures hours: Sunday 6:00 PM ET – Friday 5:00 PM ET. European and Asian indices follow their respective local exchange hours. | Pair | Max Leverage | Opening Fee | | - | - | - | | US500/USD (US 500) | 200x | 3 bps | | US100/USD (US Tech 100) | 75x | 3 bps | | US30/USD (US Wall Street 30) | 200x | 3 bps | | GER40/EUR (Germany 40) | 75x | 3 bps | | UK100/GBP (UK 100) | 75x | 3 bps | | JP225/JPY (Japan 225) | 50x | 3 bps | | HK50/HKD (Hong Kong 50) | 50x | 3 bps | *** ## Forex 9 major and emerging currency pairs with leverage from 100x to 200x depending on the pair and 3–5 bps opening fees. Rollover fees apply (derived from futures term structure). Market hours: Sunday 5:00 PM ET – Friday 5:00 PM ET (continuous 24/5). | Pair | Max Leverage | Opening Fee | | - | - | - | | AUD/USD | 100x | 3 bps | | EUR/USD | 200x | 3 bps | | GBP/USD | 200x | 3 bps | | NZD/USD | 150x | 3 bps | | USD/CAD | 200x | 3 bps | | USD/CHF | 200x | 3 bps | | USD/JPY | 100x | 3 bps | | USD/MXN | 150x | 5 bps | | USD/KRW | 150x | 5 bps | *** ## Crypto 9 major cryptocurrencies with leverage up to 200x and 10 bps opening fees. Rollover fees accrue continuously per block, same as all other asset classes. Market hours: 24/7, 365 days. | Pair | Max Leverage | Opening Fee | | - | - | - | | BTC/USD | 200x | 10 bps | | ETH/USD | 200x | 10 bps | | SOL/USD | 150x | 10 bps | | XRP/USD | 100x | 10 bps | | BNB/USD | 100x | 10 bps | | ADA/USD | 100x | 10 bps | | LINK/USD | 100x | 10 bps | | TRX/USD | 100x | 10 bps | | HYPE/USD | 100x | 10 bps | *** ## Execution Model All pairs use Bid/Ask execution: longs open at the ask price and close at the bid; shorts open at the bid and close at the ask. The spread between bid and ask reflects underlying market liquidity. **Dynamic spreads** are enabled for all crypto and stock pairs. On these pairs, trades execute at a Price-After-Impact that applies zero spread under balanced order flow and wider spreads when flow becomes one-sided. All other pairs (ETFs, commodities, indices, forex) use standard bid/ask execution. *** ## Holding Costs All pairs incur rollover fees that accrue continuously per block. See [Fees](/traders/reference/fees) for formulas and worked examples. | Asset Class | Holding Cost | Basis | | - | - | - | | **Stocks** | Rollover fee | SOFR + carry premium | | **ETFs** | Rollover fee | SOFR + carry premium | | **Commodities** | Rollover fee | Futures term structure + carry premium | | **Indices** | Rollover fee | SOFR + carry premium | | **Forex** | Rollover fee | Futures term structure + carry premium | | **Crypto** | Rollover fee | Funding rates + futures term structure + carry premium | *** ## FAQ No. Stocks trade Monday–Friday, 9:30 AM – 4:00 PM ET. Day trades (intraday positions with leverage above the overnight cap) auto-close at 3:45 PM ET. You can place limit and stop orders outside market hours; they queue and execute at market open. Crypto is 24/7; forex is 24/5. Limit and stop orders queue until the market reopens and execute at the first available price. Market orders are rejected during closed hours. Note that prices can gap between close and open, so queued orders may fill at a different level than when placed. Ostium regularly expands its market offerings. New pairs are announced in official channels and added to this page. *** ## What to Read Next * **[Fees](/traders/reference/fees)** — Opening fees, holding costs, oracle fees, and liquidation. * **[Opening a Trade](/traders/trading/opening-a-trade)** — Step-by-step from collateral to order confirmation. * **[Stocks: Day Trading](/traders/trading/stocks-day-trading)** — Intraday leverage rules and auto-close timing. # Closing a Trade Source: https://docs.ostium.com/traders/trading/closing-a-trade Manual closes, automated TP/SL, liquidation, and what happens to your collateral on each path. There are four ways a position closes on Ostium: manual full close, manual partial close, automated close via TP/SL, or liquidation. *** ## Manual Close ### Full Close Click **Close** on any open position to exit entirely at the current bid (longs) or ask (shorts). Your collateral plus or minus PnL is returned to your wallet. The \$0.10 oracle fee charged at open is refunded on a successful full close. ### Partial Close Close a portion of your position while keeping the rest open. Set the dollar amount or percentage in the close dialog. Each partial close incurs a \$0.10 oracle fee. The remaining position must still meet the pair's minimum trade size. *** ## Automated Close: TP and SL Take-profit and stop-loss orders close your position automatically when the market reaches your specified level. Both are set and managed from the Positions panel (see [Managing Positions](/traders/trading/managing-positions)). * **Take-Profit (TP):** Triggers when price moves in your favor. Executes as a limit close at your target price. * **Stop-Loss (SL):** Triggers when mid-price crosses your level. Executes as a market close at the bid/ask. Automated TP and SL executions do not charge an oracle fee. No cancellation fees apply. *** ## Liquidation Liquidation is an automatic close triggered when your collateral falls below the liquidation threshold. There is no margin call. Keeper bots (Gelato Functions) execute liquidations onchain; the protocol pays the gas fee. After liquidation, remaining collateral is retained by the protocol as part of settlement. You do not receive any remaining collateral. See [Vault Overview](/vault/overview) for how settlement flows reconcile onchain and offchain. See [Liquidation](/traders/trading/liquidation) for thresholds, formulas, and how to avoid it. *** ## Collateral After Close | Outcome | What Happens | | - | - | | **Positive PnL** | Initial collateral + profits returned to your wallet. | | **Negative PnL** | Initial collateral minus losses returned to your wallet. Losses retained by the protocol as part of settlement. | | **Liquidation** | All remaining collateral retained by the protocol as part of settlement. Nothing returned. | *** ## FAQ Profitable closes within the first 15 seconds of opening incur an early-close fee that decays linearly from 40 bps to 0. The fee is capped at the position's realized profit, so it cannot make a trade net-negative. Closes after 15 seconds, and losing or breakeven closes within 15 seconds, pay nothing to close. The oracle fee from opening is refunded on a successful full close. See [Early-Close Fee](/traders/reference/fees#early-close-fee) for the full mechanics and a worked example. Yes — see **Partial Close** above. A \$0.10 oracle fee applies per partial close, and the remaining position must meet the pair's minimum trade size. No. Remaining collateral is retained by the protocol as part of settlement. Liquidation thresholds, formulas, and mechanics for avoiding liquidation (stop-losses, lower leverage, added collateral) are documented on the [Liquidation](/traders/trading/liquidation) page. *** **Building this programmatically?** The Builder SDK exposes [`closeTrade()`](/developer/reference/close-trade) for full and partial closes. See [Close a Trade](/developer/traders/close-a-trade). ## What to Read Next * **[Liquidation](/traders/trading/liquidation)** — Thresholds, formulas, and worked examples. * **[Fees](/traders/reference/fees)** — All costs on Ostium in one page. * **[Managing Positions](/traders/trading/managing-positions)** — Adjust TP/SL and collateral while open. # Liquidation Source: https://docs.ostium.com/traders/trading/liquidation How liquidation works on Ostium: thresholds, formulas, worked examples, and how to avoid it. Liquidation is an automatic position close triggered when your collateral falls below a dynamically calculated threshold. Ostium uses margin-based liquidation with no margin calls. *** ## Liquidation Threshold Ostium maintains a **25% collateral backstop** for all leveraged trades. At maximum leverage for a given pair, liquidation triggers at a 75% loss. At lower leverage, the threshold is deeper (closer to total loss). The formula: ``` Liquidation Threshold (% loss) = 100% − (Leverage / MaxLeveragePair × 25%) ``` **Example**: 20x long on BTC/USD (max leverage 200x): ``` 100% − (20 / 200 × 25%) = 97.5% ``` Liquidation triggers at a 97.5% loss of collateral, meaning a price move of roughly 97.5% / 20 = **4.875%** against you. *** ## Worked Examples All examples assume 1,000 USDC collateral. The price move column shows approximately how far the asset must move against you to trigger liquidation. | Leverage | Max Pair Leverage | Threshold (% loss) | Price Move to Liquidate | | - | - | - | - | | 5x | 200x | 99.375% | \~19.9% | | 10x | 200x | 98.75% | \~9.9% | | 20x | 200x | 97.5% | \~4.9% | | 50x | 200x | 93.75% | \~1.9% | | 100x | 200x | 87.5% | \~0.9% | | 200x | 200x | 75% | \~0.4% | Higher leverage means a smaller price move triggers liquidation. At 200x, a move of less than half a percent liquidates the position. ### Liquidation Price For a long position, the approximate liquidation price is: ``` Liquidation Price ≈ Entry Price × (1 − Threshold / Leverage) ``` For a short position: ``` Liquidation Price ≈ Entry Price × (1 + Threshold / Leverage) ``` These are approximations. Accrued rollover fees reduce your effective collateral over time, which brings the actual liquidation price closer to your entry. The UI displays the exact liquidation price accounting for all fees. *** ## How Liquidation Executes Liquidations are executed automatically by **keeper bots** via **Gelato Functions**. When the mid-price crosses your liquidation price, the bot submits a liquidation transaction onchain. The protocol pays the gas fee. You are not charged. Execution typically occurs within seconds of the threshold being breached, depending on network congestion. *** ## Collateral After Liquidation There is no partial recovery after liquidation. All remaining collateral is retained by the protocol as part of settlement. See [Vault Overview](/vault/overview) for how settlement flows reconcile onchain and offchain. *** ## Reducing Liquidation Risk Four mechanics affect how close your position is to liquidation: **Stop-loss orders.** An SL closes the position before the liquidation threshold is reached. Placing an SL above the liquidation price (longs) or below it (shorts) exits the position in advance of the liquidation trigger. An SL at a 20–30% loss on a 20x position exits long before the 97.5% threshold. **Leverage.** Lower leverage gives a deeper loss threshold and requires a larger price move to liquidate. A 5x position tolerates nearly a 20% move against you; a 200x position tolerates less than 0.4%. **Added collateral.** Depositing additional USDC into an open position reduces effective leverage and pushes the liquidation price further away. This costs nothing. See [Managing Positions](/traders/trading/managing-positions). **Holding costs.** Rollover fees accrue continuously on all pairs and reduce effective collateral. On multi-day positions, these costs bring the liquidation threshold meaningfully closer. *** ## FAQ No. Remaining collateral is retained by the protocol as part of settlement. Mechanics for reducing liquidation risk (stop-losses, lower leverage, added collateral, holding-cost awareness) are covered in the section above. Typically within seconds of the mid-price crossing your liquidation threshold. You cannot reverse a liquidation once it begins. Yes. There are no margin calls or advance warnings. Liquidation is automatic and executes whenever the mid-price crosses your threshold, regardless of whether you are online. Stop-loss orders execute autonomously for this reason. Your liquidation threshold (percentage loss) is fixed at open. However, accrued rollover fees reduce your effective collateral, which moves your actual liquidation price closer to the current market price over time. The UI updates the displayed liquidation price to reflect this. *** ## What to Read Next * **[Managing Positions](/traders/trading/managing-positions)** — Add collateral or adjust SL to improve your margin. * **[Fees](/traders/reference/fees)** — Rollover fees and how holding costs affect your collateral. * **[Opening a Trade](/traders/trading/opening-a-trade)** — How leverage, collateral, and fees determine your position. # Managing Positions Source: https://docs.ostium.com/traders/trading/managing-positions Adjustments to open positions: TP/SL bounds, collateral mechanics, and worked examples. While your position is open, you can adjust take-profit and stop-loss targets for free, add collateral to lower leverage, or remove collateral to free up capital. All changes preserve the position. Only collateral removal incurs a fee (\$0.10 oracle). | Action | Fee | Effect | | - | - | - | | Update Take-Profit | Free | Changes the price at which your position auto-closes in profit | | Update Stop-Loss | Free | Changes the price at which your position auto-closes at a loss | | Add Collateral | Free | Lowers leverage, moves liquidation price further away | | Remove Collateral | \$0.10 oracle fee | Raises leverage, moves liquidation price closer | *** ## Take-Profit (TP) A TP automatically closes your position when the market reaches your target price. Updating it is free and can be done as many times as you want. * For **longs**: TP must be above the current market price and below the max TP (900% above entry, i.e., entry × 10). * For **shorts**: TP must be below the current market price and above the max TP (same 10x constraint in the opposite direction). * TP executes as a **limit close** at your exact target price. * Automated TP execution does not charge an oracle fee. * If you don't set a TP, the system applies the 900% cap automatically. Your position remains open until you close it manually or get liquidated. You continue accruing holding costs (rollover or funding). Some traders skip TP for open-ended directional plays and rely on manual exits instead. *** ## Stop-Loss (SL) An SL automatically closes your position when the market moves against you past a specified level. Updating it is free. * For **longs**: SL must be between your liquidation price and the current market price. * For **shorts**: SL must be between the current market price and your liquidation price. * SL executes as a **market close** when the mid-price crosses your level. Slippage is possible in volatile conditions. * Automated SL execution does not charge an oracle fee. * You cannot set an SL beyond your liquidation price. Yes. Once your trade is in profit, you can move your SL to your entry price. This caps downside to zero on the position while keeping upside open. Free to adjust, and you can move it again at any time. *** ## Adding Collateral Deposit additional USDC into an open position to lower effective leverage and push your liquidation price further away. This costs nothing. **Example**: You have a 10x long on ETH with 100 USDC collateral (1,000 USDC notional). You add 50 USDC: * New collateral: 150 USDC * New effective leverage: 1,000 / 150 = \~6.7x * Liquidation price moves further from current market *** ## Removing Collateral Withdraw USDC from an open position back to your wallet. This raises your effective leverage and moves your liquidation price closer. Costs \$0.10 (oracle fee to fetch the current price for recalculation, deducted from your collateral). You cannot remove collateral below the minimum margin requirement. **Example**: Same 10x position (100 USDC, 1,000 USDC notional). Price rises 10%, your collateral is now \~200 USDC. You remove 25 USDC: * New collateral: \~174.90 USDC (25 removed, \$0.10 oracle fee) * New effective leverage: 1,000 / 174.90 = \~5.7x * Liquidation price moves closer to current market *** ## Holding Costs While Open Positions accrue **rollover fees** continuously while open. Rollover applies to all pairs and accrues per block, reducing your effective collateral over time. Depending on current market skew, the rollover rate can be positive for one side, meaning you collect rather than pay. On multi-day positions, holding costs can materially affect PnL and bring your liquidation price closer to the market. Monitor the Positions panel for current accrued fees. See [Fees](/traders/reference/fees) for formulas, rate sources, and worked examples. *** ## FAQ Not directly. Leverage is fixed at open. However, adding collateral lowers your effective leverage, and removing collateral raises it. Adding 50 USDC to a 100 USDC position (10x) changes effective leverage to \~6.7x. Adding is free; removing costs \$0.10. No. Update them as many times as you want at no cost. Only removing collateral incurs a \$0.10 oracle fee. Your position is liquidated. Keeper bots monitor all positions continuously and trigger liquidation when collateral falls below the threshold. You do not receive remaining collateral after liquidation. See [Liquidation](/traders/trading/liquidation). *** **Building this programmatically?** The Builder SDK exposes [`getOpenPositions()`](/developer/reference/get-open-positions), [`updateCollateral()`](/developer/reference/update-collateral), and [`modifyOrder()`](/developer/reference/modify-order) for managing positions from code. See [Manage Positions](/developer/traders/manage-positions). ## What to Read Next * **[Closing a Trade](/traders/trading/closing-a-trade)** — Full and partial closes, and what happens to your collateral. * **[Fees](/traders/reference/fees)** — Opening, rollover, funding, and oracle fee details. * **[Liquidation](/traders/trading/liquidation)** — Thresholds, formulas, and how to avoid it. # Opening a Trade Source: https://docs.ostium.com/traders/trading/opening-a-trade Walkthrough for opening your first position on Ostium, with fee math and a worked example. To open a trade on Ostium, select a market, choose long or short, set leverage (1x–200x), deposit USDC collateral, optionally configure take-profit and stop-loss, and submit your order for onchain settlement in seconds. *** ## Step-by-Step Select from 75 markets across 6 asset classes: Stocks, ETFs, Commodities, Indices, Forex, and Crypto, all settled in USDC. * **Stocks**: AAPL, TSLA, NVDA, MSFT, and 29 more (33 total) * **ETFs**: HYG, KR2550, TLT, UNG, URA, XLE (6 total) * **Commodities**: XAU/USD (gold), XAG/USD (silver), WTI/USD (crude oil), and 4 more * **Indices**: US500/USD, US100/USD, US30/USD, GER40/EUR, and 3 more * **Forex**: EUR/USD, GBP/USD, USD/JPY, and 6 more (9 total) * **Crypto**: BTC/USD, ETH/USD, SOL/USD, and 6 more (9 total) Each pair has a maximum leverage cap and specific fee rate. See [Markets](/traders/reference/markets) for the full list. Choose **Long** (profit if price rises) or **Short** (profit if price falls). Both sides use the same leverage ranges and fee structures. All collateral and PnL are denominated in USDC. Leverage multiplies your position size: **Notional = Collateral × Leverage**. * **Range**: 1x to 200x, depending on the pair * **Lower-volatility pairs** (e.g., EUR/USD): higher caps (up to 200x) * **Higher-volatility pairs** (e.g., certain ETFs): lower caps (as low as 50x) * **Liquidation price**: Moves closer to entry as leverage increases. See [Liquidation](/traders/trading/liquidation) for thresholds. **Example**: 100 USDC collateral at 20x leverage = 2,000 USDC notional position. Deposit USDC (Arbitrum native or bridged). This is your margin. All position sizing, fees, and PnL derive from it. * **Minimum collateral**: Pair-specific (typically \$10–\$100 USDC) * **Effective collateral**: Deposited amount minus opening fee minus oracle fee * **Position size**: Effective collateral × leverage **Take-Profit (TP):** * Automatically closes your position at a target price * For longs, TP must be above current price; for shorts, below * Maximum TP: 900% above entry (i.e., entry price × 10). If you don't set one, the system applies this cap automatically. **Stop-Loss (SL):** * Automatically closes your position if price moves against you past this level * Must be set between current price and liquidation price * Free to set and adjust. Automated SL execution incurs no oracle fee. Leave both blank to manage manually from the Positions panel. * **Market**: Executes immediately at the current ask (long) or bid (short) price. * **Limit**: Executes only when price reaches your target. Canceling a pending limit order costs \$0.10. * **Stop**: Triggers when price crosses a level, then executes as a market order. See [Order Types](/traders/trading/order-types) for detailed mechanics and examples. Review your order summary: pair, side, leverage, collateral, effective margin, notional size, TP/SL prices, estimated opening fee, oracle fee, and liquidation price. Click **Submit**. The keeper network fetches the current oracle price, deducts fees from your collateral, and opens the position onchain. This typically takes 1–2 seconds. Once open, your trade appears in the **Positions** panel with live PnL, mark price, liquidation price, and margin ratio. From there you can update TP/SL, add or remove collateral, or close manually at any time. See [Managing Positions](/traders/trading/managing-positions) for details. *** ## What It Costs to Open Two fees are deducted from your collateral at open: the **opening fee** and the **oracle fee**. ### Opening Fee The opening fee is a one-time charge calculated on your **notional position size** (collateral × leverage) and deducted from collateral. | Asset Class | Fee | | - | - | | Stocks | 6 bps | | ETFs | 5 bps | | Commodities | 3–5 bps (gold 3 bps, others 5 bps) | | Indices | 3 bps | | Forex | 3 bps (5 bps for USD/MXN, USD/KRW) | | Crypto | 10 bps | ### Oracle Fee A flat \$0.10 USDC per price request. Charged at open. Refunded on a successful full close. Not charged on automated TP/SL executions. If a market open fails due to slippage, your collateral is returned but the \$0.10 oracle fee is consumed. ### Effective Collateral ``` Effective Collateral = Deposited Collateral − Opening Fee − Oracle Fee Position Notional = Effective Collateral × Leverage ``` ### Worked Example **Scenario**: Open a 10x long on ETH/USD with 1,000 USDC collateral. 1. Deposit: **1,000 USDC** 2. Notional position: 1,000 × 10 = **10,000 USDC** 3. Opening fee: 10,000 × 10 bps = **10 USDC** (calculated on notional, deducted from collateral) 4. Oracle fee: **\$0.10** 5. Effective collateral: 1,000 − 10 − 0.10 = **989.90 USDC** 6. Final notional: 989.90 × 10 = **9,899 USDC** If ETH/USD moves \~10% against you, your loss approaches your effective collateral and the position is liquidated. For the full fee schedule, holding costs (rollover and funding), and liquidation details, see [Fees](/traders/reference/fees). *** ## FAQ Your position stays open until you manually close it or price reaches your liquidation threshold. Without a stop-loss, large moves against you can wipe out your collateral before you have time to react. Not directly. Leverage is set at open. However, you can adjust your effective leverage by adding collateral (which lowers leverage) or removing collateral (which raises it). See [Managing Positions](/traders/trading/managing-positions). The opening fee and oracle fee are deducted from collateral at open. See the **Worked Example** above for the full calculation. *** **Building this programmatically?** The Builder SDK exposes [`openTrade()`](/developer/reference/open-trade) for market, limit, and stop orders. See [Trader Quickstart](/developer/traders/approvals-and-first-trade) for a working example. ## What to Read Next * **[Managing Positions](/traders/trading/managing-positions)** — Adjust TP/SL, add collateral, and track PnL. * **[Fees](/traders/reference/fees)** — Complete fee breakdown: opening, rollover, funding, liquidation. * **[Order Types](/traders/trading/order-types)** — Market, limit, and stop orders with examples. # Order Types Source: https://docs.ostium.com/traders/trading/order-types Reference for Market, Limit, Stop, TP, SL, Liquidation, and Close Market orders on Ostium. Ostium supports seven order types: three for opening positions (Market, Limit, Stop) and four for closing (Close Market, Take-Profit, Stop-Loss, Liquidation). All orders execute at bid/ask prices. *** ## Opening Orders ### Market Order Executes immediately at the current ask (longs) or bid (shorts). * **Trigger:** Immediate on submission. * **Execution:** Bid/ask price. * **Oracle fee:** \$0.10 at open. ### Limit Order Waits for the actual trade price (bid or ask) to reach your specified level, then executes at that price or better. * **Trigger:** Bid/ask crossing your limit price. * **Execution:** At the limit price or better. * **Oracle fee:** \$0.10 at placement. Canceling costs an additional \$0.10. If price never reaches your limit, the order stays open until you cancel it. ### Stop Order Waits for the mid-price to cross your stop level, then executes immediately as a market order. * **Trigger:** Mid-price crossing your stop price. * **Execution:** Bid/ask price (market execution after trigger). * **Oracle fee:** \$0.10 at placement. Canceling costs an additional \$0.10. Execution price is not guaranteed to match the stop level. After triggering, the order fills at whatever the current bid/ask is. *** ## Closing Orders ### Close Market Exits your position immediately at the current bid (longs) or ask (shorts). * **Trigger:** Immediate on submission. * **Execution:** Bid/ask price. * **Oracle fee:** Refunded on a successful full close. \$0.10 charged on partial closes. ### Take-Profit (TP) Closes your position automatically when price reaches your target in the profitable direction. * **Trigger:** Bid/ask crossing your TP price. * **Execution:** At the TP price (limit-style close). * **Oracle fee:** Not charged on automated execution. TP is set and adjusted from the Positions panel at no cost. Maximum TP is 900% above entry (entry × 10). See [Managing Positions](/traders/trading/managing-positions). ### Stop-Loss (SL) Closes your position automatically when price moves against you past a specified level. * **Trigger:** Mid-price crossing your SL price. * **Execution:** Bid/ask price (market-style close). * **Oracle fee:** Not charged on automated execution. SL must be set between the current market price and your liquidation price. Free to set and adjust. See [Managing Positions](/traders/trading/managing-positions). ### Liquidation Automatically closes your position when collateral falls below the liquidation threshold. Not user-initiated. * **Trigger:** Mid-price crossing the calculated liquidation price. * **Execution:** Bid/ask price, executed by keeper bots (Gelato Functions). * **Cost:** Protocol pays gas. Remaining collateral is retained by the protocol as part of settlement. See [Liquidation](/traders/trading/liquidation) for thresholds and formulas. *** ## Bid, Ask, and Mid-Price Three prices matter on Ostium: * **Bid:** the price at which you can sell (close a long or open a short). * **Ask:** the price at which you can buy (open a long or close a short). Always slightly higher than the bid. * **Mid-price:** the midpoint between bid and ask. Used as a reference for triggering stops, stop-losses, and liquidations, but you never actually execute at mid-price. The difference between bid and ask is the **spread**. Your actual entry or exit price is always the bid or ask, never the mid. This is why a stop-loss may trigger (mid-price hit your level) but execute at a slightly different price (the bid or ask at that moment). *** ## Execution Model All pairs currently use **bid/ask execution**: longs open at the ask and close at the bid; shorts open at the bid and close at the ask. The spread between bid and ask reflects underlying market liquidity. **Dynamic spreads** are enabled for all crypto and stock pairs. On these pairs, orders execute at a **Price-After-Impact** that adjusts based on short-term order flow imbalance: zero spread under balanced conditions, wider spread when flow is one-sided. All other pairs use standard bid/ask execution. See [Markets](/traders/reference/markets) for details. *** ## Summary Table | Order Type | Side | Trigger | Execution | Cancel Cost | | - | - | - | - | - | | Market | Open | Immediate | Bid/ask | N/A | | Limit | Open | Bid/ask crosses limit | At limit or better | \$0.10 | | Stop | Open | Mid-price crosses stop | Bid/ask (market) | \$0.10 | | Close Market | Close | Immediate | Bid/ask | N/A | | Take-Profit | Close | Bid/ask crosses TP | At TP (limit) | Free | | Stop-Loss | Close | Mid-price crosses SL | Bid/ask (market) | Free | | Liquidation | Close | Mid-price crosses liq. price | Bid/ask (market) | N/A | *** ## FAQ A **Stop** (Open Stop) triggers entry into a new position when mid-price crosses a level, then executes as a market order. A **Stop-Loss** closes an existing position when mid-price hits your stop level, also as a market order. Both trigger on mid-price, but one opens and one closes. Yes. You can set one TP and one SL on a single position simultaneously. Whichever triggers first closes the position and cancels the other. You can also have pending Open Limit or Open Stop orders while other positions are open. Limit orders trigger on the actual bid/ask price, not the mid-price. The mid-price may touch your level while the bid or ask remains above (for long limits) or below (for short limits). The order fills only when the execution price reaches your limit or better. *** **Building this programmatically?** The Builder SDK supports market, limit, and stop orders via [`openTrade()`](/developer/reference/open-trade), and order modification via [`modifyOrder()`](/developer/reference/modify-order). See [Open a Limit or Stop Order](/developer/traders/open-limit-or-stop-order). ## What to Read Next * **[Opening a Trade](/traders/trading/opening-a-trade)** — Step-by-step from market selection to order submission. * **[Managing Positions](/traders/trading/managing-positions)** — Adjust TP/SL and collateral on open positions. * **[Fees](/traders/reference/fees)** — Oracle fees, opening fees, and all other costs. # Stocks: Day Trading Source: https://docs.ostium.com/traders/trading/stocks-day-trading Day-trading rules for stocks on Ostium: leverage tiers, auto-close timing, and overnight transitions. All 33 stocks on Ostium support day trading with up to 100x leverage during market hours. Positions above the overnight leverage cap are automatically closed at 3:45 PM ET to eliminate overnight gap risk. ## Leverage Tiers Stocks have two leverage caps: * **Day trading leverage:** up to 100x (or the pair's maximum). Available from 9:35 AM to 3:45 PM ET. Positions above the overnight cap will auto-close at 3:45 PM ET. * **Overnight leverage:** a lower cap per stock (typically 5x–20x). Positions at or below this cap can be held indefinitely across market sessions. The UI shows both caps in the leverage selector. When you set leverage above the overnight cap, a "Day Trading" label appears with a countdown to auto-close. ## Auto-Close At **3:45 PM ET** (15 minutes before market close), all positions with leverage above the overnight cap are automatically closed at the current bid/ask. This is not optional; there is no grace period or extension. * Auto-close executes at market price. Slippage is possible, especially on lower-volume stocks. * A countdown timer in the UI shows time remaining before auto-close. * Take-profit orders can exit positions before auto-close if you'd prefer to control your exit price. ## Holding Overnight To keep a stock position past market close, your leverage must be at or below the overnight cap. You can either open the position at overnight leverage from the start, or reduce your leverage below the cap before 3:45 PM ET to avoid auto-close. ## FAQ Your position is automatically closed at market price. You may experience slippage. There is no grace period. Yes, if leverage is at or below the overnight cap for that stock. Overnight positions are not auto-closed and can be held indefinitely. Yes. You can increase to day-trading leverage during market hours, or reduce back to overnight leverage before 3:45 PM to keep the position open past close. *** ## What to Read Next * **[Opening a Trade](/traders/trading/opening-a-trade)** — Place your first stock trade. * **[Markets](/traders/reference/markets)** — All stocks with leverage caps and trading hours. * **[Liquidation](/traders/trading/liquidation)** — Thresholds at different leverage levels. # Welcome to Ostium Source: https://docs.ostium.com/traders/welcome What Ostium is, how it works, and where to start trading. Ostium is the onchain gateway to the world's most liquid global markets. It offers perpetual-instrument exposure to 75 trading pairs across Stocks, ETFs, Commodities, Indices, Forex, and Crypto, with up to 200x leverage, instant settlement in USDC, self-custody, and full transparency on every fill. ## What Ostium Is Ostium operates at the distribution layer of global markets. It consolidates global demand into a single transparent, onchain venue and connects flow to the deepest underlying liquidity for each asset. Traders deposit USDC, open leveraged long or short positions, and settle directly into their own wallet. The protocol is purpose-built to complement existing exchange and data infrastructure rather than replace it. Every fill is quoted against the most liquid sources for a given pair, so execution on Ostium closely mirrors execution on the underlying market. **Ostium aims to be for global markets what stablecoins are for the dollar.** Stablecoins did not replace the dollar — they extended its reach to millions of new users, generating entirely new demand for dollar-denominated assets. Ostium does the same for the world's most liquid markets. ## How It Works Trades settle instantly onchain in USDC through a dedicated settlement layer, the liquidity pool vault. Directional flow is hedged off-chain through a network of institutional partners, across market makers (like Jump), prime brokers, and other major institutional partners. These partners supply pricing from the deepest underlying markets, while trader collateral remains self-custodied in segregated smart contracts and every fill remains verifiable onchain. ```mermaid theme={null} flowchart LR Trader[Trader] --> Onchain[Onchain Settlement Layer] Onchain -->|net delta| Offchain[Offchain Hedging Layer] Offchain --> Markets[Underlying Markets] Onchain <-.->|daily settlement| Offchain ``` For the full protocol architecture, including the settlement infrastructure and oracle system, see [How Ostium Works](/protocol/how-ostium-works). ## What You Get as a Trader Every position you open on Ostium benefits from five structural properties that together preserve self-custody while delivering institutional-grade execution: collateral stays in segregated smart contracts, settlement is instant in USDC, every fill is verifiable onchain, liquidity scales with the depth of the underlying market, and you can manage positions through any contract-enabled wallet without depending on the Ostium interface. Collateral lives in segregated smart contracts. Ostium cannot access or move your funds. When you close a position, USDC moves directly to your wallet. There is no multi-day settlement delay. Every historical fill is viewable onchain, and every price used to fill a trade is publicly auditable. Liquidity scales with the depth of the underlying markets, not with a fixed onchain pool. Slippage on large orders reflects venue depth, and execution closely mirrors the underlying exchange. You can manage your own positions through any wallet that can sign Ostium contract calls, not just the Ostium interface. You're never locked into a single frontend. ## At a Glance Ostium has processed over \$50B in cumulative trading volume across 800K+ trades from 26K+ unique traders, supporting 75 perpetual instrument pairs across six asset classes — Stocks, ETFs, Commodities, Indices, Forex, and Crypto. The protocol is deployed on Arbitrum, settles in USDC, and supports up to 200x leverage on select pairs. Cumulative volume Total trades Traders Trading pairs ## FAQ Anyone with a compatible wallet and USDC on Arbitrum can trade on Ostium, except in restricted jurisdictions: the United States, the United Kingdom, the European Union, the Philippines, and any country subject to comprehensive US sanctions (currently Iran, Syria, Cuba, North Korea, and the Crimea, Donetsk, and Luhansk regions of Ukraine). The protocol is non-custodial, meaning you retain control of your funds at all times. See the [Terms of Use](/legal/terms-of-use) for full restrictions. Trades settle instantly onchain through Ostium's onchain settlement layer. Directional flow is hedged offchain through a network of institutional partners, across market makers (like Jump), prime brokers, and other major institutional partners. These partners provide pricing from the most liquid underlying markets, so fills on Ostium closely mirror the underlying exchange. Ostium offers 75 perpetual instrument trading pairs across six asset classes: Stocks, ETFs, Commodities, Indices, Forex, and Crypto. Leverage goes up to 200x on select assets. The full list with per-pair leverage caps and market hours is on the [Markets](/traders/reference/markets) page. **Building on Ostium?** The Builder SDK gives you programmatic access to trading, market data, and positions. Start at the [Developer Documentation](/developer/sdk/overview). ## What to Read Next Set up a wallet and fund it with USDC. Walk through your first position from collateral to close. Two-layer architecture, settlement and hedging, oracle system, and the four core services that run the protocol. # How to Deposit Source: https://docs.ostium.com/vault/getting-started/deposit Deposit USDC and receive OLP tokens representing your share of the vault Depositing USDC into the Vault is a request-and-settle flow. You submit a deposit, it sits in a pending state until the next daily settlement at 00:00 UTC, and at settlement your USDC converts to OLP. You then click **Redeem** to move the OLP to your wallet. Pending deposits can be canceled before settlement with no penalty. **You must Redeem before you can take the next action.** After settlement, your OLP sits in a "pending redeem" state. Until you click Redeem and move it to your wallet, you cannot submit a withdrawal request against it. The same applies to settled withdrawals: you must redeem the USDC to your wallet before it's usable. ## How Your Funds Move Open the Ostium trading interface and click the Vault section. You'll see the Deposit tab selected by default. Enter the USDC amount you want to deposit. The UI displays: * Current OLP price (e.g., \$1.05) * Estimated OLP tokens you'll receive at settlement (e.g., "95.24 OLP for 100 USDC") The displayed OLP count is an estimate based on the current live OLP price. The exact conversion is locked at settlement, so the final number can differ slightly. Your USDC enters a pending state in the Vault and is marked as "pending settlement." You can cancel at any time before settlement completes. At settlement, all pending deposits are netted and converted to OLP at that day's settlement price. Your OLP then sits in a "pending redeem" state in the Vault UI. Click **Redeem** to move your OLP to your wallet. There is no deadline; it sits assigned to you until you redeem. Once redeemed, OLP is a standard ERC-20 and can be held, transferred, or used as the starting position for a future withdrawal request. ## Settlement and Timing Settlement happens once per day at 00:00 UTC. Your OLP conversion price is locked at settlement: * **Deposit at 10:00 UTC** → settlement at 00:00 UTC the next calendar day → receive OLP based on that day's settlement price * **Deposit at 23:50 UTC** → settlement at 00:00 UTC (10 minutes later) → receive OLP at that settlement price OLP starts earning fees from the moment it is minted at settlement, even while it is still in the pending-redeem state. There is no additional waiting period. OLP price updates continuously as fees accrue, but your conversion uses the settlement price, not the price when you deposited. If OLP rises between your deposit and settlement, you receive fewer tokens. ## Stacking Deposits Multiple deposits submitted in the same settlement window are netted into a single cumulative amount. This means: * Submit three separate 100 USDC deposits before settlement → they settle as one 300 USDC conversion at the same OLP price. * Your UI shows a single combined pending deposit rather than three individual entries. Deposits spanning two different settlement windows display separately, because they settle at different prices. ## Canceling a Pending Deposit Before settlement completes, you can cancel your pending deposit to recover your USDC with no penalty: 1. Navigate to Vault > Pending Deposits 2. Click "Cancel" on your deposit 3. Confirm in your wallet 4. USDC returns to your wallet within 1 block Once settlement processes, your deposit is final and cannot be canceled. The resulting OLP can be redeemed to your wallet, and you'd need to submit a withdrawal request to convert back to USDC. ## Legacy Locked Deposits New locked deposits are no longer available. The locking feature has been removed from the smart contracts. Any existing locked positions are honored until their expiration date. If you previously locked a deposit (7 to 365 days), your locked position is still held as an NFT in your wallet and accrues its lock bonus as expected. When your lock period ends: 1. Navigate to Vault > Pending and find your expired lock 2. Click **Redeem** to burn the lock NFT 3. You receive the original OLP plus any bonus OLP in your wallet 4. The OLP is now fully liquid and can be withdrawn via the normal flow ## Risk Disclosure OLP holds the **senior loss position** of the Ostium Vault. A dedicated buffer of junior capital absorbs trader PnL first, in full, before any loss can reach OLP. This subordination structure is analogous to the senior tranche of a CLO or structured credit deal. OLP earns yield from opening fees and is not insured. Under normal conditions, OLP price accrues at each daily settlement. An extreme event that fully depletes the buffer would cause OLP to take a loss. See [Vault Overview](/vault/overview) for the full picture of vault mechanics and risk profile. If the buffer is fully depleted and losses begin drawing on OLP, the vault enters **UC state** and automatically blocks new deposits until the buffer is restored. This is an accounting measure: deposits during a pending loss would create share-pricing ambiguity. ## FAQ Settlement runs once per day at 00:00 UTC. Depending on when you deposit, your OLP becomes ready to redeem anywhere from minutes to 24 hours later. Click **Redeem** to move it to your wallet. There is no deadline to redeem. Yes. Before settlement completes, navigate to "Pending Deposits" and click "Cancel." Your USDC returns within 1 block with no penalty. Once settlement processes, the deposit is final. Your OLP received is calculated at the daily settlement price, not your deposit price. If OLP rises, you receive fewer tokens. If OLP falls, you receive more tokens. The settlement price is locked in at 00:00 UTC; you cannot adjust it. You likely need to **Redeem** your OLP to your wallet first. After settlement, OLP sits in a "pending redeem" state. Until you redeem it to your wallet, you cannot submit a withdrawal request against it. No. Locking has been removed from the smart contracts. Existing locks are honored until expiration. ## What to Read Next * **[How to Withdraw](/vault/getting-started/withdraw)** — Withdraw OLP and recover USDC. * **[OLP Token](/vault/reference/olp-token)** — Understand OLP pricing and reward accrual. * **[Vault Overview](/vault/overview)** — Learn how the vault works and how LPs earn. # How to Withdraw Source: https://docs.ostium.com/vault/getting-started/withdraw Request withdrawal of OLP and redeem USDC from the vault Withdrawing from the Vault is a request-and-settle flow. You submit a withdrawal request against your OLP, wait for settlement (typically 2-3 days), and then click **Redeem** to move USDC to your wallet. Your request can be canceled at any time before settlement with no penalty. **You must Redeem before you can take the next action.** After settlement, your USDC sits in a "pending redeem" state. Until you click Redeem and move it to your wallet, it's not usable. The same applies to settled deposits: you must redeem OLP to your wallet before you can request a withdrawal against it. ## How Your Funds Move Navigate to Vault > Withdraw, enter the amount of OLP you want to redeem, and sign the transaction. Your OLP is locked in the vault and marked as "pending withdrawal." You stop earning fees on the locked OLP from this point forward. Withdrawals settle through one or more daily settlement runs. The number of settlements required and the maximum time per settlement are both dynamic — set by the smart contracts based on current vault state. Full settlement typically takes 2-3 days. Until settlement completes, you can cancel at any time and your OLP returns to your balance immediately. The dynamic delay protects the vault from concentrated outflows coinciding with high-exposure periods. Once the settlement delay elapses, your OLP is burned and converted to USDC at the OLP price at settlement. The USDC sits in a "pending redeem" state in the Vault UI. Click **Redeem** on your settled withdrawal. Sign the transaction. USDC moves to your wallet within one block. There is no deadline; you can redeem at any time after settlement. Only the step before settlement is cancellable. Once your withdrawal settles (OLP is burned and converted to USDC), the transaction is final and you must redeem the resulting USDC. ## Stacking Withdrawals Multiple withdrawal requests submitted within the same settlement window are bundled into a single cumulative amount. Requests spanning two different settlement windows display separately in the UI, because they process at different times. ## Canceling a Pending Withdrawal Before settlement completes, you can cancel at any time: 1. Navigate to Vault > Withdraw Requests 2. Click "Cancel" on your pending withdrawal 3. Confirm in your wallet 4. Your OLP unlocks and returns to your balance immediately with no penalty Cancelled OLP resumes earning fees from the next block. Once settlement processes, cancellation is no longer possible. Your OLP is burned and the corresponding USDC becomes redeemable. ## Withdrawal Price The OLP-to-USDC conversion uses the OLP price at settlement, not at request submission: * **Request at OLP = \$1.10** → settles \~2-3 days later at \$1.12 → you receive USDC at \$1.12 * If OLP rises during the delay, you receive more USDC; if it falls, you receive less Because your OLP is locked during the delay, it does not earn fees during this period. ## Legacy Locked Deposits New locked deposits are no longer available. If you hold an expired lock, redeem it to your wallet first and then submit a withdrawal request through the normal flow above. See [How to Deposit](/vault/getting-started/deposit#legacy-locked-deposits) for the full redemption steps. ## FAQ Typically 2-3 days from request to redemption. The exact number of settlements required and the time per settlement are dynamic values set by the smart contracts based on current vault state. The delay protects the vault from concentrated outflows coinciding with high-exposure periods. Yes, at any time before settlement. Navigate to Withdraw Requests and click "Cancel." Your OLP unlocks immediately and resumes earning fees. Once settlement processes, the withdrawal is final and you must redeem the resulting USDC. You receive USDC at the OLP price on the day your withdrawal settles, not the day you submitted the request. If OLP rises during the delay, you benefit; if it falls, you receive less USDC. No. Once you submit a withdrawal request, the OLP backing that request is locked and stops earning fees. If you cancel before settlement, your OLP resumes earning fees from the next block. During the vault upgrade, all pre-existing pending withdrawals were canceled as part of the migration. Your OLP was returned to your balance as if you never requested the withdrawal. Submit a new withdrawal request through the current flow to receive your USDC. No. Once your withdrawal settles and USDC becomes redeemable, you can redeem it to your wallet at any time. ## What to Read Next * **[How to Deposit](/vault/getting-started/deposit)** — Deposit USDC and receive OLP. * **[Vault Overview](/vault/overview)** — Understand how the vault works and how you earn yield. * **[OLP Token](/vault/reference/olp-token)** — Learn about OLP pricing and token mechanics. # Vault Overview Source: https://docs.ostium.com/vault/overview How the Ostium Vault settles every trade onchain, and where OLP sits in the protocol's loss order. The Ostium Vault is the onchain settlement layer for every position traded on the protocol. LPs deposit USDC, receive OLP tokens, and earn yield from protocol opening fees. OLP capital sits in the **senior loss position**, protected by a buffer that absorbs trader PnL first, and also functions as working capital for the settlement system. ## Two Pools of USDC The vault smart contract holds two distinct pools of USDC that work together to settle every trade and protect LPs from directional risk: OLP capital deposited by liquidity providers, and a buffer of junior capital posted by Ostium affiliates and strategic partners. Losses follow a strict order — the buffer absorbs them first, in full, before any loss can touch OLP. Deposited by LPs in exchange for OLP tokens. This is the senior tranche. Dedicated capital posted by Ostium affiliates and strategic partners. This is the junior tranche. In structured-credit terms, OLP is the senior tranche and the buffer is the equity tranche beneath it. The same architecture is used in collateralized loan obligations (CLOs), securitized credit deals, and clearinghouse default waterfalls. ```mermaid theme={null} flowchart TD Loss[Trader Loss] Buffer[Junior Buffer] OLP[OLP — Senior Tranche] Loss -->|absorbs first, in full| Buffer Buffer -.->|only if fully depleted| OLP ``` Across a normal trading day: * When traders net **win**, the vault pays them. The buffer shrinks onchain during the day, then is replenished at daily settlement from the mirror hedge's matching gain offchain. * When traders net **lose**, the vault retains their losses. The buffer grows onchain, then sends the excess offchain at settlement to keep the hedging book funded. OLP is unaffected in both directions until the buffer is gone. OLP capital is the last pool of money to take a loss in the system. The only way OLP takes a loss is if the entire buffer is wiped out first. ## OLP as Working Capital The same structure that protects OLP also places it at the center of intraday cash flow. When a trader closes a winning position, the vault pays them in USDC immediately from onchain capital. The mechanics: The vault pays out onchain, immediately. The trade was mirrored offchain at open through Jump Trading, Ostium's flagship hedging partner. The offchain hedge has an equal and opposite gain. Net-net, the protocol is flat. USDC in the vault goes down. USDC in the offchain hedging book goes up by the same amount. Once per day, a settlement run moves USDC between the two books to restore the buffer onchain to its target size. Total USDC sitting in the vault smart contract will fluctuate throughout the day as trades open and close. That movement is **operational, not a loss**. OLP capital is effectively lending to the settlement system in the intraday window, then being restored at daily settlement. The closest traditional-finance analog is a money market fund. Investor cash is actively deployed into short-term instruments during the day; the fund's share price only updates at a set time. The deployment itself is not the risk. The risk lives in what the cash is deployed *into*. For OLP, that "what" is the protocol's settlement obligations, which are backed by the buffer taking losses first. ## What You'll See in the UI The Ostium app surfaces four key vault metrics for OLP holders, designed to keep intraday operational cash flow distinct from actual gains and losses. The most important is OLP price, which only updates at daily settlement; intraday vault USDC swings are operational, not PnL accrual. The total USDC sitting in the vault smart contract will swing up and down throughout the day. This reflects trade settlement, not PnL accrual. OLP price updates once per day at settlement, reflecting opening fees earned since the prior settlement. The price does not change intraday — by design, to avoid users seeing scary-looking moves driven by normal settlement cash flow rather than actual gains or losses. The protocol surfaces a buffer metric that indicates how much junior capital sits between trader PnL and your OLP capital. If the buffer is fully depleted and additional losses begin drawing on OLP, the vault enters UC state and automatically blocks new deposits. This is an accounting measure: deposits during a pending loss would create share-pricing ambiguity. OLP price will reflect any realized loss at the next daily settlement. If the vault's onchain USDC balance swings intraday, or briefly drops below the total OLP notional, that is normal settlement activity. OLP price is what matters for your share's value, and it only recomputes after each daily settlement. ## How LPs Earn Post-upgrade, OLP yield has a single source: **opening fees**. ``` OLP APR = (Opening fees paid to OLP per year) / (Outstanding OLP shares) ``` Every trade opened on Ostium pays an opening fee, and 30% of that fee flows to OLP holders. There are no rollover fees accruing to OLP, no share of trader PnL, and no conditional state-based accrual. The opening-fee allocation to OLP is a tunable protocol parameter, periodically reviewed. Live and historical APR are published on the [Dune dashboard](https://dune.com/ostium_app/stats). Pre-upgrade, OLP APR ranged from approximately -4% to +50% depending on trader PnL and vault state. That range reflects the old mechanics (OLP as junior counterparty) and no longer applies. The post-upgrade design produces a tighter, more stable range. ## Protocol TVL, Vault TVL, and Vault USDC Three different numbers track the protocol's capital in different ways, and dashboards may surface any of the three. Vault TVL is the value of LPs' claim (OLP price × outstanding shares). Total vault USDC is everything in the vault smart contract, including buffer capital and intraday settlement flows. Protocol TVL adds trader collateral held in the trading contract on top of vault TVL. OLP price × outstanding OLP shares — the *value of LPs' claim* on the vault. This is what an OLP holder cares about for their position's worth. Every USDC sitting in the vault smart contract: OLP capital, buffer capital, and any intraday settlement flow in motion. Depending on intraday flows (e.g., right after a large winning trade settles), this can be larger OR smaller than vault TVL. The broader protocol-level metric, which includes vault TVL plus the trader collateral held in the tradingStorage contract backing open positions. This is what dashboards typically report as "Protocol TVL" and is generally the largest of the three. Dashboards showing "USDC in the vault contract" report total vault USDC, which differs from vault TVL and from protocol TVL. Pay attention to which figure a given dashboard surfaces. ## FAQ OLP holds the senior loss position in the protocol. A dedicated buffer of junior capital absorbs trader PnL first, in full, before any loss can reach your OLP capital. OLP deposits are not insured. An extreme event that fully depletes the buffer would cause OLP to take a loss. The vault is the instant-settlement layer for every trade on Ostium. When traders close winning positions, the vault pays them out immediately onchain. Those flows are mirrored by offchain hedges, so the protocol stays balanced. Only the *location* of the USDC changes intraday. Once per day, a settlement run moves USDC between the two books to restore the buffer to its target size. OLP price only updates after settlement, so intraday USDC movement does not affect your share's value. Opening fees paid to OLP, divided by outstanding OLP shares, annualized. No rollover fees, no share of trader PnL, no conditional state-based accrual. The fee allocation is a tunable protocol parameter. Live and historical APR are published on the [Dune dashboard](https://dune.com/ostium_app/stats). The buffer is dedicated capital that sits in the vault smart contract alongside OLP capital, posted by Ostium affiliates and strategic partners. It is the junior tranche: it takes trader PnL first, in full, before any loss touches OLP. The buffer is rebalanced onchain during daily settlement to keep its size close to a target level appropriate for expected daily PnL swings. UC state means the buffer has been fully depleted and additional losses are drawing on OLP capital. When this happens, the vault automatically blocks new deposits for accounting reasons: deposits during a pending loss state would create share-pricing ambiguity. Your OLP balance appears in your wallet. Multiply by the current OLP price (visible in the app or via the Dune dashboard) to see your USDC-equivalent value. Historical OLP price, buffer health, TVL, and APR are all published on the [Dune dashboard](https://dune.com/ostium_app/stats). ## What to Read Next Step-by-step for depositing USDC and receiving OLP. Deeper detail on OLP pricing, share mechanics, and yield. Withdrawal windows and timing. # OLP Token Source: https://docs.ostium.com/vault/reference/olp-token Reference for OLP pricing, share mechanics, deposits, withdrawals, and yield. OLP is an ERC-20 token on Arbitrum that represents a proportional share of the Ostium Vault. Unlike traditional LP tokens where 1 token equals 1 unit of the underlying asset, OLP's price accrues with protocol fee earnings. Deposits and withdrawals both convert at the current OLP price, which is the primary performance metric for an LP. OLP price is recomputed once per day at settlement. ## What Is OLP? OLP stands for Ostium Liquidity Provider token. It is minted when you deposit USDC at settlement and burned when you withdraw at settlement. OLP is not staked or locked in a contract. Once redeemed to your wallet, it exists as a standard ERC-20 and can be transferred, traded, or held freely. The token accrues value passively. There is no separate claim flow and no staking interface. Protocol-level opening fees that accrue to the vault are reflected directly in OLP's price-per-token at each daily settlement. **Key property:** 1 OLP ≠ 1 USDC. OLP price accrues. If OLP = \$1.05 and you withdraw 100 OLP, you receive 105 USDC. ## OLP's Position in the Protocol OLP sits in the senior loss position of the Ostium Vault: a dedicated buffer of junior capital absorbs trader PnL first, in full, before any loss can reach OLP. OLP is also the working capital that the vault uses to pay winning trades during the day, with balances restored at daily settlement from the offchain hedge. See [Vault Overview](/vault/overview) for the full explanation of the two-tranche structure and daily settlement cadence. ## OLP Price: Mechanism and Examples OLP price is recomputed once per day at settlement. It does not update intraday — by design. Cash flows from opening fees do reach the vault in real time as trades open, but the per-token price reflects those flows only after the daily settlement run reconciles the onchain vault and the offchain hedging book. This avoids users seeing OLP price swings driven by normal intraday settlement activity (where vault USDC can briefly fall below total OLP notional during a winning-trade payout window) rather than by actual gains or losses. Each daily settlement reflects: * **Opening fees earned** since the prior settlement, allocated to OLP, divided across outstanding OLP shares. * **Buffer-overflow losses**, only if trader PnL during the day fully depleted the buffer and additional losses touched OLP capital. Under normal conditions this term is zero. Under normal conditions, OLP price moves monotonically upward at each daily settlement, by the amount of opening fees earned per share since the prior settlement. **Worked example — Alice deposits and holds over 1 month:** * Day 1: Alice deposits 1,000 USDC when OLP settles at \$1.00 and receives 1,000 OLP. * Days 1–30: Each daily settlement credits Alice's share with a pro-rata portion of opening fees earned that day. * Day 30: Suppose OLP has climbed to \$1.005. Alice's 1,000 OLP is worth \$1,005. * If Alice withdraws, she receives \$1,005 USDC at the end-of-window settlement price, a gain of 5 USDC over the month. ## Minting OLP (Deposit) When you deposit USDC, OLP is minted at the next settlement price: **Calculation:** `OLP received = USDC amount / settlement OLP price` **Example:** You deposit 100 USDC when OLP settles at \$1.05. * OLP minted = 100 / 1.05 = 95.24 OLP * You receive 95.24 OLP after settlement New locked deposits are no longer available. The locking feature has been removed from the smart contracts. Any existing locks are honored until their expiration date and continue to accrue their original lock bonus. ## Redeeming OLP (Withdraw) When you withdraw, OLP is burned and you receive USDC at the settlement price: **Calculation:** `USDC received = OLP amount × settlement OLP price` **Example:** You withdraw 100 OLP when OLP settles at \$1.10. * USDC received = 100 × 1.10 = 110 USDC * You burn 100 OLP and receive 110 USDC The price you receive depends on when your withdrawal settles (see [How to Withdraw](/vault/getting-started/withdraw) for the withdrawal window). If OLP rises during the settlement delay, you benefit; if OLP falls, you receive less. ## How LPs Earn OLP earns from a single source: **opening fees**. ``` OLP APR = (Opening fees paid to OLP per year) / (Outstanding OLP shares) ``` Every trade opened on Ostium pays an opening fee, and 30% of that fee flows to OLP holders at each daily settlement. There is no share of trader PnL, no rollover fees accruing to OLP, and no conditional state-based accrual. The opening-fee allocation to OLP is a tunable protocol parameter, periodically reviewed. Live and historical APR are published on the [Dune dashboard](https://dune.com/ostium_app/stats). **Worked example:** Vault earns \$500/day in opening fees allocated to OLP, OLP = \$1.05, supply = 1,000,000 OLP. * Annualized opening fees to OLP = \$500 × 365 = \$182,500 * Total OLP-denominated value = 1,000,000 × \$1.05 = \$1,050,000 * APR = \$182,500 / \$1,050,000 ≈ 17.4% **Pre-upgrade, OLP APR ranged from approximately -4% to +50%** depending on trader PnL and vault state. That range reflects the pre-JLU mechanics (OLP as junior counterparty to trader PnL) and no longer applies. The post-upgrade design produces a tighter, more stable range. APR is not guaranteed. It depends on trading volume and the opening-fee allocation parameter. Past APR is not indicative of future returns. ## OLP Supply and Dilution OLP supply changes as LPs deposit and withdraw: * **Deposit:** New OLP minted at daily settlement (supply increases). * **Withdraw:** OLP burned at end-of-window settlement (supply decreases). Because both deposits and withdrawals settle at the same daily settlement price, there is no dilution or advantage between new and existing LPs. Everyone transacts at the same per-share price set by the most recent settlement. ## What You'll See in the UI Recomputed once per day at settlement. It does not update intraday. This is the number that matters for your share's value. Indicates how much junior capital sits between trader PnL and your OLP. Normal state is collateralized. UC (under-collateralized) state is rare, temporary, and blocks new deposits until the buffer is restored. OLP price × outstanding OLP shares. Indicates the size of the senior tranche. This differs from the vault's total USDC balance, which also includes the buffer and any in-transit settlement flow. ## FAQ Under normal conditions, no. OLP price accrues at each settlement as opening fees are credited. The only scenario where OLP price declines is if the buffer is fully depleted and additional losses reach OLP capital. OLP deposits are not insured. OLP price is recomputed once per day at settlement, matching the vault's daily reconciliation between onchain and offchain books. It does not update intraday. This is a deliberate design choice: it isolates LPs from intraday vault USDC swings (e.g., when a trader closes a winning position and the vault pays them out before the matching offchain hedge gain has been settled in) so the per-share price only moves on actual realized accounting, not on settlement cash flow in motion. Yes, OLP is a standard ERC-20 and can be transferred to another wallet or listed on a DEX. Secondary markets may have low liquidity; withdrawing directly through the Vault UI is generally safer and more efficient. Post-upgrade, OLP's yield source is simplified to opening fees only. Because OLP is no longer the counterparty to trader directional flow, the previous accrual streams tied to that relationship (rollover fees and liquidation rewards in UC state) no longer flow to OLP holders. The fee allocation is a tunable protocol parameter, periodically reviewed. UC state means the buffer has been fully depleted and additional losses are drawing on OLP. When this happens, the vault blocks new deposits as an accounting measure (deposits during a pending loss would create share-pricing ambiguity). OLP price reflects any realized loss at the next daily settlement. ## What to Read Next How the two-tranche vault and daily settlement system work. Deposit USDC and mint OLP. Withdraw OLP and recover USDC.