span pays SOL's release hour on its candle. A ticket names one hour and a length. When the hour closes, the ticket pays 10 USDC for every 1% of candle past that length, up to 40, whichever way SOL went and wherever it closed. The 40 USDC is in the ticket before the hour opens.
A perp settles the same hour on its body, open to close. On — the jobs report took SOL to —% and —% inside the hour, and the hour closed —% from its open. The body paid next to nothing, either way. A 2% ticket on that candle paid — USDC.
Below, in the order a ticket lives through it: the rule and the code that settles it, how the hour is read and how SPAN keeps what the reads miss, how to buy and sell, every call and value the program holds, what the 2026 release hours measured, and what you are trusting. Every number on this page comes from the program on mainnet or from a 2026 release hour replayed under its rule.
The body and the candle
Candlestick charts reached Western markets with Steve Nison's book in 1991 [1]. Each candle is one period. The body runs from the open to the close; the wicks run out to the highest and the lowest price. An hour that closes where it opened is a doji, and with long wicks on both sides, a long-legged doji [1]. Chart readers call it indecision. The hour itself was not still.
A perp is paid on the body. A span is paid on the candle, from the bottom of the lower wick to the top of the upper one. The candle always holds the body, so a span's hour is never shorter than a perp's. Across the — release hours of 2026 it was — times as long.
Each hour stands at its body, on the line where the candle would equal the body. Everything above the line is wick: the move a perp hands back by the close, and a span keeps. Median body —%, median candle —%.
The length
A seller opens each ticket with a length, from 0% to 5% in steps of 0.25%. The ticket is paid only for the candle past it. A 0% ticket is paid on the whole candle.
payout = min(40, 10 × max(100 × (high − low) / open − length, 0)) USDC, length in percent. Past the length, every 1% of candle pays 10 USDC. At the length plus 4% the payout reaches 40 and stops: 40 is all the ticket holds. In the program it is one function.
pub fn payout(p0: u64, high: u64, low: u64, strike_bps: u16) -> Result<u64> {
require!(p0 > 0 && high >= low, SpanError::InvalidValue);
let width = u128::from(high.checked_sub(low).ok_or(SpanError::Overflow)?);
let numerator = width
.checked_mul(1_000_000_000)
.ok_or(SpanError::Overflow)?;
let raw = numerator
.checked_div(u128::from(p0))
.ok_or(SpanError::Overflow)?;
let strike = u128::from(strike_bps).checked_mul(100_000).ok_or(SpanError::Overflow)?;
Ok(raw.saturating_sub(strike).min(u128::from(VAULT_CAP)) as u64)
}
math.rs · payout · lines 8–19 · commit 3a5c5b8 · prices carry 8 decimals; the result is in USDC base units, 40,000,000 at most
A longer length is paid less often, so it should sell for less. The premium is the seller's to set, from 0.10 to 39 USDC.
The release hour
This site lists a candle for each scheduled US release: CPI, PPI and the jobs report at 08:30 ET [4], FOMC decisions at 14:00 ET [5]. The candle opens one minute before the release and lasts sixty minutes, so the release's first move is inside it. The program itself takes a candle that starts on any minute.
| Release | Opens | Closes |
|---|
Of the — release hours of 2026, — drew a candle past 1%, — past 2% and — past 3%.
Reads
The program reads each candle thirteen times: at the open, then every 300 seconds through the close. A read is accepted only from a DOVES price published within — seconds after its boundary and at most — seconds old when it lands. Anyone can send a read. span runs a public keeper that sends all thirteen.
A read takes the first DOVES price published at or after its boundary. A price inside a read's window waits for that read before a ticket can use it as a wick.
A missed read does not move the wicks. Missing data favors the seller. Of the — reads in the 2026 replays, — missed.
Thirteen reads see the hour at five-minute marks, and the price goes further between them. Across the 2026 release hours, reads alone drew —% of the candle. On — they drew —% of an hour that reached —%.
SPAN
SPAN is how a ticket keeps the wick between reads. The buyer loads SPAN into the ticket and names a reader: the public keeper by default, or any key the buyer chooses. The reader records each new high or low as DOVES publishes it, one transaction per reading. A reading counts only if it stretches a wick by at least the buyer's step: 2, 5, 10 or 25 bp of the open.
A reading that raises the payout burns a fixed amount of SPAN from the ticket. A reading that does not, under the length or on the far side of the candle, is recorded free. It still counts: a later wick on the other side can carry the candle past the length, and the earlier one is part of it.
require!(ctx.accounts.span_hold.amount >= burn_per_mark, SpanError::SpanShort);
let before = math::payout(p0, high, low, t.strike_bps)?;
let after = math::payout(p0, if side { price.price } else { high }, if side { low } else { price.price }, t.strike_bps)?;
let burn = if after > before { burn_per_mark } else { 0 };
lib.rs · mark · lines 453–456 · commit 3a5c5b8
Readings stop when the candle is 4% past the length, because the payout is already 40, or when the ticket holds less SPAN than one burn. Only the ticket's reader can record its readings. Unused SPAN goes back to the buyer when the ticket settles.
| Step | Readings an hour | Candle recorded | Feb 6, 2% ticket |
|---|
2026 release hours, replayed: the median readings an hour, the average share of the candle recorded together with the thirteen reads, and on Feb 6 the readings that raised a 2% ticket's payout.
The SPAN mint and the burn per reading are set once, together, and no call changes them after. —
Payout and settlement
The seller deposits 40 USDC less the premium when opening a ticket. The buyer pays the premium. From the sale on, the whole 40 is in the ticket's vault. — seconds after the hour closes, anyone can settle: one transaction pays the buyer the payout and the seller the rest of the 40. If the open read was missed, the candle is void and both sides get back what they put in.
| Candle (example) | Length | Buyer | Seller |
|---|
—
—
Buying and selling
You need a Solana wallet in this browser, USDC, and a little SOL for network fees and account rent. Reading needs none. The page builds each transaction; your wallet signs it and sends it.
Compare. On Book, set a length and a price, or bring in a ticket on sale, and read every release hour at those terms: what the ticket would have paid and what each side would have kept. Then carry the terms to Ticket or Sell.
Buy. On Ticket, pick the hour and a ticket on sale. Its length and premium are the seller's. Once SPAN is set, choose a step and how much SPAN to load. Then buy. Buying closes — seconds before the hour opens.
Sell. On Sell, pick the hour, a length and a premium, and open the ticket. 40 USDC less the premium moves into its vault. Until it sells, you can withdraw it.
| Account | Rent | Paid by | Comes back |
|---|
Rent as the runtime charges it now. Network fees are separate.
When money waits
Nobody buys. The ticket stays on sale until buying closes. While it is unsold the seller can withdraw it at any time, and the deposit and the ticket's rent come back.
The open read is missed. The candle is void. Settlement returns the premium to the buyer and the deposit to the seller.
A later read is missed. The wicks stay where they were. Missing data favors the seller; a ticket carrying SPAN still records between reads.
The keeper stops. read and settle take no key of ours. Anyone can send them with the same accounts, or run the public keeper from its source [2]. A read sent after its window is missed.
SPAN runs short. Readings stop once the ticket holds less than one burn. The candle keeps every wick already recorded.
Nobody settles. The 40 USDC waits in the vault. Settlement has no deadline, and anyone can send it.
A side has no USDC account. Settlement creates it. The public keeper pays for up to — SOL of these a day; past that the ticket waits, and anyone can settle it with their own key.
Tickets and calls
Every state a ticket passes through, shown on a real hour (Feb 6 jobs report), and the calls that move it.
| Call | Who | What it does |
|---|---|---|
init | the upgrade authority, once | sets the admin, the USDC mint, the DOVES account and the read values |
set_span | the admin, once | sets the SPAN mint and the burn per reading |
set_feed | the admin | points span at another DOVES account for SOL; open candles read it from their next read |
set_params | the admin | changes the read window, age limit and buy cutoff for candles opened later |
open_candle | anyone | creates the candle the first time a ticket is opened on it |
open_ticket | seller | deposits 40 − premium and sets the length and the premium |
withdraw | seller | takes back an unsold ticket, its deposit and its rent, at any time |
buy | buyer | pays the premium, until — seconds before the candle opens |
load_span | buyer | loads SPAN, sets the step and names the reader |
read | anyone | records one of the thirteen reads from DOVES |
mark | the ticket's reader | records a reading that stretches a wick by at least the step; burns SPAN when it raises the payout |
settle | anyone | after the close, pays both sides from the vault and returns unused SPAN and the rent |
—
Values
Read from the program's settings on mainnet, as span's tape last saw them. A candle keeps the read window, age limit and buy cutoff it was opened with, so a change reaches only candles opened after it.
| Value | Now | What it does |
|---|
—
Price
Prices come from Jupiter's DOVES oracle account for SOL, the same price Jupiter perps fill against [3]. Reading it costs nothing.
// DOVES SOL/USD account, read on chain
price u64 at byte 168 // 8 decimals
publish_time i64 at byte 177 // unix seconds
—
Measured on 2026
Every 2026 release hour, replayed under the program's rule: the thirteen reads as the keeper sends them, and a reader that records every reading a 5 bp step allows.
| Release | Hours | Median body | Median candle | Past 2% | Reads drew | SPAN drew | 2% ticket, average |
|---|
—
Trust assumptions
- span is one program on Solana. Its source is public, and the deployed program is a verified build of commit 3a5c5b8, executable hash 8e758c7e… [2]. Rebuild it and compare the hash before you rely on anything on this page.
- The program is upgradeable, and its upgrade authority is the admin key, —. No admin call moves a vault or changes a ticket's length, premium or payout rule. An upgrade could change any rule; the verified build is how you check which one is running.
- The admin can point span at another DOVES account for SOL; open candles read it from their next read. The admin can change the read window, age limit and buy cutoff for candles opened later; an open candle keeps its own. The SPAN mint and the burn per reading are set once.
- DOVES is Jupiter's price account [3]. span reads it as written and has no other price.
- A ticket's payout is capped at 40 USDC because the 40 USDC is already in the ticket. Nothing is borrowed.
- span runs the public keeper. Anyone can run another from the same source, and reads and settlement take no key of ours.
- This site reads span's tape, a cached copy of the chain. Nothing you sign depends on it: the program checks every transaction.
Problems
Data on this site
The candles here not marked on chain are replays: the DOVES SOL price of each 2026 release hour, rebuilt from the oracle account's own Solana transactions. The reads follow the program's rule. They were computed by this code:
// Read j (j = 0..12) is due at boundary b = t0 + 300 j. It takes the account as it stands once
// Clock reaches b, from the first value published at or after b. It holds only if that value
// was published in [b, b + W], is at most A seconds old at Clock, and read 0 holds.
function reads(S: State[], t0: number): (State | null)[] {
const out: (State | null)[] = [];
for (let j = 0; j <= 12; j++) {
const b = t0 + 300 * j;
let k = S.findIndex((s) => s.publish >= b);
while (k >= 0 && k < S.length && S[k].clock < b) k++;
const s = k >= 0 && k < S.length ? S[k] : null;
const held = s !== null && b <= s.publish && s.publish <= b + W && s.clock - s.publish <= A;
out.push(held && (j === 0 || out[0] !== null) ? s : null);
}
return out;
}
replay.ts · reads() · W = 20, A = 20
Each minute is drawn from its DOVES prices: open, low, high, close for a minute that closed up; open, high, low, close for one that closed down. That order inside the minute is a drawing. The wicks and every number on this site come from the recorded prices alone.
References
- S. Nison, Japanese Candlestick Charting Techniques, New York Institute of Finance, 1991.
- span program and keeper source, github.com/spancandle/span. Verified build of commit 3a5c5b8, executable hash
8e758c7ebba1a3a3d84d2ddcdd2ef53a2d1f7be7b3882ecac96e60736321f2fa, verify.osec.io, 28 Oct 2026. - DOVES price program
DoVEsk76QybCEHQGzkvYPWLQu9gzNoZZZt3TPiL597e; SOL accountFYq2BWQ1V5P1WFBqr3qB2Kb5yHVvSv7upzKodgQE5zXh. - U.S. Bureau of Labor Statistics, release calendar: CPI, PPI and the Employment Situation.
- Board of Governors of the Federal Reserve System, FOMC meeting calendars.