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.
228 lines
4.7 KiB
Markdown
228 lines
4.7 KiB
Markdown
# Phase 1 서비스 계약서
|
|
|
|
## 1. 목적
|
|
|
|
이 문서는 각 서비스와 adapter가 어떤 입력을 받고 어떤 출력을 내야 하는지 정의합니다.
|
|
AI 코딩 에이전트는 이 계약을 기준으로 인터페이스를 고정해야 합니다.
|
|
|
|
## 2. 공통 원칙
|
|
|
|
- 모든 서비스는 명시적 입력 객체를 받습니다.
|
|
- 모든 서비스는 typed result 또는 typed error를 반환합니다.
|
|
- 외부 API 호출 결과는 raw 저장 이후에만 정규화됩니다.
|
|
- 서비스는 가능하면 pure function 형태를 유지합니다.
|
|
- DB write는 application layer에서 수행하고, parser/adapter core는 side-effect를 최소화합니다.
|
|
|
|
## 3. 공통 타입
|
|
|
|
### 3.1 FetchRequest
|
|
|
|
```json
|
|
{
|
|
"source": "sec",
|
|
"entity": "issuer|symbol|series|date",
|
|
"key": "0000789019",
|
|
"start_date": "2026-01-01",
|
|
"end_date": "2026-03-31",
|
|
"run_mode": "backfill|daily|replay"
|
|
}
|
|
```
|
|
|
|
### 3.2 FetchResult
|
|
|
|
```json
|
|
{
|
|
"status": "success|partial|failed|skipped",
|
|
"raw_object_ids": ["RAW::..."],
|
|
"records_seen": 3,
|
|
"records_written": 3,
|
|
"warnings": [],
|
|
"errors": []
|
|
}
|
|
```
|
|
|
|
### 3.3 NormalizeResult
|
|
|
|
```json
|
|
{
|
|
"status": "success|failed",
|
|
"canonical_records": [{"...": "..."}],
|
|
"warnings": [],
|
|
"errors": []
|
|
}
|
|
```
|
|
|
|
## 4. SEC adapter 계약
|
|
|
|
### 4.1 입력
|
|
- CIK 또는 accession
|
|
- 기간 또는 개별 filing key
|
|
- run_mode
|
|
|
|
### 4.2 출력
|
|
- submissions raw object
|
|
- filing raw object
|
|
- exhibit raw object list
|
|
- canonical document metadata
|
|
|
|
### 4.3 함수 예시
|
|
|
|
```python
|
|
def fetch_submissions(cik: str) -> FetchResult: ...
|
|
def fetch_filing(accession_no: str, cik: str) -> FetchResult: ...
|
|
def normalize_filing(raw_object_id: str) -> NormalizeResult: ...
|
|
```
|
|
|
|
### 4.4 실패 규칙
|
|
- HTTP 실패 → retryable error
|
|
- 404 → non-retryable warning
|
|
- parsing 실패 → raw는 유지, normalize fail
|
|
|
|
## 5. Alpaca adapter 계약
|
|
|
|
### 5.1 입력
|
|
- symbol list
|
|
- timeframe
|
|
- start/end
|
|
|
|
### 5.2 출력
|
|
- canonical OHLCV record list
|
|
|
|
### 5.3 함수 예시
|
|
|
|
```python
|
|
def fetch_bars(symbols: list[str], timeframe: str, start: str, end: str) -> FetchResult: ...
|
|
def normalize_bars(raw_object_id: str) -> NormalizeResult: ...
|
|
```
|
|
|
|
## 6. FRED adapter 계약
|
|
|
|
```python
|
|
def fetch_series(series_id: str, start: str | None = None, end: str | None = None) -> FetchResult: ...
|
|
```
|
|
|
|
출력:
|
|
- series metadata
|
|
- observation records
|
|
|
|
## 7. FINRA adapter 계약
|
|
|
|
```python
|
|
def fetch_daily_short_volume(trade_date: str) -> FetchResult: ...
|
|
def normalize_daily_short_volume(raw_object_id: str) -> NormalizeResult: ...
|
|
```
|
|
|
|
주의:
|
|
- symbol mapping 실패 가능
|
|
- 원본 ticker_raw는 반드시 유지
|
|
|
|
## 8. Event Parser 계약
|
|
|
|
입력:
|
|
|
|
```json
|
|
{
|
|
"document_id": "DOC::...",
|
|
"source_name": "sec",
|
|
"form_type": "8-K",
|
|
"issuer_id": "ISSUER::...",
|
|
"filing_date": "2026-01-29",
|
|
"accepted_at_utc": "2026-01-29T21:05:00Z",
|
|
"text": "...document text...",
|
|
"metadata": {
|
|
"item_numbers": ["2.02", "7.01"],
|
|
"exhibits": ["EX-99.1"]
|
|
}
|
|
}
|
|
```
|
|
|
|
출력:
|
|
- `parser_event.schema.json`을 만족하는 JSON
|
|
|
|
실패:
|
|
- invalid schema → `validation_status=invalid`
|
|
- parser exception → error object 반환, event 생성 금지
|
|
|
|
## 9. Feature Builder 계약
|
|
|
|
입력:
|
|
- event row
|
|
- related market data
|
|
- optional macro/short volume rows
|
|
|
|
출력 예시:
|
|
|
|
```json
|
|
{
|
|
"event_id": "EVT::...",
|
|
"snapshot_name": "event_v1",
|
|
"snapshot_version": "1.0.0",
|
|
"feature_json": {
|
|
"guidance_direction": "raised",
|
|
"oneoff_penalty": 0,
|
|
"reaction_day_return": 0.042,
|
|
"volume_ratio_20d": 2.3
|
|
}
|
|
}
|
|
```
|
|
|
|
## 10. Job Runner 계약
|
|
|
|
입력:
|
|
- job_name
|
|
- source_name
|
|
- run_date
|
|
- mode
|
|
|
|
출력:
|
|
- `job_runs` 테이블 row 업데이트
|
|
- 로그 스트림
|
|
|
|
상태 전이:
|
|
- pending → running → succeeded
|
|
- pending → running → partial
|
|
- pending → running → failed
|
|
|
|
## 11. 에러 객체 표준
|
|
|
|
```json
|
|
{
|
|
"error_class": "RateLimitError",
|
|
"message": "HTTP 429 from source",
|
|
"retryable": true,
|
|
"source_name": "sec",
|
|
"entity_key": "0000789019",
|
|
"context": {"url": "..."}
|
|
}
|
|
```
|
|
|
|
## 12. 로그 포맷 표준
|
|
|
|
```json
|
|
{
|
|
"timestamp": "2026-03-12T10:00:00Z",
|
|
"level": "INFO",
|
|
"service": "sec_collector",
|
|
"job_run_id": "...",
|
|
"message": "fetched submissions",
|
|
"source": "sec",
|
|
"entity_id": "0000789019",
|
|
"records_seen": 1,
|
|
"records_written": 1
|
|
}
|
|
```
|
|
|
|
## 13. 재시도 계약
|
|
|
|
- source adapter의 네트워크 실패는 최대 3회 지수 백오프
|
|
- validation 실패는 재시도하지 않음
|
|
- DB deadlock/connection issue는 retryable
|
|
- schema mismatch는 raw 보존 후 failed 처리
|
|
|
|
## 14. 금지 규칙
|
|
|
|
- adapter가 임의로 심볼명을 정정하지 말 것
|
|
- parser가 raw text를 수정 저장하지 말 것
|
|
- feature builder가 원문 source를 재호출하지 말 것
|
|
- job runner가 실패를 성공으로 덮어쓰지 말 것
|