orallexa 확신도 보정 — 게이트가 막은 BUY 와 채점 못 하던 WAIT 을 반사실 주문으로 재기
34편 orallexa 의 확신도 게이트가 p_up 0.55 짜리 BUY 를 막았습니다. 그 「안 낸 주문」을 계좌를 건드리지 않고 실제로 내서 채점해 봤고, Brier 표본이 20행에서 31행이 되는 길도 같이 실측했습니다.
orallexa 확신도 보정 — 게이트가 막은 BUY 와 채점 못 하던 WAIT 을 반사실 주문으로 재기이 글의 완료 조건: 독자가 자기 도구의 WAIT·SKIP·「게이트에 막힌 BUY」 한 건을 골라, 계좌를 전혀 건드리지 않고 그 판단의 성적표 한 줄을 받아 자기 채점 스크립트에 먹일 수 있으면 성공입니다.
| 하는 일 | 도구가 주문을 내지 않기로 한 그 시점·그 종목에 대해 반사실 시험 주문을 실제로 내고, 체결·청산·비용까지 끌고 가 성적표를 만듭니다 |
| 맞는 사람 | 확신도·확률을 숫자로 내는 도구를 쓰는데, 그 숫자가 맞았는지 재 본 적이 없는 사람 |
| 안 맞는 사람 | 표본 하나로 결론을 내고 싶은 사람. 이 경로가 주는 것은 분포를 쌓는 길이지 한 건의 정답이 아닙니다 |
| 이 글의 결과물 | 「이 판단이 값어치를 내려면 10분 안에 최소 몇 % 움직였어야 하나」라는 숫자 하나와, 그것을 뽑는 레시피 한 장 |
| 준비물·비용 | 코드 0원 · 모델 비용 0원 · weltiq pro 계정 (시험 주문 월 1,000회) |
| 시간·난도 | 도구 기록이 이미 있다면 20분 · 중 (curl·JSON) |
| weltiq 와의 관계 | 이 글이 전부 그 이야기입니다 — 절차 글이라 5절이 따로 없습니다 |
| 검증 환경·날짜 | 2026-09-28 (KST) · 격리 서버 · 합성 호가 (5절에 한계를 그대로 적었습니다) |
| 제휴 고지 | 필자는 weltiq 로부터 이 연재의 원고료를 받습니다. 아래 숫자는 전부 필자가 직접 돌린 것이고, 미판정으로 끝난 것도 그대로 적었습니다 |
사람 쪽 문장은 실제로 친 명령을 대화로 옮긴 것이고, 출력은 실측이며 숫자는 손대지 않았습니다.
1. 이 도구가 남기던 빈칸
34편에서 orallexa 를 돌렸습니다. 이 연재에서 계측 설비가 가장 두꺼운 도구입니다 — Brier 점수, 신뢰도 다이어그램, ECE, Platt 보정까지 코드에 들어 있습니다. 확신도를 그냥 띄우는 게 아니라 그 확신도가 맞았는지 자기가 채점하려고 만든 물건입니다.
16종목을 한 번에 돌린 기록(raw/probe-basket.json)이 이렇게 나왔습니다. 판정 분포는 BUY 5 · SELL 1 · WAIT 10.
| 종목 | 판정 | probabilities.up |
down | 화면 확신도 |
|---|---|---|---|---|
| NVDA | WAIT | 0.40 | 0.25 | 42.6 |
| AAPL | WAIT | 0.45 | 0.25 | 42.6 |
| QQQ | WAIT | 0.35 | 0.35 | 42.6 |
| META | WAIT | 0.25 | 0.45 | 42.6 |
| MSFT | BUY | 0.55 | 0.17 | 50.8 |
| BTC-USD | BUY | 0.55 | 0.20 | 50.8 |
16종목 전부에 대해 LLM 이 쓴 확신도 원값과 화면값이 몇 개 값으로만 몰려 있습니다. 화면에 뜬 값은 42.6% · 47.6% · 50.8% 셋. 반면 같은 판단이 함께 내는 p_up(상승 확률)은 훨씬 넓게 벌어집니다 — **이 글에서 볼 곳은 오른쪽 p_up 칸**입니다. 화면 확신도가 아니라 이 숫자가 채점에 들어갑니다
보실 곳은 화면 확신도가 아니라 p_up 열입니다. 다음 절에서 이 구분이 전부가 됩니다.
orallexa 자체 UI. MSFT 를 SWING·1D 로 돌린 화면입니다. 가운데 아래 CONFIDENCE 칸과 그 위 UPSIDE PROBABILITY 를 같이 보세요 — 「얼마나 확신하나」로 읽히는 숫자가 한 화면에 둘 있고 서로 벌어져 있습니다. 이 글에서 채점에 들어가는 것은 **위쪽 확률** 이고 아래 확신도가 아닙니다
이 도구를 처음 보는 분을 위해: 판단 한 건이 이렇게 생겼습니다. 화면에 보이는 숫자와 채점에 쓰이는 숫자가 다르다는 것이 34편의 결론이었고, 이 글은 그 위에서 시작합니다.
그리고 이 도구에는 확신도 게이트가 있습니다. 파일럿 기본값이 60%입니다.
DECISION MSFT decision=BUY confidence=50.8% risk=MEDIUM elapsed=4.1s
SKIP MSFT — confidence 50.8% below gate 60.0%
PILOT_DONE trades=0 decisions=1
판단은 BUY 입니다. 게이트가 막아서 주문이 안 나갔습니다. trades=0.
여기가 빈칸입니다. 이 게이트가 옳았는지 아무도 모릅니다. 주문이 안 나갔으니 결과가 없고, 결과가 없으니 채점할 것도 없습니다.
그리고 더 큰 빈칸 — WAIT 행 열한 개
이 도구의 Brier 감사(brier_audit.py)는 결정 로그를 읽어 채점합니다. 그런데 무엇을 채점하느냐가 중요합니다 — forecast_p 로 쓰는 값이 화면 확신도가 아니라 probabilities.up 입니다(brier_audit.py:301).
받은 그대로 돌리면 결정 로그 경로가 안 맞아 0행을 읽습니다. 경로를 실제 로그로 바꿔 끼우면 20행을 읽는데, **그중 채점 가능한 것은 극소수**입니다. 아래쪽 Platt 보정 줄의 「Need at least 30 observations」를 보세요 — 이 도구가 스스로 요구한 표본 수입니다
20행 중 WAIT 11행은 「방향 주장이 없어 채점 대상이 아님」 으로 빠집니다(RUN-LOG.md:214). 남은 BUY/SELL 9행 중 8행은 "scored": null 인데, 그 이유는 게이트가 아니라 하루가 안 지나서입니다.
그런데 그 WAIT 11행도 probabilities.up 을 가지고 있습니다(NVDA 0.40 · AAPL 0.45 · QQQ 0.35 …). 빠진 것은 확률이 아니라 방향입니다.
2. 왜 지금까지 못 쟀나
「안 사기로 한 판단」의 성적표가 지금까지 비어 있던 이유는 도구가 게을러서가 아닙니다.
재려면 사 봐야 하고, 사면 계좌가 움직입니다. 자본이 묶이고, 손실 한도를 갉아먹고, 성과 집계에 섞입니다. 재는 행위가 재려는 대상을 망가뜨립니다. 그래서 안 쟀습니다.
게이트에 막힌 BUY 는 특히 그렇습니다. 게이트를 내려서 실제로 내 보면 그 판단이 계좌에 들어가 버립니다 — 게이트를 검증하려다 게이트를 없앤 셈이 됩니다.
사지 않기로 한 판단도 성적표가 남습니다. 계좌를 건드리지 않고요.
시험 주문은 잔고·손익·한도·성과 집계 어디에도 들어가지 않는 별도 원장에서 그 판단을 끝까지 끌고 갑니다. 게이트는 그대로 둔 채, 게이트가 막은 그 주문만 따로 냅니다.
계약 한 줄만 먼저
p_up 같은 숫자를 주문에 실으려면 문자열로 실어야 합니다.
"metadata": {"p_up": "0.55"} // 숫자로 넣으면 500 입니다
canonical_json 이 결정론 규칙으로 float 을 거부합니다(weltiq/core/canonical.py:18 — "float 금지 — Decimal 또는 str을 사용 (결정론)"). 1차 시도에서 확신도를 숫자로 실었다가 여덟 건이 전부 500 이 났고, 문자열로 바꿔 통과시켰습니다.
3. 레시피 — 그대로 도는 것
레시피 한 장을 올려 뒀습니다: 07-trial-order-orallexa-calibration.sh. 네 칸으로 돕니다.
| 칸 | 무엇 |
|---|---|
| ① 심기 | 도구의 WAIT·게이트에 막힌 BUY 를 반사실 주문으로. client_tracking_id 를 심습니다 |
| ② 회수 | GET /v1/forward-tests?tracking=<런 ID> — 정확 일치, 내 계정 안에서만 |
| ③ 집행 기록 | GET /v1/forward-tests/orders?format=csv&tracking=… — 계정 전체를 한 번에 |
| ④ 조인 | 추적 ID + client_order_id 로 도구 로그와 잇고, actual 을 순손익 부호로 채웁니다 |
의도는 도구가 갖습니다. 서버로 가는 것은 client_order_id·client_tracking_id·문자열 metadata 뿐이고, 게이트 값이나 왜 그렇게 판단했는지는 tool_log.csv 에만 씁니다. 나중에 둘을 잇는 것은 추적 ID 하나입니다.
③이 예전과 달라진 자리입니다. 종전에는 회수가 「목록 1회 + 시험마다 1회」였습니다. 지금은 필터에 걸린 전부를 한 번에 주고, 열이 시험 하나 내보내기와 글자까지 같아서 이어붙여도 안 깨집니다. 그리고 자동 청산 주문이 진입의 추적 ID 를 물려받습니다 — 실현 손익은 그 청산 행에 붙으므로, 이게 없으면 ?tracking= 회수가 진입만 가져가고 손익을 빼놓습니다.
틱에 걸리는 자리 — 원값을 먼저 보내 보세요
34 의 BTC-USD 판단에는 레벨이 딸려 있습니다(raw/btc-decision.json): yf_entry_price 84138.4609375 · stop_loss_price 82034.9994 · take_profit_price 88345.384 · approved: true.
원값을 그대로 보내면 이렇습니다.
| 케이스 | 본문 | 응답 |
|---|---|---|
P34-BTC-RAW |
stop 82034.9994 / target 88345.384 (원값) |
422 (틱 0.01) |
P34-BTC |
stop 82035.00 / target 88345.38 |
201 |
조용히 반올림해 주지 않습니다. 조건 가격도 실제 주문과 같은 격자에 있어야 하고, 사용자가 준 가격을 서버가 몰래 바꾸는 쪽이 더 위험합니다.
반올림 방향을 적어 두는 것이 중요합니다. 손절은 올림(82034.9994 → 82035.00), 목표는 버림(88345.384 → 88345.38). 롱 기준으로 손절을 올리면 더 가깝고 목표를 내리면 더 가깝습니다 — 양쪽 다 보수적입니다. 어느 쪽으로 굴렸는지 안 적으면 나중에 그 반올림이 결과를 만들었는지 아무도 모릅니다.
방향은 어떻게 정했나
세 건 다 p_up > p_down 이라 롱으로 냈습니다. 하락을 시사한 WAIT 도 있습니다(META 0.25/0.45 · AMD 0.25/0.45 · PLTR 0.30/0.42). 그런데 34 의 기록 어디에도 그 세 종목의 가격이 없습니다. "그 도구 기록의 가격대 근처"라는 규칙을 지킬 수 없어 안 돌렸습니다. 임의 가격을 넣으면 반사실이 아니라 창작입니다.
아래 숫자의 환경: 격리 임시 서버 · 합성 호가(각 값은 그 도구 기록에 적힌 가격대에서 가져왔습니다) · 운영이 아닙니다 · 손익은 시장 사실이 아닙니다.
4. 돌려 본 결과
세 건을 냈습니다. 전부 201 로 접수됐습니다.
| 케이스 | p_up | 응답 | 진입가 | 청산가 | close_reason | 수수료 | 순손익 | 손익분기 |
|---|---|---|---|---|---|---|---|---|
| BTC (BUY, 게이트에 막힘) | 0.55 | 201 |
84147.91385 | 84129.08615 | close_after |
0.01346216 | −0.0149683760 | 0.2224% |
| NVDA (WAIT) | 0.40 | 201 |
— | — | rejected:market_closed |
0 | — | 미판정 |
| MSFT (BUY, 게이트에 막힘) | 0.55 | 201 |
— | — | rejected:market_closed |
0 | — | 미판정 |
읽는 법은 손익 숫자가 아니라 마지막 열입니다. 호가를 그 도구가 기록한 가격에 고정해 두고 600초 뒤 순손익을 보면, 고정 시장에서 순손익은 왕복 비용과 정확히 같습니다. 그래서 |순손익| ÷ 진입 금액 이 곧 「이 판단이 값어치를 내려면 10분 안에 최소 얼마가 움직였어야 하나」 가 됩니다.
0.2224%. 뒤집어 말하면 — 이 게이트가 막은 BUY 가 값어치를 내려면 BTC 가 10분 안에 최소 0.2224% 올랐어야 했습니다.
도구 자신의 손절 82,035 과 목표 88,345.38 은 10분 창에서 한 번도 닿지 않았습니다(진입 84,147.91 기준 −2.51% / +4.99%). 도구가 risk_reward_ratio: 2.0 으로 잡은 그 폭은 일 단위 지평선을 전제로 하고, 관망의 「지금」을 재는 10분 창과는 시간 척도가 다릅니다.
우리 쪽 시험 상세 — 반사실 한 건이 접수되고 체결되고 시한으로 닫힌 화면입니다. 보실 곳은 close_reason 과 그 옆 exit_trigger_px — **시한으로 닫힌 거래에는 발동 호가가 없어서 null** 입니다. 있는 척 0 으로 채우지 않습니다
같은 화면의 미판정 건. 201 로 접수됐지만 배치에서 rejected:market_closed 로 되돌아왔습니다. 보실 곳은 **한도 표시** — 체결이 한 번도 없었으므로 이 건의 1회는 환불됩니다
미국 주식 두 건은 미판정입니다
돌린 시각에 us-equity 가 닫혀 있었습니다.
venue=us-equity local_time=2026-09-28T00:27-04:00 is_open=False state=closed
next_open=2026-09-28T09:30-04:00 (= 22:30 KST)
시각을 속여 돌리지 않았습니다. 그렇게 얻은 체결은 실전 규칙을 통과한 체결이 아닙니다. 22:30~05:00 KST 에 같은 레시피를 그대로 돌리면 같은 기준으로 판정됩니다.
그래서 Brier 표본이 어떻게 되나
이 편의 값어치는 위의 0.2224% 가 아니라 여기입니다. 세 층으로 갈립니다.
(ㄱ) 게이트에 막힌 BUY 는 이미 채점 대상입니다. 34 는 decision_log 에 판단을 남기고 Brier 감사는 그 로그를 읽습니다 — 주문이 나갔는지는 보지 않습니다. raw/brier-scored.json 의 BUY 9행 중 8행이 "scored": null 인데 이유는 게이트가 아니라 하루가 안 지나서입니다. 그러니 MSFT·BTC 의 p_up 0.55 는 계약상 이미 들어갑니다. 반사실 시험 주문은 여기서 actual 을 더 빨리·더 싸게 주는 경로입니다 — 10분 창에 실물 비용이 포함된 채로.
(ㄴ) WAIT 행은 지금 못 들어갑니다. 반사실이 그 문을 엽니다. 20행 중 WAIT 11행이 "방향 주장이 없어 채점 대상 아님"으로 빠지는데, 그 행들도 probabilities.up 을 가지고 있습니다. 빠진 것은 확률이 아니라 방향이고, 반사실 주문이 정확히 그것만 공급합니다. forecast_p = probabilities.up 은 그대로 두고 actual 만 채우면 됩니다. 표본이 20행에서 31행이 됩니다.
(ㄷ) 그런데 계약이 두 군데서 막습니다. 둘 다 이번에 실측했습니다.
- weltiq 쪽:
metadata에 float 을 넣으면 500 입니다(2절). 확률을 1급 수치로 싣고 Brier 를 서버에서 계산하려면metadata가 아닌 전용 칸(Decimal) 이 필요합니다.metadata는 해시되는 계약 본문이라 여기에 숫자를 넣는 설계 자체가 부딪힙니다. - 34 쪽: 신뢰도 구간 표의 최저 버킷이
50-60%입니다(brier_audit.py:390). WAIT 행의 p_up 0.40·0.45·0.35 는 떨어질 칸이 없습니다. 그리고 Platt 보정은 30관측 이상을 요구합니다("Need at least 30 observations, got 1"). 반사실로 표본을 늘리는 것이 바로 그 30을 채우는 길인데, 버킷 하한을 0까지 내리는 수정이 먼저여야 합니다.
계약상 가능합니다. 단 우리 쪽에 확률 전용 수치 칸이 있어야 하고 34 쪽 버킷 하한을 내려야 합니다. 그 전까지는 문자열 metadata + 바깥 채점으로 우회합니다.
5. 이 조합의 한계
① 표본 하나로는 아무 말도 못 합니다. 위 0.2224% 는 한 건입니다. 관망 한 건이 손실로 끝났다고 그 관망이 옳았던 것이 아닙니다 — 분포가 필요하고, 그 분포를 쌓는 것이 이 경로의 용도입니다. 34 자신이 요구한 30관측도 아직 한참 멉니다.
② 반사실은 한쪽만 잽니다. "샀으면 어땠나"는 재지만 "안 사서 무엇을 아꼈나"는 여전히 판단입니다. 이 표에는 전자만 있습니다.
③ 우리는 그 도구가 옳다/틀리다를 말하지 않습니다. 재고 기록할 뿐입니다. 위 표가 말하는 것은 "orallexa 의 게이트가 옳았다"가 아니라 "그 게이트가 틀리려면 10분 안에 0.2224% 가 필요했다" 입니다. 그 둘은 다른 문장입니다.
④ 손익은 시장 사실이 아닙니다. 합성 호가 위의 산술입니다. 여기서 확인된 것은 배선과 판정 틀이지 BTC 가 실제로 어떻게 움직였는지가 아닙니다.
⑤ 같은 회차에 몰아 내면 확신도가 사라집니다. 이게 이번에 제일 크게 걸린 제약입니다. 판정이 난 시각이 아니라 나중에 한 회차로 모아서 내면, 고정 시장에서 손익을 결정하는 것은 확신도가 아니라 왕복 비용입니다. 실제로 다른 편에서 확신도 0.88·0.90·0.89 와 0.20 짜리 네 건이 소수점 끝까지 같은 손익으로 나왔습니다. 확신도-결과 상관을 재려면 도구가 관망을 낸 그 순간에 반사실 주문이 나가야 합니다.
⑥ 시간 척도가 안 맞습니다. 34 의 레벨은 일 단위 지평선을 전제로 하는데 이번 창은 10분이었습니다. 도구의 지평선에 맞춘 한 벌을 따로 내는 것이 다음 과제입니다.
⑦ 하락을 시사한 WAIT 은 못 냈습니다. 그 종목들의 가격이 34 기록에 없습니다. 가장 값어치 있었을 표본이 빠진 채로 남아 있습니다.
6. 언제 쓰고 언제 쓰지 마라
쓰세요.
- 도구가 확률이나 확신도를 숫자로 내는데 그 숫자의 성적표가 없을 때. 34 가 정확히 이 경우입니다
- 게이트·필터가 주문을 막는 구조일 때. 막은 쪽이 옳았는지가 기록으로 남지 않는 자리입니다
- 채점 도구가 표본 수를 스스로 요구할 때. 30건이든 384건이든, 계좌를 안 쓰는 경로라야 그 숫자를 채울 수 있습니다
쓰지 마세요.
- 한 건으로 결론을 내려 할 때. 이 경로는 분포를 쌓는 길이고, 한 건은 왕복 비용을 재는 것에 가깝습니다
- 비중(포트폴리오 %)이 산출의 핵심인 도구를 재려 할 때. 수량을 서버가 정해서 비중이 접힙니다
- 그 도구 기록에 가격이 없을 때. 임의 가격을 넣는 순간 반사실이 아니라 창작입니다. 안 돌린 것은 안 돌렸다고 적는 쪽이 낫습니다
- 미국 주식을 폐장 시간에 재려 할 때. 접수는 되지만
rejected:market_closed로 미판정입니다. 시각을 속이지 마세요
이 글의 증거: A축 반사실 측정 기록 · 케이스별 요청·응답 원문 · 레시피. 원 도구 회차는 34편 orallexa에 있습니다.