본문 바로가기
C.W.K.
Stream
Lesson 01 of 05 · published

Completed-Close Baseline

~12 min · correctness, baseline, day-change, subtle-bug

Level 0Open Gate
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"'오늘 변동' 은 캐묻기 전까진 뻔해 보여. 근데 정확히 언제부터의 변동인데? 그 '언제' 를 틀리면 화면의 빨강 초록 숫자가 전부 작은 거짓말이 돼."

순해 보이는 숫자

포트폴리오 앱이라면 다 'day change' 를 보여줘. 이 포지션이 오늘 얼마나 움직였는지. 계산도 시시해 보여. 현재가에서 previous close 를 빼면 끝이잖아. 근데 그 'previous close' 라는 말 속에, 대충 넘기면 숫자를 조용히 오염시키는 질문이 숨어 있어. 도대체 어느 종가를 말하는 거야? Keep 의 답은 정확해. live tick 은 언제나 가장 최근에 완결된 종가에 대고 재. 반사적으로 '어제 종가' 를 집는 게 아니라, 실제로 장이 끝났고 durable 하게 저장된 가장 최근의 종가를 골라 내는 거야.

순진한 prev_close 는 어디서 틀리나

함정은 이래. 저장된 일일 row 가 월요일 장 마감 후에 마지막으로 갱신돼서 월요일 종가를 들고 있다고 하자. 지금은 화요일 장중이고, live tick 이 막 도착했어. 이때 변동을 tick - stored_prev_close 로 계산하면 한 세션 전이 아니라 두 세션 전 값을 빼고 있는 걸 수도 있어. 저장된 'previous' close 는 오늘 기준으로 무엇이 previous 인지가 아니라, 그 row 가 마지막으로 언제 쓰였는지에 따라 정해지거든. 결과는 두 세션에 걸친 움직임이 하루 변동이라는 라벨을 달고 나오는 것. 변동성이 큰 구간에선 반올림 오차 수준이 아니야. 당당한 얼굴로 틀려 있는, 눈에 띄게 잘못된 숫자지.

delta 의 정확도는 기준선의 정확도를 못 넘어. '변동' 은 숫자 하나의 속성이 아니라, 값과 선택된 기준점 사이의 관계야. 기준점을 잘못 박으면 현재값이 아무리 정밀해도 delta 는 틀려. 차이를 믿기 전에 반드시 물어봐. 정확히 무엇 대비 변동이지?

Keep 가 올바른 기준선을 고르는 법

규칙은 두 갈래야. durable 하게 저장된 row 의 날짜가 live tick 의 날짜와 같으면, 그러니까 row 가 이미 오늘을 담고 있으면, 올바른 기준선은 previous close 야. 어제 종가지. 오늘 row 는 지금 진행 중인 세션이니까. 반대로 저장 row 의 날짜가 더 이르면, 그러니까 이전 세션에서 갱신이 멈춰 오늘을 못 따라왔으면, 그 row 의 last close 가 올바른 기준선이야. 조건문 하나짜리 작은 분기인데, 이 덕분에 day change 가 말 그대로의 의미를 갖게 돼. 그리고 결정적으로 프론트엔드가 이 로직을 그대로 mirror 해. 브라우저가 서버와 다른 기준선을 계산하는 일은 없어.

이걸 raw prev_close 로 '단순화' 하지 마. 언젠가 미래의 독자가 이 두 갈래 분기를 보고 쓸데없이 복잡하다며 '항상 previous close 를 쓰게 정리' 하고 싶어질 거야. 그 정리가 바로 two-session 버그를 되살리는 짓이야. 이 복잡성은 구조를 받치고 있어. 참인 day change 와 그럴듯하게 틀린 day change 를 가르는 게 이 분기라고. 주석을 달아 두고, 평평하게 만들고 싶은 충동은 참아.
구현은 둘, 진실은 하나. 서버와 브라우저가 둘 다 기준선을 계산하니, 둘은 반드시 같은 답을 내야 해. 그래서 프론트엔드의 기준선 로직은 일부러 백엔드를 그대로 비춰. 같은 규칙이 두 곳에 살면 drift 가 위험인데, 여기선 그 mirror 관계를 명시적이고 의도적으로 관리해. 두 사람이 기억력으로 sync 를 맞추길 기대하는 게 아니라.

Code

가장 최근 completed close 규칙 (예시)·python
def completed_close(stored_row, live_tick_date):
    # durable row 가 이미 오늘을 담고 있으면, 올바른 기준선은
    # PREVIOUS close 야. 오늘 row 는 지금 진행 중인 세션이니까.
    if stored_row.data_date == live_tick_date:
        return stored_row.prev_close
    # 아니면 row 는 이전 세션에서 멈춰서 오늘을 못 따라온 거야.
    # 그 경우엔 last close 가 기준선이야.
    return stored_row.last_close

def day_change(live_tick, stored_row):
    base = completed_close(stored_row, live_tick.date)
    return live_tick.value - base   # '언제부터' 가 올바른 delta

External links

Exercise

네가 만든 것 중에서 'X 이후 변동' 류의 숫자를 하나 찾아 봐. 오늘 걸음 수, 이번 달 지출, 마지막 확인 이후 성장률 같은 것. 그 기준선이 정확히 뭐고 어떻게 정해지는지 적어 봐. 그다음, 기준선이 슬그머니 엉뚱한 기준을 가리키게 되는 경우를 만들어 봐. 낡은 저장값이든 시간대 경계든 놓친 갱신이든. 현재값은 완벽히 맞는데 delta 만 틀려지는 상황 말이야. 그걸 고치는 조건문은 뭘까?
Hint
버그는 현재값엔 없어. 언제나 기준선에 있어. 스스로 물어봐. 내 기준점이 내 가정과 다른 기간의 값일 수 있나? 흔한 범인은 저장된 'previous' 값이야. 'previous' 가 '지금 바로 이전 기간' 이 아니라 '이 row 가 마지막으로 쓰인 시점' 을 뜻하게 슬쩍 바뀌어 있거든.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.