Expected move
How far the options market expects the chart's market to move, read off its own option chain.
A card at the bottom of the pane, in the terminal look, leads with the move by the horizon the Horizon setting picks (1, 5, 7, 14, 30, 60 or 90 calendar days, or to the earnings expiry), in percent and in price ("±1.24% (±8.18) in 1 day"), then the earnings report the Earnings date setting names with the earnings expiry's implied move, the one-standard-deviation move and the straddle move side by side, the at-the-money implied volatility at seven constant maturities, and the next six expiries after today with each one's implied move in price and in percent. Two pairs of rails run across the chart from the prior session's close with a price tag at the axis each: the one-standard-deviation move in sky, the straddle move (about 0.68 of it) in dashed amber. The earnings expiry is the first one after the report the Earnings date setting names.
The parts are a celled options_chain.cells input read on the live bar (Data sources), the bar's time.trade_date for the prior session's close (The market's own calendar), the Earnings date setting for the report, the options kit's IvTerm, expectedMove, straddleMove, chainPricedAtMs and optionsTradeDay (Options kit), line and label handles for the rails and their tags (Drawing objects), and a render.hud card with look: "terminal" over data-only outputs and ten text slots (HUD cards). This is also the expected-move template: the Expected Move card under HUDs in the editor's starter list, and it compiles as written.
The wrun indicator
// Expected Move: how far the options market expects the chart's market to move, read off its own option chain. The
// at-the-money implied volatility at seven constant maturities (1, 5, 7, 14, 30, 60 and 90 calendar days, interpolated
// in total variance between the listed expiries, an expiry settling today never an anchor) reads in a card at the
// bottom of the pane, in the terminal look. Two pairs of rails run across the chart for the horizon the Horizon
// setting picks, centred on the prior session's close: the one-standard-deviation move (the horizon's IV times the
// close times the square root of the horizon in years, sky) and the straddle move (0.85 of the at-the-money
// straddle, about 0.68 of the first, amber, dashed), each with a price tag at the axis. Under them the card lists the
// next six expiries after today with each one's implied move in price and in percent of its underlying, and marks the
// earnings expiry: the first one after the report the Earnings date setting names. The Earnings horizon sizes the
// rails to that expiry: its at-the-money IV over its own time, and 0.85 of its straddle. The report is a setting and
// never a chart fill, so every host runs the package, the hosted lanes included. The chain rides the live bar only:
// history bars draw nothing, and everything is measured on the last bar.
section("Horizon");
param.choice("horizon", ["1d", "5d", "7d", "14d", "30d", "60d", "90d", "earnings"], "1d", { label: "Rails horizon", description: "The calendar days the rails cover (1, 5, 7, 14, 30, 60 or 90), or earnings: to the first expiry after the Earnings date" });
param.time("earnings_date", 0, { label: "Earnings date", description: "The report, in UTC: the first expiry after it is marked, its implied move read out, and the Earnings horizon runs to it; 0 (1970-01-01) is off" });
param.number("rate_pct", 4, { min: 0, max: 20, step: 0.25, label: "Rate, percent", description: "The rate that carries a US stock's spot to each expiry's forward; futures and crypto chains already quote the forward" });
input("close", ohlcv.close); // the chart's own close: the prior session's close is the last one of the trade date before today's
input("chain", options_chain.cells, { max_cells: 4000, venue: "auto", description: "The chart's own option chain: OPRA on a US stock, CME on futures, Deribit on BTC and ETH" }); // [strike, expiry_ms, side, oi, gamma, delta, mark_iv, underlying, multiplier, vega] per contract
input("trade_date", time.trade_date); // the bar's trade date: the UTC date on crypto, New York's on a US stock, CME's from 17:00 Chicago
market.zone(); // the market's clock: 0 UTC (crypto), 1 New York (US stocks), 2 Chicago (CME): the calendar and the rate rule
// The readings, data-only: the card's tiles read them and the Console can too. Each is NaN on history bars.
output("iv_1d", none, overlay, { description: "At-the-money IV 1 calendar day out, constant maturity, percent; live bar only" });
output("iv_5d", none, overlay, { description: "At-the-money IV 5 calendar days out, percent" });
output("iv_7d", none, overlay, { description: "At-the-money IV 7 calendar days out, percent" });
output("iv_14d", none, overlay, { description: "At-the-money IV 14 calendar days out, percent" });
output("iv_30d", none, overlay, { description: "At-the-money IV 30 calendar days out, percent" });
output("iv_60d", none, overlay, { description: "At-the-money IV 60 calendar days out, percent" });
output("iv_90d", none, overlay, { description: "At-the-money IV 90 calendar days out, percent" });
output("prior_close", none, overlay, { description: "The prior session's close: the last close of the trade date before today's, the rails' centre" });
output("em_pct", none, overlay, { description: "The one-standard-deviation move by the horizon, percent: its IV times the square root of the horizon in years" });
output("sm_pct", none, overlay, { description: "The straddle move by the horizon, percent: 0.85 of the at-the-money straddle at its IV" });
output("em_hi", none, overlay, { color: "#38bdf8", description: "The prior close plus the one-standard-deviation move" });
output("em_lo", none, overlay, { color: "#38bdf8", description: "The prior close minus the one-standard-deviation move" });
output("sm_hi", none, overlay, { color: "#f8c000", description: "The prior close plus the straddle move" });
output("sm_lo", none, overlay, { color: "#f8c000", description: "The prior close minus the straddle move" });
output("front_move_pct", none, overlay, { description: "The first expiry after today: its implied move, percent of its underlying" });
output("earnings_move_pct", none, overlay, { description: "The earnings expiry (the first after the report): its implied move, percent; NaN with no report ahead" });
output("earnings_days", none, overlay, { description: "Days to that expiry on the market's calendar" });
output("report_days", none, overlay, { description: "Days to the report on the market's calendar, 0 on its day; NaN with no report ahead" });
string("title", { max_bytes: 64 }); // the card's title: the horizon and the close the rails start from
string("move_text", { max_bytes: 48 }); // the headline: the move in percent and in price, or why there is none
string("earnings_text", { max_bytes: 64 }); // the report: its date and session, the days to it, the earnings expiry's move
string("tag", { max_bytes: 40 }); // one bounded slot the four price tags are written through, one at a time
string("expiry_1", { max_bytes: 48 }); // the next six expiries: date, days to go, the implied move in price and percent
string("expiry_2", { max_bytes: 48 });
string("expiry_3", { max_bytes: 48 });
string("expiry_4", { max_bytes: 48 });
string("expiry_5", { max_bytes: 48 });
string("expiry_6", { max_bytes: 48 });
handles.line({ width: 1, extend: "both" }); // the four rails, across the whole chart
handles.label({ anchor: "right", align: "right", size: 11, color: "#e2e8f0" }); // price tags: x in pixels from the right edge, y in price
// The card, in the terminal look: the move by the horizon leads as the headline, the two moves in percent beside each
// other, then the constant-maturity IVs and the next six expiries as rows. A tile's label is fixed text, so the
// expiry rows read their words from the six slots.
render.hud("expected_move", {
position: "bottom_center",
look: "terminal",
title: "{{title}}",
columns: 2,
tiles: [
tile.pill("Expected move", "move_text", { headline: true }),
tile.pill("Earnings", "earnings_text"),
tile.value("1 sd move", "em_pct", { format: "%" }),
tile.value("Straddle move", "sm_pct", { format: "%" }),
tile.rows("At-the-money IV", [
["1 day", "iv_1d", "%"],
["5 days", "iv_5d", "%"],
["7 days", "iv_7d", "%"],
["14 days", "iv_14d", "%"],
["30 days", "iv_30d", "%"],
["60 days", "iv_60d", "%"],
["90 days", "iv_90d", "%"],
]),
tile.rows("Implied move by expiry", [
["1)", "expiry_1"],
["2)", "expiry_2"],
["3)", "expiry_3"],
["4)", "expiry_4"],
["5)", "expiry_5"],
["6)", "expiry_6"],
]),
],
});
const TUPLE = 10; // f64s per contract: strike, expiry_ms, side, oi, gamma, delta, mark_iv, underlying, multiplier, vega
const LISTED = 6; // expiries in the card's list
const HORIZON_DAYS: f64[] = [1.0, 5.0, 7.0, 14.0, 30.0, 60.0, 90.0];
const EARNINGS = 7; // the horizon setting's last choice: the rails run to the earnings expiry
const MONTHS: String[] = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"];
const SKY = rgba(56, 189, 248, 255);
const AMBER = rgba(248, 192, 0, 255);
const PILL = rgba(15, 23, 42, 235); // the tags' backdrop
const lines: LineHandle[] = [draw.line(0), draw.line(1), draw.line(2), draw.line(3)]; // 1 sd high, 1 sd low, straddle high, straddle low
const tags: LabelHandle[] = [draw.label(4), draw.label(5), draw.label(6), draw.label(7)]; // ids are one space across kinds
const tagPrices = new StaticArray<f64>(4); // the tags placed so far on this bar, so a level near another steps inward
const tagSlots = new StaticArray<i32>(4); // the step inward each placed tag took
const term = new IvTerm(64); // the chain's at-the-money term; its buffers are its only allocation
const dateClock = new Clock("UTC"); // reads a date from its day number
let horizonChoice = 0; // settings, read in onStart()
let horizon = 1.0;
let reportMs: f64 = NaN; // the report the card reads: the Earnings date setting's instant, NaN when off
let rate = 0.04;
let zone = 0;
let close: f64 = NaN; // this bar
let t: f64 = NaN;
let firstT: f64 = NaN; // the first bar's open time: where the rails start
let sessionKey: f64 = NaN; // the trade date the bars are in, days since 1970-01-01
let sessionClose: f64 = NaN; // the last close seen in it
let priorClose: f64 = NaN; // the last close of the trade date before it
let nowMs: f64 = NaN; // when the chart priced the chain
function onStart(): void {
horizonChoice = i32(p_horizon());
horizon = horizonChoice == EARNINGS ? NaN : HORIZON_DAYS[horizonChoice];
reportMs = p_earnings_date() > 0.0 ? p_earnings_date() * 1000.0 : NaN;
zone = i32(p_market_zone());
rate = zone == 1 ? p_rate_pct() / 100.0 : 0.0; // a US stock's spot carries the rate to each forward; futures and crypto already quote it
}
// ── The prior session's close: the last close of the trade date before the one the bars are in ──
function trackSession(): void {
const stamp = in_trade_date(); // epoch seconds of the trade date, as the chart writes it
const key = isFinite(stamp) ? Math.floor(stamp / 86400.0) : optionsTradeDay(t * 1000.0, zone);
if (isNaN(key)) return;
if (isNaN(sessionKey)) sessionKey = key;
else if (key > sessionKey) {
priorClose = sessionClose; // a new trade date: the last close of the one before is the prior session's
sessionKey = key;
}
if (!isNaN(close)) sessionClose = close;
}
// ── Text helpers ──
function sbGrouped(n: i64): void { // 84210 -> 84,210
if (n >= 1000) {
sbGrouped(n / 1000);
sb_text(",");
const r = n % 1000;
if (r < 100) sb_text("0");
if (r < 10) sb_text("0");
sb_int(r);
} else sb_int(n);
}
function sbPrice(v: f64): void { // decimals follow the price's size: 6,652 / 660.10 / 48.125
if (v >= 1000.0) sbGrouped(i64(Math.round(v)));
else if (v >= 100.0) sb_f64(v, 2);
else sb_f64(v, 3);
}
function sbAmount(v: f64): void { // a move in price: 1,840 / 8.18
if (v >= 1000.0) sbGrouped(i64(Math.round(v)));
else sb_f64(v, 2);
}
function near(a: f64, b: f64): bool { // two levels within 0.3% of each other would share a tag row
return !isNaN(a) && !isNaN(b) && Math.abs(a - b) <= Math.abs(b) * 0.003;
}
function stepTaken(which: i32, price: f64, step: i32): bool { // an earlier tag within 0.3% of this price already sits at this step
for (let j = 0; j < which; j += 1) if (tagSlots[j] == step && near(tagPrices[j], price)) return true;
return false;
}
function drawRail(which: i32, name: String, price: f64, ink: i32, style: LineStyle): void { // a rail across the chart and its price tag
if (isNaN(price)) {
lines[which].delete(); // no-ops when never drawn
tags[which].delete();
tagPrices[which] = NaN;
tagSlots[which] = -1;
return;
}
lines[which].set(firstT, price, t, price).color(ink).width(style == LineStyle.Solid ? 1.5 : 1.0).style(style).extend(Extend.Both);
let step = 0; // the first step inward that no earlier tag within 0.3% holds
while (stepTaken(which, price, step)) step += 1;
tagPrices[which] = price;
tagSlots[which] = step;
sb_clear();
sb_text(name);
sb_text(" ");
sbPrice(price);
tags[which].set(56.0 + 112.0 * f64(step), price).text(str_tag_sb).color(ink).fill(PILL); // 56 px in from the right edge clears the axis tags; each step is 112 px further in
}
function writeDays(days: f64): void { // "1 day", "5 days"
sb_int(i64(days));
sb_text(days == 1.0 ? " day" : " days");
}
function writeDate(ms: f64): void { // "24OCT": an instant's trade date on the market's clock
dateClock.update(optionsTradeDay(ms, zone) * 86400.0);
if (dateClock.dayOfMonth() < 10) sb_text("0");
sb_int(dateClock.dayOfMonth());
sb_text(MONTHS[dateClock.month() - 1]);
}
function writeExpiry(slot: i32, e: i32, earningsRow: i32): void { // "16OCT 1d ±5.17 0.78%", the earnings expiry marked
sb_clear();
if (e >= 0 && e < term.expiries()) {
writeDate(term.expiry(e)); // the expiry's trade date
sb_text(" ");
sb_int(i64(term.days(e)));
sb_text("d ");
const move = term.impliedMove(e);
if (isNaN(move)) sb_text("no IV");
else {
sb_text("±");
sbAmount(move);
sb_text(" ");
sb_f64((move / term.underlying(e)) * 100.0, 2);
sb_text("%");
}
if (e == earningsRow) sb_text(" earnings");
}
if (slot == 0) str_expiry_1_sb();
else if (slot == 1) str_expiry_2_sb();
else if (slot == 2) str_expiry_3_sb();
else if (slot == 3) str_expiry_4_sb();
else if (slot == 4) str_expiry_5_sb();
else str_expiry_6_sb();
}
// onBar() runs once per bar: every bar feeds the session tracker; the live bar measures the chain, writes the readings
// (NaN on history rows), the rails and the card's words.
function onBar(): void {
close = bar.close();
t = bar.time();
if (isNaN(firstT) && !isNaN(t)) firstT = t;
trackSession();
let measured = false; // the live bar carried a chain with a live expiry
let chainCells = -1;
if (bar.isLast() && !isNaN(t)) {
chainCells = in_chain_cells();
if (chainCells >= TUPLE) {
const cells = in_chain_view(); // the live chain in place: the first n values of the build's own buffer
nowMs = chainPricedAtMs(cells, chainCells, t * 1000.0);
measured = term.load(cells, chainCells, nowMs, isNaN(close) ? 0.0 : close, zone, rate) > 0;
}
}
const centre = measured ? priorClose : NaN;
const front = measured ? term.front() : -1;
// The earnings expiry: the first one to settle after the report's instant, while the report is ahead.
const clockMs = measured ? nowMs : t * 1000.0;
const reportAhead = bar.isLast() && reportMs > clockMs;
let earningsRow = -1;
if (measured && reportAhead) {
for (let e = 0; e < term.expiries(); e += 1) {
if (term.expiry(e) > reportMs) {
earningsRow = e;
break;
}
}
}
// The rails' horizon: the setting's days at the constant-maturity IV, or the earnings expiry's own time and IV.
let emPct: f64 = NaN;
let smPct: f64 = NaN;
if (horizonChoice == EARNINGS) {
if (earningsRow >= 0) {
const days = term.years(earningsRow) * 365.0;
emPct = expectedMove(1.0, term.atmIv(earningsRow), days) * 100.0; // NaN without an IV
smPct = straddleMove(1.0, term.atmIv(earningsRow), days) * 100.0;
}
} else {
const horizonIv = measured ? term.iv(horizon) : NaN;
emPct = expectedMove(1.0, horizonIv, horizon) * 100.0; // NaN without an IV
smPct = straddleMove(1.0, horizonIv, horizon) * 100.0;
}
const reportDays = reportAhead ? optionsTradeDay(reportMs, zone) - optionsTradeDay(clockMs, zone) : NaN;
out_iv_1d(measured ? term.iv(1.0) * 100.0 : NaN);
out_iv_5d(measured ? term.iv(5.0) * 100.0 : NaN);
out_iv_7d(measured ? term.iv(7.0) * 100.0 : NaN);
out_iv_14d(measured ? term.iv(14.0) * 100.0 : NaN);
out_iv_30d(measured ? term.iv(30.0) * 100.0 : NaN);
out_iv_60d(measured ? term.iv(60.0) * 100.0 : NaN);
out_iv_90d(measured ? term.iv(90.0) * 100.0 : NaN);
out_prior_close(centre);
out_em_pct(emPct);
out_sm_pct(smPct);
out_em_hi(centre * (1.0 + emPct / 100.0));
out_em_lo(centre * (1.0 - emPct / 100.0));
out_sm_hi(centre * (1.0 + smPct / 100.0));
out_sm_lo(centre * (1.0 - smPct / 100.0));
out_front_move_pct(front >= 0 ? (term.impliedMove(front) / term.underlying(front)) * 100.0 : NaN);
out_earnings_move_pct(earningsRow >= 0 ? (term.impliedMove(earningsRow) / term.underlying(earningsRow)) * 100.0 : NaN);
out_earnings_days(earningsRow >= 0 ? term.days(earningsRow) : NaN);
out_report_days(reportDays);
if (!bar.isLast()) return;
// The rails, centred on the prior session's close: the one-standard-deviation pair, then the straddle pair.
drawRail(0, "1 sd high", centre * (1.0 + emPct / 100.0), SKY, LineStyle.Solid);
drawRail(1, "1 sd low", centre * (1.0 - emPct / 100.0), SKY, LineStyle.Solid);
drawRail(2, "Straddle high", centre * (1.0 + smPct / 100.0), AMBER, LineStyle.Dashed);
drawRail(3, "Straddle low", centre * (1.0 - smPct / 100.0), AMBER, LineStyle.Dashed);
// The card's words: the title, the headline, the report, the six expiries after today.
sb_clear();
if (horizonChoice == EARNINGS) sb_text("Expected move to the earnings expiry");
else {
sb_text("Expected move, ");
writeDays(horizon);
}
if (!isNaN(centre)) {
sb_text(", from ");
sbPrice(centre);
}
str_title_sb();
sb_clear();
if (chainCells < TUPLE) sb_text("Waiting for the options chain");
else if (!measured) sb_text("No live expiry in the chain");
else if (horizonChoice == EARNINGS && !reportAhead) sb_text("No earnings report ahead");
else if (horizonChoice == EARNINGS && earningsRow < 0) sb_text("No expiry after the report");
else if (isNaN(emPct)) sb_text("No at-the-money IV in the chain");
else {
sb_text("±");
sb_f64(emPct, 2);
sb_text("%");
if (!isNaN(centre)) {
sb_text(" (±");
sbAmount((centre * emPct) / 100.0);
sb_text(")");
}
if (horizonChoice == EARNINGS) {
sb_text(" by ");
writeDate(term.expiry(earningsRow));
} else {
sb_text(" in ");
writeDays(horizon);
}
}
str_move_text_sb();
sb_clear();
if (isNaN(reportMs)) sb_text("Set the Earnings date to read the report");
else if (!reportAhead) sb_text("The report date has passed");
else {
writeDate(reportMs);
if (reportDays <= 0.0) sb_text(", today");
else {
sb_text(", in ");
writeDays(reportDays);
}
if (earningsRow >= 0) {
const move = term.impliedMove(earningsRow);
if (isNaN(move)) sb_text(": no IV");
else {
sb_text(": ±");
sb_f64((move / term.underlying(earningsRow)) * 100.0, 2);
sb_text("%");
}
} else if (measured) sb_text(", no expiry after it");
}
str_earnings_text_sb();
for (let k = 0; k < LISTED; k += 1) writeExpiry(k, front >= 0 ? front + k : -1, earningsRow);
}How it works
The at-the-money term. IvTerm reads every live expiry's at-the-money implied volatility: the mean of the call and the put IV at the strike nearest the expiry's forward, among the strikes within 20% of its underlying. Between two expiries it interpolates in total variance, IV squared times years, to a constant maturity in calendar days, and an expiry that settles today is listed but never anchors: its IV swings with the hours left (The at-the-money term). iv_1d through iv_90d are the seven maturities in percent. On a US stock the forward is the spot carried at the Rate setting (4% by default); a futures or crypto chain already quotes each expiry's forward. The time to each expiry runs from chainPricedAtMs(), the moment the chart priced the chain, in 365-day years.
Two moves by the horizon. Both read the horizon's constant-maturity IV. The one-standard-deviation move is that IV times the square root of the horizon in years: about a two-in-three chance the market closes the horizon inside it (em_pct, expectedMove). The straddle move is 0.85 of the at-the-money straddle priced at that IV, the implied move flow desks quote, about 0.68 of the first (sm_pct, straddleMove). 30 days at a 14.9% IV reads 2.9% as a straddle move.
The prior session's close. Every bar feeds a tracker: the bar's time.trade_date is its session (the UTC date on crypto, New York's on a US stock, CME's trade day from 17:00 Chicago), and when it moves on, the last close of the session before becomes the prior close. The live bar's own close never counts. On a chart of a day or longer each bar is a session, so it is the previous bar's close. A host that writes no trade date falls back to optionsTradeDay() on the bar's time.
The rails. em_hi and em_lo are the prior close plus and minus the one-standard-deviation move, sm_hi and sm_lo the same for the straddle move; each is a line handle across the chart with its price tag at the axis. A tag within 0.3% of an earlier one steps 112 px inward, so the 1 sd high and the straddle high never print over each other on a short horizon.
The next six expiries. The card lists the six expiries after today on the market's own calendar, each as its date, its days to go, its implied move in price and in percent of its underlying (16OCT 1d ±5.17 0.78%): the straddle rule at the expiry's own at-the-money IV and time. front_move_pct is the first one's.
Earnings. The report is the instant Earnings date names, in UTC (0, 1970-01-01, is off). It is a setting and never a chart fill, so every host runs the package as it ran 0.1.0, a Protected copy on OpenMarket's servers included. The earnings expiry is the first expiry to settle strictly after that instant. It is marked earnings in the list (when it is one of the six), its implied move and days to go read out as earnings_move_pct and earnings_days, the report's days to go as report_days, and the card's Earnings line reads them (21OCT, in 6 days: ±7.45%). The Earnings horizon sizes the rails to that expiry: its own at-the-money IV over its own time for the one-standard-deviation move, 0.85 of its straddle for the straddle move, centred on the prior close as on every horizon. A report that has passed reads nothing.
The card reads the outputs. The headline is the one-standard-deviation move by the horizon in percent and, once a prior close is known, in price (±7.45% (±49.18) by 24OCT on the Earnings horizon); the Earnings line follows it; the two tiles are the two moves in percent; then the seven IVs and the six expiries as rows. The title names the horizon and the close the rails start from (Expected move, 1 day, from 660.10, or Expected move to the earnings expiry, from 660.10).
Where it runs
Charts of a coin Deribit lists options for (BTC, ETH, SOL and the rest of its list): that is where the copy you run from the editor reads a chain. On a US stock chart venue: "auto" reads the chart's own OPRA chain, and on a CME futures chart the chain of its root; the chart serves both to OpenMarket's official wrun indicators and discloses the source in the legend. A copy you run from the editor or publish yourself does not read them yet.
When data is missing
The headline says why instead of the card going blank: "Waiting for the options chain" while the live bar carries none, "No live expiry in the chain" when every listed expiry has passed, and "No at-the-money IV in the chain" when no expiry after today has an IV near the money; on the Earnings horizon, "No earnings report ahead" without a report and "No expiry after the report" when the chain lists none after it. The Earnings line reads "Set the Earnings date to read the report" until the setting names one. Until the chart has crossed a session boundary there is no prior close: the rails do not draw and the headline gives the move in percent alone. An expiry without an IV at the money reads no IV in the list.
Customize it
- A longer horizon. Set Horizon to
7dor30dfor a weekly or monthly band; the rails widen with the square root of the days. - Into earnings. Set Earnings date to the report's date and time and Horizon to
earnings: the rails span the move the market prices through the report. - A different rate. Set Rate to today's short rate on a US stock; it moves the forward, so the strike read as at the money on a long expiry.
Run it
- In the editor's Explorer, press the Templates icon ("Browse starter templates") and pick Expected Move under HUDs.
- Press Run on a BTC chart on a 1h interval: the four rails draw from the prior session's close once the chain arrives, and the terminal card appears at the bottom centre.
- At the editor's Console prompt, type
em_pct,sm_pctandiv_30dto read the two moves and the 30-day IV on the live bar.
Concepts used
- Data sources for the
options_chaincelled class, its tuple and thevenueword - The market's own calendar for
time.trade_date - Options kit for
IvTerm, the expected move forexpectedMoveandstraddleMove - Drawing objects for line handles extended across the chart and right-anchored tags
- HUD cards, Blocks and tiles and Looks for the card, its tiles and the slot in the title