Skip to content

[Weekly Report] Week of 11/20 #6

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions