본문으로 건너뛰기
5분 AI.
GITHUB TRENDING PYTHON WEEKLY #13 딥다이브 · 2026-10-23 분석

Kronos 딥다이브
— 숫자로 된 캔들을 읽고, 다음 장면을 생성하는 모델

모델

빠른 판단

무엇
금융 캔들의 가격·거래량을 토큰화해 미래 구간의 캔들을 생성하는 사전학습 시계열 모델
이럴 때
캔들 예측과 자체 데이터 미세조정을 연구하며 토큰화·시계열 평가·데이터 누수 검사를 실험할 때
입력
과거 시점의 시가·고가·저가·종가·거래량·거래대금
결과
미래 구간의 생성 캔들 수치
주가 차트를 문장처럼 읽는다는 말은 무슨 뜻일까요? Kronos는 가격·거래량·거래대금 여섯 수치를 작은 토큰으로 바꾸고, Transformer가 다음 토큰을 생성하도록 학습한 금융 시계열 모델입니다. 이 글은 데이터 전처리 → 이산화 → 자기회귀 생성 → 검증을 실제 함수와 배열 모양으로 따라갑니다. Python 약 11,200줄 중 핵심 모델은 약 1,250줄입니다. 저장소 shiyu-coder/Kronos · ⭐43,318 · 포크 7,137 · MIT · 2026-10-23 GitHub 기준. 소스 설명은 커밋 67b630e 기준입니다.
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

여섯 개의 시장 수치를 토큰으로 압축하고, 다음 시점의 모습을 생성한다

Kronos는 과거의 금융 캔들 여러 개를 입력받아 미래 구간의 캔들 수치를 생성하는 사전학습 모델입니다. 핵심은 가격을 곧바로 맞히는 회귀식 대신, 시장의 움직임을 토큰으로 바꿔 다음 토큰을 예측한다는 점입니다. 여기서 토큰은 한국어 단어나 종목명이 아니라, 학습된 숫자 패턴의 식별자입니다.

입력의 기본 단위는 한 시점의 open, high, low, close, volume, amount입니다. 가격 네 개와 거래량·거래대금 두 개를 묶어 시간순으로 나열합니다. 미래 뉴스, 기업 공시, 주문장, 투자자의 자연어 질문을 받는 범용 챗봇 인터페이스는 핵심 모델에 없습니다.

먼저 알아둘 말
캔들·K-line·OHLCVA
하루 또는 5분 같은 한 구간을 요약한 데이터입니다. O는 시가, H는 고가, L은 저가, C는 종가, V는 거래량, A는 거래대금입니다. 예를 들어 5분봉 400개는 400일이 아니라 5분짜리 관측 400개입니다. 휴장·점심시간이 있으면 실제 경과 시간은 단순 곱셈과 다릅니다.
핵심 비유

캔들을 “시장 동작 카드”로 바꾸고, 다음 카드를 이어 붙입니다

여섯 숫자를 매번 길게 설명하는 대신, 비슷한 움직임에 카드 번호를 붙인다고 생각해 보세요. 토크나이저는 숫자를 카드로 바꾸는 압축기이고, Kronos는 앞 카드들을 보고 뒤 카드를 고르는 이야기 생성기입니다.

마지막에는 선택한 카드를 다시 숫자로 풉니다. 압축에서 정보가 줄고, 생성에서 우연성이 들어갑니다. 따라서 출력은 관측된 미래 사실이 아니라 학습한 패턴을 바탕으로 만든 가능한 경로입니다.

사용자가 만나는 세 가지 객체

객체담당하는 일소스에서 읽을 곳
KronosTokenizer연속 수치 ↔ 두 계층의 정수 토큰 변환model/kronos.py의 encode(), decode()
Kronos앞 토큰을 읽고 다음 토큰의 확률 계산같은 파일의 forward(), decode_s1(), decode_s2()
KronosPredictorDataFrame 검사·정규화·추론·원래 단위 복원같은 파일의 predict(), predict_batch()
이 글을 읽고 얻을 것

모델 수식을 모두 외우기보다, 한 DataFrame이 어떤 모양의 텐서와 토큰으로 바뀌는지 설명하는 것을 목표로 삼으세요. 그다음 “학습 때 쓴 정보가 추론 때도 있는가?”를 묻는 단계까지 가면, 다른 시계열 저장소도 훨씬 잘 읽을 수 있습니다.

2왜 주목받는가

금융 데이터에 맞춘 표현 학습과, 작은 코드로 보이는 전체 연구 흐름

2026-10-23 분석 대상은 GitHub Trending Python Weekly 13위의 Kronos입니다. 다만 순위와 스타 수만으로 특정 주간의 유입 원인까지 알 수는 없습니다. 여기서는 공개된 연구와 코드가 관심을 끌 만한 이유를 세 가지로 나눠 봅니다.

  1. 금융 캔들 전용 표현: 종가 한 줄뿐 아니라 가격 네 개와 거래 활동을 함께 압축합니다. 여섯 채널을 하나의 시장 상태로 학습하는 구조를 코드에서 확인할 수 있습니다.
  2. 사전학습 모델의 재사용: README는 mini·small·base 가중치를 공개 대상으로 안내합니다. 처음부터 거대한 데이터셋을 모으지 않고도 추론과 미세조정의 구조를 공부할 수 있습니다.
  3. 연구에서 화면까지 연결: 토크나이저, 예측기, 두 학습 경로, Qlib 백테스트, Flask 화면이 같은 저장소에 있습니다. 모델 한 개를 서비스 형태로 감쌀 때 생기는 문제도 함께 보입니다.

Kronos 논문은 45개 거래소의 120억 건이 넘는 K-line으로 사전학습했다고 설명합니다. 가격 예측의 RankIC 개선도 보고하지만, 이는 논문의 데이터·비교 모델·실험 조건에 대한 결과입니다. 전체 사전학습 원자료가 이 저장소에 들어 있는 것은 아니므로, 코드만으로 해당 결과 전체를 재현했다고 볼 수 없습니다.

다른 접근과 비교하면 무엇을 배우기 좋은가

다음 표는 설계 관점의 비교입니다. Chronos는 2024년 원 논문, TimesFM은 2024년 수정 논문의 구조를 기준으로 하며, 각 프로젝트의 모든 후속 버전을 묶어 평가하지 않습니다.

접근수치를 다루는 방식Kronos에서 더 잘 보이는 학습 지점
마지막 값 유지 마지막 관측값을 미래에도 반복하는 단순 기준선 토큰 압축과 사전학습이 실제로 추가 가치를 만드는지 비교할 수 있음
직접 회귀 모델 LSTM·Transformer 등이 연속적인 미래 수치를 직접 출력하도록 구성 연속값 오차와 토큰 분류 오차를 분리하는 두 단계 학습을 관찰
Chronos 원 모델 스케일링 후 고정 구간으로 양자화하여 언어 모델로 학습 고정 구간 대신 학습된 다변량 압축기와 계층형 토큰을 사용
TimesFM 초기 모델 연속 시계열을 패치로 묶어 decoder 기반 모델에 입력 시간 묶음과 별개로, 한 캔들의 상태를 이산 토큰으로 표현하는 선택을 비교

비교 근거: Chronos 원 논문 소개, TimesFM 초기 논문. 금융 입력에 잘 맞는 설계라는 사실이 모든 데이터에서 더 높은 정확도를 보장하지는 않습니다.

이 저장소의 교육적 가치는 예측선 자체보다, 표현 학습과 생성 모델을 하나의 데이터 파이프라인으로 연결해 볼 수 있다는 데 있습니다.

성능 숫자를 읽는 법
제로샷과 RankIC
제로샷은 대상 데이터에 추가 학습하지 않고 이미 배운 모델을 적용하는 방식입니다. RankIC는 예측 점수의 순위와 실제 결과의 순위가 얼마나 함께 움직이는지 보는 지표입니다. 수익률이나 가격 오차와 같은 값이 아니므로, “RankIC 개선”을 “수익률 개선”으로 바꾸어 읽으면 안 됩니다.

3기술 스택 전체 지도

중심은 PyTorch 연구 코드, 화면은 Flask와 단일 HTML 템플릿

3-1. 백엔드·모델·데이터 처리

루트 requirements.txt가 기본 의존성 선언입니다. pyproject.toml로 빌드되는 패키지 구조는 없습니다. README 기준 Python 요구 버전은 3.10 이상이며, 아래 버전은 의존성 파일에 적힌 값입니다.

기술실제 선언이 저장소에서 하는 일
PyTorchtorch>=2.0.0텐서·자동미분·Attention·분산 학습
NumPynumpy — 버전 미고정열별 통계·정규화·예측 경로 평균
pandaspandas와 pandas==2.2.2 중복CSV·시간 특성·DataFrame 반환; 고정 선언도 함께 적용됨
einopseinops==0.8.1양자화 손실에서 그룹 단위 텐서 재배열
Hugging Face Hubhuggingface_hub==0.33.1PyTorchModelHubMixin으로 설정·가중치 읽기와 저장
Safetensorssafetensors==0.6.2Hub 모델 가중치 직렬화 경로 지원
시각화·진행 표시matplotlib==3.9.3, tqdm==4.67.1예측 비교 그림·시간 단계 진행률

3-2. 프론트엔드·HTTP 계층

webui/templates/index.html은 1,238줄의 HTML 한 파일입니다. 인라인 JavaScript 약 600줄, 인라인 CSS 약 430줄이 포함되며 이 수치는 HTML 줄 수와 중복됩니다. React·Vue·TypeScript 빌드가 아니라, Flask가 템플릿을 전달하고 JavaScript가 JSON API를 호출하는 구조입니다.

구성실제 버전·경로읽어 볼 연결점
Flaskflask==2.3.3webui/app.py의 index(), load_model(), predict()
CORS 확장flask-cors==4.0.0CORS(app) 호출로 교차 출처 요청 설정
차트Python plotly==5.17.0create_prediction_chart()가 그림을 JSON으로 직렬화
브라우저 라이브러리Plotly의 plotly-latest.min.js, Axios의 버전 없는 CDN 주소템플릿의 Axios API 호출과 Plotly.newPlot(); 브라우저 쪽 버전은 고정되지 않음
Web UI 전용 요구torch>=2.1.0, numpy>=1.26.0기본 파일보다 하한이 높음; 출처는 webui/requirements.txt

3-3. 학습·인프라·빌드의 실제 경계

구성 비유

PyTorch가 엔진, pandas가 재료 손질대라면 Flask와 HTML은 계기판입니다. Qlib는 별도의 주행 시험장입니다. 계기판이 있다는 사실만으로 엔진의 성능 측정이나 운영 배포까지 끝난 것은 아닙니다.

환경 재현에서 놓치기 쉬운 점

두 requirements 파일은 완전한 잠금 파일이 아닙니다. 기본 의존성 설치만으로 모든 예제·학습·테스트가 준비된다고 볼 수 없습니다. 특히 use_comet=False로 바꾸어도 Qlib 학습 스크립트의 최상위 import comet_ml은 남습니다. 실행 목적별 import와 필요 데이터를 먼저 구분해야 합니다.

4아키텍처 심화 분석

DataFrame 하나가 다시 미래 DataFrame으로 나오는 길을 추적한다

아래 구조에서 B는 한 번에 처리하는 시계열 수, T는 과거 길이, H는 예측 길이입니다. S는 시계열 하나당 생성할 경로 수입니다. 모델의 실질적인 입력 채널은 여섯 개이고, 시간 정보는 별도의 다섯 채널로 전달됩니다.

[CSV / pandas DataFrame]                [과거·미래 시각]
           |                                 |
           v                                 v
 KronosPredictor.predict()          calc_time_stamps()
 검사·열 보완·정규화·clip           분/시/요일/일/월
           |                                 |
           | x: (B,T,6)                       | (B,T,5), (B,H,5)
           +----------------+----------------+
                            v
              auto_regressive_inference()
              경로 복제: B --> B*S
                            |
                            v
               KronosTokenizer.encode()
               Linear --> Transformer --> BSQ
                            |
                     s1, s2: (B*S,T)
                            |
              +-------------v-----------------+
              | 과거 토큰 + 시간 임베딩       |
              | Kronos.decode_s1() --> s1 추출 |
              | Kronos.decode_s2() --> s2 추출 |
              | 새 토큰을 창에 추가           |
              +-------------+-----------------+
                            | H회 반복
                            v
                KronosTokenizer.decode()
                마지막 창의 수치 복원
                            |
                    S개 경로의 평균
                            |
                 원래 단위로 역정규화
                            v
              미래 DataFrame: (H,6) / 시계열

[학습] Qlib/CSV --> Dataset --> 토크나이저 복원 학습
                          --> 다음 토큰 예측 학습
[화면] HTML --> Flask JSON API --> Predictor --> 차트 JSON
[저장] Hub 가중치 / 학습 체크포인트 / 예측 결과 JSON

4-1. 설계 패턴 ① — 압축기와 예측기의 책임 분리

KronosTokenizer.forward()는 입력을 선형 변환하고 Transformer를 거쳐 s1_bits + s2_bits 차원으로 줄입니다. model/module.py::BSQuantizer.forward()는 이를 정규화한 뒤 이진 양자화를 수행합니다. encode(..., half=True)는 앞부분과 뒷부분의 비트를 각각 정수 토큰으로 돌려줍니다.

공개 Tokenizer-base 설정은 d_in=6, d_model=256, s1_bits=10, s2_bits=10, group_size=4입니다. 각 계층의 후보는 1,024개이며, 두 번호를 합친 이론적 조합은 2의 20승입니다. 백만 개의 학습 가능한 코드 벡터를 그대로 저장한다는 뜻은 아닙니다.

# model/module.py::BinarySphericalQuantizer.quantize() 핵심
zhat = torch.where(z > 0, 1, -1)
quantized = z + (zhat - z).detach()

# BSQuantizer는 먼저 F.normalize(z, dim=-1)를 적용한다.
# 순전파에서는 부호로 바꾸고, 역전파에서는 z로 기울기를 보낸다.
어려운 한 줄 해설
양자화와 직선 통과 추정기
양자화는 연속적인 수치를 제한된 번호로 바꾸는 일입니다. 부호를 고르는 연산은 보통의 방식으로 미분하기 어렵습니다. 위 detach() 표현은 계산할 때는 이산값을 쓰되 학습 신호는 원래 값으로 통과시키는 방법입니다. 흔히 직선 통과 추정기라고 부릅니다.

토크나이저 학습은 z_pre와 z라는 두 복원값을 만듭니다. 앞 계층만으로도 원래 입력을 복원하게 하고, 두 계층을 모두 쓰면 더 풍부하게 복원하게 합니다. finetune/train_tokenizer.py::train_model()의 손실은 (MSE(z_pre,x) + MSE(z,x) + bsq_loss) / 2입니다. 양자화 손실에는 표현이 양자화 결과에 가까워지도록 하는 항과 코드 사용 분포를 조절하는 항이 들어갑니다.

공개 설정의 n_enc_layers=4를 그대로 “Transformer 블록 네 개”라고 읽는 것도 주의해야 합니다. 생성자는 range(self.enc_layers - 1)로 블록을 만듭니다. 디코더도 같은 방식입니다. 설정 이름보다 실제 생성 코드를 읽는 습관을 배우기 좋은 대목입니다.

4-2. 설계 패턴 ② — 한 캔들의 두 토큰을 조건부로 생성

HierarchicalEmbedding.forward()는 s1·s2 임베딩을 이어 붙인 뒤 선형 투영합니다. 여기에 TemporalEmbedding이 분·시·요일·일·월 임베딩의 합을 더합니다. 그 결과를 TransformerBlock들이 읽습니다. 이 블록은 RMSNorm → Attention → 잔차 연결 → RMSNorm → 게이트형 FeedForward → 잔차 연결 순서입니다.

# model/kronos.py::auto_regressive_inference() 흐름을 축약
s1_logits, context = model.decode_s1(s1_ids, s2_ids, stamp)
s1_next = sample_from_logits(s1_logits[:, -1, :], ...)
s2_logits = model.decode_s2(context, s1_next)
s2_next = sample_from_logits(s2_logits[:, -1, :], ...)

# 개념적인 확률 분해 — 정확한 미래값을 확정하는 식이 아니다.
P(다음 토큰 쌍 (s1, s2) | 과거)
  = P(s1 | 과거) * P(s2 | 과거, 이번에 뽑은 s1)

DualHead는 s1·s2의 출력층을 따로 두고, DependencyAwareLayer는 s1 임베딩을 질의로 사용해 문맥을 참조합니다. 핵심은 두 번호를 독립적으로 뽑지 않는다는 점입니다. 앞 계층을 먼저 정한 뒤 뒤 계층의 확률을 계산합니다.

Kronos.forward()에는 use_teacher_forcing 옵션도 있습니다. 그러나 finetune/train_predictor.py의 실제 호출은 이 옵션을 넘기지 않습니다. 기본 분기에서는 모델이 뽑은 s1으로 s2를 조건화합니다. 정답 s1을 항상 넣어 학습한다고 단정하면 구현과 달라집니다.

MultiHeadAttentionWithRoPE.forward()는 PyTorch의 scaled_dot_product_attention(..., is_causal=True)를 사용합니다. 시간 순서 뒤쪽을 보지 못하도록 하는 장치입니다. 위치 관계를 표현하는 RoPE와 달력 정보를 표현하는 시간 임베딩은 서로 다른 역할입니다.

4-3. 설계 패턴 ③ — Predictor가 복잡한 입력 계약을 감싼다

KronosPredictor.predict()는 사용자와 모델 사이의 창구입니다. DataFrame 여부와 필수 가격 열을 검사하고, 거래량·거래대금 열을 보완한 뒤 여섯 입력 열의 결측값을 검사합니다. 열별 평균을 빼고 표준편차에 1e-5를 더한 값으로 나눕니다. 기본 clip=5 범위로 자르고, 결과는 같은 통계로 되돌립니다.

입력 상태predict()·predict_batch()의 실제 동작
가격 열 누락시가·고가·저가·종가 중 하나라도 없으면 오류
volume 없음volume과 amount를 모두 0으로 설정. 기존 amount가 있어도 덮어씀
거래량만 있음amount = volume × OHLC 평균으로 근사
두 거래 열 모두 있음해당 수치를 입력에 사용
열 보완 후 입력 열에 NaN여섯 입력 열 중 NaN이 남으면 오류. volume이 없어서 덮어쓴 기존 amount의 NaN은 검사 대상에서 사라짐. 무한대·시간 정렬·경제적 타당성까지 모두 검사하는 것은 아님

README의 배치 설명에는 선택 열이 없으면 0으로 채운다는 안내가 있지만, 코드는 위처럼 경우를 나눕니다. 또 calc_time_stamps()는 .dt 접근자를 쓰므로, 문서화된 일부 타입 표현만 믿기보다 datetime형 pandas Series를 전달하는 편이 정확합니다.

4-4. 설계 패턴 ④ — 제한된 창에서 반복 생성하고 경로를 평균

auto_regressive_inference()는 처음 입력을 sample_count만큼 복제합니다. 매 단계 s1·s2를 생성하고 토큰 버퍼에 추가하며, 버퍼가 차면 torch.roll(..., shifts=-1)로 오래된 항목을 밀어냅니다. 마지막에는 수치로 복원한 경로들을 np.mean(..., axis=1)로 평균합니다.

sample_count를 늘려도 현재 공개 API가 반환하는 것은 여러 경로의 평균이며, 경로별 분포나 신뢰구간은 반환하지 않습니다. 여러 경로를 평균했다는 사실과 불확실성을 정량화했다는 사실은 구분해야 합니다.

슬라이딩 창 비유

긴 두루마리 위에 작은 창을 놓고 한 칸씩 미는 방식입니다. 다음 칸을 만들 때 보는 범위는 제한되지만, 창 밖의 과거를 사전에 읽고 정리하는 비용은 남을 수 있습니다. “입력을 자른다”는 설명을 볼 때는 어느 단계에서 자르는지까지 확인하세요.

5디렉토리 구조 해부

핵심 모델, 두 종류의 학습 경로, 예제와 데모를 구분해서 읽는다
Kronos/
|-- model/                  핵심 신경망과 예측 API
|   |-- kronos.py           Tokenizer / Kronos / Predictor
|   |-- module.py           BSQ / Attention / 임베딩 / 손실
|   `-- __init__.py         공개 객체와 get_model_class()
|-- finetune/               Qlib 기반 미세조정·백테스트
|   |-- config.py           경로·기간·하이퍼파라미터
|   |-- dataset.py          QlibDataset와 과거 기반 정규화
|   |-- qlib_data_preprocess.py
|   |-- train_tokenizer.py
|   |-- train_predictor.py
|   |-- qlib_test.py         예측 점수와 포트폴리오 평가
|   `-- utils/              DDP·시드·모델 크기 도우미
|-- finetune_csv/           CSV 기반 별도 미세조정 경로
|   |-- configs/            YAML 설정 예시
|   |-- data/               홍콩 종목 5분봉 CSV 예시
|   |-- config_loader.py    YAML 읽기·출력 경로 계산
|   |-- finetune_base_model.py
|   |-- finetune_tokenizer.py
|   `-- train_sequential.py 두 단계 순차 실행
|-- examples/               추론·데이터 수집·GUI·백테스트 예제
|-- tests/                  CPU 회귀 테스트
|   `-- data/               입력 CSV·기대 출력·생성 도구
|-- webui/                  Flask 앱과 실행 도우미
|   |-- templates/index.html
|   |-- prediction_results/ 예측 결과 JSON 예시
|   `-- requirements.txt
|-- figures/                README용 그림
|-- requirements.txt
|-- README.md
`-- LICENSE
읽는 목적권장 경로구분할 점
첫 예측 흐름examples/prediction_example.py → predict()예제가 참조하는 루트 data/XSHG_5min_600977.csv는 커밋에 포함되지 않음
모델 원리model/kronos.py → model/module.py핵심 Python 3파일, 총 1,249줄
학습 원리finetune/dataset.py → 두 finetune/train_*.pyQlib 데이터와 CUDA 분산 환경을 전제하는 경로
CSV로 확장finetune_csv/config_loader.py → CustomKlineDatasetQlib 경로와 정규화·장치 선택·설정 규칙이 같지 않음
결과를 화면에webui/app.py → webui/templates/index.html모델 함수와 HTTP 계층 사이에서 데이터가 다시 가공됨

저장소 전체는 파일 92개이며 Python 30파일·11,196줄입니다. 그중 examples/가 6,060줄로 약 54%를 차지합니다. 따라서 전체 줄 수만 보고 핵심 모델이 거대하다고 판단할 필요는 없습니다. 우선 API 한 함수 → 그 함수가 호출하는 모델 → 학습 데이터 순서로 읽으면 범위를 줄일 수 있습니다.

예제 CSV가 있는 곳과 기본 예제가 찾는 경로는 서로 다릅니다. tests/data/regression_input.csv는 입력 계약을 공부할 때 유용하고, finetune_csv/data/HK_ali_09988_kline_5min_all.csv는 CSV 학습 형식의 실제 예시입니다. 저장소에 일부 시세가 있다고 해서 모든 예제가 그대로 준비되는 것은 아닙니다.

6학습 포인트 (기술별)

라이브러리 이름보다, 코드가 지키는 계약과 깨지는 경계를 배운다

6-1. PyTorch — 배치·시간·특성 축을 끝까지 보존하기

초보자가 가장 자주 놓치는 것은 텐서의 축입니다. Qlib 기본 설정은 lookback_window=90, predict_window=10이고, QlibDataset.window는 여기에 1을 더한 101입니다. 다음 토큰을 정답으로 만들 때 한 칸이 필요하기 때문입니다.

# finetune/train_predictor.py::train_model()의 학습 준비
# batch_x: (B, 101, 6), 각 token_seq: (B, 101)
token_seq_0, token_seq_1 = tokenizer.encode(batch_x, half=True)
token_in = [token_seq_0[:, :-1], token_seq_1[:, :-1]]
token_out = [token_seq_0[:, 1:], token_seq_1[:, 1:]]
# token_in: t=0..99, token_out: t=1..100
# s1_logits: (B, 100, 1024) — 공개 small 설정 기준

커밋 67b630e의 학습 루프는 batch_x를 장치에 옮길 때 배치 축을 유지합니다. 크기가 1인 축을 무조건 없애는 squeeze()를 넣으면, 마지막 배치만 1개일 때 배열 모양이 달라질 수 있습니다. 반면 단일 예측 API에서 쓰는 squeeze(0)는 반환을 위해 의도적으로 배치 축을 제거하는 자리입니다.

실습 아이디어

실제 가중치 없이 종이에 (1,101,6), (2,101,6)를 적고 squeeze()와 squeeze(0)의 결과를 각각 써 보세요. 이어서 reshape(-1, vocab_size)가 교차 엔트로피 계산을 위해 어떤 축을 합치는지 설명해 보세요.

6-2. pandas·NumPy — 정규화도 예측 시스템의 일부

finetune/dataset.py::QlibDataset.__getitem__()는 처음 90개 관측으로 평균·표준편차를 계산하고, 그 통계를 전체 101개에 적용합니다. 반면 finetune_csv/finetune_base_model.py::CustomKlineDataset.__getitem__()는 전체 창으로 평균·표준편차를 계산합니다. 후자는 미래 평가 구간의 값이 과거 입력 변환에 영향을 줄 수 있는 구조입니다.

# QlibDataset의 원리
past_x = x[:lookback_window]
mean = past_x.mean(axis=0)
std = past_x.std(axis=0)
normalized = (x - mean) / (std + 1e-5)

# CSV 경로의 현재 원리 — x에는 뒤쪽 구간도 포함된다.
mean_all = x.mean(axis=0)
std_all = x.std(axis=0)

모델이 미래를 보지 않도록 Attention을 가려도, 전처리 통계에 미래값이 섞이면 평가의 공정성은 무너질 수 있습니다. 위 두 경로를 비교하면 데이터 누수가 모델 바깥에서도 생긴다는 사실을 배울 수 있습니다.

Qlib 경로도 별도 점검이 필요합니다. finetune/config.py의 학습 기간은 2022-12-31까지인데 검증 기간은 2022-09-01부터 시작합니다. 주석은 과거 문맥 확보를 위한 중첩이라고 설명하지만, prepare_dataset()는 날짜 마스크로 자르고 QlibDataset는 그 안에서 창을 고릅니다. 중첩 구간이 문맥으로만 쓰이도록 정답 위치를 제한하는 장치는 이 두 함수에 보이지 않습니다.

실습 아이디어

과거 4개는 고정하고 미래 2개만 10배로 바꾼 장난감 배열을 만드세요. 과거 기준 정규화와 전체 기준 정규화에서 처음 4개의 변환값이 달라지는지 비교하면 됩니다. 이어서 학습·검증 창의 정답 날짜 집합이 겹치는지도 점검해 보세요.

6-3. Transformer — 같은 블록 안의 서로 다른 역할 구분

구현배울 질문작은 실습
RMSNorm값의 크기를 조절하는 정규화가 왜 블록 앞에 있을까?수치 3개로 제곱 평균의 제곱근을 직접 계산
RotaryPositionalEmbedding순서 정보와 날짜 정보는 왜 따로 필요할까?같은 가격열의 시각만 한 시간 옮겼을 때 입력 차이를 설명
FeedForwardsilu(w1(x)) * w3(x)의 곱은 무엇을 제어할까?두 갈래 변환과 최종 투영의 입출력 차원을 도식화
TemporalEmbeddinglearn_te가 고정·학습 임베딩 중 무엇을 선택할까?분·시·요일·일·월 임베딩의 항목 수 60·24·7·32·13을 확인

공개 Kronos-small 설정은 d_model=512, n_heads=8, n_layers=8, ff_dim=1024, learn_te=true입니다. 한 Attention 헤드의 폭은 512÷8=64입니다. 생성자의 일반 매개변수와 실제 공개 체크포인트의 설정을 함께 읽어야 구체적인 모양이 보입니다.

6-4. 학습 루프 — 손실·기울기·분산 처리를 나누어 읽기

finetune/train_predictor.py::train_model()는 토크나이저를 torch.no_grad() 안에서 실행하고, 예측기만 AdamW로 갱신합니다. DualHead.compute_loss()는 s1·s2 교차 엔트로피의 평균을 사용합니다. OneCycleLR가 학습률을 바꾸고, 기울기는 최대 노름 3.0으로 제한합니다.

setup_ddp()와 DistributedSampler, dist.all_reduce()를 따라가면 장치별 계산과 전체 검증 손실 집계를 구분할 수 있습니다. 가장 좋은 검증 손실을 만났을 때 rank 0 프로세스가 save_pretrained()로 체크포인트를 저장합니다.

이름과 실제 계산을 대조하기

토크나이저 학습의 accumulation_steps는 여러 DataLoader 배치를 모으는 대신 한 배치를 잘라 여러 번 역전파하는 방식입니다. 따라서 출력 메시지의 “배치 크기 × 누적 횟수”를 실제 표본 수로 그대로 해석하면 안 됩니다. 배치 크기가 누적 횟수로 나누어떨어지지 않으면 정수 나눗셈 때문에 남는 표본도 확인해야 합니다.

실습 아이디어

배치 50개, 누적 횟수 2와 3을 가정해 start_idx·end_idx를 적으세요. 역전파마다 몇 표본을 보는지와, 옵티마이저를 한 번 갱신하기 전 총 몇 표본을 보는지가 어떻게 다른지 계산해 보세요.

6-5. 테스트 — 소프트웨어 회귀와 예측 성능을 구분하기

tests/test_kronos_regression.py는 CPU·시드 123·문맥 길이 256/512·top_k=1 조건을 사용합니다. 모델과 토크나이저는 각각 MODEL_REVISION, TOKENIZER_REVISION으로 Hub 리비전을 고정합니다. 첫 테스트는 저장된 CSV 출력과 상대 허용오차 1e-5로 비교하고, 다른 테스트는 정해진 표본의 평균 MSE가 기대값과 가까운지 확인합니다.

이런 테스트는 코드 변경 후 동작이 달라졌는지 찾는 데 적합합니다. 반면 새로운 시장에서 기준선보다 잘 예측하는지, 거래 비용을 감안해도 의미가 있는지는 별도의 평가입니다. 고정 출력 재현 → 보지 않은 기간의 예측 → 전략 평가는 서로 다른 검증 단계입니다.

6-6. Flask·웹 개발 — API를 감싸며 바뀌는 의미 읽기

webui/app.py::predict()는 핵심 Predictor와 같은 이름이지만 책임이 다릅니다. HTTP 본문을 읽고 파일을 열며, 날짜 구간과 표시용 데이터를 만든 뒤 모델에 넘깁니다. 다음 차이를 실제 코드와 대조하면 서비스 계층의 역할이 선명해집니다.

표면적인 안내코드에서 확인할 사실
최신 데이터 예측시작일을 주지 않은 분기는 df.iloc[:lookback]를 사용함. 마지막 구간이 아니라 파일 앞부분임
거래대금 열 지원로더는 amount를 읽지만 예측용 required_cols에서는 제외함. Predictor에서 다시 근사될 수 있음
모델이 없으면 모의 예측안내 문구에는 남아 있지만 예측 라우트는 모델이 준비되지 않으면 HTTP 400을 반환함
데이터 자동 탐색load_data_files()는 루트 data/를 탐색함. CSV 학습 예제 폴더를 자동으로 탐색하지 않음

실습으로는 “입력 CSV → 모델에 전달한 열·시각 → 차트에 표시한 시각”을 한 줄씩 대응시켜 보세요. 화면이 그럴듯한 것과 데이터의 의미가 일관된 것은 다른 문제입니다.

7하드웨어 / 시스템 요구사항

코드 읽기, 소규모 추론, 미세조정은 필요한 자원이 다르다

README는 Python 3.10 이상을 안내하지만, GPU별 최소 VRAM이나 처리 속도 표는 제공하지 않습니다. 따라서 아래에서 코드가 선택할 수 있는 장치, 가중치만의 산술적 크기, 실험 설계 제안을 구분합니다. 확인되지 않은 “몇 GB면 반드시 된다”는 최소 사양으로 읽으면 안 됩니다.

모델파라미터·문맥 길이FP32 가중치만 계산공개 상태
Kronos-mini4.1M · 2,048약 16.4 MBREADME상 공개, Tokenizer-2k와 짝
Kronos-small24.7M · 512약 98.8 MBREADME상 공개, Tokenizer-base와 짝
Kronos-base102.3M · 512약 409.2 MBREADME상 공개, Tokenizer-base와 짝
Kronos-large499.2M · 512약 1,996.8 MBREADME상 미공개

모델 크기·문맥 길이·공개 여부의 출처는 README의 Model Zoo입니다. 저장량은 표의 반올림된 파라미터 수에 4바이트를 곱한 십진 MB 계산입니다. 토크나이저 가중치, 중간 텐서, Attention, 라이브러리, 학습 기울기·옵티마이저 상태는 포함하지 않았습니다. 다운로드 파일의 실제 크기나 최소 RAM·VRAM 측정값이 아닙니다.

7-1. 목적별 환경 선택

목적필요한 환경·근거처음 줄일 값
소스·CSV 읽기일반 텍스트 편집기와 데이터 도구. GPU·가중치 없이 학습 가능읽을 파일 범위를 핵심 모델과 Dataset으로 제한
작은 추론KronosPredictor.__init__()는 CUDA → MPS → CPU 순으로 자동 선택lookback=256, pred_len=8, sample_count=1부터 실험
Web UIFlask 프로세스에 모델도 함께 로드. HTTP 요청과 추론 자원이 같은 프로세스에 있음한 사용자·한 요청 기준으로 먼저 측정
Qlib 미세조정setup_ddp()의 NCCL과 cuda:local_rank 선택 때문에 CUDA 학습 환경을 전제batch_size, 창 길이, 데이터 로더 작업자 수
CSV 미세조정SequentialTrainer._setup_device()에 CUDA·CPU 분기가 있음. MPS 학습 선택 분기는 없음설정 경로와 데이터 분할을 검토한 뒤 작은 배치로 설계

CPU·MPS 분기가 있다는 사실은 모든 운영체제·PyTorch 버전에서 실행이 검증되었다는 의미는 아닙니다. 첫 추론은 CPU의 작은 입력으로 기능을 확인하고, GPU가 필요해지면 같은 입력·샘플링 조건으로 시간과 메모리를 비교하는 순서를 권합니다.

7-2. 메모리를 키우는 세 개의 손잡이

파라미터 수가 작은 모델이라도 문맥 길이와 배치·샘플 수가 커지면 추론 메모리와 시간이 크게 늘어날 수 있습니다. 이 구현은 여러 경로를 실제 배치로 복제하므로, 한 시계열의 sample_count=5는 한 경로와 같은 양의 작업이 아닙니다.

7-3. 실습 환경을 준비할 때의 순서

다음은 기본 추론을 위한 준비 명령 예시입니다. Web UI·Qlib·CSV 학습·테스트의 추가 의존성은 3절의 구분대로 따로 확인합니다. 저장소 코드와 모델 가중치의 버전도 각각 기록하세요.

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
# Web UI를 공부할 때는 webui/requirements.txt도 확인한다.
# from_pretrained()의 첫 호출은 Hub 가중치를 내려받을 수 있다.
데모 서버의 실행 설정

webui/app.py와 webui/run.py의 실행 설정은 debug=True, host='0.0.0.0', port=7070입니다. 인증·요청 큐·모델별 자원 격리까지 갖춘 운영 서버 구성은 아닙니다. 외부 공개 전에 디버그 모드·바인딩·파일 경로 입력·동시 추론 정책을 별도로 설계해야 합니다.

8직접 해볼 수 있는 실습 과제

작은 입력 확인에서 시작해, 재현과 공정한 평가까지 — 난이도별 다섯 과제

다음 예시는 저장소 루트에서 읽는 경로를 사용합니다. 처음에는 원본 파일을 보존하고 별도 실험 파일에서 진행하세요. 목표는 높은 수익률이 아니라, 입력 계약·배열 모양·검증 조건을 설명할 수 있는 결과를 만드는 것입니다.

과제 1 입문 · 30~60분

CSV를 읽고, 모델에 넣어도 되는 데이터인지 판단하기

tests/data/regression_input.csv의 열과 시간 순서를 검사하세요. 가중치를 읽지 않아도 할 수 있는 과제입니다. 단위·시간 간격·결측값·중복 시각을 적은 짧은 데이터 설명서를 만듭니다.

import pandas as pd

df = pd.read_csv(
    "tests/data/regression_input.csv", parse_dates=["timestamps"]
)
cols = ["open", "high", "low", "close", "volume", "amount"]
print(df[cols].dtypes)
print("결측값:", df[cols].isna().sum().to_dict())
print("시간순:", df["timestamps"].is_monotonic_increasing)
print("중복 시각:", df["timestamps"].duplicated().sum())
valid_high = df["high"].ge(df[["open", "close", "low"]].max(axis=1))
valid_low = df["low"].le(df[["open", "close", "high"]].min(axis=1))
print("가격 관계 위반:", int((~(valid_high & valid_low)).sum()))

완료 기준: 정상 입력과 오류 입력을 각각 한 가지 이상 설명하고, “핵심 Predictor가 검사하는 조건”과 “직접 추가한 조건”을 구분합니다. 위 코드는 숫자형·결측값 결과를 먼저 확인한 뒤 가격 관계를 해석해야 합니다.

과제 2 입문 · 1~2시간 + 가중치 준비

짧은 예측 한 번으로 API 계약 확인하기

small 모델과 Tokenizer-base를 짝지어 문맥 256개, 예측 8개를 사용합니다. 아래 리비전은 회귀 테스트에 고정된 값입니다. 미래 구간에서는 시각만 모델에 전달하며 실제 가격은 평가용으로 남깁니다.

import pandas as pd
import torch
from model import Kronos, KronosTokenizer, KronosPredictor

torch.manual_seed(123)
df = pd.read_csv(
    "tests/data/regression_input.csv", parse_dates=["timestamps"]
)
tokenizer = KronosTokenizer.from_pretrained(
    "NeoQuasar/Kronos-Tokenizer-base",
    revision="0e0117387f39004a9016484a186a908917e22426",
)
model = Kronos.from_pretrained(
    "NeoQuasar/Kronos-small",
    revision="901c26c1332695a2a8f243eb2f37243a37bea320",
)
tokenizer.eval()
model.eval()
predictor = KronosPredictor(model, tokenizer, device="cpu", max_context=512)
cols = ["open", "high", "low", "close", "volume", "amount"]
past_ts = df["timestamps"].iloc[:256].reset_index(drop=True)
future_ts = df["timestamps"].iloc[256:264].reset_index(drop=True)
pred = predictor.predict(
    df=df[cols].iloc[:256], x_timestamp=past_ts, y_timestamp=future_ts,
    pred_len=8, T=1.0, top_k=1, top_p=1.0,
    sample_count=1, verbose=False,
)
assert pred.shape == (8, 6)
print(pred.head())

완료 기준: 출력 열 여섯 개와 반환 인덱스의 의미를 한국어로 설명합니다. 같은 환경·같은 입력의 반복 결과를 비교하고, no_grad()는 기울기 기록을 끄며 eval()은 Dropout 같은 층의 동작을 바꾼다는 차이도 적습니다. Predictor 자체는 eval()을 호출하지 않습니다.

과제 3 중급 · 2~3시간

정규화와 선택 열 보완의 회귀 사례 만들기

학습된 모델 없이 6절의 정규화를 작은 배열로 옮겨 보세요. 과거는 고정하고 미래만 바꾸는 경우, 거래량이 없는 경우, 거래량만 있는 경우, NaN이 있는 경우를 각각 만듭니다. 기존 코드를 복제해 검증하기보다, 지켜야 할 데이터 성질을 먼저 정합니다.

완료 기준: 두 Dataset 경로의 차이를 숫자 표로 보여 주고, CSV 학습 경로에서 바꿔야 할 통계 계산 범위를 제안합니다. 좋은 모델을 고르는 일과 좋은 입력 변환을 만드는 일이 별개임을 설명할 수 있어야 합니다.

과제 4 고급 · 1~2일

시간을 앞으로 밀며 기준선과 비교하기

여러 기준 시점에서 과거 256개로 다음 8개를 예측하는 평가표를 설계하세요. 모델 설정은 먼저 고정하고 검증 기간에서만 조정합니다. 마지막 종가를 반복하는 기준선을 같은 구간에 적용하고, 테스트 기간은 끝까지 남겨 둡니다.

완료 기준: 모델이 이긴 구간과 진 구간이 모두 드러나는 표를 만듭니다. 수익률을 추가한다면 수수료·체결 시점·슬리피지를 별도 명시합니다. finetune/qlib_test.py도 거래 비용을 넣지만, 그것만으로 모든 시장의 체결 현실을 표현하지는 않습니다.

과제 5 고급 · 1~2일

평균선 뒤의 경로와 추론 비용 관찰하기

별도 실험 모듈에서 auto_regressive_inference()의 경로 평균 직전 배열을 보존하는 인터페이스를 설계하세요. 반환 모양을 (B,S,H,6)으로 정의하고, 평균 API와 경로 API의 차이를 설명합니다.

완료 기준: 경로별 출력과 그 평균이 일치함을 확인하고, 더 많은 경로에 드는 비용을 보고합니다. 모델 생성의 다양성과 통계적 보정의 차이를 설명하면 과제의 목적을 달성한 것입니다.

좋은 실습 결과는 예측선 한 장이 아니라, 어떤 입력·버전·시점·기준선으로 검증했는지 다시 따라갈 수 있는 기록입니다.

9관련 기술 심화 학습 로드맵

6주 동안 입력 계약에서 시작해 모델과 평가를 연결한다

Python의 함수·클래스와 표 형태의 데이터를 읽을 수 있다는 전제의 학습 순서입니다. 매주 “읽을 소스”와 “만들 결과물”을 함께 정하면, 어려운 논문을 읽다가 길을 잃는 일을 줄일 수 있습니다. 시간이 부족하면 1·2·5주차를 먼저 진행해도 됩니다.

주차공부할 기술연결할 소스주말에 남길 결과물
1주차pandas·시간 인덱스·OHLCVA·결측 처리 predict(), calc_time_stamps(), 예제 CSV 입력 열·단위·시각·검사 규칙을 정리한 데이터 설명서
2주차PyTorch 텐서·배치 축·자동미분·학습과 평가 모드 QlibDataset, DualHead.compute_loss() 배치 1·2·50일 때 입력과 정답의 모양 표
3주차오토인코더·양자화·비트 인덱스·복원 손실 KronosTokenizer, BSQuantizer 장난감 비트열 ↔ 정수 변환과 두 계층 복원 구조도
4주차Attention·인과 마스크·RoPE·자기회귀 샘플링 TransformerBlock, decode_s1(), decode_s2() 다음 캔들 한 개를 만드는 호출 순서와 확률 분해 설명
5주차시간 분할·정규화 누수·기준선·재현 가능한 평가 두 Dataset 구현, tests/test_kronos_regression.py 고정 출력 회귀와 보지 않은 구간의 예측 평가를 구분한 보고서
6주차DDP·체크포인트·API 계약·자원 측정 finetune/utils/training_utils.py, finetune/train_predictor.py, webui/app.py 학습 데이터부터 화면 표시까지의 경계와 운영 확장 제안

처음부터 모든 수식을 이해하려 하기보다, 입력과 출력의 모양을 고정하고 그 사이의 한 함수를 설명하는 방식으로 깊이를 늘리세요. 토크나이저를 다 읽지 못했더라도, 미래값이 정규화에 섞이는 문제나 시간 인덱스가 어긋나는 문제는 먼저 이해할 수 있습니다.

논문을 읽는 순서

먼저 Kronos의 전체 구조 그림과 입력 정의를 보고, 코드에서 두 토큰의 흐름을 찾으세요. 그다음 BSQ 논문의 양자화 원리로 돌아가고, 마지막에 평가 지표와 실험 조건을 읽습니다. 이 순서는 용어·코드·실험이 서로 무엇을 설명하는지 연결하는 데 도움이 됩니다.

10핵심 키워드 사전

소스를 다시 읽을 때 옆에 놓을 용어표
용어쉬운 설명
시계열관측 순서 자체가 의미를 갖는 데이터. 금융에서는 같은 숫자라도 언제 관측했는지가 중요합니다.
캔들·OHLCVA한 시간 구간의 시가·고가·저가·종가·거래량·거래대금을 묶은 표현입니다.
파운데이션 모델큰 데이터에서 미리 학습한 표현을 여러 대상과 작업에 재사용하려는 모델입니다.
사전학습·미세조정먼저 넓은 데이터로 배우고, 나중에 특정 데이터에 맞추어 추가 학습하는 두 단계입니다.
토크나이저여기서는 여섯 연속 수치를 정수 번호로 압축하고 다시 복원하는 학습된 변환기입니다.
양자화·BSQ연속 표현을 제한된 코드로 바꾸는 것. BSQ는 정규화된 표현의 각 성분을 부호 기반 값으로 바꿉니다.
s1·s2한 캔들을 표현하는 두 계층의 토큰. s1만으로도 복원을 배우며, s2는 s1에 조건화해 생성합니다.
직선 통과 추정기이산 선택을 순전파에 쓰면서 역전파에는 연속적인 학습 신호가 흐르도록 하는 근사 방법입니다.
임베딩토큰 번호나 요일 같은 범주를 신경망이 다룰 수 있는 벡터로 바꾸는 표현입니다.
Attention현재 위치를 계산할 때 다른 위치의 정보를 어떤 비중으로 참고할지 정하는 연산입니다.
인과 마스크시간 뒤쪽 위치의 정보를 앞쪽 위치가 미리 참고하지 못하게 가리는 규칙입니다.
RoPE질의와 키 벡터를 위치에 따라 회전시켜 순서 관계를 반영하는 위치 표현 방식입니다.
자기회귀이미 있는 값과 방금 만든 값을 사용해 다음 값을 하나씩 생성하는 방식입니다.
문맥 길이한 번의 모델 계산에서 참고하는 과거 토큰 수의 범위. 전체 데이터 길이와 같지 않을 수 있습니다.
로짓·온도 T로짓은 확률로 바꾸기 전의 점수입니다. 온도는 이 점수를 나누어 분포의 집중 정도를 조절합니다.
top-k·top-p후보를 상위 k개 또는 누적 확률 기준으로 제한하는 샘플링 방식입니다. 이 구현에서는 top-k 분기가 우선합니다.
sample_count입력 하나에서 생성할 경로 수입니다. 현재 Predictor는 경로별 값 대신 그 평균을 반환합니다.
MSE·교차 엔트로피MSE는 연속값의 제곱 오차, 교차 엔트로피는 정답 토큰에 얼마나 확률을 주었는지 보는 분류 손실입니다.
데이터 누수실제 예측 시점에 알 수 없는 정보가 입력·전처리·모델 선택에 섞이는 문제입니다.
워크포워드 평가기준 시점을 앞으로 옮기며, 각 시점 이전의 정보로만 이후 구간을 평가하는 방법입니다.
DDP·rank여러 프로세스가 데이터를 나누어 계산하고 기울기를 동기화하는 학습 방식과, 각 프로세스의 번호입니다.
체크포인트·리비전체크포인트는 저장한 모델 상태, 리비전은 어떤 버전의 파일인지 지정하는 식별자입니다.
회귀 테스트코드 변경으로 이전 동작이 깨졌는지 확인하는 소프트웨어 검사입니다. 회귀 분석이라는 모델 종류와 구분합니다.
백테스트·슬리피지과거 데이터로 거래 규칙을 평가하는 절차와, 기대 가격과 실제 체결 가격 사이의 차이입니다.

11참고 링크

저장소의 상태, 분석 범위, 더 깊이 읽을 원문

현재 상태 (2026-10-23 확인)

항목상태·근거
공식 저장소shiyu-coder/Kronos
선정GitHub Trending Python Weekly #13 · 2026-10-23 분석
스타·포크⭐43,318 · 포크 7,137 — 2026-10-23 GitHub 기준
주 언어Python
생성일2025-07-01
최신 릴리스GitHub 릴리스 없음. Hugging Face의 모델 가중치 공개와는 별개
최근 push2026-04-13
최근 커밋67b630e · 2026-04-13 · Merge pull request #243 from ElhamDevelopmentStudio/fix/batch-dimension-training
Python 규모30파일 · 11,196줄. 핵심 model/은 3파일 · 1,249줄
화면·설정 규모HTML 1,238줄, Shell 40줄, YAML 72줄. HTML 안의 JavaScript 약 600줄·CSS 약 430줄은 HTML과 중복 집계
규모 산정 범위저장소 파일 92개. 물리적 줄 수이며 빈 줄·주석 포함. CSV·JSON 데이터와 이미지·문서는 코드 줄 수에서 제외
라이선스MIT · 저작권 표기 Copyright (c) 2025 ShiYu

공식 저장소·논문·모델

코드를 다시 읽을 때의 핵심 길잡이

관련 기술의 공식 자료

쓰기 전에 알아둘 한계
연구 모델·예제·실제 의사결정 사이에는 검증 단계가 남아 있습니다

학습 규모와 성능 개선의 출처는 논문·README이며, 전체 사전학습 데이터와 평가 자료가 저장소에 포함된 것은 아닙니다. 구현 설명은 커밋 67b630e 기준입니다.

두 학습 경로는 정규화와 데이터 분할 규칙이 다릅니다. CSV 경로의 미래 통계 사용과 Qlib 분할의 날짜 중첩을 먼저 검토해야 합니다. README도 Qlib 파이프라인을 단순화된 미세조정 예제로 설명하며, 완성된 실거래 시스템으로 제시하지 않습니다.

예측 출력에는 고가·저가의 순서, 거래량의 비음수성 같은 시장 제약을 강제로 만족시키는 후처리가 보이지 않습니다. y_timestamp는 미래 가격이 아니라 미래 시각이며, 휴장·거래 세션·시간대의 적절성은 호출자가 관리해야 합니다. 여러 경로의 평균도 실제로 관측 가능한 캔들 경로라고 보장되지 않습니다.

회귀 테스트의 일치나 보기 좋은 예측선은 새로운 시장에서의 성능·수익을 보장하지 않습니다. 가중치 리비전과 입력 단위를 기록하고, 보지 않은 기간의 기준선 비교 및 비용·체결 가정을 갖춘 평가를 별도로 진행하세요.