/ 투자 인사이트 ← 인사이트 목록

KST 모드 토요일이 비는 이유 — 미국 금요일 세션 매핑의 비밀

2026.05.17 · 캘린더 · KST · 데이터 모델링

한국에서 미국 주식을 보유하면 한 가지 곤란한 질문이 생깁니다. 미국장이 마감되는 시각은 한국 시간으로 토요일 새벽 5~6시. 그 변동을 캘린더에 표시할 때 "미국 금요일 (현지 날짜)" 칸에 넣어야 할까요, 아니면 "한국 토요일 (사용자의 잠에서 깨어난 날)" 칸에 넣어야 할까요? 이 글은 그 결정이 단순한 표시 차이가 아니라 "오늘의 수익률"이 정직한지 여부를 결정한다는 점을 코드 레벨에서 풀어봅니다.

발견된 증상

실제 사용자 제보로 시작된 이야기입니다. "캘린더의 토요일 셀에 SOXL +16.33% 가 분명히 표시되는데 합계는 -0.49% 로 나옵니다. 마이너스인 게 믿기지 않아요."

SOXL 은 미국 금요일 세션에 16% 넘게 올랐고, 사용자는 한국 시간 토요일 아침에 그 데이터를 확인했습니다. 하지만 포트폴리오 합계는 마치 미국 금요일 세션이 없었던 것처럼 직전 거래일의 수치만 보여주고 있었죠.

이 한 줄 제보가 며칠에 걸친 데이터 모델 정리로 이어졌습니다. 결론을 미리 말하면 — 이건 단순한 버그가 아니라 "미국 종가를 어느 날짜에 매핑하느냐"의 정책 자체가 흔들리고 있던 문제였습니다.

두 가지 매핑 모드

멀티폴리오스의 설정에는 "캘린더 날짜 기준" 이라는 옵션이 있습니다. 두 가지 모드:

모드미국 종가를 어디에 표시이 모드를 쓰는 사용자
시장 기준 (Market)미국 현지 날짜. Yahoo Finance 원본 그대로.미국 증권사를 직접 쓰는 사용자, 미국 현지 보도와 일치시키고 싶을 때.
KST 기준미국 종가를 +1일 시프트. 미국 금요일 → KST 토요일.한국·일본에서 미국 주식을 보유한 사용자. "잠에서 깬 그 날" 의 변동을 보고 싶을 때.

기본값은 한국어 사용자에게 KST. 일본어·영어 사용자에게 Market. 이 선택은 단순한 표시 옵션이 아닙니다. 캘린더 셀의 숫자, 자산 추이 그래프의 단계, "오늘의 요약" 의 일일 변동률 — 이 모든 것이 같은 데이터를 어떤 날짜에 매핑하느냐에 따라 달라집니다.

데이터 모델 — 날짜는 어디에 사는가

캘린더 스냅샷을 빌드하는 함수는 다음과 같은 흐름으로 동작합니다:

// pseudocode
for each holding:
  history = fetchYahooHistory(symbol)  // 일별 종가 배열
  for each (date, close) in history:
    if mode === 'kst' && isUSSymbol(symbol):
      // 미국 종목만 +1일 시프트
      priceMap[symbol][shiftByOne(date)] = close
    else:
      priceMap[symbol][date] = close

for each calendar day d:
  for each holding:
    price = priceMap[symbol][d] || forwardFill(...)
    total += price * shares
  snapshot[d] = total

핵심: shiftByOne 은 미국 종목에만 적용됩니다. 한국·일본 종목은 그대로. 이 비대칭이 KST 모드의 본질입니다.

구체적으로 따라가 봅시다. 2026년 5월 8일 (미국 금요일):

버그가 숨어 있던 자리

사용자가 보고한 -0.49% 문제는 두 군데에서 발생했습니다.

1) 주말 lookup 의 과도한 일반화

"오늘의 요약" 은 오늘 날짜에 해당하는 캘린더 셀을 찾아 변동률을 표시합니다. 주말에는 시장 활동이 없으니 직전 금요일로 굴려 표시하는 로직이 들어가 있었죠. 코드는 단순했습니다:

while (lookup.getDay() === 0 || lookup.getDay() === 6) {
  lookup.setDate(lookup.getDate() - 1);
}

시장 기준 모드에서는 이게 맞습니다. 토요일·일요일에는 어느 시장도 새 데이터를 안 만들어요. 하지만 KST 모드의 토요일은 다릅니다. 미국 금요일 세션이 KST 토요일에 매핑되어 있죠. 토요일을 금요일로 돌려버리면 그 시프트된 데이터를 놓치게 됩니다. 결과: 사용자가 토요일 아침에 본 변동률은 "미국 목요일 세션 + 한국 금요일 세션" — 미국 금요일이 빠진 마이너스.

2) directDayPct 의 시장 기준 가정

두 번째는 더 미묘했습니다. 오늘 날짜의 변동률을 정밀하게 계산하기 위해 별도 경로가 있었습니다 — 각 종목의 currentPriceprevClose 를 직접 빼서 합산하는 방식. 이게 평소엔 정확하지만, KST 모드 토요일에서는 잘못된 답을 줍니다.

왜? Yahoo Finance API 가 알려주는 regularMarketPreviousClose각 종목 자체의 직전 거래 세션 종가입니다. SOXL 의 경우 토요일에 조회하면 prevClose = 미국 목요일 종가. 그런데 KST 토요일 스냅샷은 이미 "미국 금요일 종가" 를 들고 있어서, currentPrice (Fri) − prevClose (Thu) = 금요일 세션 변동을 over-count 합니다.

한국 종목은 더 심각합니다. KST 토요일에 삼성의 currentPrice = 금요일 종가, prevClose = 목요일 종가. 그런데 KST 5/9 스냅과 KST 5/8 스냅 둘 다 한국 금요일 종가를 forward-fill 로 들고 있으니, 실제로 한국 입장에서 5/9 → 5/8 변동은 0 이어야 합니다. directDayPct 는 한국 Fri-Thu 변동까지 한 번 더 끼워 넣어버립니다.

"같은 변동률 공식이 모드에 따라 거짓을 말한다." — 이 깨달음이 수정의 방향을 정했습니다.

수정의 원칙

두 가지 원칙을 세웠습니다.

  1. 주말 lookup 은 모드 인지. 시장 기준 모드는 토·일 모두 직전 금요일로 굴리되, KST 모드는 토요일을 유지. 일요일은 어느 모드든 직전 거래일로 굴림 (KST 일요일은 새 데이터가 정말 없으니까).
  2. KST 모드에서는 directDayPct 를 쓰지 않는다. 대신 스냅샷 기반 dayRet (오늘 total − 어제 total) 을 사용. 이건 KST 시프트가 이미 반영된 데이터를 그대로 빼는 거라 모든 요일·시간대에 일관되게 정확합니다.

결과적으로 KST 모드는 더 단순해졌습니다. "오늘 KST 총합 − 어제 KST 총합" 한 줄로 모든 케이스가 풀립니다. 시장 기준 모드는 기존 directDayPct 경로를 유지 (한국·일본 사용자가 미국 현지 시각으로 보고 싶을 때 그게 의미 있음).

다른 트래커가 이걸 어떻게 처리할까

대부분의 외산 포트폴리오 트래커는 미국 사용자 기준이라 이 문제가 아예 안 떠오릅니다. 미국 종목 → 미국 날짜. 끝. 한국 종목이 있어도 시장 기준으로 표시하고 끝나죠.

한국 트래커는 종종 한국 종목만 깊이 다루고 미국·일본은 보조 기능 정도여서, "여러 시장의 종가를 KST 캘린더에 일관되게 표시" 라는 요구 자체가 잘 다뤄지지 않습니다.

멀티폴리오스가 KST 모드를 굳이 만든 이유는 — 한국·일본에서 미국 주식을 보유한 사용자가 실제로 사는 시간 감각을 데이터 모델에 반영하기 위해서입니다. 미국 금요일 세션의 폭락 (또는 폭등) 을 토요일 아침 커피와 함께 확인하는 사람에게, 그 변동이 토요일 칸에 있어야 정직합니다.

실전 사용자에게 주는 시사점

정직한 숫자를 위한 코드

"오늘의 수익률" 같이 사소해 보이는 숫자가 정확하려면, 그 사용자가 어느 시간대에서 어떤 시장을 보유하고 있는지를 데이터 모델이 알아야 합니다. 일반 트래커가 다루지 않는 영역이라서 깔끔한 정답이 없습니다 — 모드 선택권을 주고, 각 모드에서 일관된 의미를 보장하는 게 현실적 해법입니다.

이 글에서 다룬 데이터 모델은 멀티폴리오스 캘린더와 "오늘의 요약" 에 그대로 들어가 있습니다. 설정 → 캘린더 날짜 기준에서 두 모드를 바꿔보면 같은 자산이 어떻게 다르게 매핑되는지 직접 확인할 수 있습니다.