Analyzing CBOE 1-Year VIX (VIX1Y) Price Trends Over the last 24 hours with Indices-API Time-Series Data
Your task: chart and quantify how the CBOE 1-Year VIX (VIX1Y) moved over the last 24 hours, then compute a simple period return and max drawdown you can wire into a dashboard or alert. By the end of this walkthrough you will query a daily time series window for VIX1Y using Indices-API, understand how to interpret the base currency and rate pairs you receive, and produce metrics that can backfill charts or trigger notifications in production.
The analysis goal and what “last 24 hours” means for VIX1Y
“Last 24 hours” typically means comparing the most recent completed trading day to the prior one. Indices-API’s time-series data is daily; weekend and holiday gaps will appear as missing dates. To analyze the last 24 hours for VIX1Y:
- Pick the most recent completed calendar date that is not “today” (end_date cannot be today).
- Pull a 1–2 day daily window that includes that date and the previous business day.
- Compute close-to-close return and max drawdown from those points (or from a longer recent window if you want intraperiod drawdowns across multiple days).
If you are unsure about the exact symbol code, confirm it on the Indices-API Supported Symbols page. For this article we use VIX1Y for the CBOE 1-Year VIX.
Querying the time-series window for VIX1Y
For a last-24-hours comparison, query the /timeseries endpoint for VIX1Y with start_date set to the prior business day and end_date set to the most recent completed date (not today). The time-series endpoint returns a daily dictionary keyed by date with rate values relative to the base currency (USD by default). The response nests rates under dates, and each date contains a map of symbols to rates.
Note: If your chosen dates include a weekend or holiday, the response will simply omit those non-trading dates. Always validate that your start and end dates yield at least two trading days if you want a return.
Endpoint behavior in this workflow
- Timeseries endpoint: daily historical values between start_date and end_date for VIX1Y, suitable for calculating period returns and drawdowns.
- Latest endpoint: a single snapshot of the most recently available rates; useful as a reference for the current session or to confirm symbol mappings and units before pulling a time series.
For all endpoints, authentication is via the access_key query parameter. See the Indices-API Documentation for request parameters, date formats, and response fields.
Official sample response: interpreting base, date, and rates for VIX1Y
Below is an official sample JSON response for VIX1Y to illustrate field naming and units. You will use the same fields when processing time-series responses (success, timestamp, base, date, and rates):
{"data":{"success":true,"timestamp":1792543200,"date":"2026-10-21","base":"USD","rates":{"VIX1Y":0.045351473922902,"USD":1,"USDVIX1Y":22.05000000000024}}}
What to read from this:
- success: Indicates the API processed the request successfully.
- timestamp: Unix epoch for the data snapshot (UTC). Use this for cache keys and to align data across services.
- date: The calendar date for this snapshot (daily granularity).
- base: USD. Indices-API quotes are relative to USD by default.
- rates: A map of symbol pairs to numeric values. For indices, you will typically use the index symbol keyed directly under rates. Here:
- VIX1Y: The “USD per index unit” quote for the 1-Year VIX measure.
- USD: The base currency rate is 1 by definition.
- USDVIX1Y: The inverse pair. Interpreting both VIX1Y and USDVIX1Y is helpful when you need the reciprocal for conversions or cross-rate logic.
Important: Because base is USD, rates["VIX1Y"] means the price of one VIX1Y unit in USD terms. If you need the reverse (how many VIX1Y units per USD), use rates["USDVIX1Y"] or invert the VIX1Y rate.
Python: compute last-24h return and max drawdown from a VIX1Y time series
The snippet below requests a daily time-series window for VIX1Y, extracts close values in chronological order, then computes:
- Simple period return: last_close / first_close - 1
- Max drawdown across the window: the worst peak-to-trough decline
Choose start_date and end_date so that end_date is the most recent completed calendar date (not today). If the prior day was a non-trading day, extend start_date backward until you obtain at least two data points.
import os
import sys
import requests
from datetime import date, timedelta
ACCESS_KEY = os.getenv("INDICES_API_KEY", "YOUR_API_KEY")
def last_completed_date_utc():
# End date cannot be today. Use yesterday by default.
return (date.today() - timedelta(days=1)).isoformat()
def compute_return_and_mdd(values):
# values: list of floats in chronological order
if not values or len(values) < 2:
return None, None
start = values[0]
end = values[-1]
period_return = (end / start) - 1.0
peak = values[0]
mdd = 0.0
for v in values:
if v > peak:
peak = v
drawdown = (v / peak) - 1.0
if drawdown < mdd:
mdd = drawdown
return period_return, mdd
def fetch_timeseries_vix1y(access_key, start_date, end_date):
# Build your /timeseries request (see API docs for full parameter set)
# Ensure the same base (USD) across requests for consistent comparisons.
params = {
"access_key": access_key,
"start_date": start_date,
"end_date": end_date,
"symbols": "VIX1Y",
"base": "USD"
}
# Replace with the documented timeseries endpoint URL.
# Refer to: Indices-API Documentation for the correct base URL and path.
url = "REPLACE_WITH_TIMESERIES_ENDPOINT_URL"
r = requests.get(url, params=params, timeout=30)
r.raise_for_status()
payload = r.json()
# Expected shape (conceptual):
# {
# "success": true,
# "timeseries": true,
# "start_date": "...",
# "end_date": "...",
# "base": "USD",
# "rates": {
# "YYYY-MM-DD": {"VIX1Y": <float>},
# ...
# }
# }
if not payload.get("success"):
raise RuntimeError(f"API error: {payload}")
base = payload.get("base", "USD")
if base != "USD":
raise ValueError(f"Unexpected base {base}; set base=USD for consistent math.")
rates_by_date = payload.get("rates", {})
# Sort dates chronologically and extract close values
dates = sorted(rates_by_date.keys())
closes = [rates_by_date[d]["VIX1Y"] for d in dates if "VIX1Y" in rates_by_date[d]]
return dates, closes, payload
if __name__ == "__main__":
end_date = last_completed_date_utc()
# For a 24h comparison, ask for two days ending on end_date.
start_date = (date.fromisoformat(end_date) - timedelta(days=2)).isoformat()
try:
dates, closes, raw = fetch_timeseries_vix1y(ACCESS_KEY, start_date, end_date)
except Exception as e:
print(f"Request failed: {e}", file=sys.stderr)
sys.exit(1)
if len(closes) < 2:
print("Not enough trading days in window; extend start_date backward.")
sys.exit(0)
period_return, mdd = compute_return_and_mdd(closes)
print("Dates:", dates)
print("Closes:", closes)
print("Period return (last 24h):", period_return)
print("Max drawdown over window:", mdd)
Notes:
- Replace REPLACE_WITH_TIMESERIES_ENDPOINT_URL with the documented time-series URL. See Indices-API Documentation.
- The code validates base=USD to keep return math consistent.
- If you receive only one data point (because the prior day was non-trading), extend start_date backward.
- Cache the result keyed by symbol+start_date+end_date+base to avoid repeat requests in your UI loop.
How to use the latest snapshot alongside your time series
When bootstrapping a chart or confirming symbol-direction math, request a latest snapshot, inspect base and rates, and wire those units into your rendering and alert logic. The official sample above shows how VIX1Y and USDVIX1Y appear under rates with base: "USD". If your dashboard wants to display “index points,” use the USD→index orientation consistently. If you need the reciprocal (index units per USD), use the inverse pair (e.g., USDVIX1Y).
Because “latest” is a single date, it cannot itself compute returns without a prior observation. Combine the latest snapshot with your previous close from the time-series window if you want to show “since last close” deltas in the header of a chart.
Operational details that save time
Base currency and units
- Responses are relative to the specified base (USD by default). Keep your base constant across calls when computing returns or drawdowns.
- For VIX1Y, read rates["VIX1Y"] as “USD per index unit.” If present, rates["USDVIX1Y"] is the inverse. Do not mix the two orientations in the same calculation.
Trading days, weekends, and holidays
- Time-series is daily. Non-trading days (weekends/holidays) are not returned.
- If your 24-hour window lands on a Monday (or a holiday), you may need to back up multiple days to get two observations. Always check the count of returned dates before computing returns.
Update frequency and “today” logic
- Latest endpoint updates intra-day depending on plan; treat timestamps as the source of truth when aligning with other feeds.
- Do not use today as end_date. Use the most recent completed calendar date for time-series windows. If you need a near-real-time comparison, pair time-series “previous close” with the latest snapshot.
Caching and idempotence
- Cache time-series responses by (symbol, start_date, end_date, base). They are immutable for completed days.
- For latest snapshots, cache briefly using the timestamp from the payload; invalidate when the timestamp changes.
Error handling and data hygiene
- Always check success before reading fields.
- Validate base. If it’s not USD (or your expected base), re-run with base=USD to keep values comparable.
- Guard against missing dates: don’t assume contiguous daily keys.
- Round as late as possible. Keep raw float precision for metrics and round only for display.
Building a last-24h VIX1Y widget: end-to-end checklist
- Verify the symbol code on Indices-API Supported Symbols (VIX1Y).
- Fetch a time-series window that ends on the last completed calendar date (not today). Aim for 2–5 days to compute return and drawdown robustly.
- Compute:
- Last-24h return (close-to-close): last / prior - 1.
- Max drawdown: min over t of (value_t / running_peak - 1).
- Optionally fetch a latest snapshot to display an intraday tick while your headline metrics still reference the previous close.
- Cache the series by dates and recalc only when the window shifts to a new completed day (or when you unthrottle latest).
Where to find more and get an API key
Review request parameters, response field definitions, and endpoint paths in the Indices-API Documentation. If you haven’t yet, you can create your access_key here: Register. For symbol discovery and validation at build time, bookmark the Symbols directory. For broader platform capabilities, visit MCP.
If you’re new to volatility indices or want additional context around term-structure measures like VIX1Y, consult the CBOE resources and methodology notes: CBOE VIX resources and a primer on the VIX ecosystem on Wikipedia.
FAQ
Q1: What if my time-series response doesn’t include yesterday’s date?
It was likely a non-trading day for the index. Extend start_date backward until you have at least two trading days to compute a return, and ensure end_date is the latest completed calendar date (not today).
Q2: How do I interpret VIX1Y vs USDVIX1Y in the rates map?
With base=USD, rates["VIX1Y"] is USD per VIX1Y unit. rates["USDVIX1Y"] is the inverse. Use a single orientation consistently; do not mix them in the same calculation.
Q3: Can I request intraday candles for VIX1Y?
An intraday endpoint exists for interval-based candles. For this article we focused on daily time-series because the goal is a last-24h (close-to-close) comparison. See the Documentation for supported intervals and parameters.
Q4: What timezone should I assume for timestamps?
The timestamp in responses is Unix epoch in UTC. Use it for caching and alignment across systems. The date field reflects the data’s calendar day; it is not a wall-clock timestamp.
Q5: Why can’t I set end_date to today?
Daily time-series represents completed days. Today’s data may be incomplete or subject to change, so the endpoint requires end_date to be a completed calendar date. Use the latest endpoint if you need a near-real-time view.
Ship your VIX1Y 24-hour chart and analytics today. Get an access_key in minutes at Register, validate the symbol on Symbols, and follow the parameter details in the Documentation to plug the time-series into your dashboard, alerting pipeline, or backtest.