Docs
Open the Book X Buy $UNWICK
Docs · v1.0.0

Paid for the way back.

Unwick is a ticket on one hour of SOL. It names a stop: a distance below the hour's open for a long, above it for a short. If the price touches the stop and the hour closes back past it, the ticket pays 10 USDC for every 1% of the close past the stop, up to 40.

A stop-loss order is a promise to leave at the worst price of the hour. Most of the time that is the right call. Some hours the wick takes every stop in its reach and the candle closes as if nothing happened. A ticket is paid on exactly those hours, and only by how far the close came back.

Every ticket holds its 40 USDC before the hour opens: the seller's deposit plus the buyer's premium. Settlement only splits it. The whole rule is one function in unwick.js, which you can import straight from this site.

Get started

Quick start

The module has no dependencies. Import it from this site in a browser or in Node 19 and newer. The replay of 36 hours of 2026 sits next to it, in cents.

import { loadReplay, settle } from "https://unwick.vercel.app/lib/unwick.js";

// 36 hours of 2026, Binance SOL/USDT one-minute candles
const { hours } = await loadReplay();
const feb20 = hours.find((h) => h.t === 1771606800); // Fri Feb 20, 17:00 UTC

const r = settle(feb20.m, { side: "long", stop: 1, premium: 3 });
console.log(r.armedBy, r.payout, r.buyer); // "read" 9.88 6.88
# the same hour, straight from Binance
curl "https://api.binance.com/api/v3/klines?symbol=SOLUSDT&interval=1m&startTime=1771606800000&limit=60"

# the replay file the site reads
curl -O "https://unwick.vercel.app/assets/replay.json"
<script type="module">
  import { fetchHour, mark, nextHour } from "https://unwick.vercel.app/lib/unwick.js";
  // this hour, as if it closed now
  const start = nextHour() - 3600000;
  const h = await fetchHour(start);
  document.body.textContent = JSON.stringify(mark(h.m, { side: "long", stop: 1, premium: 3 }));
</script>
NOTEIn Node, save the file as unwick.mjs or import it by URL with a loader. Node 19+ has fetch built in, which fetchHour() needs.
Get started

Try it

Pick an hour and terms. The output is what settle() returns, from the same module the main page uses.

// pick an hour and press Settle
How it works

The rule

A ticket pays only when two things happened in its hour: the price reached the stop, and the close is back on the ticket's side of it.

armed = the stop was touched, by a read or by the witness
payout = armed ? min(40, 10 × max(close past the stop, 0)) : 0
close past the stop = (close − stop) / open × 100 for a long, (stop − close) / open × 100 for a short

The payout is measured from the stop, not from the low. The part of the wick below a long's stop is never paid: the ticket pays for the way back, not the way down. At 4% past the stop the payout reaches 40 and stops there, because 40 is all a ticket holds.

export function payout(open, close, stopPx, side, armed) {
  if (!armed) return 0;
  const past = side === "long" ? (close - stopPx) / open * 100 : (stopPx - close) / open * 100;
  return cents(Math.min(RULE.vault, RULE.perPct * Math.max(past, 0)));
}

Three hours of 2026

Hour · UTCTicketLowClosePays
Fri Feb 20 · 17:00long, 1.00%−1.99%−0.01%9.88
Thu Jun 04 · 02:00long, 2.00%−2.67%+2.10%40.00
Sun Mar 29 · 22:00long, 1.00%−3.88%−1.47%0.00

The last one took the stop and never came back. The ticket was armed and pays nothing, and the seller keeps the 40. A stop that was right is not a wick.

How it works

The stop

A seller opens a ticket with a side and a stop distance from 0.25% to 5%, in steps of 0.25%. The distance is fixed when the ticket opens. The stop price is fixed at the hour's first read, so nobody knows the exact number until the hour starts.

  • Long: stop below the open. Pays when SOL wicks down through it and closes back above it.
  • Short: stop above the open. Pays when SOL wicks up through it and closes back below it.

A tight stop is taken often and pays small. A deep stop is taken rarely, and when it is, the wick that reached it was usually fast. That is where the witness earns its burn.

How it works

Reads

Every hour is read thirteen times: at the open, then every 300 seconds, and the last read is the close. Anyone can send a read. A read takes the first price published at or after its boundary.

Reads decide two things: the open, which fixes the stop price, and the close, which fixes the payout. They can also arm a ticket, if one of them lands beyond the stop. Five-minute reads miss most of what happens between them, and the wick that takes a stop often lasts less than a minute.

In the replay

Read j for j = 0 … 11 is the open of minute 5j. Read 12 is the close of minute 59.

export function reads(m) {
  shape(m);
  const out = [];
  for (let j = 0; j < 12; j++) out.push(m[5 * j][0]);
  out.push(m[59][3]);
  return out;
}
How it works

The witness

A buyer can load $UNWICK into a ticket. The ticket then has a witness: a recorder that watches every published price and records the first one that reaches the stop. A witness record can only arm a ticket. It never changes the open or the close, so it never changes how much an armed ticket pays.

  • A record that arms the ticket burns 2,500 $UNWICK.
  • A record the reads already covered, or a price that never reached the stop, is free.
  • Unburned $UNWICK goes back to the buyer at settlement.
Long stopPaid, reads onlyPaid, with witness
1.00%22 of 3624 of 36
1.50%23 of 3625 of 36
2.00%9 of 3617 of 36
2.50%5 of 3610 of 36
3.00%2 of 368 of 36
NOTEThe replay gives the witness one-minute highs and lows. A witness on the live feed sees every published price, so on the same hours it arms at least as many tickets.
How it works

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 full 40 sits in the ticket's vault. 41 seconds after the hour closes, anyone can settle: the buyer receives the payout, the seller receives the rest of the 40.

buyer = payout − premium
seller = premium − payout
break-even = the close is premium / 10 percent past the stop

Neither side can lose more than it put in. A buyer's worst case is the premium. A seller's worst case is the deposit, on an hour that took the stop and closed 4% or more past it.

How it works

When money waits

  • Nobody buys. The ticket stays on sale until 5 seconds before the hour opens. Until it sells, the seller can withdraw the deposit.
  • The open read is missed. There is no stop price, so the hour is void. Both sides get back what they put in.
  • A later read is missed. It arms nothing. A ticket with a witness still arms on the first price past the stop.
  • The close read is missed. Settlement uses the last read that landed. Missing data favours the seller.
  • The witness runs short. A ticket holding less than one burn is not witnessed. Reads still apply.
  • Nobody settles. The 40 waits in the vault. Settlement has no deadline and anyone can send it.
unwick.js

settle()

settle(m, ticket) applies the rule to one hour. m is 60 one-minute candles [open, high, low, close]. ticket is { side, stop, premium, witness }; witness defaults to true.

FieldMeaning
open, closeRead 0 and read 12.
stopPxThe stop price, fixed at the open.
lowPct, highPct, closePctPercent from the open.
touchMinuteFirst minute whose extreme reached the stop, or null.
readHitIndex of the first read beyond the stop, or null.
armedBy"read", "witness" or null.
armedAtMinute the ticket was armed.
payoutUSDC to the buyer, 0 to 40.
buyer, sellerEach side's result after the premium.
burn$UNWICK burned: 2,500 if the witness armed it, else 0.
breakEvenPctHow far past the stop the close must be for the buyer to break even.
unwick.js

book()

book(hours, ticket) settles the same terms on every hour and adds them up. It is what the Book on the main page draws.

import { loadReplay, book } from "https://unwick.vercel.app/lib/unwick.js";
const { hours } = await loadReplay();
const b = book(hours, { side: "long", stop: 2, premium: 3, witness: true });
console.log(b.paid, b.average, b.buyer, b.seller); // 17 6.8 136.95 -136.95
unwick.js

fetchHour() and mark()

fetchHour(start) loads one UTC hour of SOL/USDT one-minute candles from Binance. start is milliseconds on the hour. While the hour is running it returns the minutes so far, with complete: false.

mark(partial, ticket) settles a running hour as if it closed at its last price. The main page uses it for "This hour, live".

import { fetchHour, mark, nextHour } from "https://unwick.vercel.app/lib/unwick.js";
const h = await fetchHour(nextHour() - 3600000);
const now = mark(h.m, { side: "short", stop: 0.5, premium: 2 });
console.log(h.m.length, now.armedBy, now.payout);
WARNINGA running hour is not a settled one. mark() pays on the price right now; the ticket pays on the close.
unwick.js

reads(), payout(), stopPrice()

The parts settle() is built from, exported on their own: reads(m) returns the thirteen read prices, stopPrice(open, side, stop) the stop, payout(open, close, stopPx, side, armed) the USDC. check(ticket) validates terms and throws an UnwickError. nextHour(now) returns the next hour's start, and RULE holds the values below.

Reference

Values

ValueNowWhat it does
vault40 USDCWhat every ticket holds and the most it pays.
perPct10 USDCPaid for each 1% the close is past the stop.
stop0.25–5%, step 0.25Set by the seller on each ticket.
premium0.10–39 USDCSet by the seller on each ticket.
reads13, every 300 sThe open, eleven in between, the close.
buyCutoff5 sBuying closes this long before the hour opens.
settleAfter41 sSettlement opens this long after the close.
burn2,500 $UNWICKBurned when a witness record arms a ticket.
Reference

Ticket lifecycle

StateWho actsWhat happens
opensellerDeposits 40 − premium, sets side, stop and premium.
withdrawsellerTakes back an unsold ticket at any time.
buybuyerPays the premium, until 5 s before the hour.
loadbuyerLoads $UNWICK and names the witness.
readanyoneRecords one of the thirteen reads.
witnessthe named witnessRecords the first price past the stop and burns 2,500 $UNWICK.
settleanyone41 s after the close: payout to the buyer, the rest to the seller.
Reference

Errors

CodeWhen
E_SIDEside is not "long" or "short".
E_STOP_RANGEstop is outside 0.25% to 5%.
E_STOP_STEPstop is not a multiple of 0.25%.
E_PREMIUM_RANGEpremium is outside 0.10 to 39 USDC.
E_HOUR_SHAPEthe hour is not 60 candles of [o, h, l, c].
E_HOUR_STARTfetchHour got a start that is not on the hour.
E_FEEDBinance answered with an error.
Reference

Data on this site

The Book replays 36 hours of 2026: the hours with the deepest wick that closed at least 60% of the way back, one per day, from Binance SOL/USDT. Each hour is 60 one-minute candles in cents, in assets/replay.json (sha256 0f94624e…82958). "This hour, live" and the rail price read Binance directly from your browser.

Inside a minute, the drawing goes open, low, high, close for a minute that closed up and open, high, low, close for one that closed down. That order is a drawing. Every number comes from the candles alone.

Project

Limits

  • The rule pays on one price feed. Whatever the feed says the close was, that is the close.
  • The replay is one-minute resolution. Sub-minute wicks that never showed in a minute's high or low are not in it.
  • The 36 hours were picked because they wicked and came back. They are a book of shakeouts, not an average hour. An average over them is not a price for the next one.
  • A seller who sells tight stops cheap pays for it on the hours this page is made of.
Project

$UNWICK

$UNWICK is what a witness burns. The more tickets with deep stops, the more fast wicks get recorded, and the more of it goes.

Contract: soon

Project

FAQ

Is this a stop-loss?

No. A stop-loss sells at the stop. A ticket sells nothing and is paid at the close, if the close came back past the stop.

Why not pay on the whole wick?

The part of the wick past the stop is what the stop was there for. Paying it would pay every crash. Unwick pays only the part that came back.

Which hour can I buy?

Any UTC hour, until 5 seconds before it opens. The main page prices the next one.

Do I need $UNWICK to buy a ticket?

No. Without it the ticket is armed by reads only. With it the first price past the stop counts.

Unwick docs · v1.0.0 · Binance SOL/USDTlib/unwick.js