§ 01

One stack, three asset classes.

# forex — ISO 4217 currency pairs
forex_quote(from_currency: str, to_currency: str) -> str
forex_convert(from_currency: str, to_currency: str, amount: float = 1.0) -> str

# crypto — symbol-keyed, exchange-aware via Massive
crypto_snapshot(ticker: str) -> str
crypto_movers(direction: str = "gainers", limit: int = 10) -> str

# indices — the benchmark layer
indices_snapshot(tickers: str) -> str     # ^GSPC, ^DJI, ^IXIC, ^VIX, ...

The asymmetry is deliberate. FX has convert because users actually need to denominate one currency in another (a real workflow — "what's this €120k retainer in USD?"). Crypto has movers because the asset class is dominated by sentiment-driven leaderboards. Indices have only snapshot because they exist to be benchmarks, not to be traded directly.

§ 02

Forex — convert vs. quote.

Two tools that look similar and answer different questions. forex_quote returns the rate ("EUR to USD is 1.0842"). forex_convert applies the rate to an amount and returns the converted value with the rate inlined. Naive wrappers around the same call — but the wording matters. A user who asks "how much is €50,000 in dollars" wants a number, not an exchange-rate fact sheet.

# under the hood: same provider call, different framing
rate   = provider.get_fx_rate(from_currency, to_currency)
result = amount * rate
return format_output(f"{amount} {from_currency} = {result:.2f} {to_currency} (rate {rate:.4f})")
Design note

ISO 4217 codes are non-negotiable. "Yen" is ambiguous (CNY? JPY?); "JPY" is not. The tool rejects unrecognized codes and returns the canonical list, because silent currency mismatches are the kind of bug that ends up in regulatory letters.

§ 03

Crypto — different market, different hours, different metric set.

Crypto markets do not close. There is no "previous close" the way there is for equities — there is the price 24 hours ago. Volatility is annualized by √365, not √252, because the asset class trades every day. Volume figures are exchange-fragmented; a single canonical "BTC volume" requires aggregating across spot exchanges, and providers disagree on which exchanges count.

# crypto-specific defaults
TRADING_DAYS_PER_YEAR = 365            # equities use 252
RETURN_BASIS          = "24h"           # equities use "previous close"
VOLUME_AGGREGATION    = "exchange_weighted"

crypto_movers returns the top gainers or losers over the last 24 hours. Useful as a sentiment scan, dangerous as a trading signal — leaderboards are dominated by low-cap names with thin liquidity, and the move you see at 9 AM is rarely the move you can transact at 9:01.

§ 04

Indices — the benchmark layer.

Indices exist to be the denominator. Beta is computed against ^GSPC; sector rotation is read against ^IXIC vs. ^DJI; risk-on/risk-off is read against ^VIX. indices_snapshot returns the level, the day's change, and the year-to-date — three numbers that frame everything else on the screen.

SymbolIndexUse
^GSPCS&P 500The default beta benchmark. Large-cap US equity.
^DJIDow Jones Industrial30 names, price-weighted. Cyclical proxy.
^IXICNASDAQ CompositeTech-heavy. Use for sector decomposition.
^RUTRussell 2000Small-cap. Liquidity and credit signal.
^VIXCBOE Volatility30-day implied vol on S&P options. Fear gauge.
§ 05

Cross-asset correlation in stress.

The reason this page exists as a single category, not three: correlations regime-shift in stress. In calm markets, BTC and ^GSPC have low correlation. In a March-2020-style flight-to-cash, every asset class correlates to 1 against the dollar. A risk system that treats stocks, crypto, and FX in separate silos misses that, structurally.

"Diversification is a property of the regime, not of the portfolio. The portfolio you held does not know it stopped being diversified."

The toolset exposes the data needed to see the shift — pull crypto and equity index returns through the same correlation_map, and the regime change is visible. Acting on it is still the analyst's job.

§ 06

What this page is not.