Files
worldmonitor/docs/api/EconomicService.openapi.yaml
Elie Habib a8f8c0aa61 feat(economic): Middle East grocery basket price index (#1904)
* feat(economic): add ME grocery basket price index

Adds a grocery basket price comparison panel for 9 Middle East
countries (UAE, KSA, Qatar, Kuwait, Bahrain, Oman, Egypt, Jordan,
Lebanon) using EXA AI to discover prices from regional e-commerce
sites (Carrefour, Lulu, Noon, Amazon) and Yahoo Finance for FX rates.

- proto: ListGroceryBasketPrices RPC with CountryBasket/GroceryItemPrice messages
- seed: seed-grocery-basket.mjs, 90 EXA calls/run, 150ms delay, hardcoded
  FX fallbacks for pegged GCC currencies, 6h TTL
- handler: seed-only RPC reading economic:grocery-basket:v1
- gateway: static cache tier for the new route
- bootstrap/health: groceryBasket key in SLOW tier, 720min stale threshold
- frontend: GroceryBasketPanel with scrollable table, cheapest/priciest
  column highlighting, styles moved to panels.css
- panel disabled by default until seed is run on Railway

* fix(generated): restore @ts-nocheck in economic service codegen

* fix(grocery-basket): tighten seed health staleness and seed script robustness

- Set maxStaleMin to 360 (6h) matching CACHE_TTL so health alerts on first missed run
- Use ?? over || for FX fallback to handle 0-value rates correctly
- Add labeled regex patterns with bare-number warning in extractPrice
- Replace conditional delay logic with unconditional per-item sleep

* fix(grocery-basket): fix EXA API format and price extraction after live validation

- Use contents.summary format (not top-level summary) — previous format returned no data
- Support EXA_API_KEYS (comma-separated) in addition to EXA_API_KEY
- Extract price from plain-text summary string (EXA returns text, not JSON schema)
- Remove bare-number fallback — too noisy (matched "500" from "pasta 500g" as SAR 500)
- Fix LBP FX rate zero-guard: use fallback when Yahoo returns 0 for ultra-low-value currencies
Validated locally: 9 countries seeded, Redis write confirmed, ~111s runtime

* fix(grocery-basket): validate extracted currency against expected country currency

- matchPrice now returns the currency code alongside the price
- extractPrice rejects results where currency != expected country currency
  (prevents AED prices from being treated as JOD prices on gcc.luluhypermarket.com)
- Tighten item queries (white granulated sugar, spaghetti pasta, etc.) to reduce
  irrelevant product matches like Stevia on sugar queries
- Replace Jordan's gcc.luluhypermarket.com (GCC-only) with carrefour.jo + ounasdelivery.com
- Sync scripts/shared/grocery-basket.json

* feat(bigmac): add Big Mac Index seed + drop grocery basket includeDomains

Grocery basket:
- Remove includeDomains restriction — EXA neural search finds better sources
  than hardcoded domain lists; currency validation prevents contamination
- Tighten query strings (supermarket retail price suffix)

Big Mac seed (scripts/seed-bigmac.mjs):
- Two-tier search: specialist sites (theburgerindex.com, eatmyindex.com) first,
  fall back to open search for countries without per-country indexed pages
- Handle thousands-separator prices (480,000 LBP)
- Accept USD prices from cost-of-living index sites as fallback
- Exclude ranking/average pages (Numbeo country_price_rankings, Expatistan)
- Validated live: 7/9 countries with confirmed prices
  UAE=19AED, KSA=19SAR, QAR=22QAR, KWD=1.4KWD, EGP=135EGP, JOD=3JOD, LBP=480kLBP

* feat(economic): expand grocery basket to 24 global countries, drop Big Mac tier-2 search

Grocery basket: extend coverage from 9 MENA to 24 countries across all
regions (US, UK, DE, FR, JP, CN, IN, AU, CA, BR, MX, ZA, TR, NG, KR,
SG, PK, AE, SA, EG, KE, AR, ID, PH). Add FX fallbacks and fxSymbols
for all 23 new currencies. CCY regex in seed script updated to match
all supported currency codes.

Big Mac: remove tier-2 open search (too noisy, non-specialist pages
report combo prices or global averages). Specialist sites only
(theburgerindex.com, eatmyindex.com) for clean per-country data.

* feat(bigmac): wire Big Mac Index RPC, proto, bootstrap, health

Add ListBigMacPrices RPC end-to-end:
- proto/list_bigmac_prices.proto: BigMacCountryPrice + request/response
- service.proto: register ListBigMacPrices endpoint (GET /list-bigmac-prices)
- buf generate: regenerate service_server.ts + all client stubs
- server/list-bigmac-prices.ts: seed-only handler reads economic:bigmac:v1
- handler.ts: wire listBigMacPrices into EconomicServiceHandler
- api/bootstrap.js: bigmac key in BOOTSTRAP_CACHE_KEYS + SLOW_KEYS
- api/health.js: bigmac key in BOOTSTRAP_KEYS + SEED_META (maxStaleMin: 1440)
- _bootstrap-cache-key-refs.ts: groceryBasket + bigmac refs

* feat(bigmac): add BigMacPanel + register in panel layout

BigMacPanel renders a country-by-country Big Mac price table sorted by
USD price (cheapest/most expensive highlighted). Wired into bootstrap
hydration, refresh scheduler, and panel registry. Registered in
panels.ts (enabled: false, to be flipped once seed data is verified).

Also updates grocery basket i18n from ME-specific to global wording.

* fix(bigmac): register bigmac in cache-keys and RPC_CACHE_TIER

Add bigmac to BOOTSTRAP_CACHE_KEYS and BOOTSTRAP_TIERS in
server/_shared/cache-keys.ts, and to RPC_CACHE_TIER (static tier)
in gateway.ts. Both were caught by bootstrap and RPC tier parity tests.

* fix(generated): restore @ts-nocheck in all generated service files after buf regenerate

buf generate does not emit @ts-nocheck. Previous convention restores it
manually post-generate to suppress strict type errors in generated code.

* fix(grocery-basket): restore includeDomains per country, add userLocation, fix currency symbol parsing

Root cause of 0-item countries (UK, JP, IN, NG): removing includeDomains
caused EXA neural search to return USD-priced global comparison pages
(Numbeo, Tridge, Expatistan) which currency validation correctly rejected.

Fixes:
- Add per-country sites[] in grocery-basket.json (researched local
  supermarket/retailer domains: tesco.com, kaufland.de, bigbasket.com, etc.)
- Pass includeDomains: country.sites to restrict EXA to local retailers
- Pass userLocation: country.code (ISO) to bias results to target country
- Add currency symbol fallback regex (£→GBP, €→EUR, ¥→JPY, ₹→INR,
  ₩→KRW, ₦→NGN, R$→BRL) — sites like BigBasket use ₹ not INR
- Summary query now explicitly requests ISO currency code
- Simplify item queries (drop country name — context from domains)

Smoke test results:
  UK sugar → GBP 1.09 (tesco.com) ✓
  IN rice  → ₹66 (bigbasket.com) ✓
  JP rice  → JPY 500 (kakaku.com) ✓

* fix(grocery-basket): add Firecrawl fallback, parallel items, bulk caps, currency floors

- Add Firecrawl as JS-SPA fallback after EXA (handles noon.com, coupang, daraz, tokopedia, lazada)
- Parallelize item fetching per country with 200ms stagger: runtime 38min to ~4.5min
- Add CURRENCY_MIN floors (NGN:50, IDR:500, KRW:1000, etc.) to reject product codes as prices
- Add ITEM_USD_MAX bulk caps (sugar:8USD, salt:5USD, rice:6USD, etc.) applied to both EXA and Firecrawl
- Fix SA: use noon.com/saudi-en + carrefour.com.sa (removes luluhypermarket cross-country pollution)
- Fix EG: use carrefouregypt.com + spinneys.com.eg + seoudi.com (removes GCC luluhypermarket)
- Expand sites for DE, MX, ZA, TR, NG, KR, IN, PK, AR, ID, PH to improve coverage
- Sync scripts/shared/grocery-basket.json with shared/grocery-basket.json

* fix(grocery-basket): address PR review comments P1+P2

P1 - fix ranking with incomplete data:
  only include countries with >=70% item coverage (>=7/10) in
  cheapest/mostExpensive ranking — prevents a country with 4/10
  items appearing cheapest due to missing data

P1 - fix regex false-match on pack sizes / weights:
  try currency-first pattern (SAR 8.99) before number-first to
  avoid matching pack counts; use matchAll and take last match

P2 - mark seed-miss responses as non-cacheable:
  add upstream_unavailable to proto + return true on empty seed
  so gateway sets Cache-Control: no-store on cold deploy

* fix(generated): update EconomicService OpenAPI docs for upstream_unavailable field
2026-03-20 16:51:35 +04:00

1120 lines
44 KiB
YAML

openapi: 3.1.0
info:
title: EconomicService API
version: 1.0.0
paths:
/api/economic/v1/get-fred-series:
get:
tags:
- EconomicService
summary: GetFredSeries
description: GetFredSeries retrieves time series data from the Federal Reserve Economic Data.
operationId: GetFredSeries
parameters:
- name: series_id
in: query
description: FRED series ID (e.g., "GDP", "UNRATE", "CPIAUCSL").
required: false
schema:
type: string
- name: limit
in: query
description: Maximum number of observations to return. Defaults to 120.
required: false
schema:
type: integer
format: int32
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetFredSeriesResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/list-world-bank-indicators:
get:
tags:
- EconomicService
summary: ListWorldBankIndicators
description: ListWorldBankIndicators retrieves development indicator data from the World Bank.
operationId: ListWorldBankIndicators
parameters:
- name: indicator_code
in: query
description: World Bank indicator code (e.g., "NY.GDP.MKTP.CD").
required: false
schema:
type: string
- name: country_code
in: query
description: Optional country filter (ISO 3166-1 alpha-2).
required: false
schema:
type: string
- name: year
in: query
description: Optional year filter. Defaults to latest available.
required: false
schema:
type: integer
format: int32
- name: page_size
in: query
description: Maximum items per page.
required: false
schema:
type: integer
format: int32
- name: cursor
in: query
description: Cursor for next page.
required: false
schema:
type: string
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListWorldBankIndicatorsResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/get-energy-prices:
get:
tags:
- EconomicService
summary: GetEnergyPrices
description: GetEnergyPrices retrieves current energy commodity prices from EIA.
operationId: GetEnergyPrices
parameters:
- name: commodities
in: query
description: Optional commodity filter. Empty returns all tracked commodities.
required: false
schema:
type: string
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetEnergyPricesResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/get-macro-signals:
get:
tags:
- EconomicService
summary: GetMacroSignals
description: GetMacroSignals computes 7 macro signals from 6 upstream sources with BUY/CASH verdict.
operationId: GetMacroSignals
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetMacroSignalsResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/get-energy-capacity:
get:
tags:
- EconomicService
summary: GetEnergyCapacity
description: GetEnergyCapacity retrieves installed capacity data (solar, wind, coal) from EIA.
operationId: GetEnergyCapacity
parameters:
- name: energy_sources
in: query
description: |-
Energy source codes to query (e.g., "SUN", "WND", "COL").
Empty returns all tracked sources (SUN, WND, COL).
required: false
schema:
type: string
- name: years
in: query
description: Number of years of historical data. Default 20 if not set.
required: false
schema:
type: integer
format: int32
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetEnergyCapacityResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/get-bis-policy-rates:
get:
tags:
- EconomicService
summary: GetBisPolicyRates
description: GetBisPolicyRates retrieves central bank policy rates from BIS.
operationId: GetBisPolicyRates
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetBisPolicyRatesResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/get-bis-exchange-rates:
get:
tags:
- EconomicService
summary: GetBisExchangeRates
description: GetBisExchangeRates retrieves effective exchange rates from BIS.
operationId: GetBisExchangeRates
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetBisExchangeRatesResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/get-bis-credit:
get:
tags:
- EconomicService
summary: GetBisCredit
description: GetBisCredit retrieves credit-to-GDP ratio data from BIS.
operationId: GetBisCredit
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetBisCreditResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/get-fred-series-batch:
post:
tags:
- EconomicService
summary: GetFredSeriesBatch
description: GetFredSeriesBatch retrieves multiple FRED series in a single call.
operationId: GetFredSeriesBatch
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/GetFredSeriesBatchRequest'
required: true
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetFredSeriesBatchResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/list-grocery-basket-prices:
get:
tags:
- EconomicService
summary: ListGroceryBasketPrices
description: ListGroceryBasketPrices retrieves grocery basket price comparison across 24 countries worldwide.
operationId: ListGroceryBasketPrices
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListGroceryBasketPricesResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/list-bigmac-prices:
get:
tags:
- EconomicService
summary: ListBigMacPrices
description: ListBigMacPrices retrieves Big Mac Index prices across Middle East countries.
operationId: ListBigMacPrices
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/ListBigMacPricesResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/api/economic/v1/get-national-debt:
get:
tags:
- EconomicService
summary: GetNationalDebt
description: GetNationalDebt retrieves national debt clock data for all countries.
operationId: GetNationalDebt
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/GetNationalDebtResponse'
"400":
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
default:
description: Error response
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Error:
type: object
properties:
message:
type: string
description: Error message (e.g., 'user not found', 'database connection failed')
description: Error is returned when a handler encounters an error. It contains a simple error message that the developer can customize.
FieldViolation:
type: object
properties:
field:
type: string
description: The field path that failed validation (e.g., 'user.email' for nested fields). For header validation, this will be the header name (e.g., 'X-API-Key')
description:
type: string
description: Human-readable description of the validation violation (e.g., 'must be a valid email address', 'required field missing')
required:
- field
- description
description: FieldViolation describes a single validation error for a specific field.
ValidationError:
type: object
properties:
violations:
type: array
items:
$ref: '#/components/schemas/FieldViolation'
description: List of validation violations
required:
- violations
description: ValidationError is returned when request validation fails. It contains a list of field violations describing what went wrong.
GetFredSeriesRequest:
type: object
properties:
seriesId:
type: string
minLength: 1
description: FRED series ID (e.g., "GDP", "UNRATE", "CPIAUCSL").
limit:
type: integer
format: int32
description: Maximum number of observations to return. Defaults to 120.
required:
- seriesId
description: GetFredSeriesRequest specifies which FRED series to retrieve.
GetFredSeriesResponse:
type: object
properties:
series:
$ref: '#/components/schemas/FredSeries'
description: GetFredSeriesResponse contains the requested FRED series data.
FredSeries:
type: object
properties:
seriesId:
type: string
minLength: 1
description: Series identifier (e.g., "GDP", "UNRATE", "CPIAUCSL").
title:
type: string
description: Series title.
units:
type: string
description: Unit of measurement.
frequency:
type: string
description: Data frequency (e.g., "Monthly", "Quarterly").
observations:
type: array
items:
$ref: '#/components/schemas/FredObservation'
required:
- seriesId
description: FredSeries represents a FRED time series with metadata.
FredObservation:
type: object
properties:
date:
type: string
description: Observation date as YYYY-MM-DD string.
value:
type: number
format: double
description: Observation value.
description: FredObservation represents a single data point from a FRED economic series.
ListWorldBankIndicatorsRequest:
type: object
properties:
indicatorCode:
type: string
minLength: 1
description: World Bank indicator code (e.g., "NY.GDP.MKTP.CD").
countryCode:
type: string
description: Optional country filter (ISO 3166-1 alpha-2).
year:
type: integer
format: int32
description: Optional year filter. Defaults to latest available.
pageSize:
type: integer
format: int32
description: Maximum items per page.
cursor:
type: string
description: Cursor for next page.
required:
- indicatorCode
description: ListWorldBankIndicatorsRequest specifies filters for retrieving World Bank data.
ListWorldBankIndicatorsResponse:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/WorldBankCountryData'
pagination:
$ref: '#/components/schemas/PaginationResponse'
description: ListWorldBankIndicatorsResponse contains World Bank indicator data.
WorldBankCountryData:
type: object
properties:
countryCode:
type: string
minLength: 1
description: ISO 3166-1 alpha-2 country code.
countryName:
type: string
description: Country name.
indicatorCode:
type: string
minLength: 1
description: World Bank indicator code (e.g., "NY.GDP.MKTP.CD").
indicatorName:
type: string
description: Indicator name.
year:
type: integer
format: int32
description: Data year.
value:
type: number
format: double
description: Indicator value.
required:
- countryCode
- indicatorCode
description: WorldBankCountryData represents a World Bank indicator value for a country.
PaginationResponse:
type: object
properties:
nextCursor:
type: string
description: Cursor for fetching the next page. Empty string indicates no more pages.
totalCount:
type: integer
format: int32
description: Total count of items matching the query, if known. Zero if the total is unknown.
description: PaginationResponse contains pagination metadata returned alongside list results.
GetEnergyPricesRequest:
type: object
properties:
commodities:
type: array
items:
type: string
description: Optional commodity filter. Empty returns all tracked commodities.
description: GetEnergyPricesRequest specifies which energy commodities to retrieve.
GetEnergyPricesResponse:
type: object
properties:
prices:
type: array
items:
$ref: '#/components/schemas/EnergyPrice'
description: GetEnergyPricesResponse contains energy price data.
EnergyPrice:
type: object
properties:
commodity:
type: string
minLength: 1
description: Energy commodity identifier.
name:
type: string
description: Human-readable name (e.g., "WTI Crude Oil", "Henry Hub Natural Gas").
price:
type: number
format: double
description: Current price in USD.
unit:
type: string
description: Unit of measurement (e.g., "$/barrel", "$/MMBtu").
change:
type: number
format: double
description: Percentage change from previous period.
priceAt:
type: integer
format: int64
description: 'Price date, as Unix epoch milliseconds.. Warning: Values > 2^53 may lose precision in JavaScript'
required:
- commodity
description: EnergyPrice represents a current energy commodity price from EIA.
GetMacroSignalsRequest:
type: object
description: GetMacroSignalsRequest requests the current macro signal dashboard.
GetMacroSignalsResponse:
type: object
properties:
timestamp:
type: string
description: ISO 8601 timestamp of computation.
verdict:
type: string
description: 'Overall verdict: "BUY", "CASH", or "UNKNOWN".'
bullishCount:
type: integer
format: int32
description: Number of bullish signals.
totalCount:
type: integer
format: int32
description: Total number of evaluated signals (excluding UNKNOWN).
signals:
$ref: '#/components/schemas/MacroSignals'
meta:
$ref: '#/components/schemas/MacroMeta'
unavailable:
type: boolean
description: True when upstream data is unavailable (fallback result).
description: GetMacroSignalsResponse contains the full macro signal dashboard with 7 signals and verdict.
MacroSignals:
type: object
properties:
liquidity:
$ref: '#/components/schemas/LiquiditySignal'
flowStructure:
$ref: '#/components/schemas/FlowStructureSignal'
macroRegime:
$ref: '#/components/schemas/MacroRegimeSignal'
technicalTrend:
$ref: '#/components/schemas/TechnicalTrendSignal'
hashRate:
$ref: '#/components/schemas/HashRateSignal'
priceMomentum:
$ref: '#/components/schemas/PriceMomentumSignal'
fearGreed:
$ref: '#/components/schemas/FearGreedSignal'
description: MacroSignals contains all 7 individual signal computations.
LiquiditySignal:
type: object
properties:
status:
type: string
description: '"SQUEEZE", "NORMAL", or "UNKNOWN".'
value:
type: number
format: double
description: JPY 30d ROC percentage, absent if unavailable.
sparkline:
type: array
items:
type: number
format: double
description: Last 30 JPY close prices.
description: LiquiditySignal tracks JPY 30d rate of change as a liquidity proxy.
FlowStructureSignal:
type: object
properties:
status:
type: string
description: '"PASSIVE GAP", "ALIGNED", or "UNKNOWN".'
btcReturn5:
type: number
format: double
description: BTC 5-day return percentage.
qqqReturn5:
type: number
format: double
description: QQQ 5-day return percentage.
description: FlowStructureSignal compares BTC vs QQQ 5-day returns.
MacroRegimeSignal:
type: object
properties:
status:
type: string
description: '"RISK-ON", "DEFENSIVE", or "UNKNOWN".'
qqqRoc20:
type: number
format: double
description: QQQ 20d ROC percentage.
xlpRoc20:
type: number
format: double
description: XLP 20d ROC percentage.
description: MacroRegimeSignal compares QQQ vs XLP 20-day rate of change.
TechnicalTrendSignal:
type: object
properties:
status:
type: string
description: '"BULLISH", "BEARISH", "NEUTRAL", or "UNKNOWN".'
btcPrice:
type: number
format: double
description: Current BTC price.
sma50:
type: number
format: double
description: 50-day simple moving average.
sma200:
type: number
format: double
description: 200-day simple moving average.
vwap30d:
type: number
format: double
description: 30-day volume-weighted average price.
mayerMultiple:
type: number
format: double
description: Mayer multiple (BTC price / SMA200).
sparkline:
type: array
items:
type: number
format: double
description: Last 30 BTC close prices.
description: TechnicalTrendSignal evaluates BTC price vs moving averages and VWAP.
HashRateSignal:
type: object
properties:
status:
type: string
description: '"GROWING", "DECLINING", "STABLE", or "UNKNOWN".'
change30d:
type: number
format: double
description: Hash rate change over 30 days as percentage.
description: HashRateSignal tracks Bitcoin hash rate momentum.
PriceMomentumSignal:
type: object
properties:
status:
type: string
description: '"STRONG", "MODERATE", "WEAK", or "UNKNOWN".'
description: PriceMomentumSignal uses the Mayer Multiple (price/SMA200) as a market-adaptive signal.
FearGreedSignal:
type: object
properties:
status:
type: string
description: Classification label (e.g., "Extreme Fear", "Greed").
value:
type: integer
format: int32
description: Current index value (0-100).
history:
type: array
items:
$ref: '#/components/schemas/FearGreedHistoryEntry'
description: FearGreedSignal tracks the Crypto Fear & Greed index.
FearGreedHistoryEntry:
type: object
properties:
value:
type: integer
maximum: 100
minimum: 0
format: int32
description: Index value (0-100).
date:
type: string
description: Date string (YYYY-MM-DD).
description: FearGreedHistoryEntry is a single day's Fear & Greed index reading.
MacroMeta:
type: object
properties:
qqqSparkline:
type: array
items:
type: number
format: double
description: Last 30 QQQ close prices for sparkline.
description: MacroMeta contains supplementary chart data.
GetEnergyCapacityRequest:
type: object
properties:
energySources:
type: array
items:
type: string
description: |-
Energy source codes to query (e.g., "SUN", "WND", "COL").
Empty returns all tracked sources (SUN, WND, COL).
years:
type: integer
format: int32
description: Number of years of historical data. Default 20 if not set.
GetEnergyCapacityResponse:
type: object
properties:
series:
type: array
items:
$ref: '#/components/schemas/EnergyCapacitySeries'
EnergyCapacitySeries:
type: object
properties:
energySource:
type: string
name:
type: string
data:
type: array
items:
$ref: '#/components/schemas/EnergyCapacityYear'
EnergyCapacityYear:
type: object
properties:
year:
type: integer
format: int32
capacityMw:
type: number
format: double
GetBisPolicyRatesRequest:
type: object
description: GetBisPolicyRatesRequest requests central bank policy rates.
GetBisPolicyRatesResponse:
type: object
properties:
rates:
type: array
items:
$ref: '#/components/schemas/BisPolicyRate'
description: GetBisPolicyRatesResponse contains BIS policy rate data.
BisPolicyRate:
type: object
properties:
countryCode:
type: string
description: ISO 2-letter country code (US, GB, JP, etc.)
countryName:
type: string
description: Country or region name.
rate:
type: number
format: double
description: Current policy rate percentage.
previousRate:
type: number
format: double
description: Previous period rate percentage.
date:
type: string
description: Date as YYYY-MM.
centralBank:
type: string
description: Central bank name (e.g. "Federal Reserve").
description: BisPolicyRate represents a central bank policy rate from BIS.
GetBisExchangeRatesRequest:
type: object
description: GetBisExchangeRatesRequest requests effective exchange rates.
GetBisExchangeRatesResponse:
type: object
properties:
rates:
type: array
items:
$ref: '#/components/schemas/BisExchangeRate'
description: GetBisExchangeRatesResponse contains BIS effective exchange rate data.
BisExchangeRate:
type: object
properties:
countryCode:
type: string
description: ISO 2-letter country code.
countryName:
type: string
description: Country or region name.
realEer:
type: number
format: double
description: Real effective exchange rate index.
nominalEer:
type: number
format: double
description: Nominal effective exchange rate index.
realChange:
type: number
format: double
description: Percentage change from previous period (real).
date:
type: string
description: Date as YYYY-MM.
description: BisExchangeRate represents effective exchange rate indices from BIS.
GetBisCreditRequest:
type: object
description: GetBisCreditRequest requests credit-to-GDP ratio data.
GetBisCreditResponse:
type: object
properties:
entries:
type: array
items:
$ref: '#/components/schemas/BisCreditToGdp'
description: GetBisCreditResponse contains BIS credit-to-GDP data.
BisCreditToGdp:
type: object
properties:
countryCode:
type: string
description: ISO 2-letter country code.
countryName:
type: string
description: Country or region name.
creditGdpRatio:
type: number
format: double
description: Total credit as percentage of GDP.
previousRatio:
type: number
format: double
description: Previous quarter ratio.
date:
type: string
description: Date as YYYY-QN.
description: BisCreditToGdp represents total credit as percentage of GDP from BIS.
GetFredSeriesBatchRequest:
type: object
properties:
seriesIds:
type: array
items:
type: string
maxItems: 10
minItems: 1
description: FRED series IDs (e.g., "WALCL", "FEDFUNDS"). Max 10.
maxItems: 10
minItems: 1
limit:
type: integer
format: int32
description: Maximum number of observations per series. Defaults to 120.
description: GetFredSeriesBatchRequest looks up multiple FRED series in a single call.
GetFredSeriesBatchResponse:
type: object
properties:
results:
type: object
additionalProperties:
$ref: '#/components/schemas/FredSeries'
description: Map of series_id -> FRED series for found series.
fetched:
type: integer
format: int32
description: Number of series successfully fetched.
requested:
type: integer
format: int32
description: Number of series requested.
description: GetFredSeriesBatchResponse contains the requested FRED series data.
ResultsEntry:
type: object
properties:
key:
type: string
value:
$ref: '#/components/schemas/FredSeries'
ListGroceryBasketPricesRequest:
type: object
ListGroceryBasketPricesResponse:
type: object
properties:
countries:
type: array
items:
$ref: '#/components/schemas/CountryBasket'
fetchedAt:
type: string
cheapestCountry:
type: string
mostExpensiveCountry:
type: string
upstreamUnavailable:
type: boolean
CountryBasket:
type: object
properties:
code:
type: string
name:
type: string
currency:
type: string
flag:
type: string
totalUsd:
type: number
format: double
fxRate:
type: number
format: double
items:
type: array
items:
$ref: '#/components/schemas/GroceryItemPrice'
GroceryItemPrice:
type: object
properties:
itemId:
type: string
itemName:
type: string
unit:
type: string
localPrice:
type: number
format: double
usdPrice:
type: number
format: double
currency:
type: string
sourceSite:
type: string
available:
type: boolean
ListBigMacPricesRequest:
type: object
ListBigMacPricesResponse:
type: object
properties:
countries:
type: array
items:
$ref: '#/components/schemas/BigMacCountryPrice'
fetchedAt:
type: string
cheapestCountry:
type: string
mostExpensiveCountry:
type: string
BigMacCountryPrice:
type: object
properties:
code:
type: string
name:
type: string
currency:
type: string
flag:
type: string
localPrice:
type: number
format: double
usdPrice:
type: number
format: double
fxRate:
type: number
format: double
sourceSite:
type: string
available:
type: boolean
GetNationalDebtRequest:
type: object
description: GetNationalDebtRequest requests national debt data for all countries.
GetNationalDebtResponse:
type: object
properties:
entries:
type: array
items:
$ref: '#/components/schemas/NationalDebtEntry'
seededAt:
type: string
description: ISO 8601 timestamp when seed data was written.
unavailable:
type: boolean
description: True when upstream data is unavailable (fallback result).
description: GetNationalDebtResponse wraps the full list of national debt entries.
NationalDebtEntry:
type: object
properties:
iso3:
type: string
description: ISO3 country code (e.g. "USA").
debtUsd:
type: number
format: double
description: Total debt in USD at baseline_ts.
gdpUsd:
type: number
format: double
description: GDP in USD (nominal, latest year).
debtToGdp:
type: number
format: double
description: Debt as % of GDP.
annualGrowth:
type: number
format: double
description: Year-over-year debt growth percent (2023->2024).
perSecondRate:
type: number
format: double
description: Deficit-derived accrual in USD per second.
perDayRate:
type: number
format: double
description: Deficit-derived accrual in USD per day.
baselineTs:
type: string
format: int64
description: UTC ms timestamp anchoring the debt_usd figure (2024-01-01T00:00:00Z).
source:
type: string
description: Human-readable source string.
description: NationalDebtEntry holds debt data for a single country.