0 also reads the live
config.params.borrowGraceS (see funding).
An open is an order
Your stake is taken when the open lands, and the venue’s next price sets your entry. The open carries no price. The program records it as an order with a target slot a short, governed delay after the slot in which it landed (d slots). The entry is the first price of the venue’s price
feed at or after that target. A filler on the venue’s list writes it, and the order becomes a
position. The barrier and the target are distances from that entry.
- The price on your screen when you tap is not your entry. Your entry is the next price after the delay.
- An order that is not filled in time is returned. If the first price comes too late or does not meet the venue’s quality rule, if the market closes, or if no filler lands inside the fill window, anyone can return the order, and the venue’s keepers do. You get your whole stake back.
- You cannot fill your own order. Only a filler on the venue’s list can write an entry.
- A landed open is not yet a position. Read your entry when the order is filled, never from the screen at the tap.
The five choices
1
Asset and direction
Which market you are trading, and whether you are long or short. The market names the price
feed that decides your outcome — see the price that decides.
2
Stake
Your collateral, between the venue’s
minCollateral and maxCollateral. It, and any entry fee
paid on it, is the entire amount at risk. The bounds are governed and live on chain; read them
from the config account.3
Target (optional)
A take-profit target you can add, as a multiple of the stake. Any multiple at or above 2.00x is
admitted, up to the protocol’s payout cap — the one ceiling, read as
config.params.payoutCapMultiple. Without one, the target is the payout cap.4
1000x
How far the price has to move to reach either end, so how fast the position ends.
1000x on every market. Pass
tier on open: 0 means the market’s own. A market’s tier is
the ceiling and the venue’s config.minTier is the floor. Above the ceiling is refused
(LeverageAboveMarketTier), below the floor is refused (LeverageBelowMinTier), and so is a
value the program does not list. Both values are governed: read them from the chain.The 1000x sets the DISTANCE to both levels. The fee terms read the size of the price move, so the
same target pays differently at another tier.The barrier
Every position has a barrier: a price, fixed at open, a set distance on the losing side of your entry. If the price touches it, the position is knocked out and you get nothing back. Three things to know:- It is a distance, not a dollar amount. The distance is set by the position’s 1000x tier and its loss tax rate, both locked in at open. At 1000x the barrier is near, which is why a position ends fast.
- It is direction-relative. For a long it sits below entry; for a short, above.
- It is fixed at your open. Its distance is frozen when your order lands, and its price is set when the order is filled. A governance change later does not move a barrier that already exists.
openPreview().barrierMicroBp, and the resulting price by levels(). Read it, show it to the
person taking the risk, and do not hand-compute it.
The target
The target is optional. It is the other side of the barrier: a price, also fixed at open, sitting the distance away that corresponds to your chosen multiple. Touch it and the position has a gross gain of the multiple less one, times your stake: a 2.00x target is a gain equal to the stake. What you receive is that gain less the share of it the terms withhold and less the exit fee, so a target pays less than its multiple. Fees and limits has a worked example. A target can be any multiple of your stake at or above 2.00x. The floor isRUNG_FLOOR_BPS, 2.00x. Without a
target, the position’s target is the payout cap, the one ceiling, config.params.payoutCapMultiple; a market carries
no take-profit ceiling of its own. A value above the live cap is refused RungAbovePayoutCap.
Adding to a position
A trader may add collateral to a position that is already live. It is one order, not two: the stake grows, the entry becomes the average of the prices actually paid, and both levels move with it. An add is an order too. It takes the added stake when it lands (CollateralCommitted) and
carries no price. The add is priced at the first price of the venue’s price feed at or after the
same short delay, and then one of two things happens:
- It is filled (
CollateralAdded): the entry becomes the blend, and both levels move with it. - It is returned (
AddReversed), in full: if no price or no filler comes in time, or if at the add’s price the position is already at its barrier or its target. A returned add keeps the time it added to your timer.
M_add slots), you cannot close the position, move its target or add again (AddPending). In
that time a price from before the add that breached the old barrier still proves a knockout: the
position is knocked out on its old stake, and the added stake comes back. A touch of the target
while an add waits for its price does not count, and it is lost if the add is then filled.
Adding neither realises nor creates a profit or a loss. A trader who is $0.40 down and adds $1 is
still $0.40 down at the add’s price: the entry is the collateral-weighted harmonic
mean of the old entry and the fill price, which is the only blend with that property, and it is
also the average cost basis every trading interface already shows.
- The add is fee-inclusive, exactly as an open is. You hand
added_budget— the total to add — the venue takes its entry fee from inside it, and the debit is at most that.min_added_collateral_outis the trader’s mandatory floor on the increment SIZE, the signature over what the add buys. - The stake bounds bind on two different quantities. The minimum binds on the increment, the
maximum on the total. So a position already holding more than
maxCollateral − minCollateralhas no legal add at all — quote the admissible range and never render a control whose every value is refused. - The clock may only be lengthened.
extend_timer_sis a delta in seconds and it only ever goes forward, and never past the tenor frozen on the position. A double-down is the only way to move a position’s own timer, and it cannot shorten it. - A position that has touched a level cannot be added to. An add whose price is at or through
the barrier, or at or through the take-profit, is returned in full (
AddReversed). - The hold clock restarts. A filled add re-prices the position, so the minimum hold before a close you ask for runs again from the add’s price.
Sizing an add from a total
The trader can name what leaves their wallet instead of naming the increment.sizeAddForTotal is
that inverse, and it is not sizeForTotal with a different argument.
setsTimerdoes not change the debit. Setting a timer is free, on an open or an extension.- The bounds are
admissibleAdd’s interval, notconfig.params. The ceiling binds on the total, so what a position may still take is the governed ceiling less what it already holds.
size.debit is never above the total, so the number the trader typed is the added_budget you sign
and the chain debits at most that. A fee change landing between the quote and the signature can only
shrink the increment, and the min_added_collateral_out floor you set from size.collateral turns
that into a BudgetBelowCollateralFloor revert rather than a silent shrink.
addPreview, admissibleAdd, addCollateral and addImpact answer “what would this add do”
and “what increments are legal”, which covers the blended entry, the admissible range and the
barrier’s new price. Quote with them; do not derive the blend by hand from the formula above, and
do not offer the control without showing where the barrier moves to. addGates is the gate report
for an add — see reading gates.The tenor
The tenor is the protocol’s own clock for a position. It isconfig.params.tMaxSeconds, a governed
parameter, and it is frozen onto your position at open. The tenor is the indefinite value, so a
position has no protocol clock: it ends by its barrier, its target, your own close, your own timer if
you set one, the close of its session on a market with trading hours, or the no-price close under
How a position ends. A position keeps the tenor it froze at open. The SDK
tests for it with isIndefiniteTenor(); show “no limit”, not a date. A position that froze a finite
tenor is closable by anyone when the tenor runs out.
On a market with trading hours, the tenor is shorter. It is config.params.tMaxSeconds or the
time left until market.sessionBufferS before the session’s close, whichever is shorter, so the
position ends before its session closes. No live market has trading hours; see
markets.
The freeze is a rule of the program: settlement reads the tenor stamped on your position, so a
governance change afterwards cannot change a position you already hold. Read the live value
rather than typing it, and do not build an interface that promises a reader a duration from a
constant.
You may also set a shorter timer of your own. The two clocks are independent, and the earlier one
is the moment your position first becomes closable by a stranger. A double-down can push your own
timer out, never in — see adding to a position. The SDK computes both
from the position itself:
How a position ends
Knockout — the price touched the barrier
Knockout — the price touched the barrier
The position is over and the trader gets nothing back. Plan for it: at 1000x the barrier sits
close enough to entry that an ordinary move reaches it. A knockout settles at
the barrier no matter how far past it the price ran, so it needs no exit price to price it.Anyone may prove it with any signed price that is newer than the entry and at most
W_ko
slots old, a governed setting. So a position can be knocked out by a recent price that has
already moved back on your screen. After a close request or an expiry mark, only a price that is
not later than the exit price can knock the position out.Take-profit — the price reached your rung
Take-profit — the price reached your rung
The position closes at its target, with a gross gain of the multiple less one, times your stake.
You receive that gain less the share the terms withhold and less the exit fee, within the payout
cap. It is proved the same way as a knockout, and the price that proves it must also clear the minimum
hold. A touch while a double-down waits for its price does not count. After
you move your target, only a price at least
d slots later proves the new one.Expiry — a clock ran out
Expiry — a clock ran out
Either your own timer or the protocol’s finite tenor (an indefinite tenor never expires). From the deadline, anyone may mark the expiry
(
mark_expiry). The position settles at the first price at or after d slots from the mark,
by the same window rule as a close you ask for, whatever that price is: a position expiring in
profit is paid, and one expiring in loss is settled where it stands.Voluntary — you closed it
Voluntary — you closed it
You ask for the close with
request_close, signed by you or by a session key you authorised.
The request carries no price, so it cannot fail on a stale one, and it cannot be withdrawn.
The exit price is the first price of the venue’s price feed at or after d slots from the
request. Anyone may then send the settle that pays it, and the venue’s keepers do.The window rule. If nobody settles inside the exit window (W slots) from that target, the
price becomes the first price of the next window, and so on, and a knockout price in between
still counts. So the close price is not locked when you ask, and no interface should say it
is. You cannot ask inside the minimum hold.Last resort — no price could be obtained
Last resort — no price could be obtained
If no price can be obtained for a long time, a position can be closed with no quote, only while no fresh price exists.A live position is paid its stake back with the exit fee waived; a position already stamped at a
level is paid that level, and a target level pays the exit fee. The close is refused while the oracle is frozen, on an order that is
not filled, and while an add waits for its price.A position that is not settled before its session’s close ends at par, on a market with trading
hours: a quote from a later session never prices it.
voluntary, knockout,
takeProfit, userExpiry, tenorExpiry, lastResort and borrowSpent. The last is a close that
funding makes possible once it has used a position up; it cannot arise while the funding rate is 0.
The minimum hold
A position cannot be closed by its owner in the first slots after its entry price. The venue has one hold for every market,resolveMinHoldSlots(config.minHoldSlots) slots, and a market can
have a longer one, market.closeHoldSlots. The longer of the two applies. Both are governed
settings: read them from the chain.
- The hold starts at your entry price, and again at the price of each double-down.
- A close request inside it is refused (
MinimumHoldNotMet,MarketHoldNotMet). The position is not affected. Send the request again from the first slot the hold allows:closableFromSlotOf(position, config, market)gives that slot from three public accounts, so an app can show “can close in N seconds” with no guess. - A take-profit must also clear the hold, measured to the slot of the price that proves it. The venue’s hold also applies to the end of your own timer.
- A knockout is never held back, and a market’s own hold never holds back a timer end.
Settlement is permissionless
Every close ends with asettle that anyone may send. Only one step needs the owner: the
request for a voluntary close. A knockout and a take-profit are proved by the price, and the two
expiries and lastResort by the clock. Every priced close carries a signed quote from the venue’s
price feed; lastResort needs none.
Two switches can stop closes: the guardian’s oracle freeze starves every priced close of a price and
refuses lastResort, and its settle kill-switch refuses every close. Only the config authority lifts
either. Read config.oracleFrozen and config.settlesDisabled.
Nobody is paid for sending a close. The protocol pays its submitter nothing — no fee, no share
of the settlement, no gas rebate. If you run a keeper, budget for it as a cost.
The payout cap
No target can be set above the payout cap. The cap is the governedpayoutCapMultiple, the largest
multiple the program lets a target take. A position with no target of its own has the cap as its
target. Read it rather than typing it.
A win is paid in full. Part of it may be paid later, in order. There is no guaranteed time. The
amount queued ahead of you is shown. How, and what a client shows, is in
how a win is paid.
The fees
Four, all on chain. Three are charged on an event; funding is charged on time. Setting a timer is free. The rates, with the date they were read, are on Fees and limits.- an entry fee (
config.params.entryFeeBps, basis points of the stake), taken from inside your budget when you open, and from the increment when you add. It is 0, so an open costs the stake and nothing more. The venue is fee-inclusive: you hand a total, it takes the fee from within it, and the debit is at most the number you signed; - a loss tax, charged at a close at a loss and taken from the position’s equity
before the exit fee. It is a share of the loss (
config.params.lossTaxBps), frozen onto the position at open. Fees and limits has the rate, the steps and a worked example; - an exit fee, charged at every close except a knockout, and waived on a live position closed
by
lastResort. It is a share of the exit value, the money the position closes with before the fee. The rate depends on the price move at the close: one rate when the close is a gain beyond a small band around the entry price, a higher rate when it is a loss beyond the band, and a rate between the two inside the band. On a gain, the terms also withhold part of the gain: the share you keep is smaller for a small move and rises with the size of the move. Fees and limits has the values, dated, and a worked example. A position freezes its terms when it opens, so a later change to a market’s terms never reaches a position that is already open. The terms of a market are read from its fee-terms account (feeTermsTablePdain the SDK), and the share of each close is on itsSettlementFeeTermsevent. A wallet linked to a referrer pays less exit fee (Referrals); - funding, a rate on the time held. The rate is 0: nothing is charged for holding.
Funding
The funding rate is 0, so nothing is charged for holding a position. It is a governed field, and a position freezes the rate it opens with. Funding is charged out of the payout at settlement, after the loss tax and the exit fee, never out of your equity, so it does not move the price that ends your position. All of it goes to the pool. Its fields are namedborrow in the program and the SDK (borrowRateBpsPerHour, borrowGraceS).
A position freezes its rate when it opens, and a stored grace of 0 reads the live
config.params.borrowGraceS. Fees and limits has the rate in force; read the position’s
own borrowRateBpsPerHour to price its settlement.
Every one of these parameters is governed: they can be changed on chain by the protocol’s
authority. Do not cache them. Read them from the config account, and show the reader how old
your copy is.
The price that decides your outcome
It is the price feed of the market you traded, not “the price of SOL” on some other screen. Every venue reports a slightly different number. Every price is a signed update from the market’s price feed, and the program checks the signature before it uses it.- Your entry is the first price at or after your order’s target slot. An order is filled only by a price that meets the venue’s quality rule for an entry. Otherwise it is returned.
- Your exit is the first price at or after your close’s target slot, by the window rule, or the price that proves a level.
- If no quote can be obtained at all,
lastResortis the backstop.
Your positions live in one account
A trader has a single account holding several position slots — twelve by default in the SDK, and a client may ask for anywhere from 1 to 12 when the account is created, or resize it later. That account is created by its own instruction, not by opening a position — but account creation and your first open fit in one transaction, so a first-time trader signs once and pays the account’s rent only on that first trade. The rent comes back to whoever paid it when the account is closed. That transaction is one an interface composes; the SDK’s own composer will not build it for you. Opening a position has the recipe. Slots are reused, so a slot index is not a position handle. The SDK gives you{ trader, slot, seq } and settlement addresses positions by seq, so a stale handle finds
nothing instead of closing a neighbour. See reading positions.