Edge Data and Derived Metrics
Edge data is outside information your strategy reads next to the venue's own order book: Coinbase crypto prices and indicators, National Weather Service (NWS) observations and forecasts, and the official FOMC and CPI announcement calendars. Derived metrics turn one of those values into a distance from a Kalshi market's strike, such as "BTC spot is $250 above this market's strike".
Studio's AI writes this YAML for you. Use this section to check what each key means, which values are allowed, and what your Bot does when the data is late or missing.
Besides this page, the section has six pages, listed below: one for declaring and reading aliases, one field catalog per provider, one for derived metrics, and one for complete examples and validation errors. This page covers what applies to every provider: how edge data fits into a strategy, where it works, what backtests support, and how freshness and fail-closed behavior work.
Note: Every example in this section uses small, illustrative sizes and thresholds to show the syntax. They are not recommendations, and none of them implies a strategy will make money.
In this section
- Declaring and Reading Edge Data: The keys of an edge alias (name, provider, selector, fields, refresh) and how rule conditions read its values: units, two-field comparisons, text fields and unavailable values.
- Coinbase Edge Fields: Every Coinbase field (prices and quotes, change windows, highs and lows, moving averages, EMA distance, VWAP, velocity and MACD), its backtest support, and when candle-based fields go unavailable.
- NWS Weather Edge Fields: How to choose a station, every National Weather Service field (observations, daily and hourly forecasts, alerts, precipitation text), and how NWS values differ in backtests.
- Economic Calendar Edge Fields: The FOMC and CPI event selectors, the countdown fields and why they freeze between refreshes, and a recipe that pauses a strategy around each announcement.
- Derived Metrics: The
derived:block and its one kind,signed_distance_from_strike: which Kalshi markets have a strike, when a metric blocks entries, backtest caveats, and a spot-and-EMA recipe. - Edge Data Examples and Validation Errors: Six complete strategies (Coinbase change, EMA distance and MACD filters, NWS forecasts on Polymarket US and against a Kalshi strike, and an FOMC/CPI blackout) and a table of common edge validation errors.
How edge data works
You declare named aliases in a top-level edge: block. Each alias names one provider, one selector for that provider (a Coinbase product, an NWS station or a set of calendar events), the fields your rules may read, and how often to refresh. Rules then read a value as edge.<alias>.<field>. Every key is described in Declaring and Reading Edge Data.
edge:
btc: # your alias name
provider: coinbase # coinbase, nws or economic_calendar
symbol: BTC-USD # the selector: symbol, station or event, fixed by the provider
fields: [price, change_15m]
refresh: 10s # optional; Coinbase defaults to 5s
rules:
- name: exit_on_reversal
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: edge.btc.change_15m, op: "<", value: 0}
action: sell_all
- name: enter_on_up_move
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: edge.btc.change_15m, op: ">", value: 0.004} # up more than 0.4% in 15 minutes
action: buy_yes
size: 1A separate top-level derived: block (Kalshi only) declares numbers the Bot calculates from one edge field and the market's strike. Rules read them as derived.<name>. See Derived metrics.
Edge data takes effect only in strategy: custom on Kalshi and Polymarket US. See Where edge data works. For how rules, conditions and actions work in general, see Custom Rules.
Where edge data works
Where edge data and derived metrics work
| Platform and strategy | Edge data | Derived metrics | Backtests with edge data |
|---|---|---|---|
| Kalshi, custom | YesAll three providers | Yes | PartialPer-field and per-station limits |
| Polymarket US, custom | YesAll three providers | Rejected | NoPolymarket US cannot be backtested |
| Kalshi or Polymarket US, built-in strategies | IgnoredSaves, but nothing is fetched | Rejected | n/aEdge data is never used |
| Polymarket (regular) | Rejected | Rejected | No |
| Kalshi Perps | Rejected | Rejected | No |
| Arbitrage | Rejected | Rejected | No |
A few details the table leaves out:
- When data goes missing, both venues block new entries on that market while exits keep running. Kalshi also cancels the strategy's resting entry orders there; Polymarket US leaves resting orders in place. See When an alias goes missing.
- Built-in strategies such as
spread_captureormean_reversionaccept anedge:block, but never fetch it, so it has no effect and there is nothing to backtest. - Regular Polymarket rejects
edge:withregular Polymarket strategies do not support edge aliases. - Kalshi Perps custom rules read six Coinbase MACD fields by name instead; see Kalshi Perps.
- Arbitrage's own
net_edge_bpsfield is unrelated to edge data; see Arbitrage.
# Rejected: derived metrics need a Kalshi custom strategy, so Polymarket US refuses them
# error: derived metrics are supported only for custom Kalshi strategies
version: 1
platform: polymarket_us
strategy: custom
strategy_name: Derived metric on Polymarket US
market:
slug: example-market-slug
edge:
btc:
provider: coinbase
symbol: BTC-USD
fields: [price]
derived:
spot_vs_strike:
kind: signed_distance_from_strike
observed: edge.btc.price
risk:
max_position: 1
price_floor: 0.05
price_ceiling: 0.90
loop:
interval: 30
rules:
- name: exit_below_strike
when:
all:
- {field: position_size, op: ">", value: 0}
- {field: derived.spot_vs_strike, op: "<", value: 0}
action: sell_all
- name: enter_above_strike
when:
all:
- {field: position_size, op: "==", value: 0}
- {field: derived.spot_vs_strike, op: ">", value: 100}
action: buy_yes
size: 1Backtest support
Historical backtests with edge data run on Kalshi only. Support depends on the provider and field:
| Provider | Backtestable | How history differs from live |
|---|---|---|
coinbase | 35 of 39 fields. bid, ask, spread and spread_bps are live-only, and a rule that reads one fails the backtest with no historical backfill for field. | Rebuilt from one-minute samples of Coinbase candles. Fields other than MACD and ema_26_15m can see candle data early: up to 60 seconds for price and 1-minute fields, 5 minutes for 5-minute fields, 1 hour for hourly fields. Results can therefore look better than live. |
nws | 38 stations: KLGA, KJFK, KEWR, KBOS, KORD, KMDW, KSFO, KOAK, KLAX, KSAN, KDEN, KPHX, KLAS, KMIA, KMCO, KATL, KIAH, KHOU, KDFW, KSEA, KPDX, KDCA, KIAD, KBWI, KPHL, KMSP, KDTW, KCLT, KSLC, KMEM, KBNA, KTPA, KTBW, KHSE, KILM, KCHS, KJAX, KMSY. Any other station stops the backtest. | Rebuilt from public weather archives, not NWS itself, and several fields change meaning. See NWS in backtests. |
economic_calendar | Yes, when the official calendars cover the whole window. Otherwise the run fails with official economic calendar does not bracket requested window. | Seconds are computed exactly at every simulated tick, so backtests never show the live refresh lag. |
A few rules apply to every provider:
- Only fields named in rule conditions are guaranteed to be loaded. A field used only as a derived metric's
observedvalue may be missing unless a rule condition also reads it. See Backtesting derived metrics. - Aliases that no rule reads are ignored, although live they are still fetched and can still block ticks.
refreshis ignored. Instead, a Coinbase value older than 10 minutes or an NWS value older than 2 hours counts as unavailable.- An unavailable value makes every condition false, including
!=, as it does live. - Single-market backtests count a tick where a rule-referenced edge value is unavailable as blocked, and cancel the simulated resting orders. That blocked tick runs no exits either, while a live Bot blocks only entries during an outage, so a backtest can hold a position through an outage that a live stop-loss would have closed.
See Backtest data for how Studio treats historical data in general.
Freshness, missing data and fail-closed behavior
Edge data fails closed for entries: when an alias cannot be refreshed in time, the Bot opens nothing in that market rather than trading on old numbers, while exits that don't need the data keep running. A few NWS fields are exceptions and fail open.
What happens each tick
For a custom strategy on Kalshi or Polymarket US, each market tick runs in this order:
- Read every alias. Each declared alias is read from its cache, fetched again if needed. This happens before any rule runs, whether or not a rule reads that alias.
- Block entries if an alias is missing. Every field of a missing alias reads as unavailable, and the Bot logs a blocked
edge_datadecision. No buy rule may place an order on that market this tick: a matching one is skipped, and the rules below it still run. On Kalshi the Bot also cancels this strategy's resting entry orders on that market; its resting exit orders, such as take-profits, stay. On Polymarket US nothing is cancelled. - Compute derived metrics (Kalshi only). If the strike or the observed value is unavailable, every derived field reads as unavailable and entries are blocked the same way. See When a derived metric blocks entries.
- Run the rules top to bottom. A condition on an unavailable field is false, whatever the operator (see Unavailable values).
The refresh cache
Each alias has its own cache:
- A value younger than
refreshis reused without fetching. - An older value triggers a fetch. If the fetch fails, the last good values are reused while they are at most 3 × refresh old.
- Past that, the alias is missing and entries are blocked.
Refresh, stale limit and loop interval
refresh old. Once a value is older than one refresh, the next tick fetches again. A failed fetch does not restart the clock, so the Bot retries on every tick and keeps the last good values until they are 3 × refresh old. In A the loop is longer than that limit, so one failed fetch blocks that tick's entries; exits that don't read the alias still run.Three consequences are easy to miss:
- The very first fetch has no fallback. If it fails right after the Bot starts, the alias is missing at once.
- A long loop leaves no stale tolerance. Once
loop.intervalis longer than 3 × refresh, a single failed fetch blocks that tick's entries. - Failures are retried every tick. A failed fetch does not reset the refresh clock, so the Bot retries a failing provider on every tick and for every market it evaluates. Each request can wait a few seconds before timing out, so an unreachable provider can slow the whole loop.
Values measured relative to the fetch, such as seconds_to_next, seconds_since_previous and observation_age_sec, stay frozen between fetches: up to one refresh normally, and up to 3 × refresh while fetches fail.
When an alias goes missing
A missing alias blocks new entries on that market until data returns. Exits keep running: a stop-loss or take-profit that reads only market data (price, the book, position_size, unrealized_pnl) fires as usual, and max_loss keeps being checked. An exit whose own condition reads the missing alias can't fire meanwhile, because that condition is false. On Kalshi the Bot also cancels the strategy's resting entry orders on that market, which keeps a maker strategy from leaving quotes on stale data; resting exit orders stay.
Keep aliases to what your rules need. A failing alias that no rule reads still blocks every entry.
Fields that fail open
Some NWS fields fall back to a "nothing happening" value instead of becoming unavailable when a sub-lookup fails:
| Field | Reads during a lookup failure |
|---|---|
alert_active | 0 (no alert) |
alert_severity | none |
precip_type | none |
precip_amount_in | 0 |
The forecast temperatures and all precip_prob* fields go unavailable instead, so conditions on them are false. Every precip_prob* field also reads 0 when NWS publishes a period without a probability. Don't treat an alert flag of 0 as proof that the weather is calm.
Schedules and active windows
On Kalshi, aliases are fetched before trading_schedule is checked, because the schedule only blocks entries. Outside trading hours the Bot keeps fetching every loop, and an outage still cancels resting entry orders. Before active_window starts, the Bot idles and fetches nothing. After it ends, the Bot keeps fetching for the markets it still holds or has orders in, so their exits keep running; entries stay blocked either way.
Checking live values in Studio
On Kalshi, the Studio live terminal's Live market data panel lists each alias's fields with current values. Studio fetches those values itself on every terminal refresh, so they can differ from what your Bot evaluated on its last tick. A value that is unavailable, or a field of a failed alias, shows as a dash.
The panel also fills in related Coinbase fields you did not list: any one MACD field shows all three for that timeframe, and an EMA or either of its distances shows both _distance_usd and _distance_pct. Your Bot also records the finite values of its listed edge fields, and its derived metrics, in its trading journal samples.
Related pages
- Strategy Reference overview
- Kalshi and Polymarket US for market selection and risk keys
- Custom Rules for conditions, operators and actions
- Backtest data and Monitoring