You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
10 KiB
10 KiB
Phase 1 DB 스키마
1. 설계 원칙
- PostgreSQL은 운영 상태와 canonical metadata를 담당합니다.
- 대량 시계열과 연구용 매트릭스는 Parquet/DuckDB로 분리합니다.
- 각 테이블은 가능한 한 append-safe + upsert-safe 하게 설계합니다.
- 모든 핵심 테이블은
created_at_utc,updated_at_utc를 가집니다. - 모든 외부 문서는 source checksum을 가집니다.
2. PostgreSQL 핵심 테이블
2.1 source_registry
외부 데이터 원천 정의
| column | type | note |
|---|---|---|
| source_name | text PK | sec, alpaca, fred, finra |
| source_type | text | filing, market_data, macro, short_volume |
| enabled | boolean | 사용 여부 |
| config_json | jsonb | adapter 설정 |
| created_at_utc | timestamptz | 생성 시각 |
| updated_at_utc | timestamptz | 수정 시각 |
2.2 issuer_master
발행사 마스터
| column | type | note |
|---|---|---|
| issuer_id | text PK | 내부 발행사 ID |
| cik | text unique | SEC CIK |
| ticker | text | 대표 ticker |
| issuer_name | text | 회사명 |
| exchange | text | 거래소 |
| country_code | text | 국가 |
| is_active | boolean | 활성 여부 |
| created_at_utc | timestamptz | |
| updated_at_utc | timestamptz |
2.3 symbol_master
종목 마스터
| column | type | note |
|---|---|---|
| symbol_id | text PK | 내부 종목 ID |
| issuer_id | text FK | issuer_master |
| ticker | text | 심볼 |
| venue | text | 거래 venue |
| asset_type | text | common_stock 등 |
| currency | text | 통화 |
| start_date | date | 유효 시작 |
| end_date | date nullable | 유효 종료 |
| is_primary | boolean | 대표 종목 여부 |
| created_at_utc | timestamptz | |
| updated_at_utc | timestamptz |
2.4 job_runs
배치/수집 실행 로그
| column | type | note |
|---|---|---|
| job_run_id | uuid PK | 실행 ID |
| job_name | text | job 이름 |
| source_name | text | source |
| run_date | date | 기준 일자 |
| status | text | pending/running/succeeded/failed/partial |
| started_at_utc | timestamptz | 시작 시각 |
| finished_at_utc | timestamptz nullable | 종료 시각 |
| records_seen | integer | 관측 수 |
| records_written | integer | 적재 수 |
| records_skipped | integer | 스킵 수 |
| error_count | integer | 에러 수 |
| error_summary | text nullable | 요약 |
| metadata_json | jsonb | 기타 메타 |
2.5 raw_objects
원문 보관 메타데이터
| column | type | note |
|---|---|---|
| raw_object_id | text PK | 내부 원문 ID |
| source_name | text | source |
| source_object_key | text | 원천 고유 키 |
| storage_path | text | raw 파일 경로 |
| content_type | text | mime type |
| checksum_sha256 | text | 체크섬 |
| collected_at_utc | timestamptz | 수집 시각 |
| published_at_utc | timestamptz nullable | 원천 게시 시각 |
| metadata_json | jsonb | sidecar metadata |
| created_at_utc | timestamptz |
2.6 documents
정규화된 문서 메타
| column | type | note |
|---|---|---|
| document_id | text PK | 내부 문서 ID |
| source_name | text | 보통 sec |
| issuer_id | text FK | |
| symbol_id | text nullable FK | |
| accession_no | text nullable | SEC accession |
| form_type | text | 8-K, 10-Q 등 |
| filing_date | date | filing date |
| accepted_at_utc | timestamptz nullable | SEC acceptance time |
| primary_document_name | text nullable | primary doc |
| raw_object_id | text FK | 원문 참조 |
| text_path | text nullable | 추출 텍스트 경로 |
| html_path | text nullable | html 경로 |
| parsed_status | text | pending/succeeded/failed |
| created_at_utc | timestamptz | |
| updated_at_utc | timestamptz |
고유 제약:
(source_name, accession_no, primary_document_name)unique
2.7 document_exhibits
부속 문서 목록
| column | type | note |
|---|---|---|
| exhibit_id | text PK | 내부 exhibit ID |
| document_id | text FK | |
| exhibit_code | text | EX-99.1 등 |
| exhibit_name | text | 파일명 |
| raw_object_id | text FK | |
| text_path | text nullable | |
| html_path | text nullable | |
| created_at_utc | timestamptz |
2.8 events
문서에서 추출된 이벤트 단위
| column | type | note |
|---|---|---|
| event_id | text PK | 내부 이벤트 ID |
| issuer_id | text FK | |
| symbol_id | text nullable FK | |
| primary_document_id | text FK | |
| event_type | text | earnings_release 등 |
| event_direction | text | bullish/bearish/mixed/unknown |
| event_date | date | 거래 로직 기준 일자 |
| filed_at_utc | timestamptz nullable | filing/published time |
| parser_version | text | parser 버전 |
| parse_confidence | numeric | 0~1 |
| status | text | pending/valid/rejected |
| created_at_utc | timestamptz | |
| updated_at_utc | timestamptz |
2.9 event_parses
파서 원출력 저장
| column | type | note |
|---|---|---|
| event_parse_id | bigserial PK | |
| event_id | text FK | |
| parser_kind | text | rule / llm / merged |
| parser_version | text | |
| schema_version | text | |
| output_json | jsonb | full parser output |
| validation_status | text | valid/invalid |
| validation_errors | jsonb nullable | |
| created_at_utc | timestamptz |
2.10 market_bars_daily
일봉 canonical 저장
| column | type | note |
|---|---|---|
| symbol_id | text FK | |
| trade_date | date | |
| open | numeric | |
| high | numeric | |
| low | numeric | |
| close | numeric | |
| volume | bigint | |
| vwap | numeric nullable | |
| trade_count | bigint nullable | |
| source_name | text | |
| created_at_utc | timestamptz | |
| updated_at_utc | timestamptz |
PK:
(symbol_id, trade_date, source_name)
2.11 market_bars_intraday
분봉 canonical 저장
| column | type | note |
|---|---|---|
| symbol_id | text FK | |
| bar_start_utc | timestamptz | |
| timeframe | text | 1Min, 5Min 등 |
| open | numeric | |
| high | numeric | |
| low | numeric | |
| close | numeric | |
| volume | bigint | |
| vwap | numeric nullable | |
| trade_count | bigint nullable | |
| source_name | text | |
| created_at_utc | timestamptz |
PK:
(symbol_id, bar_start_utc, timeframe, source_name)
2.12 macro_series
거시 시계열 메타
| column | type | note |
|---|---|---|
| series_id | text PK | FRED series_id |
| title | text | |
| frequency | text | |
| units | text | |
| source_name | text | |
| metadata_json | jsonb | |
| created_at_utc | timestamptz |
2.13 macro_observations
거시 시계열 값
| column | type | note |
|---|---|---|
| series_id | text FK | |
| observation_date | date | |
| value | numeric nullable | |
| created_at_utc | timestamptz |
PK:
(series_id, observation_date)
2.14 short_sale_daily
FINRA short sale volume 정규화
| column | type | note |
|---|---|---|
| symbol_id | text nullable FK | mapping 실패 가능 |
| ticker_raw | text | 원본 심볼 |
| trade_date | date | |
| short_volume | bigint | |
| short_exempt_volume | bigint nullable | |
| total_volume | bigint nullable | |
| source_name | text | |
| created_at_utc | timestamptz |
PK:
(ticker_raw, trade_date, source_name)
2.15 feature_snapshots
이벤트 시점 특징 저장
| column | type | note |
|---|---|---|
| feature_snapshot_id | bigserial PK | |
| event_id | text FK | |
| snapshot_name | text | market_v1, event_v1 등 |
| snapshot_version | text | |
| feature_json | jsonb | |
| created_at_utc | timestamptz |
2.16 order_plans
Phase 1에서는 계획만 정의
| column | type | note |
|---|---|---|
| order_plan_id | bigserial PK | |
| event_id | text FK | |
| symbol_id | text FK | |
| side | text | buy/sell |
| planned_entry_date | date | |
| planned_order_type | text | market/limit |
| planned_price | numeric nullable | |
| stop_price | numeric nullable | |
| take_profit_price | numeric nullable | |
| quantity_plan | numeric nullable | |
| status | text | draft/ready/canceled |
| created_at_utc | timestamptz |
3. 권장 인덱스
documents(issuer_id, filing_date desc)documents(form_type, filing_date desc)events(event_type, event_date desc)events(primary_document_id)market_bars_daily(symbol_id, trade_date desc)market_bars_intraday(symbol_id, timeframe, bar_start_utc desc)short_sale_daily(ticker_raw, trade_date desc)job_runs(job_name, run_date desc)
4. DuckDB / Parquet 권장 구조
data/parquet/
market/daily/year=2026/month=03/*.parquet
market/intraday/date=2026-03-12/*.parquet
events/year=2026/month=03/*.parquet
features/version=v1/date=2026-03-12/*.parquet
labels/horizon=3d/*.parquet
5. SQL DDL 초안
create table if not exists source_registry (
source_name text primary key,
source_type text not null,
enabled boolean not null default true,
config_json jsonb not null default '{}'::jsonb,
created_at_utc timestamptz not null default now(),
updated_at_utc timestamptz not null default now()
);
create table if not exists issuer_master (
issuer_id text primary key,
cik text unique,
ticker text,
issuer_name text not null,
exchange text,
country_code text,
is_active boolean not null default true,
created_at_utc timestamptz not null default now(),
updated_at_utc timestamptz not null default now()
);
create table if not exists symbol_master (
symbol_id text primary key,
issuer_id text references issuer_master(issuer_id),
ticker text not null,
venue text,
asset_type text,
currency text,
start_date date,
end_date date,
is_primary boolean not null default true,
created_at_utc timestamptz not null default now(),
updated_at_utc timestamptz not null default now()
);
create table if not exists job_runs (
job_run_id uuid primary key,
job_name text not null,
source_name text,
run_date date,
status text not null,
started_at_utc timestamptz not null default now(),
finished_at_utc timestamptz,
records_seen integer not null default 0,
records_written integer not null default 0,
records_skipped integer not null default 0,
error_count integer not null default 0,
error_summary text,
metadata_json jsonb not null default '{}'::jsonb
);
나머지 DDL은 migration 파일에서 분리 관리합니다.
6. 스키마 검증 체크포인트
- 동일 accession 문서 중복 적재가 없어야 합니다.
- 동일 symbol/date/day-bar 중복 적재가 없어야 합니다.
- parser output은 event와 별도 테이블에 버전별 보존되어야 합니다.
- raw_object가 없으면 documents를 만들 수 없어야 합니다.
- issuer/symbol 매핑 실패는 nullable 허용하되 경고 로그를 남겨야 합니다.