본문으로 건너뛰기미국 세인트루이스 연준의 FRED/ALFRED 에서 거시 시계열을 받아 PostgreSQL 에 쌓은 것이다. 값의 개정 이력을 원천이 준 그대로 보관하는 것이 이 데이터의 특징이다. 그래서 "지금 값" 과 "그때 발표된 값" 을 둘 다 답할 수 있다.
이 문서에 측정값을 적지 않는다. 행 수와 기간과 개체 수는 화면이 1절에 그때 읽어 채우고, 그 밖의 수를 직접 세는 방법은 8절에 있다. 왜 적지 않는지는 docs/structure.md 의 부패할 것을 만들지 않는다 에 있다.
1. 한눈에
1. 한눈에| 원천 | FRED / ALFRED REST API (https://api.stlouisfed.org/fred) |
|---|
| 제공자 | Federal Reserve Bank of St. Louis |
|---|
| 갱신 | 매일 08:00 KST 시작, 마감 08:50 |
|---|
| 보관처 | PostgreSQL, DB 이름 a42_fred |
|---|
| 값 테이블 | fred_observations_latest |
|---|
| 개정 이력 테이블 | fred_observation_vintages |
|---|
| 발표 지연 테이블 | fred_observation_lags |
|---|
| 화면 | /fred |
|---|
데이터셋 목록을 가져오지 못했습니다
데이터 서버에 닿지 못했습니다.
데이터 서버가 꺼져 있을 수 있습니다. 터미널에서 uv run a42-data-view up 으로 켠 뒤 새로고침하세요.
2. 무엇이 들어 있나
무엇을 받을지는 선언 파일 하나가 정한다. 코드에 시리즈 이름이 없다.
2. 무엇이 들어 있나| 정본 | apps/a42_collector/config/fred_series.toml |
|---|
| 한 항목이 가진 값 | series_id 와 group 둘 |
|---|
| 켜고 끄기 | enabled = false 면 수집에서 빠진다 |
|---|
| 고른 기준 | 널리 쓰이는 거시 대시보드 지표. 원천에 실재하는지 하나씩 확인해 넣었다 |
|---|
시리즈 전체 목록은 여기 적지 않는다. 화면(8절)이 그 목록을 제목, 단위, 주기, 기간과 함께 보여주고 그것이 DB 를 직접 읽는다. 이 문서에 목록을 또 적으면 어긋난다.
2.1 분류별
분류는 우리가 붙인 것이다. 선언 파일의 group 이 정본이고, 한글 이름은 frontend/lib/fred-groups.mjs 에 있다.
2.1 분류별| 분류 | 무엇 | 대표 |
|---|
growth | GDP, 소비, 산업생산, 신규주문, 재고 | GDP, GDPC1, INDPRO |
labor | 실업률, 고용, 구인과 이직, 임금 | UNRATE, PAYEMS, ICSA |
treasury | 국채 만기별 수익률과 기간 스프레드 | DGS10, DGS2, T10Y2Y |
inflation | CPI, PCE, PPI, 기대인플레 | CPIAUCSL, PCEPILFE, T10YIE |
risk | 변동성, 신용 스프레드, 금융환경, 대출태도 | VIXCLS, BAMLH0A0HYM2, NFCI |
fx | 주요 통화 환율과 달러지수 | DEXKOUS, DEXUSEU, DTWEXBGS |
money | 통화량, 연준 대차대조표, 지준, 재무부 계정 | M2SL, WALCL, WRESBAL |
housing | 착공, 허가, 거래, 가격, 공실률 | HOUST, PERMIT, CSUSHPISA |
rates | 정책금리, 은행 대출금리, 주택담보대출 | FEDFUNDS, SOFR, MORTGAGE30US |
equity | 주가지수 | SP500, NASDAQCOM, DJIA |
분류별 시리즈 수와 관측 행수를 세는 질의는 8.2 에 있다.
2.2 주기별
주기는 원천이 준 문자열을 그대로 둔다. 우리가 묶으면 넷이다.
2.2 주기별| 묶음 | 원천 문자열 |
|---|
| 월별 | Monthly, Monthly, End of Period |
| 일별 | Daily, Daily, Close, Daily, 7-Day |
| 주별 | Weekly, Ending Friday, Weekly, Ending Saturday, Weekly, Ending Wednesday, Weekly, Ending Thursday, Weekly, As of Wednesday |
| 분기 | Quarterly, Quarterly, End of Period |
시리즈당 관측 행수의 폭이 크다. 주기와 시작 연도가 그것을 정한다. 1950년대 부터 있는 일별 시리즈와 1990년대부터 있는 분기 시리즈가 양 끝이다.
2.3 단위
단위는 환산하지 않는다. 원천이 준 영어 문자열을 그대로 fred_series.units 에 넣는다.
여러 시리즈가 함께 쓰는 것이 있고 (Percent, Millions of Dollars, Index, Billions of Dollars, Index 1982-1984=100) 지표 하나에만 쓰이는 것이 있다 (South Korean Won to One U.S. Dollar, Dollars per Hour, Index 1966:Q1=100, +1 or 0).
단위가 같은 두 시리즈를 한 축에 그려도 되는지는 사람이 판단한다. 문자열이 같은지 보는 것으로는 부족하다.
2.4 시리즈 설명
원천이 붙인 영어 설명이 fred_series_catalog.notes 에 있다.
설명이 없는 시리즈가 있다. 원천이 그 칸을 비워 둔 것이고 우리가 채우지 않는다. 어느 시리즈인지 보는 질의는 8.2 에 있다.
긴 것은 대부분 라이선스 고지다. 지표의 뜻을 아는 데 필요한 문장은 보통 앞쪽에 있다. 7절이 다루는 라이선스 제약의 근거도 이 설명 안에 있다.
3. 어떻게 받아오나
3. 어떻게 받아오나| 원천 | FRED/ALFRED REST API |
|---|
| 인증 | API 키 하나. apps/a42_collector/.env |
|---|
| 요청 단위 | 시리즈 1개 |
|---|
| 시리즈 하나에 부르는 경로 | /series, /series/vintagedates, /series/observations |
|---|
| 받는 범위 | 매 실행이 전체 기간을 다시 받는다. 이어받기가 없다 |
|---|
| 그렇게 하는 이유 | 개정이 과거 값을 바꾼다. 같은 값을 다시 써도 결과가 같은 upsert 다 |
|---|
| 개정 이력 | realtime_start/realtime_end 구간으로 요청. 판 날짜가 많으면 창을 나눈다 |
|---|
| 판 날짜 목록으로 묻지 않는 이유 | 그렇게 물으면 원천이 끝나는 날을 요청한 마지막 판 날짜로 잘라서 준다. 열린 구간이 응답에 없다 (7.2) |
|---|
| 창을 나누는 이유 | 한 구간에 담을 수 있는 판 날짜에 원천 상한 2,000 이 있다. 넘치면 400 이 온다 |
|---|
| 잘린 것을 아는 법 | 응답의 count 가 그 요청의 실제 전체 행수다 |
|---|
| 이어 받기 | count 만큼 받을 때까지 offset 을 민다 |
|---|
| 요청 간격 | 0.6초 |
|---|
| 재시도 | 같은 요청을 최대 4회 시도. 사이에 1초 |
|---|
| 재시도 대상 | HTTP 423, 429, 500, 502, 503, 504 |
|---|
| 개정 이력이 없는 시리즈 | /series/vintagedates 가 400 을 주면 최신값만 받는다 |
|---|
| 전량 재적재 조건 | 없다. 매 실행이 이미 전량이다 |
|---|
3.1 응답 상한이 왜 문제였나
FRED 는 상한을 넘으면 오류를 주지 않는다. 뒤가 잘린 정상 응답을 준다. 정렬이 관측일 오름차순이라 잘리면 가장 오래된 구간이 살고 최근이 통째로 빠진다. 수집은 성공으로 끝난다.
상한에 닿는 것은 시리즈의 크기가 아니라 개정의 성격이다. NFCI 와 STLFSI4 는 개정될 때마다 과거 전 구간이 다시 계산되는 지수라, 관측일 하나에 판이 수백 개씩 쌓인다. DPRIME 이나 DGS3 같은 일별 금리 시리즈는 관측일이 훨씬 많은데도 관측일당 판이 적어서 한 요청이 상한에 닿지 않는다.
4. 어떻게 저장하나
4. 어떻게 저장하나| 저장소 | PostgreSQL |
|---|
| DB 이름 | a42_fred |
|---|
| 스키마 정의 | packages/a42_fred/src/a42_fred/sql/schema.sql |
|---|
| 테이블 | 값 5개, 실행 기록 2개 |
|---|
| 접속값 | apps/a42_collector/.env |
|---|
| 시각 컬럼의 타입 | TIMESTAMPTZ. DB 세션 타임존은 Asia/Seoul |
|---|
| 날짜 컬럼의 타입 | DATE. 타임존이 없다 |
|---|
아래 표의 널 은 스키마가 허용하는지다. 실제로 비어 있는 행이 있는지는 적지 않는다. 그것은 오늘 센 값이다.
4.1 fred_observations_latest - 관측일당 가장 최근 값
보통 읽는 표다. 시리즈-관측일 하나에 행 하나다.
4.1 fred_observations_latest - 관측일당 가장 최근 값 (컬럼, 뜻, 타입, 단위, 널 칸이 있는 표)| 컬럼 | 뜻 | 타입 | 단위 | 널 |
|---|
series_id | FRED 시리즈 코드 | TEXT | | 아니오 |
observation_date | 관측 기간의 시작일. 월간은 그 달 1일, 분기는 그 분기 첫 달 1일 | DATE | | 아니오 |
realtime_start | 이 값이 유효해진 날 | DATE | | 아니오 |
realtime_end | 이 값이 유효한 마지막 날 | DATE | | 아니오 |
value | 관측값 | NUMERIC | fred_series.units | 허용 |
first_seen_at | 이 관측일을 우리가 처음 받은 시각 | TIMESTAMPTZ | | 허용 |
inserted_at | 이 행을 처음 넣은 시각 | TIMESTAMPTZ | | 아니오 |
updated_at | 이 행을 마지막으로 고친 시각 | TIMESTAMPTZ | | 아니오 |
4.1 fred_observations_latest - 관측일당 가장 최근 값 (2번째 표)| 키 | (series_id, observation_date) |
|---|
| 같은 키가 다시 오면 | 값이나 판 날짜가 달라졌을 때 덮는다 |
|---|
| 값이 없는 관측 | 새 행을 만들지 않는다. 값을 받은 적 있는 관측이 폐기되면 그 행의 value 가 NULL 이 된다 (7.2) |
|---|
value 가 NULL 이면 | 원천이 지금 그 관측을 발표하지 않는다는 뜻이다. 값이 없다는 뜻이 아니다 |
|---|
realtime_end 의 실제 값 | 모든 행이 9999-12-31 이다. 가장 늦은 판은 언제나 열린 판이다. 이 칸으로는 아무것도 가려낼 수 없다 |
|---|
| 주의 | 아직 다시 받지 않은 시리즈는 판 날짜 두 칸이 최신 판을 안 가리킬 수 있다. 7.6 을 본다 |
|---|
4.2 fred_observation_vintages - 같은 관측일의 모든 판
"그때 발표된 값" 의 근거다. 시리즈-관측일-유효기간 하나에 행 하나다.
4.2 fred_observation_vintages - 같은 관측일의 모든 판 (컬럼, 뜻, 타입, 단위, 널 칸이 있는 표)| 컬럼 | 뜻 | 타입 | 단위 | 널 |
|---|
series_id | FRED 시리즈 코드 | TEXT | | 아니오 |
observation_date | 관측 기간의 시작일 | DATE | | 아니오 |
realtime_start | 이 판이 유효해진 날 | DATE | | 아니오 |
realtime_end | 이 판이 유효한 마지막 날. 9999-12-31 은 "열려 있다" | DATE | | 아니오 |
value | 그 판의 값. NULL 은 그 기간에 원천이 값을 주지 않았다는 뜻이다 | NUMERIC | fred_series.units | 허용 |
inserted_at | 이 행을 처음 넣은 시각 | TIMESTAMPTZ | | 아니오 |
updated_at | 이 행을 마지막으로 고친 시각 | TIMESTAMPTZ | | 아니오 |
4.2 fred_observation_vintages - 같은 관측일의 모든 판 (2번째 표)| 키 | (series_id, observation_date, realtime_start, realtime_end) |
|---|
| 같은 키가 다시 오면 | 값이 달라졌을 때만 덮는다 |
|---|
| 새 판이 오면 | 새 행이 된다. 옛 행을 지우지 않는다 |
|---|
| 관측일당 판 | 여럿이다. 대부분의 관측이 한 번 이상 개정되고, 판이 하나뿐인 것도 있다 |
|---|
열린 판 (realtime_end = 9999-12-31) | 원천이 준 것이다. 우리가 만들어 넣지 않는다 |
|---|
열린 판의 value 가 NULL 이면 | 폐기 표시다. 원천이 지금 그 관측을 발표하지 않는다 (7.2) |
|---|
| 주의 | 고침 전에 든 옛 행 때문에 한 관측에 열린 판이 둘 이상일 수 있다. 7.5 를 본다 |
|---|
4.3 fred_series - 우리가 무엇을 수집하고 어떤 상태인가
4.3 fred_series - 우리가 무엇을 수집하고 어떤 상태인가 (컬럼, 뜻, 타입, 단위, 널 칸이 있는 표)| 컬럼 | 뜻 | 타입 | 단위 | 널 |
|---|
series_id | FRED 시리즈 코드 | TEXT | | 아니오 |
title | 원천이 붙인 제목 (영어) | TEXT | | 허용 |
units | 원천이 붙인 단위 문자열 (영어) | TEXT | | 허용 |
frequency | 원천이 붙인 주기 문자열 (영어) | TEXT | | 허용 |
observation_start | 원천이 지금 발표하는 첫 관측일 | DATE | | 허용 |
observation_end | 원천이 지금 발표하는 마지막 관측일 | DATE | | 허용 |
last_updated | 원천이 이 시리즈를 마지막으로 고친 시각 | TIMESTAMPTZ | | 허용 |
group_name | 우리가 붙인 분류. 선언 파일의 group | TEXT | | 허용 |
enabled | 수집 대상인가 | BOOLEAN | | 아니오 |
supports_alfred | 개정 이력을 받을 수 있는가. 거짓인 시리즈가 있다 (7.4) | BOOLEAN | | 허용 |
latest_available_observation_date | 우리가 가진 마지막 관측일 | DATE | | 허용 |
latest_initial_release_lag_days | 가장 최근 관측의 첫 발표 지연 | INTEGER | 일 | 허용 |
median_initial_release_lag_days | 첫 발표 지연의 가운뎃값 | INTEGER | 일 | 허용 |
latest_last_revision_lag_days | 가장 최근 관측의 마지막 개정 지연 | INTEGER | 일 | 허용 |
median_last_revision_lag_days | 마지막 개정 지연의 가운뎃값 | INTEGER | 일 | 허용 |
last_successful_sync_at | 이 시리즈를 마지막으로 성공해 받은 시각 | TIMESTAMPTZ | | 허용 |
last_failed_sync_at | 마지막으로 실패한 시각 | TIMESTAMPTZ | | 허용 |
inserted_at | 행을 처음 넣은 시각 | TIMESTAMPTZ | | 아니오 |
updated_at | 행을 마지막으로 고친 시각 | TIMESTAMPTZ | | 아니오 |
4.3 fred_series - 우리가 무엇을 수집하고 어떤 상태인가 (2번째 표)| 키 | series_id |
|---|
observation_start 와 우리 첫 관측일이 다를 수 있다 | 앞엣것은 원천 말이고 뒤엣것은 우리가 가진 것이다. 7.1 과 7.2 를 본다 |
|---|
last_failed_sync_at 이 last_successful_sync_at 보다 최근이면 | 지금 문제인 시리즈다 |
|---|
4.4 fred_series_catalog - FRED 가 그 시리즈를 어떻게 설명하나
시리즈 하나에 행 하나. 수집 상태가 아니라 원천의 설명이 사는 곳이다.
4.4 fred_series_catalog - FRED 가 그 시리즈를 어떻게 설명하나 (컬럼, 뜻, 타입, 단위, 널 칸이 있는 표)| 컬럼 | 뜻 | 타입 | 단위 | 널 |
|---|
series_id | FRED 시리즈 코드 | TEXT | | 아니오 |
title | 원천 제목 | TEXT | | 허용 |
units | 원천 단위 문자열 | TEXT | | 허용 |
frequency | 원천 주기 문자열 | TEXT | | 허용 |
seasonal_adjustment | 계절조정 여부 (영어 문자열) | TEXT | | 허용 |
popularity | 원천이 매긴 인기도 | INTEGER | | 허용 |
notes | 원천이 붙인 설명 원문 (영어). 정본은 여기 하나다 | TEXT | | 허용 |
observation_start | 원천이 발표하는 첫 관측일 | DATE | | 허용 |
observation_end | 원천이 발표하는 마지막 관측일 | DATE | | 허용 |
last_updated | 원천이 마지막으로 고친 시각 | TIMESTAMPTZ | | 허용 |
inserted_at | 행을 처음 넣은 시각 | TIMESTAMPTZ | | 아니오 |
updated_at | 행을 마지막으로 고친 시각 | TIMESTAMPTZ | | 아니오 |
4.4 fred_series_catalog - FRED 가 그 시리즈를 어떻게 설명하나 (2번째 표)| 키 | series_id |
|---|
fred_series 와 겹치는 칸 | 제목, 단위, 주기, 기간, 원천 갱신 시각 |
|---|
| 어긋나는가 | 아니다. 같은 응답을 같은 연결 안에서 두 표에 함께 커밋한다 |
|---|
| 이 표에만 있는 칸 | seasonal_adjustment, popularity, notes |
|---|
| 행이 수집 대상보다 많아질 수 있는가 | 그렇다. 손으로 카탈로그 전체 수집을 돌리면 FRED 전체가 들어온다. 스케쥴에는 없다 |
|---|
4.5 fred_observation_lags - 관측일별 발표 지연
4.5 fred_observation_lags - 관측일별 발표 지연 (컬럼, 뜻, 타입, 단위, 널 칸이 있는 표)| 컬럼 | 뜻 | 타입 | 단위 | 널 |
|---|
series_id | FRED 시리즈 코드 | TEXT | | 아니오 |
observation_date | 관측 기간의 시작일 | DATE | | 아니오 |
supports_alfred | 이 시리즈가 개정 이력을 갖는가 | BOOLEAN | | 아니오 |
initial_release_lag_days | first_realtime_start 에서 observation_date 를 뺀 날수 | INTEGER | 일 | 허용 |
initial_release_lag_status | 위 숫자를 잰 것으로 볼 수 있는가. 값 넷 | TEXT | | 허용 |
last_revision_lag_days | last_realtime_marker 에서 observation_date 를 뺀 날수 | INTEGER | 일 | 허용 |
last_revision_lag_status | 위 숫자를 잰 것으로 볼 수 있는가 | TEXT | | 허용 |
first_realtime_start | 이 관측의 가장 이른 판 시작일 | DATE | | 허용 |
last_realtime_marker | 이 관측의 가장 늦은 판 표시일 | DATE | | 허용 |
inserted_at | 행을 처음 넣은 시각 | TIMESTAMPTZ | | 아니오 |
updated_at | 행을 마지막으로 고친 시각 | TIMESTAMPTZ | | 아니오 |
initial_release_lag_status 의 값 넷이다.
4.5 fred_observation_lags - 관측일별 발표 지연 (값, 뜻 칸이 있는 표)| 값 | 뜻 |
|---|
measured | 잰 것. 시리즈 요약에 들어간다 |
before_vintage_history | 개정 이력이 시작되기 전의 관측. 첫 발표일을 알 수 없다 |
partial_after_tracking_started | 개정 이력이 없는 시리즈에서 우리가 보기 시작한 날 이전 |
unknown | 잴 근거가 없다 |
4.5 fred_observation_lags - 관측일별 발표 지연 (3번째 표)| 키 | (series_id, observation_date) |
|---|
| 어떻게 만드나 | 저장된 판만 읽어 매 실행이 다시 만든다. 원천을 부르지 않는다 |
|---|
| 주의 | 관측별 숫자를 그대로 쓰면 안 된다. status = 'measured' 로 거른다. 7.3 을 본다 |
|---|
4.6 sync_runs - 실행 한 건
4.6 sync_runs - 실행 한 건 (컬럼, 뜻, 타입, 단위, 널 칸이 있는 표)| 컬럼 | 뜻 | 타입 | 단위 | 널 |
|---|
id | 실행 번호 | BIGSERIAL | | 아니오 |
trigger_type | 무엇이 불렀나. scheduled 또는 manual | TEXT | | 아니오 |
command_name | 무슨 명령. sync-configured 또는 sync-series | TEXT | | 아니오 |
status | running, success, completed_with_errors | TEXT | | 아니오 |
started_at | 시작 시각 | TIMESTAMPTZ | | 아니오 |
finished_at | 끝난 시각. 도중에 죽으면 비어 있다 | TIMESTAMPTZ | | 허용 |
error_message | 실행 전체가 죽은 이유 | TEXT | | 허용 |
inserted_at | 행을 처음 넣은 시각 | TIMESTAMPTZ | | 아니오 |
updated_at | 행을 마지막으로 고친 시각 | TIMESTAMPTZ | | 아니오 |
4.6 sync_runs - 실행 한 건 (2번째 표)| 키 | id |
|---|
| 소요를 구하는 법 | finished_at - started_at |
|---|
4.7 sync_run_series - 그 실행의 시리즈별 결과
4.7 sync_run_series - 그 실행의 시리즈별 결과 (컬럼, 뜻, 타입, 단위, 널 칸이 있는 표)| 컬럼 | 뜻 | 타입 | 단위 | 널 |
|---|
id | 행 번호 | BIGSERIAL | | 아니오 |
run_id | sync_runs.id | BIGINT | | 아니오 |
series_id | FRED 시리즈 코드 | TEXT | | 아니오 |
status | success 또는 failed | TEXT | | 아니오 |
observations_written | 그 시리즈에서 upsert 를 시도한 관측 행수 | INTEGER | 행 | 아니오 |
latest_observation_date_seen | 그 실행이 본 마지막 관측일 | DATE | | 허용 |
error_message | 실패 이유 | TEXT | | 허용 |
inserted_at | 그 시리즈를 끝낸 시각 | TIMESTAMPTZ | | 아니오 |
updated_at | 행을 마지막으로 고친 시각 | TIMESTAMPTZ | | 아니오 |
4.7 sync_run_series - 그 실행의 시리즈별 결과 (2번째 표)| 키 | id. 중복 방지는 (run_id, series_id) |
|---|
observations_written 의 뜻 | 받아서 넣으려 한 개정 이력 행수다. 값이 바뀐 행수가 아니다 |
|---|
| 시리즈별 소요를 구하는 법 | 같은 실행 안에서 inserted_at 의 차이 |
|---|
5. 언제 갱신되나
5. 언제 갱신되나| 시작 | 매일 08:00 KST (cron 0 8 * * *) |
|---|
| 마감 | 08:50 KST |
|---|
| 실행 시간 상한 | 3,600초 |
|---|
| 도는 순서 | 스키마 확인(멱등) 다음 전 시리즈 동기화 |
|---|
| 단계 재시도 | 스키마 확인 1회 30초 뒤, 동기화 1회 120초 뒤 |
|---|
| 마감 확인 | 08:50 에 별도 실행이 그날 성공 실행과 시리즈 신선도를 함께 본다 |
|---|
| 마감을 놓치면 | 알림이 나가고 마감 확인 실행이 실패로 남는다 |
|---|
5.1 소요는 실행마다 다르다
같은 시리즈 묶음에서도 실행 간 폭이 크다. 원천 응답 속도에 붙는다. 실행별 소요를 보는 질의는 8.8 에 있고, 마감까지 여유가 얼마나 남는지는 7.7 을 본다.
5.2 시간은 시리즈 개수가 아니라 개정 이력 행수에 붙는다
개정 이력이 큰 시리즈 몇 개가 한 실행의 시간 대부분을 쓴다. NFCI, DAAA, DBAA, DGS10, DGS1, STLFSI4 가 그런 것들이다. 반대쪽 DRTSCILM 이나 JTSQUR 은 몇 초에 끝난다.
개수로 남은 시간을 어림하면 크게 틀린다. 한 실행 안에서 시리즈별 소요를 보는 질의는 8.8 에 있다.
5.3 실패했을 때 무엇이 남나
5.3 실패했을 때 무엇이 남나| 시리즈 하나가 실패하면 | 나머지는 계속 받는다 |
|---|
| 실행 상태 | completed_with_errors |
|---|
| 종료 코드 | 1. 스케쥴러가 실패로 표시한다 |
|---|
| 남는 것 | sync_run_series 에 그 시리즈의 status = 'failed' 와 오류 문구 |
|---|
| 시리즈 쪽 표시 | fred_series.last_failed_sync_at 이 갱신된다. 성공 시각은 그대로 남는다 |
|---|
| 반쪽 적재가 남는가 | 아니다. 시리즈 하나의 적재는 한 트랜잭션이다 |
|---|
| 옛 값이 사라지는가 | 아니다. 실패한 시리즈의 이미 들어간 값은 그대로다 |
|---|
실제로 난 것이 있다. 2026-06-04 실행에서 시리즈 여럿이 한꺼번에 실패했고 오류 문구가 전부 HTTP Error 429: Too Many Requests 였다. 원천의 호출 한도다. 실패 기록을 보는 질의는 8.8 에 있다.
5.4 성공했는데 값이 안 들어오는 것도 본다
실패보다 이쪽이 나쁘다. 매일 마감 확인이 시리즈별로 대조한다.
5.4 성공했는데 값이 안 들어오는 것도 본다| 견주는 것 | 원천의 마지막 관측일(fred_series.observation_end)과 우리 것(latest_available_observation_date) |
|---|
| 오늘과 견주지 않는 이유 | 주기마다 정상 간격이 달라 오탐이 난다 |
|---|
| 정상 | 차이 0 |
|---|
| 허용 지연 | 일별 7일, 주별 14일, 월별 45일, 분기 130일, 모르는 주기 45일 |
|---|
| 넘으면 | 어느 시리즈가 며칠 뒤처졌는지가 알림 문구에 들어간다 |
|---|
| 확인 자체가 실패하면 | 그 사실을 다른 문구로 알린다. 조용히 넘기지 않는다 |
|---|
지금 뒤처진 시리즈가 있는지 보는 질의는 8.7 에 있다.
6. 값을 믿을 수 있는 근거
6.1 개정 이력을 원천 그대로 보관한다
6.1 개정 이력을 원천 그대로 보관한다 (1번째 표)| 무엇을 보관하나 | 관측일마다 그 값이 유효했던 기간을 판별로 다 보관한다 |
|---|
| 우리가 값을 고치는가 | 아니다. 원천이 준 값을 그대로 넣는다 |
|---|
| 옛 값을 지우는가 | 아니다. 새 판은 새 행이 된다 |
|---|
| 우리가 손대는 칸 | 없다. 유효 기간 두 칸도 원천이 준 것이다. 여기에 우리 값을 넣던 때의 대가가 7.2 와 7.5 다 |
|---|
| 값 없음도 보관하나 | 그렇다. 원천이 값 없음으로 준 판은 value 가 NULL 인 행이 된다 |
|---|
| 개정되는 비율 | 대부분의 관측이 한 번 이상 개정된다 |
|---|
GDP 2025년 1분기가 좋은 예다. 아래는 이미 닫힌 판들이다. 유효 기간이 끝났으므로 값이 다시 바뀌지 않는다.
6.1 개정 이력을 원천 그대로 보관한다 (유효 시작, 유효 끝, 값 (10억 달러) 칸이 있는 표)| 유효 시작 | 유효 끝 | 값 (10억 달러) |
|---|
| 2025-04-30 | 2025-05-28 | 29,977.632 |
| 2025-05-29 | 2025-05-29 | 29,976.638 |
| 2025-06-26 | 2025-09-24 | 29,962.047 |
그 뒤의 판은 열려 있고 값이 또 바뀔 수 있다. 지금 값은 8.3 이 보여준다.
그래서 "2025년 7월 1일에 사람들이 보던 1분기 GDP" 를 되짚을 수 있다. 29,962.047 이고, 지금 값과 다르다. 되짚는 질의는 8.4 에 있다.
이것이 전략을 되짚을 때 중요하다. 지금 값으로 과거를 판단하면 그때 없던 정보를 쓰게 된다.
6.2 값이 바뀌면 무엇이 남나
6.2 값이 바뀌면 무엇이 남나| 남는 것 | 어디 |
|---|
| 옛 값과 그 값이 유효했던 기간 | fred_observation_vintages 의 옛 행 |
| 그 관측을 우리가 처음 받은 시각 | fred_observations_latest.first_seen_at |
| 값을 마지막으로 고친 시각 | fred_observations_latest.updated_at |
| 어느 실행이 그것을 썼나 | sync_run_series |
6.3 발표 지연을 어떻게 세나
6.3 발표 지연을 어떻게 세나 (1번째 표)| 무엇을 세나 | 관측 기간의 시작일부터 그 값이 처음 발표된 날까지의 날수 |
|---|
| 어디서 오나 | 그 관측의 가장 이른 realtime_start 에서 observation_date 를 뺀다 |
|---|
| 관측별 | fred_observation_lags.initial_release_lag_days |
|---|
| 시리즈 요약 | fred_series 의 가운뎃값과 가장 최근 관측의 값 |
|---|
| 가운뎃값에서 빼는 것 | 개정 이력이 시작되기 전의 관측 |
|---|
빼는 이유다. ALFRED 의 개정 이력은 시리즈마다 어느 날짜부터만 있다. 그 앞의 관측은 이력의 첫 판에 이미 들어 있어서 첫 발표일이 "이력이 시작된 날" 로 찍힌다. 그 날짜는 한 번 정해지면 바뀌지 않으므로 예를 그대로 적을 수 있다.
6.3 발표 지연을 어떻게 세나 (시리즈, 관측일, 찍힌 첫 발표일, 나오는 지연 칸이 있는 표)| 시리즈 | 관측일 | 찍힌 첫 발표일 | 나오는 지연 |
|---|
DEXJPUS (엔달러 환율) | 1971-01-04 | 2014-03-18 | 15,779일 |
USREC (경기침체 표시) | 1854-12-01 | 2014-09-18 | 58,365일 |
환율이 43년 뒤에 발표된 것이 아니다. 개정 이력이 2014년부터 있는 것이다.
빼고 난 결과다. 발표 지연이 긴 것은 분기 지표다. GDI, GDPC1, GDP, MSPUS, DRCCLACBS 의 가운뎃값이 100일을 넘는다. 월별 물가와 고용 (CPIAUCSL, PAYEMS, UNRATE)은 한 달 남짓이고, 일별 금리(DGS10)는 하루다. 지금 값을 보는 질의는 8.6 에 있다.
"최근 발표 지연" 은 빼는 규칙과 무관하다. 최근 관측은 언제나 이력 시작일 뒤에 있다.
6.4 원천 문자열을 번역하지 않는다
제목, 단위, 주기, 계절조정, 설명은 원천이 준 영어 그대로 넣는다. 우리가 붙인 것은 분류(group_name) 하나다. 그래서 어떤 칸이 원천 말이고 어떤 칸이 우리 판단인지 헷갈리지 않는다.
7. 알려진 한계
7.1 라이선스 때문에 원천이 최근 몇 해만 주는 시리즈가 다섯 있다
7.1 라이선스 때문에 원천이 최근 몇 해만 주는 시리즈가 다섯 있다| 시리즈 | 창 | 무엇 |
|---|
BAMLH0A0HYM2 | 3년 | ICE BofA 하이일드 스프레드 |
BAMLH0A0HYM2EY | 3년 | 같은 지수의 유효수익률 |
BAMLC0A0CM | 3년 | ICE BofA 투자등급 스프레드 |
SP500 | 10년 | S&P 500 |
DJIA | 10년 | 다우존스 산업평균 |
근거는 원천이 붙인 설명 안에 있다. ICE 세 개는 첫 문장이 같다.
Starting in April 2026, this series will only include 3 years of observations. For more data, go to the source.
주가지수 둘은 SP500 의 설명이 대신 말한다.
FRED and its associated services will include 10 years of daily history for Standard & Poors and Dow Jones Averages series.
창이 날마다 굴러간다. 원천이 말하는 시작일이 매일 밀린다. 우리 적재는 옛 행을 지우지 않으므로 시간이 갈수록 우리 이력이 원천보다 길어진다. 그 앞 구간은 7.2 의 문제를 함께 갖는다. 그래서 원천 시작일과 우리 첫 관측일을 이 문서에 적지 않는다. 8.5 가 그 둘을 함께 보여준다.
7.2 원천이 버린 값을 들고 있는 옛 행이 남아 있다
적재는 고쳤다. 앞으로는 안 생긴다. 이미 든 행은 남아 있다. 이 절은 그 둘을 갈라 적는다 (a42_fred-5).
원천이 시리즈를 다시 기준연도로 환산하거나 단위를 바꾸면 현재 판에서 옛 구간이 사라진다. 원천은 그것을 값 없음(.)으로 분명히 알려준다.
이제 어떻게 적재하나
이제 어떻게 적재하나 (1번째 표)| 개정 이력을 어떻게 묻나 | realtime_start/realtime_end 구간으로 묻는다. 판 날짜 목록(vintage_dates=)으로 물으면 원천이 끝나는 날을 요청한 마지막 판 날짜로 잘라서 준다. 그러면 응답에 열린 구간이 없고, 여태 그것을 우리가 만들어 넣었다 |
|---|
realtime_end | 원천이 준 것을 그대로 넣는다. 열린 구간의 9999-12-31 도 원천이 준 값이다 |
|---|
| 폐기 표시 | 값 없음 판을 버리지 않고 value 를 NULL 로 넣는다. 열린 판의 값이 NULL 이면 원천이 지금 그 관측을 발표하지 않는 것이다 |
|---|
| 값 테이블 | 폐기된 관측은 fred_observations_latest.value 가 NULL 이 된다. 값이 없는 판으로 새 행을 만들지는 않는다. 휴일처럼 값이 원래 없는 관측일이 빈 행으로 쌓이지 않게 하는 것이다 |
|---|
NEWORDER 가 그 예다. 원천이 붙인 설명이 언제 무엇을 했는지 말한다.
Effective May 21, 2001, data were reconstructed to reflect the switch from the Standard Industrial Classification (SIC) system to the North American Industry Classification System (NAICS).
그 날짜가 폐기 표시의 유효 시작일로 들어온다. 아래는 1968-02-01 에 대한 원천 응답 그대로다.
이제 어떻게 적재하나 (유효 시작, 유효 끝, 원천이 주는 값 칸이 있는 표)| 유효 시작 | 유효 끝 | 원천이 주는 값 |
|---|
| 1997-03-06 | 2001-05-20 | 4918 |
| 2001-05-21 | 열려 있다 | 값 없음 |
PCEC96 의 1959-01-01 도 같은 모양이다. 판이 여섯이고 마지막 판이 값 없음이며, 그 앞의 1356.5 는 1999-11-01 에 유효 기간이 끝난다.
그래서 무엇이 남아 있나
고침 전에 든 행을 지우지 않기로 했다 (사람의 결정, a42_fred-5). 지우는 것이 파괴적이기 때문이다. 그 행의 값은 원천에서 다시 받을 수 없다. 원천이 지금 그 구간을 발표하지 않으므로.
남는 방식이 중요하다. fred_observation_vintages 의 키가 (series_id, observation_date, realtime_start, realtime_end) 다. 고친 적재가 넣는 참 realtime_end 는 옛 행과 다른 키라서 옛 행을 덮지 않는다. 둘이 나란히 남는다.
그래서 무엇이 남아 있나| 옛 행 | 끝나는 날이 9999-12-31 로 찍혀 "지금도 유효" 로 보인다. 그 값은 원천이 이미 버린 것일 수 있다 |
|---|
| 새 행 | 참 구간이 들어온다. 폐기 표시도 함께 |
|---|
| 결과 | 그 관측에 열린 판이 둘이 된다. 7.5 가 그것이다 |
|---|
이것은 의도된 것이다. "적재만 고치고 옛 행은 남긴다" 를 고르면 이렇게 된다. 값을 살리는 대신 옛 행을 걸러 읽는 것을 받아들인 것이다.
그래서 한 시리즈를 다시 받으면 그 시리즈의 열린 판 중복이 한 번 늘어난다. 늘어난 뒤로는 같은 키가 다시 들어오므로 더 늘지 않는다. 지우지 않기로 한 선택의 값이다.
어떻게 피하나
원천이 지금 발표하는 구간만 쓴다. 그 경계가 fred_series.observation_start 다. 8.5 의 질의가 그 조건을 쓴다. 옛 행과 새 행을 함께 걸러낸다.
다시 받은 시리즈라면 value is null 로도 걸러진다. 하지만 아직 다시 받지 않은 시리즈에는 그 표시가 없다. 그래서 observation_start 조건이 정본이다.
단위가 다른 값이 한 시리즈 안에서 이어 붙는다. WRESBAL(연준 지준 잔액)이 그렇다. 원천이 단위를 Billions of U.S. Dollars 에서 Millions of U.S. Dollars 로 바꿨고, 2023-11-16 판에는 앞의 단위가 적혀 있었다. 그 판에서 온 옛 값과 지금 판의 값이 우리 표에 나란히 있으면 한 주 사이에 1,000배 뛴다. 실제 지준은 그대로였다. fred_series.units 는 지금 단위 하나만 말한다. PCEC96 은 기준연도 환산이라 배수가 아니라 몇 % 의 어긋남으로 나온다.
observation_start 조건을 넣으면 둘 다 사라진다. 8.5 가 보여준다.
7.3 첫 발표 지연을 잴 수 없는 관측이 많다
fred_observation_lags.initial_release_lag_days 의 숫자를 그대로 쓰면 안 된다. 잴 수 없는 행에도 숫자가 들어 있다. 그 숫자는 "이력이 시작된 날 - 관측일" 이다. initial_release_lag_status = 'measured' 로 거른다. 상태별 뜻은 4.5 에 있고, 상태별 개수를 세는 질의는 8.6 에 있다.
시리즈 요약(fred_series 의 가운뎃값)은 이미 걸러진 값이다.
개정 이력이 시작되는 날은 시리즈마다 다르다. 1920년대부터 있는 것도 있고, 우리가 그 시리즈를 수집 대상에 넣은 날부터인 것도 있다.
7.4 주가지수 둘은 개정 이력이 없고 발표 지연도 못 믿는다
7.4 주가지수 둘은 개정 이력이 없고 발표 지연도 못 믿는다 (SP500, DJIA 칸이 있는 표) | SP500 | DJIA |
|---|
| 개정 이력 | 없다. 원천이 개정 시점을 안 준다 | 없다 |
| 판을 어떻게 만드나 | 우리가 값이 바뀐 것을 본 날로 만든다 | 같다 |
| 우리가 보기 시작한 날 | 2026-04-26 | 2026-08-31 |
이 둘의 가운뎃값은 아주 적은 행에 얹혀 있다. 우리가 보기 시작한 날 이전의 관측은 전부 그 날짜로 찍혀 partial_after_tracking_started 가 되고, 잴 수 없다. DJIA 는 2026-08-31 에 수집 대상에 들어왔으므로 잴 수 있는 관측이 특히 적다.
나온 지연 자체도 실제보다 하루 짧다. 판의 시작일을 UTC 날짜로 찍는데 08:00 KST 실행은 UTC 로 전날이다. 2026-09-02 실행에서 실제로 그랬다.
7.4 주가지수 둘은 개정 이력이 없고 발표 지연도 못 믿는다 (2번째 표)| 무엇 | DJIA 의 2026-09-01 종가 |
|---|
| 받은 실행 | 2026-09-02 08:00 KST |
|---|
| 찍힌 판 시작일 | 2026-09-01 |
|---|
| 나온 지연 | 0일 |
|---|
| 실제 | 하루 뒤에 받았다 |
|---|
이 둘의 발표 지연 칸을 쓰지 않는 것이 안전하다. 값 자체는 괜찮다.
7.5 한 관측에 "지금도 유효한" 판이 둘 이상일 수 있다
적재는 고쳤다. 앞으로는 안 생긴다. 이미 든 것은 남아 있다. 7.2 와 같은 갈림이다.
왜 생겼나
옛 적재는 판 날짜 목록을 200개씩 끊어 물었고, 묶음마다 마지막 판의 끝나는 날을 9999-12-31 로 바꿔 넣었다. 원천이 끝나는 날을 요청한 마지막 판 날짜로 잘라 주므로 그렇게 하지 않으면 열린 구간이 아예 없었기 때문이다. 그래서 묶음 경계마다 열린 판이 하나씩 생겼다. 판 날짜가 많은 시리즈일수록 한 관측에 열린 판이 많다.
이제는
realtime_start/realtime_end 구간으로 묻고 원천이 준 끝나는 날을 그대로 넣는다. 열린 구간은 마지막 창에만 나오므로 관측 하나에 열린 판이 하나다. 창을 나누는 것은 한 구간에 담을 수 있는 판 날짜 수에 원천 상한이 있어서고, 경계에 걸린 구간은 두 행으로 갈리지만 그 둘은 닫힌 구간이다.
남아 있는 것
옛 행은 지우지 않는다. 그리고 7.2 가 적은 이유로, 다시 받은 시리즈는 옛 열린 판 옆에 참 열린 판이 새로 붙어 한 번 늘어난다.
그래서 시점 재현 질의를 realtime_start <= X and realtime_end >= X 로만 쓰면 관측 하나에 두 행 이상이 나온다. 걸리는 관측이 몇 건인지는 8.5 의 질의가 세어 준다.
realtime_start 가 가장 늦은 것 하나만 고르면 맞는다. 8.4 의 질의가 그렇게 쓴다. 적재도 값 테이블을 만들 때 같은 정렬을 쓴다. 두 곳이 어긋나면 값 테이블과 시점 재현이 다른 답을 준다.
7.6 값 테이블의 판 날짜 두 칸이 최신 판을 안 가리키는 옛 행이 있다
적재는 고쳤다. fred_observations_latest 는 같은 키가 다시 올 때 여태 값이 달라졌을 때만 행을 덮었다. 값이 그대로면 realtime_start 와 realtime_end 가 옛 판의 것으로 남았다. 지금은 판 날짜가 달라져도 덮는다.
남아 있는 것은 아직 다시 받지 않은 시리즈의 행이다. 그 시리즈가 다음에 수집될 때 고쳐진다. 어긋난 행을 세는 질의는 8.5 에 있다.
값이 어긋난 행은 없다. 어긋나는 것은 그 값이 어느 판에서 왔는지를 가리키는 날짜 두 칸이다. 값만 쓰면 문제가 없다. 판을 알아야 하면 fred_observation_vintages 를 본다.
덧붙여 fred_observations_latest.realtime_end 는 모든 행이 9999-12-31 이다. 가장 늦은 판은 언제나 열린 판이기 때문이다. 그 칸으로는 아무것도 가려낼 수 없다. 폐기된 관측을 가려내는 것은 value is null 이다 (7.2).
한 가지 더. 개정 이력 조회(views.VINTAGES_ONE_SQL)는 같은 (realtime_start, value) 를 묶어 max(realtime_end) 를 쓴다. 옛 적재가 같은 판을 닫힌 행과 열린 행 둘로 저장했기 때문이다. 옛 행이 남아 있는 동안 그 질의는 참 끝나는 날 대신 옛 9999-12-31 을 보여준다. 새 행만 있는 관측은 맞는 값이 나온다.
7.7 마감까지 여유가 얇다
7.7 마감까지 여유가 얇다| 시작 | 08:00 |
|---|
| 마감 | 08:50 |
|---|
| 실행 시간 상한 | 3,600초. 여기 걸린 적은 없다 |
|---|
정기 실행이 마감에 가깝게 끝나는 날이 있고, 실행 간 폭도 크다 (5.1). 원천 응답이 느린 날에는 마감을 넘길 수 있다. 시리즈를 더 넣으려면 먼저 이 자리를 본다. 실행별 소요와 끝난 시각은 8.8 이 보여준다.
7.8 응답 상한은 조용히 자른다
FRED 는 한 응답에 관측값을 100,000행까지만 준다. 넘치면 오류가 아니라 뒤가 잘린 정상 응답이 온다. 정렬이 관측일 오름차순이라 잘리면 최근 구간이 통째로 빠지고 수집은 성공으로 끝난다.
지금은 응답의 count 를 보고 offset 으로 이어 받아 막는다. 원천이 count 의 뜻이나 상한 규칙을 바꾸면 다시 조용히 잘린다. 5.4 의 신선도 대조가 그것을 잡는 두 번째 그물이다.
8. 직접 확인하는 법
이 문서에서 뺀 수를 여기서 센다. 접속값은 apps/a42_collector/.env 의 A42_FRED_DSN 이다. 아래 예시는 그것을 읽었다고 본다.
set -a; . apps/a42_collector/.env; set +a
8.1 재고를 직접 센다
1절의 라이브 값과 같은 것을 DB 에서 바로 센다.
psql "$A42_FRED_DSN" -c "
select
(select count(*) from fred_series) as 시리즈,
(select count(*) from fred_observations_latest) as 값_행수,
(select count(*) from fred_observation_vintages) as 개정이력_행수,
(select count(*) from fred_observation_lags) as 지연_행수,
(select min(observation_date) from fred_observations_latest) as 가장_이른_관측일,
(select max(observation_date) from fred_observations_latest) as 가장_늦은_관측일,
pg_size_pretty(pg_database_size(current_database())) as 크기;"
8.2 2절과 3절의 개수를 센다
psql "$A42_FRED_DSN" -c "
select group_name, count(*) from fred_series group by 1 order by 2 desc, 1;"
psql "$A42_FRED_DSN" -c "
select frequency, count(*) from fred_series group by 1 order by 2 desc, 1;"
psql "$A42_FRED_DSN" -c "
select units, count(*) from fred_series group by 1 order by 2 desc, 1;"
psql "$A42_FRED_DSN" -c "
select s.group_name, count(*) as 시리즈,
sum((select count(*) from fred_observations_latest o
where o.series_id = s.series_id)) as 관측_행수
from fred_series s group by 1 order by 3 desc;"
psql "$A42_FRED_DSN" -c "
select series_id from fred_series_catalog
where notes is null or notes = '' order by series_id;"
관측일당 판이 많은 시리즈다 (3.1). 응답 상한에 닿는 것이 이것들이다.
psql "$A42_FRED_DSN" -c "
select series_id, count(*) as 개정이력_행수,
count(distinct observation_date) as 관측일,
round(count(*)::numeric / count(distinct observation_date), 1) as 관측일당_판
from fred_observation_vintages group by 1 order by 4 desc limit 5;"
8.3 지금 값을 본다
psql "$A42_FRED_DSN" -c "
select observation_date, value
from fred_observations_latest
where series_id = 'GDP'
order by observation_date desc limit 8;"
8.4 그때 발표된 값을 되짚는다
realtime_start 가 가장 늦은 판 하나만 고른다. 7.5 때문이다.
psql "$A42_FRED_DSN" -c "
select observation_date, value, realtime_start, realtime_end
from fred_observation_vintages
where series_id = 'GDP'
and observation_date = '2025-01-01'
and realtime_start <= '2025-07-01'
and realtime_end >= '2025-07-01'
order by realtime_start desc
limit 1;"
2025-07-01 시점의 값은 29962.047 이다. 그 판은 닫혀 있으므로 이 답은 바뀌지 않는다 (6.1).
시리즈 전체를 한 시점으로 되짚으려면 관측일마다 그 한 판을 고른다.
psql "$A42_FRED_DSN" -c "
select observation_date, value from (
select observation_date, value,
row_number() over (partition by observation_date
order by realtime_start desc) as rn
from fred_observation_vintages
where series_id = 'GDP'
and realtime_start <= '2025-07-01'
and realtime_end >= '2025-07-01') t
where rn = 1
order by observation_date desc limit 8;"
8.5 7절의 주장을 다시 확인한다
원천이 지금 발표하는 구간만 쓰는 방법이다 (7.2).
psql "$A42_FRED_DSN" -c "
select o.observation_date, o.value
from fred_observations_latest o
join fred_series s using (series_id)
where s.series_id = 'WRESBAL'
and o.observation_date >= s.observation_start
order by o.observation_date limit 5;"
원천 창 앞에 남은 행이 어느 시리즈에 몇 개인지 센다 (7.1, 7.2).
psql "$A42_FRED_DSN" -c "
select s.series_id, s.observation_start as 원천_시작일,
min(o.observation_date) as 우리_시작일,
count(*) filter (where o.observation_date < s.observation_start) as 창_앞의_행
from fred_series s join fred_observations_latest o using (series_id)
group by 1, 2
having count(*) filter (where o.observation_date < s.observation_start) > 0
order by 4 desc;"
폐기 표시가 든 행을 센다 (7.2). 고침 뒤에 다시 받은 시리즈에만 있다. 아직 다시 받지 않은 시리즈는 여기 안 나온다. 그것이 위 질의가 여전히 정본인 이유다.
psql "$A42_FRED_DSN" -c "
select series_id, count(*) as 폐기_표시
from fred_observations_latest where value is null
group by 1 order by 2 desc;"
한 관측의 판을 원천이 준 그대로 본다 (7.2). 마지막 판의 값이 비어 있으면 원천이 그 관측을 버린 것이다.
psql "$A42_FRED_DSN" -c "
select realtime_start, realtime_end, value, inserted_at::date as 넣은날
from fred_observation_vintages
where series_id = 'NEWORDER' and observation_date = '1968-02-01'
order by realtime_start, realtime_end;"
열린 판이 둘 이상인 관측을 센다 (7.5).
psql "$A42_FRED_DSN" -c "
select count(*) as 열린_판_둘_이상 from (
select series_id, observation_date
from fred_observation_vintages
where realtime_end = '9999-12-31'
group by 1, 2 having count(*) > 1) t;"
그 중복이 옛 행 때문인지 본다 (7.2, 7.5). 고침 전에 든 행과 고침 뒤에 든 행을 넣은 날로 가른다.
psql "$A42_FRED_DSN" -c "
select inserted_at::date as 넣은날, count(*) as 열린_판,
count(*) filter (where value is null) as 그중_폐기_표시
from fred_observation_vintages
where series_id = 'NEWORDER' and realtime_end = '9999-12-31'
group by 1 order by 1;"
값 테이블이 가장 늦은 판과 어긋난 행을 센다 (7.6). 0 이 나와야 한다. 폐기 표시가 든 행도 0 을 지킨다. 값 테이블의 그 행도 NULL 이 되기 때문이다.
psql "$A42_FRED_DSN" -c "
select count(*) as 값이_어긋난_행 from (
select o.value,
(select v.value from fred_observation_vintages v
where v.series_id = o.series_id
and v.observation_date = o.observation_date
order by v.realtime_start desc limit 1) as 최신판
from fred_observations_latest o) t
where 최신판 is distinct from value;"
판 날짜 두 칸이 가장 늦은 판을 안 가리키는 행을 센다 (7.6). 다시 받은 시리즈는 0 이 되고, 아직 안 받은 시리즈의 행이 남는다.
psql "$A42_FRED_DSN" -c "
with newest as (
select series_id, observation_date, realtime_start,
row_number() over (partition by series_id, observation_date
order by realtime_start desc, realtime_end desc) rn
from fred_observation_vintages)
select l.series_id, count(*) as 판날짜_어긋남
from fred_observations_latest l
join newest n using (series_id, observation_date)
where n.rn = 1 and l.realtime_start is distinct from n.realtime_start
group by 1 order by 2 desc;"
판이 하나뿐인 관측과 전체 관측이다 (4.2, 6.1).
psql "$A42_FRED_DSN" -c "
select count(*) filter (where 판 = 1) as 판_하나, count(*) as 관측
from (select series_id, observation_date, count(*) as 판
from fred_observation_vintages group by 1, 2) t;"
8.6 발표 지연을 본다
psql "$A42_FRED_DSN" -c "
select series_id, frequency,
median_initial_release_lag_days as 평소,
latest_initial_release_lag_days as 최근
from fred_series
where median_initial_release_lag_days > 100
order by 3 desc;"
관측별로 볼 때는 잰 것만 거른다 (7.3).
psql "$A42_FRED_DSN" -c "
select observation_date, initial_release_lag_days
from fred_observation_lags
where series_id = 'GDP' and initial_release_lag_status = 'measured'
order by observation_date desc limit 8;"
psql "$A42_FRED_DSN" -c "
select initial_release_lag_status, count(*)
from fred_observation_lags group by 1 order by 2 desc;"
8.7 원천보다 뒤처진 시리즈가 있는지 본다
psql "$A42_FRED_DSN" -c "
select series_id, frequency, observation_end,
latest_available_observation_date,
(observation_end - latest_available_observation_date) as 차이
from fred_series
where observation_end <> latest_available_observation_date
order by 5 desc;"
8.8 실행 기록을 본다
실행별 소요와 끝난 시각이다 (5.1, 7.7).
psql "$A42_FRED_DSN" -c "
select id, trigger_type, status, started_at, finished_at,
(finished_at - started_at) as 소요
from sync_runs order by id desc limit 10;"
psql "$A42_FRED_DSN" -c "
with t as (
select series_id, observations_written, inserted_at,
lag(inserted_at) over (order by inserted_at) as prev
from sync_run_series
where run_id = (select max(id) from sync_runs))
select series_id, observations_written, (inserted_at - prev) as 소요
from t where prev is not null order by 3 desc limit 10;"
실패한 시리즈다 (5.3). 정상이면 최근 실행에서 아무 줄도 안 나온다.
psql "$A42_FRED_DSN" -c "
select s.started_at, r.series_id, r.error_message
from sync_run_series r join sync_runs s on s.id = r.run_id
where r.status = 'failed'
order by s.started_at desc limit 10;"
8.9 화면과 조회 API
주소는 이 저장소를 돌리는 기계 기준이다. 밖에서 여는 주소는 docs/operations.md 에 있다.
8.9 화면과 조회 API (무엇, 주소 칸이 있는 표)| 무엇 | 주소 |
|---|
| 시리즈 목록 화면 | http://127.0.0.1:3000/fred |
| 시리즈 상세 화면 | http://127.0.0.1:3000/fred/GDP |
| 수집 상태 화면 | http://127.0.0.1:3000/ops |
| 재고 화면 | http://127.0.0.1:3000/ |
| 목록 API | http://127.0.0.1:8000/api/v1/fred/series |
| 상세 API | http://127.0.0.1:8000/api/v1/fred/series/GDP |
| 관측값 API | http://127.0.0.1:8000/api/v1/fred/series/GDP/observations |
| 개정 이력 API | http://127.0.0.1:8000/api/v1/fred/series/GDP/vintages?observation_date=2025-01-01 |
| 재고 API | http://127.0.0.1:8000/api/v1/datasets |
8.9 화면과 조회 API (2번째 표)| 관측값 기본 | 2,000점 |
|---|
| 관측값 상한 | 20,000점 |
|---|
| 개정 이력 기본 | 최근 관측일 5개 |
|---|
| 개정 이력 상한 | 관측일 50개 |
|---|
개정 이력을 시리즈 통째로 주는 길은 없다. 개정 이력이 큰 시리즈는 한 시리즈가 백만 행에 가깝다. 관측일을 주거나 관측일 수를 제한해서 받는다. 전량이 필요하면 위 psql 을 쓴다.