Skip to content

[Weekly Report] Week of 11/20 #6

@jihodoo

Description

@jihodoo

신규 파일

1. DB/init_tables.sqlto show thinking)

PostgreSQL 데이터베이스 테이블 스키마 정의
· Topsy-turvying… (esc to interrupt · 45s · ↓ 1.8k tokens)
테이블 구조:

  • stocks: 티커 메타데이터 (ticker, company_name, exchange, sector, market_cap)───────────────────────────────────
  • prices: 일일 가격 데이터 (ticker, trade_date, OHLCV)
  • graph_segments: 정규화된 벡터 세그먼트 (ticker, ma_type, segment_start/end, vector[128], volatility)───────────
    ? for shortcuts
    인덱스:
  • prices: ticker, trade_date
  • graph_segments: ticker, ma_type

2. app/db_io.py

PostgreSQL 데이터베이스 연동 모듈

주요 기능:

  • init_pool(): 연결 풀 초기화 (SimpleConnectionPool)
  • get_connection(): Context manager로 안전한 연결 관리
  • fetch_all_segments(): MA20 벡터 세그먼트 일괄 조회 (128차원)
  • fetch_latest_ma20_for_tickers(): 특정 티커들의 최신 MA20 세그먼트 조회
  • get_segment_count(): 전체 세그먼트 수 확인
  • close_pool(): 연결 풀 종료

반환 형식:

vectors: np.ndarray  # Shape: (N, 128)
tickers: List[str]   # 티커 리스트
metadata: List[dict] # {id, ticker, start_date, end_date, volatility}

3. tests/test_similarity_validation.py

유사도 검증 테스트 모듈

테스트 패턴:

  • uptrend: 상승 추세
  • downtrend: 하락 추세
  • peak: 산 모양 (올라갔다 내려옴)
  • valley: 골짜기 (내려갔다 올라옴)
  • sine: 사인파 (주기적 변동)
  • flat: 평평함

평가 지표:

  • Precision@K: 상위 K개 중 정답 비율
  • Recall@K: 전체 정답 중 검색된 비율
  • NDCG@K: 순위를 고려한 정규화된 누적 이득

실행 방법:
python3 tests/test_similarity_validation.py


✏️ 수정된 파일

1. DB/build_segments.py

변경 사항:

  1. 테이블 컬럼명 변경
    - window_start → segment_start
    - window_end → segment_end
    - ma_window → ma_type (값: "MA20", "MA30")
    - length → 제거 (항상 128)
    - vec → vector
    - stdev → volatility
  2. 데이터 처리 변경
    - MA20만 처리 (MA30 제거)
    - DB에서 티커 자동 조회 (fetch_all_tickers())
    - tickers_list.txt 의존성 제거

주요 함수:
def fetch_all_tickers(conn) -> list[str]:
"""DB의 prices 테이블에서 모든 티커 조회"""

실행 결과:
[INFO] Found {N} tickers in DB
[INFO] Processing MA20 only...
[OK] {ticker} MA20: inserted {count} segments


2. DB/ingest_prices.py

변경 사항:

  1. 데이터 소스 우선순위 변경
    tickers_nasdaq.json > tickers_list.txt > NASDAQ API > FALLBACK
  2. 신규 함수 추가
    def read_tickers_json(limit: int = 1000) -> List[str] | None:
    """data/tickers_nasdaq.json에서 상위 limit개 티커 읽기"""
  3. 데이터 수집 설정 변경
    - 티커 수: 200개 → 1000개
    - 수집 기간: 3년 → 18개월 (300 거래일)

파일 경로:
DRS/
├── data/
│ └── tickers_nasdaq.json # 1000개 티커 (Market Cap 기준 정렬)
└── DB/
└── ingest_prices.py


3. app/config.py

추가된 설정:

PostgreSQL Settings

pg_host: str = "172.17.240.1"
pg_port: int = 5433
pg_database: str = "drs_db"
pg_user: str = "postgres"
pg_password: str = ""
pg_min_conn: int = 1
pg_max_conn: int = 10

Data Source Selection

data_source: str = "parquet" # "parquet" or "postgresql"

환경 변수 지원:

  • .env 파일에서 PG_HOST, PG_PORT, DATA_SOURCE 등 오버라이드 가능

4. app/main.py

변경 사항:

  1. startup 이벤트 확장
    @app.on_event("startup")
    def warmup():

    PostgreSQL 연결 풀 초기화 (data_source="postgresql"인 경우)

    if settings.data_source == "postgresql":
    db_io.init_pool(...)
    seg_count = db_io.get_segment_count()
    logger.info(f"{seg_count} segments available")
  2. 신규 엔드포인트: /similar_db
    - PostgreSQL의 graph_segments 테이블에서 직접 벡터 검색
    - 기존 /similar와 동일한 응답 형식
    - Rate limit: 20/minute

요청 예시:
curl -X POST 'http://localhost:8080/similar_db'
-H 'Content-Type: application/json'
-d '{"y": [0.1, 0.2, ..., 0.5]}'

응답:
{
"items": [
{
"ticker": "AAPL",
"score": 0.876,
"rank": 1,
"series_norm": [...], // 128차원
"sketch_norm": [...] // 128차원
}
]
}


5. app/similar.py

변경 사항: ensemble_score() 개선

AS-IS (문제점):
d_norm = -d / len(sketch) # 음수 값
score = alpha * d_norm + beta * c + gamma * s # 범위 불일치

TO-BE (개선):

DTW 거리 → 유사도 변환 (0~1)

d_normalized = d / len(sketch)
dtw_similarity = 1.0 / (1.0 + d_normalized)

Pearson, Cosine: -11 → 01 변환

c_normalized = (c + 1.0) / 2.0
s_normalized = (s + 1.0) / 2.0

앙상블 (모두 0~1 범위)

score = alpha * dtw_similarity + beta * c_normalized + gamma * s_normalized
score = max(0.0, min(1.0, score)) # 클리핑

효과:

  • 모든 유사도 지표가 0~1 범위로 정규화
  • DTW 거리가 유사도로 올바르게 변환
  • 앙상블 스코어의 해석 가능성 향상

🔄 워크플로우 변경

기존 워크플로우 (Parquet 기반)

  1. DB/ingest_prices.py → PostgreSQL에 데이터 적재
  2. app/main.py → /ingest 엔드포인트로 Parquet 생성
  3. app/main.py → /similar 엔드포인트로 검색

신규 워크플로우 (PostgreSQL 직접 사용)

  1. DB/ingest_prices.py → PostgreSQL에 데이터 적재
  2. DB/build_segments.py → graph_segments 테이블에 벡터 생성
  3. app/main.py → /similar_db 엔드포인트로 검색 (Parquet 불필요)

장점:

  • Parquet 생성 단계 생략
  • 대용량 데이터 처리 효율 (1000+ 티커)
  • 실시간 업데이트 가능

📊 테이블 스키마 비교

graph_segments (변경 전 → 변경 후)

컬럼명 (AS-IS) 컬럼명 (TO-BE) 타입 설명
window_start segment_start DATE 세그먼트 시작일
window_end segment_end DATE 세그먼트 종료일
ma_window ma_type VARCHAR(10) "MA20" / "MA30"
length (제거) - 항상 128
vec vector REAL[] 128차원 벡터
stdev volatility REAL 변동성

🧪 테스트 및 검증

  1. 유사도 알고리즘 검증
  • 테스트 패턴 6종 (uptrend, downtrend, peak, valley, sine, flat)
  • 노이즈 레벨별 검증 (low, high)
  • 평가 지표: Precision@K, Recall@K, NDCG@K
  1. 실행 방법

테스트 실행

python3 tests/test_similarity_validation.py

결과 저장 위치

tests/results/validation_results.json


📝 설정 파일 예시

.env

PostgreSQL

PG_HOST=172.17.240.1
PG_PORT=5433
PG_DATABASE=drs_db
PG_USER=postgres
PG_PASSWORD=your_password

Data Source

DATA_SOURCE=postgresql # or "parquet"

API

API_KEY=your_api_key


🚀 실행 가이드

  1. 데이터 수집 (1000 티커)

cd DB
python3 ingest_prices.py

  1. 벡터 세그먼트 생성

python3 build_segments.py

  1. 서버 실행

cd ..
uvicorn app.main:app --host 0.0.0.0 --port 8080 --reload

  1. DB 기반 검색 테스트

curl -X POST 'http://localhost:8080/similar_db'
-H 'Content-Type: application/json'
-d '{"y": [0.1, 0.2, 0.3, 0.4, 0.5]}'


🎯 주요 개선 사항 요약

  1. PostgreSQL 직접 통합: Parquet 중간 단계 제거
  2. 대용량 데이터 처리: 200 → 1000 티커 지원
  3. 테이블 스키마 개선: 명확한 컬럼명, 불필요한 필드 제거
  4. 유사도 스코어 정규화: 0~1 범위 보장, 해석 가능성 향상
  5. 자동 테스트 추가: 객관적 검증 프레임워크
  6. 설정 관리 강화: 환경 변수 기반 유연한 설정

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions