Skip to content

[AI] [FEAT]: PatchTST 중장기 추세 예측 모델 구현#312

Merged
twq110 merged 6 commits intomainfrom
20260319-#311-PatchTST-모델-구현
Mar 25, 2026

Hidden character warning

The head ref may contain hidden characters: "20260319-#311-PatchTST-\ubaa8\ub378-\uad6c\ud604"
Merged

[AI] [FEAT]: PatchTST 중장기 추세 예측 모델 구현#312
twq110 merged 6 commits intomainfrom
20260319-#311-PatchTST-모델-구현

Conversation

@vmgfh878-art
Copy link

@vmgfh878-art vmgfh878-art commented Mar 19, 2026

관련 이슈

#311

작업 내용

  • PatchTST 모델 구현 (architecture.py)
  • 학습 스크립트 작성 (train.py)
  • 파이프라인 연동 어댑터 작성 (wrapper.py)
  • 주봉/월봉 피처 추가 (중장기 추세 개선)
  • 1일/3일/5일/7일 멀티 호라이즌 예측

테스트

  • 로컬 50개 종목 기준 학습 테스트 통과
  • 입출력 형태 확인 ([2,120,17] → [2,4])
  • Loss 감소 확인 (0.684 → 0.639)

Summary by CodeRabbit

  • New Features

    • 모델이 이제 여러 시간대(1, 3, 5, 7일)에 대한 다중 출력 예측을 동시에 제공합니다.
    • 예측 인터페이스가 데이터프레임 입력을 직접 받아 시퀀스 길이 검증 및 기본 출력(중립값)을 반환합니다.
  • Refactor

    • 학습 파이프라인이 데이터 로드→전처리→시퀀스 생성→학습으로 통합되어 단일 실행 엔트리포인트를 제공합니다.
    • 전처리에 기술지표 및 다중 시간대 특징이 포함되고 스케일러가 함께 저장/로딩됩니다.
    • 모델 저장 방식이 가중치·스케일러 분리 저장으로 변경되었습니다.

@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

Warning

Rate limit exceeded

@twq110 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 30 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 20696e92-3910-4433-9dcd-2b4bb29d8f41

📥 Commits

Reviewing files that changed from the base of the PR and between 3d126b1 and 52a78bb.

📒 Files selected for processing (3)
  • .gitignore
  • AI/modules/signal/models/PatchTST/train.py
  • AI/modules/signal/models/PatchTST/wrapper.py

Walkthrough

RevIN 초기화 단순화, PatchTST 모델을 단일 출력에서 다중 지평선 출력으로 변경하고 전체 학습 파이프라인(DataLoader → 전처리 → 시퀀스 생성 → 학습)과 DataFrame 기반 추론 래퍼, 스케일러 저장/로딩을 도입했습니다. 기타 .gitignore 항목이 추가되었습니다.

Changes

Cohort / File(s) Summary
환경 설정
\.gitignore
Python venv(/venv310/), 개인 메모 파일(SISC_개인메모.md), 가중치 디렉토리(AI/data/weights/) 무시 패턴 추가.
모델 아키텍처
AI/modules/signal/models/PatchTST/architecture.py
RevIN 내부 초기화 함수 제거 및 인라인 초기화로 단순화. PatchTST_Model이 n_outputs 인자를 받아 헤드가 nn.Linear(256, n_outputs)로 다중 출력 지원하도록 변경.
학습 파이프라인
AI/modules/signal/models/PatchTST/train.py
엔드투엔드 학습 흐름 도입: load_and_preprocess()build_sequences() → train/val 분할 → 학습 루프. 고정 FEATURE_COLUMNS, 다중 지평선 라벨 생성, MinMaxScaler 적용, 모델 가중치와 scaler 별도 저장, DB용 SISCDataLoader 통합. 기존 train/run 함수 제거 및 train() 엔트리포인트 추가.
추론 래퍼
AI/modules/signal/models/PatchTST/wrapper.py
배열 기반 predict → DataFrame 기반 predict로 변경. 입력 검증, 누락 열 제로 패딩, 스케일러 적용, 마지막 윈도우 사용, 시그모이드 확률 반환(각 지평선). load()scaler_path 옵션 추가, _default_output() 추가, save/load 디렉토리 생성 및 예외 guards 추가.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Trainer as train.py
    participant Loader as SISCDataLoader
    participant Preproc as Preprocessing
    participant SeqBuilder as build_sequences()
    participant Model as PatchTST_Model
    participant Checkpoint as Checkpoint

    User->>Trainer: train()
    Trainer->>Loader: DB에서 OHLCV 로드
    Loader-->>Trainer: raw_data (티커별)
    Trainer->>Preproc: add_technical_indicators(), add_multi_timeframe_features()
    Preproc-->>Trainer: 특징 포함된 DataFrame
    Trainer->>SeqBuilder: MinMaxScaler, seq_len로 시퀀스 생성
    SeqBuilder-->>Trainer: X, y (정규화됨)
    Trainer->>Model: 배치별 학습
    Model-->>Trainer: 손실값 반환
    Trainer->>Checkpoint: model.state_dict(), scaler pickle 저장
Loading
sequenceDiagram
    participant User
    participant Wrapper as PatchTSTWrapper
    participant Scaler as MinMaxScaler
    participant Model as PatchTST_Model

    User->>Wrapper: predict(df)
    Wrapper->>Wrapper: 입력 길이/열 검증, 누락 열 제로 채움
    alt scaler와 충분한 데이터 존재
        Wrapper->>Scaler: transform(window)
        Scaler-->>Wrapper: 스케일된 입력
        Wrapper->>Model: 마지막 seq_len 윈도우 전달
        Model-->>Wrapper: logits (n_outputs)
        Wrapper->>Wrapper: sigmoid -> {patchtst_1d,...}
        Wrapper-->>User: 결과 dict
    else
        Wrapper-->>User: _default_output() (모두 0.5)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Suggested reviewers

  • Kosw6

Poem

🐰 패치가 모여 길을 잰다,
여러 지평선으로 뛰어오르네,
스케일러 손질해 창을 닦고,
데이터에 발자국 남기며,
토끼는 조용히 예측을 읊조린다.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 PatchTST 중장기 추세 예측 모델 구현이라는 주요 변경사항을 명확하게 요약하고 있으며, 변경사항 전체와 관련이 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 20260319-#311-PatchTST-모델-구현

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@AI/modules/signal/models/PatchTST/train.py`:
- Around line 211-218: The pipeline currently fits the MinMaxScaler via
build_sequences(..., fit_scaler=True) on the entire dataset then calls
train_test_split(..., shuffle=True), causing leakage (overlapping windows across
X/Y and tickers). Fix by splitting data into train/val first (use time-ordered
or group-aware split instead of shuffle, e.g., split by timestamp or ticker
groups) and then fit the scaler only on the training set (call scaler.fit on
data used by build_sequences for train or use build_sequences(...,
fit_scaler=True) only for the train partition and build_sequences(...,
fit_scaler=False) or scaler.transform for validation); ensure functions
referenced (MinMaxScaler, build_sequences, train_test_split, X_train/X_val,
y_train/y_val) reflect this ordering so val transforms use the train-fitted
scaler only.
- Around line 125-127: 현재 분기문이 "if len(sub) <= seq_len + max_horizon: continue"로
쓰여 있어 경계 길이(len(sub) == seq_len + max_horizon)인 경우에도 샘플을 건너뛰고 있습니다; 이를 고치려면 해당
조건을 "len(sub) < seq_len + max_horizon"으로 변경해 경계 케이스를 허용하도록 하세요 (참조 변수: sub,
seq_len, max_horizon, 그리고 이후에 계산되는 num_samples).
- Around line 182-187: The broad except swallowing preprocessing errors in the
loop hides which tickers failed; update the try/except around the calls to
add_technical_indicators and add_multi_timeframe_features so that on exception
you log the ticker identifier (from df_t or its source variable) and the
exception details (exception message/trace), increment a failure counter, and if
failures exceed a small threshold abort training (raise or return) instead of
silently continuing; ensure the log includes the symbols processed and use the
existing processed list handling so only successful df_t are appended.
- Around line 172-173: The code currently forces training on only the first 50
tickers by creating tickers_sample = raw_df['ticker'].unique()[:50] and
filtering raw_df, which should be optional; add a config flag (e.g.,
sample_first_n or smoke_test_mode) and default it to disabled so the default
behavior uses all tickers, and only when the flag is set use the existing
sampling logic (apply the tickers_sample selection to raw_df). Update the code
paths that reference tickers_sample/raw_df to honor the new config flag and
document the flag name in the config used by the training entrypoint.

In `@AI/modules/signal/models/PatchTST/wrapper.py`:
- Around line 184-190: The checkpoint currently saves only
self.model.state_dict() in save(), which prevents safe restoration because
load() reconstructs a new model from default config; update save() (and the
similar save at the other location) to also serialize the model/configuration
(architecture hyperparameters used to build the model: e.g., seq_len,
position_embedding size, number_of_heads, patch_size, etc.) alongside the
state_dict (e.g., save a dict {"config": self.config, "state_dict":
self.model.state_dict()}); then modify load() to read that config from the
checkpoint and call build(saved_config) to instantiate the model with the exact
architecture before loading state_dict into it so position_embedding and head
shapes match. Ensure references to save(), load(), build(), self.model,
state_dict, position_embedding, and head are used when locating and changing the
code.
- Around line 35-45: FEATURE_COLUMNS in wrapper.py is ordered differently than
in train.py causing misaligned scaler statistics and wrong predictions; update
wrapper.py to use the exact same feature ordering as build_sequences()/train.py
(ensure ma5_ratio is the second column as in train.py:71-84) by either importing
shared FEATURE_COLUMNS and HORIZONS from a common constants module or by copying
the identical list used by build_sequences(), and verify predict() uses the same
feature positions and scaler fitted order as the training pipeline.
- Around line 5-10: Docstring promises daily_routine.py will call
PatchTSTWrapper.predict, but the pipeline still uses TransformerSignalModel;
update the pipeline to instantiate and use PatchTSTWrapper instead of (or
alongside, behind a flag replacing) TransformerSignalModel: import
PatchTSTWrapper, create wrapper = PatchTSTWrapper(config) in the same
initialization location, call wrapper.load(model_path, scaler_path) where models
are loaded, and replace the TransformerSignalModel.predict call with
wrapper.predict(df) (or add an adapter to match the existing predict call
signature). Ensure any differences in return format are normalized so downstream
code remains compatible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 38d9c266-a635-4ee9-aee9-00cf30653f3b

📥 Commits

Reviewing files that changed from the base of the PR and between 576aee9 and 98e6457.

📒 Files selected for processing (4)
  • .gitignore
  • AI/modules/signal/models/PatchTST/architecture.py
  • AI/modules/signal/models/PatchTST/train.py
  • AI/modules/signal/models/PatchTST/wrapper.py

Comment on lines +5 to +10
역할: 학습된 PatchTST 모델을 파이프라인(daily_routine.py)과 연결

파이프라인이 이 wrapper를 쓰는 방식:
wrapper = PatchTSTWrapper(config)
wrapper.load(model_path, scaler_path)
result = wrapper.predict(df)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
fd 'daily_routine.py$' AI -x sed -n '80,170p' {}
rg -nP --type=py '\bPatchTSTWrapper\b|\bbuild_transformer_model\s*\(' AI

Repository: SISC-IT/sisc-web

Length of output: 4936


🏁 Script executed:

cat -n AI/modules/signal/models/PatchTST/wrapper.py | head -20

Repository: SISC-IT/sisc-web

Length of output: 744


🏁 Script executed:

rg -n 'PatchTSTWrapper' AI/pipelines/daily_routine.py

Repository: SISC-IT/sisc-web

Length of output: 42


파이프라인 통합이 아직 완료되지 않았습니다.

이 wrapper의 docstring(5-10줄)에서는 AI/pipelines/daily_routine.pyPatchTSTWrapper.predict()를 호출하는 방식으로 사용될 것을 명시하고 있습니다. 그러나 현재 daily_routine.pyTransformerSignalModel을 사용하고 있으며, PatchTSTWrapper는 전혀 호출되지 않습니다. 따라서 이 PR의 목표인 파이프라인 통합이 아직 달성되지 않았습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AI/modules/signal/models/PatchTST/wrapper.py` around lines 5 - 10, Docstring
promises daily_routine.py will call PatchTSTWrapper.predict, but the pipeline
still uses TransformerSignalModel; update the pipeline to instantiate and use
PatchTSTWrapper instead of (or alongside, behind a flag replacing)
TransformerSignalModel: import PatchTSTWrapper, create wrapper =
PatchTSTWrapper(config) in the same initialization location, call
wrapper.load(model_path, scaler_path) where models are loaded, and replace the
TransformerSignalModel.predict call with wrapper.predict(df) (or add an adapter
to match the existing predict call signature). Ensure any differences in return
format are normalized so downstream code remains compatible.

@vmgfh878-art vmgfh878-art added the AI AI 이슈 label Mar 19, 2026
@vmgfh878-art vmgfh878-art self-assigned this Mar 19, 2026
@twq110
Copy link
Contributor

twq110 commented Mar 25, 2026

확인 완료 고생했습니다.

@twq110 twq110 merged commit c079e08 into main Mar 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI AI 이슈

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants