# 축 B — 같은 시각에 한 칸만 다른 세팅을 함께 내서 즉각 비교한다 (실측)

## 환경 고지

| | |
|---|---|
| **DB** | **격리 임시 PostgreSQL** (소켓 `/tmp/weltiq-cfb-*` · 포트 55552 · 역할·DB `weltiq_cfb`). 운영 DB·운영 `.env`·실계좌·외부 거래소·배포·푸시·메일 **전부 미사용** |
| **시세** | **전부 합성 호가다.** 실시장에서 받은 값이 아니다. 값의 근거는 편마다 그 도구의 기록 문서를 적었다 |
| **손익** | **이 문서의 손익은 시장 사실이 아니다.** 합성 호가 위의 산술이다. 여기서 재는 것은 **대조 설계가 서는가** 하나다 |
| **커밋 SHA** | `0431b2a966f5a2d1766f71f9ca74147d7076737d` (작업 트리 `/Users/unolee/dev/weltiq-trial-content`) |
| **실행 시각 (KST)** | 2026-09-28 **13:25:53 ~ 13:29:46** (UTC 04:25:53 ~ 04:29:46) |
| **API** | `http://127.0.0.1:8912` · 계정 `cfb@example.invalid` (pro) · 월 한도 200 |
| **라이선스** | 지시대로 `krx`·`us-equity` 를 **open**. `cme` 는 **건드리지 않았다** — 실측 결과 `license_pending` 그대로. 크립토 넷(binance-spot·binance-usdm·bybit-spot·bybit-linear)은 기본값이 이미 open |
| **하네스** | `run_axis_b.py` · 원자료 `axis-b-evidence.json` |

### 동시 편집 고지 — 이 실행 중에 같은 작업 트리가 고쳐졌다

같은 작업 트리에서 **다른 작업이 동시에 돌고 있었다.** 정직하게 적는다.

1. **`weltiq/forward_test.py`·`weltiq/api/forward_tests.py` 가 13:29:13 (KST) 에 수정됐다.** 이 실행의 자식 프로세스는 **13:25:50 경에 모듈을 임포트**했으므로 **전부 수정 전 코드로 돌았다** (마지막 발주 13:29:39 포함 — 파이썬은 임포트 시점의 코드를 들고 있다). 아래 모든 실측은 **수정 전 코드의 실측**이다.
2. 그 수정의 내용이 하필 **§3 에서 내가 「없다」고 적은 칸**이다 — `list_page` 에 `tracking=` 정확 일치 필터를 붙이고 `q` 가 `client_tracking_id` 도 훑게 한다. **나는 그 새 코드를 돌리지 않았다.** 아래 「`q=cf-04-stoploss-width` → 0건」은 수정 전 코드의 사실이고, 수정 후에 어떻게 되는지는 이 문서가 답하지 않는다.
3. 이 디렉터리의 `initdb.txt`·`schema.txt`·`migrate.txt`·`start.txt`·`stop.txt`·`role.txt`·`db.txt` 는 **같은 디렉터리에 쓰는 다른 하네스(`run_axis_a.py`, 13:27 실행)와 파일명이 충돌했다** — 지금 남아 있는 것이 이 실행의 것이라고 단정할 수 없다. 재발 방지로 `run_axis_b.py` 의 출력 이름을 `axisb-*.txt` 로 바꿔 두었다 (이 실행 뒤의 변경이므로 지금 그 파일들은 없다).

### 호가 규약 — 「같은 호가에서 나갔다」를 어떻게 보장했나

호가는 **국면(phase)** 단위로만 바뀐다. 한 국면 안에서 값은 고정이고 그 국면의 모든 발주가 같은 bid/ask 를 본다.
국면 전환 시각은 전부 `axis-b-evidence.json` 의 `quote_phases` 에 남는다.

| 국면 | 전환 (KST) | 호가 | 근거 |
|---|---|---|---|
| A1 | 13:25:53.655 | binance-spot BTCUSDT 85198.17 / 85198.18 | 04편 `RUN-LOG.md:366` `open_rate 85198.18` |
| A2 | 13:25:57.693 | 85145.81 / 85145.82 | 04편 `close_rate = min_rate = 85145.81` |
| B1 | 13:26:42.875 | 85900.00 / 85900.01 | 14편 두 기록 진입가 사이 (85900 은 **하네스가 고른 값**) |
| C1 | 13:28:47.391 | binance-usdm BTCUSDT 76863.1 / 76863.2 | 15편 `trades[1].entry_price 76863.2` |
| C2 | 13:28:51.417 | 75943.7 / 75943.8 | 15편 `trades[1].exit_price 75943.85` (틱 0.1 격자) |
| D1 | 13:29:36.587 | **네 거래소 모두** 85483.0 / 85483.1 | 23편 우리 실측 체결 `85483.06745150` (`69-export-final.json`) |
| D2 | 13:29:40.632 | **네 거래소 모두** 85611.3 / 85611.4 | D1 의 +15bp (하네스가 고른 값) |
| E1 | 13:29:43.651 | 85400.00 / 85400.01 | 상한 측정용 (어느 편의 기록도 아니다) |

각 편의 발주는 **한 국면 안에서** 끝났고, 발주와 발주 사이에 호가를 바꾼 적이 없다.
편 사이의 국면 전환 시각은 위 표에 전부 있다.

---

## 편 04 — freqtrade · **손절 폭 한 칸**

### 두 세팅의 출처

| | 기록 | 출처 |
|---|---|---|
| **기준안** | `stoploss = -0.002` (−0.2%) · 진입 85037.82 · 손절선 84867.75 → **10분간 미발동** | `docs/tutorials/a/04-freqtrade.md:197` · `reports/a/04-freqtrade/RUN-LOG.md` 「손절 미발동 10분 관찰」 |
| **비교군** | `stoploss = -0.0005` (−0.05%) · 진입 **85198.18** · 손절선 **85155.59** → **91초 만에 `Reason: stop_loss`** · 체결 85145.81 · `profit_abs -0.26057537 USDT` | `reports/a/04-freqtrade/tight-stop.json` · `RUN-LOG.md:348-366` |

### 무엇이 한 칸인가

**`stoploss` 폭 하나다.** 종목(BTC/USDT)·전략·Dry-Run·거래소·진입 방식이 전부 같다.
원 기록에서는 두 회차의 진입가가 달랐으므로(85037.82 vs 85198.18), **폭만 가져와** 같은 진입가 85198.18 에 붙였다.
세 번째 팔(−0.10%)은 두 기록 사이를 채운 **하네스 합성값**이다.

### 발주 본문 (세 팔 공통 · 13:25:56.663 ~ .678, **국면 A1**)

```json
{"venue":"binance-spot","symbol":"BTCUSDT","side":"long","type":"market",
 "client_order_id":"04-stop-0005",              // 팔마다 다름
 "exit_plan":{"stop_loss":"85155.59","close_after_seconds":45},   // ← 이 한 칸만 다름
 "max_duration_hours":1,
 "client_tracking_id":"cf-04-stoploss-width",   // 세 팔 모두 같음
 "tags":["ab-compare","a2-04-04"],
 "metadata":{"arm":"variant","changed_field":"exit_plan.stop_loss",
             "source":"reports/a/04-freqtrade/tight-stop.json · RUN-LOG.md:366"}}
```

### 나란히 놓은 결과

| 팔 | 손절선 | 접수 (KST) | 진입 체결가 | 진입 호가 공개 시각 | 청산가 | `exit_trigger` | `exit_trigger_px` | `close_reason` | 수수료 | 순손익 | 소요 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| `04-stop-0005` (기록) | **85155.59** | 13:25:56.663 | 85206.7048175 | **13:25:57.507** | 85137.2904185 | **`stop_loss`** | **85145.81** | `stop_loss` | 0.01362752 | −0.019180671920 | **2.9초** |
| `04-stop-0010` (합성) | 85112.98 | 13:25:56.671 | 85206.7048175 | **13:25:57.507** | 85137.2904185 | — | — | `close_after` | 0.01362752 | −0.019180671920 | 46.0초 |
| `04-stop-0020` (기록 폭) | 85027.78 | 13:25:56.678 | 85206.7048175 | **13:25:57.507** | 85137.2904185 | — | — | `close_after` | 0.01362752 | −0.019180671920 | 46.0초 |

세 팔의 **진입 체결가가 소수점 끝까지 같고, 그 체결이 참조한 호가의 공개 시각(`published_at`)이 밀리초까지 같다** — 한 번 공개된 BBO 하나가 세 건을 전부 채웠다.

### 그 칸이 결과를 갈랐나 — **갈랐다. 단 「왜·언제」 를 갈랐고 「얼마」 는 아니다**

- 85145.81 이라는 **기록된 실제 최저가**가 −0.05% 선만 뚫고 −0.10%·−0.20% 선은 못 뚫었다. 원 기록이 말하던 그대로다.
- 다만 세 팔의 **순손익이 같다.** 합성 호가가 A2 이후 움직이지 않아 시한 청산도 같은 가격에 났기 때문이다. 손절이 실제로 값을 갈라 놓으려면 호가가 그 뒤로 더 움직여야 하는데, 이번 설계는 「한 칸이 조건을 발동시키는가」 만 재도록 호가를 고정했다.
- **합성 호가라 이 손익은 시장 사실이 아니다.** 여기서 선 것은 **손절 폭 대조 설계**다 — 같은 체결·같은 시각·같은 호가 위에서 손절선만 달리 걸면 `exit_trigger`·`exit_trigger_px`·`close_reason`·소요 시간이 팔마다 따로 기록된다.

---

## 편 14 — QuantDinger · **격자 최적점이 낸 진입가 한 칸** (그리고 못 세운 비교)

### 두 세팅의 출처

| | 기록 | 출처 |
|---|---|---|
| **기준안** | 가정 비용(수수료 0.0005 · 슬리피지 0.0005) 격자 1위 = **60/180** · `totalReturn -5.344065708001111` · 68거래 · PF 0.5123854981235674 | `reports/a/14-quantdinger/40-qd-grid-cp0.json` |
| **비교군** | 실측 비용(수수료 0.001 · 슬리피지 0.0001 — `52-measured-costs.json`) 격자 1위 = **120/360** · `totalReturn -1.9871885445930992` · 33거래 · PF 0.678789397136766 | `reports/a/14-quantdinger/40-qd-grid-cp1.json` |

### **이 비교는 기록만으로 서지 않는다** — 없는 것을 먼저 적는다

1. **격자 두 줄 어디에도 거래별 진입·청산 레벨이 없다.** `40-qd-grid-cp*.json` 의 `rows` 는 `fast`·`slow`·`totalReturn`·`totalTrades`·`totalCommission`·`profitFactor`·`maxDrawdown`·`finalEquity` 뿐이다. 「두 최적점이 **같은 봉에서** 어떻게 갈리는가」는 이 기록으로 답할 수 없다.
2. **기간쌍은 시험 주문 본문에 들어가는 칸이 아니다.** `TrialBuyReq`(`weltiq/api/forward_tests.py:68-83`)에 `fast`·`slow` 같은 칸은 없고, 있어도 우리 규칙 문법이 360 을 못 받는다 — `53a-rules-reject-cp1-1m.json` 에 `422 {"code":"invalid_rules","detail":"period_limit"}` (`weltiq/pine_v1.py:14` `MAX_PERIOD=200`) 로 이미 기록돼 있다.

**이 비교가 서려면 무엇이 있어야 하나 — 격자 행마다 거래 목록.** 즉 `{entry_time, entry_price, exit_time, exit_price, direction, exit_reason}` 배열. 15편 Moss 는 이것을 실제로 내놓는다(`21-moss-own-backtest-30d.json` 의 `trades[]`), QuantDinger 의 `/backtest` 결과는 내놓지 않는다. 그 한 칸만 있으면 두 최적점의 진입 레벨을 같은 시각에 나란히 낼 수 있다.

### 대신 무엇을 대조했나 — **두 설정이 우리 쪽에서 실제로 낸 진입가**

| | 진입가 (우리 체결) | 출처 |
|---|---|---|
| 60/180 (1분봉) | `85979.70711050` (expected 85971.11) | `54-export-final-cp0.json` `fills[0].px` |
| 120/360 → 5분봉 24/72 번역 | `85795.14865650` (expected 85786.57) | `59-export-cp1.json` `fills[0].px` |

한 칸 = **`limit_price`**. 손절은 두 팔을 **같은 81605.00** 으로 묶었다 — 규칙 문서의 「보호 손절 5%」(`43-rules-submit-cp0.json`·`53-rules-submit-cp1.json`)는 두 설정이 같지만 진입가가 달라 손절선이 갈리므로, 한 칸만 남기려고 국면 호가 기준 `85900 × 0.95` 하나로 고정했다.

### 발주 본문 (13:26:45.882 / .889, **국면 B1**)

```json
{"venue":"binance-spot","symbol":"BTCUSDT","side":"long","type":"limit",
 "limit_price":"85979.70",                       // ← 이 한 칸만 다름 (비교군 85795.14)
 "client_order_id":"14-grid-60-180",
 "exit_plan":{"stop_loss":"81605.00","close_after_seconds":45},
 "max_duration_hours":1,
 "client_tracking_id":"cf-14-grid-optimum",
 "tags":["ab-compare","a2-04-14"],
 "metadata":{"arm":"base","changed_field":"limit_price",
             "source":"reports/a/14-quantdinger/54-export-final-cp0.json fills[0].px 85979.70711050"}}
```

버림 처리: `85979.70711050 → 85979.70`, `85795.14865650 → 85795.14` (틱 0.01). 롱 지정가는 내리는 쪽이 보수적이다.

### 나란히 놓은 결과

| 팔 | 지정가 | 접수 (KST) | 상태 | 진입 체결가 | 청산가 | `close_reason` | 수수료 | 순손익 | 소요 |
|---|---|---|---|---|---|---|---|---|---|
| `14-grid-60-180` (60/180) | 85979.70 | 13:26:45.882 | `closed` | 85908.6050005 | 85891.4049995 | `close_after` | 0.01374400 | −0.015120000080 | 46.0초 |
| `14-grid-120-360` (120/360) | 85795.14 | 13:26:45.889 | **`entering`** | **미체결** | — | **없음** | 0 | **null** | — |

### 그 칸이 결과를 갈랐나 — **갈랐다. 체결 여부에서**

- 같은 호가(ask 85900.01)에서 85979.70 은 즉시 체결되고 85795.14 는 **호가에 걸린 채 남았다.**
- 그리고 **미체결 팔은 `close_after_seconds` 시계가 시작되지도 않는다.** 상대 시한의 기준이 「첫 진입 체결의 공개 시각」(`weltiq/forward_test.py:788`)이라서, 안 채워지면 `max_duration_hours` 가 될 때까지 그대로 남는다. 관측 창(45초) 안에서는 비교군이 **아무 결과도 안 낸다.**
- **합성 호가라 이 손익은 시장 사실이 아니다.** 여기서 선 것은 **지정가 대조 설계**이고, **격자 파라미터 대조 설계는 서지 않았다** — 도구가 레벨을 안 내놓기 때문이다.

---

## 편 15 — Moss · **`tp_rr_ratio` 한 칸**

### 두 세팅의 출처

| | 기록 | 출처 |
|---|---|---|
| **기준안** | `tp_rr_ratio = 3.0` · 그 값으로 돈 백테스트의 `trades[1]`: **SHORT · entry 76863.2 → exit 75943.85 · `exit_reason: take_profit` · `pnl_pct 0.1196`** | `reports/a/15-moss/21-moss-own-backtest-30d.json` |
| **비교군** | `tp_rr_ratio = 3.3` — 우리 비용 원문(`pnl -98.02 fees 247.83`)을 먹인 뒤 Moss 가 바꾼 36칸 중 한 칸. 이유 원문: **"높은 수수료 부담을 감안해 이익 실현 시 비용을 흡수할 여지를 늘린다"** | `reports/a/15-moss/41-moss-cp1-params.json` · `docs/tutorials/a/15-moss-trade-bot-skills.md:252` |

바뀐 6칸 중 5칸의 이유에 「수수료」가 들어갔고, 그중 **가격 레벨로 번역 가능한 칸이 `tp_rr_ratio` 하나**다.

### 무엇이 한 칸인가

**`tp_rr_ratio` 하나.** `sl_atr_mult` 은 2.0 으로 **안 바뀐 칸**(`41-moss-cp1-params.json`)이므로 손절 거리도 안 바뀐다 → 두 팔의 `stop_loss` 를 **같은 값**으로 놓았다. 진입가·방향도 같다.

**유도 (`synthesized`)** — Moss 기록에는 비율만 있고 가격 레벨이 없다:

```
기록된 tp 거리 = 76863.2 − 75943.85 = 919.35        (rr 3.0 에서 실제로 난 거리)
→ sl 거리      = 919.35 / 3.0 = 306.45
→ SL           = 76863.2 + 306.45 = 77169.65 → 77169.6  (틱 0.1, 버림)
rr 3.3 의 tp 거리 = 306.45 × 3.3 = 1011.285
→ TP(비교군)   = 76863.2 − 1011.285 = 75851.915 → 75851.9 (틱 0.1, 버림)
TP(기준안)     = 75943.85 → 75943.8 (틱 0.1, 버림 — 숏 목표가는 내리는 쪽이 보수적)
```

`binance-spot` 은 `shortable=False` 라 숏을 못 받는다 → **`binance-usdm`** (틱 0.1 · 로트 0.001 · 최소 50 USDT).

### 발주 본문 (13:28:50.398 / .406, **국면 C1**)

```json
{"venue":"binance-usdm","symbol":"BTCUSDT","side":"short","type":"market",
 "client_order_id":"15-rr-30",
 "exit_plan":{"take_profit":"75943.8",            // ← 이 한 칸만 다름 (비교군 75851.9)
              "stop_loss":"77169.6",              // 두 팔 동일
              "close_after_seconds":45},
 "max_duration_hours":1,
 "client_tracking_id":"cf-15-tp-rr-ratio",
 "tags":["ab-compare","a2-04-15"],
 "metadata":{"arm":"base","changed_field":"exit_plan.take_profit",
             "source":"reports/a/15-moss/21-moss-own-backtest-30d.json trades[1].exit_price 75943.85"}}
```

### 나란히 놓은 결과

| 팔 | `tp_rr_ratio` | 목표가 | 접수 (KST) | 진입 체결가 | 진입 호가 공개 시각 | 청산가 | `exit_trigger` | `exit_trigger_px` | `close_reason` | 수수료 | 순손익 | 소요 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| `15-rr-30` (기록) | 3.0 | **75943.8** | 13:28:50.398 | 76855.363685 | **13:28:51.240** | 75951.444375 | **`take_profit`** | **75943.8** | `take_profit` | 0.07640340 | +0.827515910 | **2.9초** |
| `15-rr-33` (Moss 수정) | 3.3 | 75851.9 | 13:28:50.406 | 76855.363685 | **13:28:51.240** | 75951.444375 | — | — | `close_after` | 0.07640340 | +0.827515910 | 46.0초 |

두 팔의 진입 체결가와 그 체결이 본 호가 공개 시각이 **밀리초까지 같다.**

### 그 칸이 결과를 갈랐나 — **갈랐다. 그리고 방향이 뼈아프다**

- Moss 가 **수수료를 보고 올린 rr 3.3 은, 그 수수료 판단의 근거였던 그 거래를 목표가로 닫지 못한다.** 시장이 실제로 간 곳(75943.85)이 3.0 의 목표가에는 닿고 3.3 의 목표가(75851.9)에는 91.95 만큼 못 미친다.
- 이 대조가 값진 이유: Moss 자기 세계에서는 이 질문 자체가 안 나온다 — 그 백테스트에 수수료가 0이라 rr 을 올릴 이유가 없고, 올린 뒤에 어떤 거래가 죽는지도 안 보여 준다. **같은 시각·같은 호가에 두 목표가를 함께 걸면 그게 바로 보인다.**
- 순손익은 두 팔이 같다 — 합성 호가가 C2 이후 안 움직여 시한 청산도 같은 가격에 났다. **합성 호가라 이 손익은 시장 사실이 아니다.** 선 것은 **rr 대조 설계**다.

---

## 편 23 — crypto-trading-arena · **요율(= venue) 한 칸**

### 두 세팅의 출처

| | 기록 |
|---|---|
| **기준안 (60bp)** | 오프라인 30회: 체결 15건 · 체결액 **$156,392** · traded 9/30(30%). 실시간 12:21:03~12:25:31: **체결 12건 · $169,332 · 수수료 $1,015.99** |
| **비교군 (0bp)** | 오프라인 30회: 체결 21건 · **$462,480** · traded 13/30(43%). 실시간 12:26:49~12:37:13: **체결 43건 · $1,439,744 · 수수료 $0** |

출처: `reports/a/23-crypto-trading-arena/41-ab-summary.txt` · `42-live-summary.txt`.
요율이 사는 곳: `raw/ab_fee.py` — `FeeModel.disclosure_prompt()` 이 커넥터 프롬프트에 수수료를 **문장으로** 적는다. **요율이 판단의 입력이다.**

### 먼저 읽어야 할 우리 쪽 한계

| 어디 | 무엇 |
|---|---|
| `weltiq/capabilities.py:73` | `"execution_resimulation": False` |
| `weltiq/api/server.py:3085` | `"basis": "same_fills_fixed_time_qty_price_refee"` |
| `docs/design/A_TOOLS_TRIAL_ORDER_2026-09-27.md:1639` | 「23 이 재는 것은 **요율이 판단을 바꾸는가**(체결이 변수)이고, 우리가 재는 것은 **요율이 비용을 바꾸는가**(체결이 상수). `execution_resimulation: False` 는 결함이 아니라 계약이다」 |
| `weltiq/api/forward_tests.py:55` | `OrderReq` 주석 — 「수량·종목·**수수료**·실거래 target 은 받지 않는다」. `TrialBuyReq` 도 같다 |

즉 **`cost_compare` 는 체결을 고정하고 요율만 다시 매기고, 시험 주문 본문에는 요율 칸이 아예 없다.**
요율은 **거래소 프로필**로만 들어온다.

### 무엇이 한 칸인가 — `venue`

같은 종목·같은 방향·같은 청산 계획으로, **네 거래소에 같은 bid/ask 를 걸고** venue 만 바꿨다.

| venue | taker | 틱 | 로트 | 최소 주문금액 |
|---|---|---|---|---|
| `binance-spot` | 0.001 (10bp) | 0.01 | 0.00001 | 5 |
| `binance-usdm` | 0.0005 (5bp) | 0.1 | 0.001 | 50 |
| `bybit-linear` | 0.00055 (5.5bp) | 0.1 | 0.001 | 5 |
| `bybit-spot` | 0.001 (10bp) | 0.1 | 0.000001 | 5 |

### 발주 본문 (13:29:39.593 ~ .617, **국면 D1** — 네 거래소 전부 85483.0 / 85483.1)

```json
{"venue":"binance-spot",                          // ← 이 한 칸만 다름
 "symbol":"BTCUSDT","side":"long","type":"market",
 "client_order_id":"23-fee-binance-spot",
 "exit_plan":{"take_profit":"85611.3","close_after_seconds":45},
 "max_duration_hours":1,
 "client_tracking_id":"cf-23-fee-profile",
 "tags":["ab-compare","a2-04-23"],
 "metadata":{"arm":"base","changed_field":"venue(=fee profile)",
             "source":"weltiq/simbroker/profile.py FeeSchedule · reports/a/23-crypto-trading-arena/41-ab-summary.txt"}}
```

목표가 `85611.3` = `85483.1 × 1.0015` (+15bp). 왕복 수수료가 spot 20bp · usdm 10bp 이므로 **그 사이에** 놓아 「같은 청산가에서 부호가 갈리는지」를 본다. 이 값은 arena 기록에 없다 — 하네스가 고른 값이다.

### 나란히 놓은 결과 — 네 팔이 **같은 진입가·같은 청산가**로 닫혔다

| venue | taker | 수량 | 명목 | 진입 체결가 | 청산가 | `exit_trigger_px` | 수수료 | 왕복 수수료(bp) | 총손익(bp) | **순손익** | 순손익(bp) | 소요 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| `binance-spot` | 10bp | 0.00008 | 6.8393 | 85491.698305 | 85602.688865 | 85611.3 | 0.01368756 | 20.013 | 12.983 | **−0.00480832** | **−7.030** | 2.9초 |
| `binance-usdm` | 5bp | 0.001 | 85.4917 | 85491.698305 | 85602.688865 | 85611.3 | 0.08554719 | 10.006 | 12.983 | **+0.02544337** | **+2.976** | 2.9초 |
| `bybit-linear` | 5.5bp | 0.001 | 85.4917 | 85491.698305 | 85602.688865 | 85611.3 | 0.09410191 | 11.007 | 12.983 | **+0.01688865** | **+1.975** | 2.9초 |
| `bybit-spot` | 10bp | 0.000074 | 6.3264 | 85491.698305 | 85602.688865 | 85611.3 | 0.01266099 | 20.013 | 12.983 | **−0.00444769** | **−7.030** | 2.9초 |

진입 체결의 `published_at` 이 네 팔 모두 13:29:40.456~.457 (밀리초 4개 차이), `expected_px` 가 네 팔 모두 **85483.1**, `qty_basis.reference_px` 가 네 팔 모두 **85483.05**.

### 그 칸이 결과를 갈랐나 — **갈랐다. 같은 체결·같은 청산가에서 부호가 뒤집혔다**

- **총손익은 네 팔이 정확히 같다(12.983bp).** 체결가가 같으니 당연하다. **순손익의 부호가 요율만으로 갈렸다**: 10bp 거래소 둘은 −7.03bp, 5bp 는 +2.98bp, 5.5bp 는 +1.98bp.
- **다만 「요율만」이 아니었다.** venue 를 바꾸면 **로트·최소 주문금액도 같이 바뀌어 수량이 달라진다** — 0.00008 / 0.001 / 0.001 / 0.000074, 명목으로 6.83 ~ 85.49 USDT, **13배 차이**. bp 로 정규화하면 비교가 서지만 절대 손익으로는 안 선다. 시험 주문에 요율 칸이 없는 한 **요율만 격리하는 대조는 우리 쪽에서 불가능하다.**
- **arena 가 재던 것은 여전히 못 잰다.** 23편의 12→43건은 「요율 문장을 보고 **모델이 더/덜 친다**」였다. 시험 주문은 **판단을 우리가 고정**해서 낸다 — 재는 것은 「고정된 한 왕복이 요율별로 살아남는가」다. 이번 실측이 보여 준 것: **같은 왕복이 요율에 따라 이익/손실로 갈린다.** 이것이 `cost_compare` 의 사후 재계산과 다른 점은 **실시간 호가 위에서 각 거래소의 로트·최소금액·슬리피지 모형을 실제로 통과시킨다**는 것 하나다.
- **합성 호가라 이 손익은 시장 사실이 아니다.** 선 것은 **요율 프로필 대조 설계**다.

---

## 추가로 답할 것

### 1. 몇 개까지 동시에 낼 수 있나

한 종목·한 호가(국면 E1, binance-spot BTCUSDT 85400.00/85400.01)에 **변형 6개를 `asyncio.gather` 로 동시 발주**했다.

| | |
|---|---|
| 결과 | **6/6 전부 201.** 실패·거절 0 |
| 소요 | **0.02초** (6건 전체) |
| 접수 시각 분포 | 13:29:46.663355 ~ .669863 — **6.5 밀리초** 안에 전부 |
| 막힌 것 | **없다.** 멱등 충돌·한도·중복 어느 코드도 안 났다 |

- 상한을 정하는 것은 **월 한도**뿐이다. 동시 보유 시험 수나 한 종목당 시험 수에 대한 상한 코드는 없다 (`MAX_VARIANTS = 8` 은 `/v1/forward-tests` 묶음의 분기 수이고, 시험 매수 한 건 = 묶음 하나라 여기 안 걸린다).
- 접수는 `pg_advisory_xact_lock` 으로 **사용자 단위 직렬화**된다(`weltiq/forward_test.py:676` `_user_lock`). 6건이 6.5ms 에 줄줄이 통과했으므로 실질 병목은 아니다.
- **하네스 제약 고지**: 이 하네스의 `ApiState` 는 psycopg 커넥션 **하나**를 공유한다(`run_part4.py` 와 같은 구성). 위 숫자는 그 구성에서의 실측이며, 커넥션 풀을 쓰는 운영 구성의 동시성 상한은 이 실험으로 정해지지 않는다.

### 2. 한도 소모 — 변형 N개 = N회인가

**그렇다. N개 = N회다.** 실측:

| 사건 | `used` 전 → 후 | 소모 |
|---|---|---|
| 04편 3팔 | 0 → 3 | **3** |
| 14편 2팔 | 3 → 5 | **2** |
| 15편 2팔 | 5 → 7 | **2** |
| 23편 4팔 | 7 → 11 | **4** |
| 동시 발주 6건 | 11 → 17 | **6** |
| **같은 `client_order_id` · 같은 본문 재전송** | 17 → 17 | **0** (HTTP **200** 멱등 재생) |
| **같은 `client_order_id` · 다른 본문** | 17 → 17 | **0** (HTTP **409** `client_order_id_conflict`) |
| **청산 체결** (`exit-plan:…` 주문) | — | **0** — 체결 기록의 `counted: false` |

최종 `used = 17 / limit = 200`. 시험 17건. 계좌 원장 스냅샷은 **T0 와 T9 가 완전히 동일**(`account_unchanged_vs_T0: true`) — 8개 계좌·거래 표 전부.

**따라서 비교군 예산은 그대로 나눗셈이다.** pro 월 1000회 기준(운영 정책), 3팔짜리 대조는 월 **333회**, 4팔짜리는 **250회**, 2팔은 **500회**. 재전송·409·청산이 공짜라 **재시도 비용은 0**이다.

### 3. 「같은 호가를 봤다」를 증명할 칸 — **있다. 단 셋 다 반쪽이다**

| 칸 | 어디 | 실측 | 한계 |
|---|---|---|---|
| `qty_basis.reference_px` | 201 응답 · `GET /v1/forward-tests/{id}` | 국면마다 팔 전체가 동일 — A1 `85198.175` · B1 `85900.005` · C1 `76863.15` · **D1 `85483.05` (네 거래소 전부)** | **접수 시점의 기준가일 뿐 체결가가 아니다.** 그리고 **주식·선물에는 없다** — `us-equity`·`krx`·`cme` 는 `rule: one_share_or_contract` 라 `qty_basis` 에 `reference_px` 칸 자체가 안 생긴다 (`weltiq/forward_test.py:393-398`) |
| 체결의 `published_at` | `GET /v1/forward-tests/{id}/orders` → `fills[].published_at`, CSV 내보내기 열 | 04편 세 팔 전부 **13:25:57.507** · 15편 두 팔 전부 **13:28:51.240** · 23편 네 팔 13:29:40.456~.457 | **체결 뒤에만 생긴다.** 접수 직후에는 없다 |
| 체결의 `expected_px` + `quote_source` | 같은 곳 | 23편 네 팔 `expected_px` 전부 **85483.1**. `quote_source` 는 `binance`/`bybit` 로 **거래소별로 다르다** | `quote_source` 는 「같은 스냅샷」이 아니라 「자기 거래소 피드」를 말한다. **여러 거래소가 같은 호가를 봤다는 것을 이 칸으로는 못 쓴다** |

**없는 칸 — 우리가 열어야 할 자리:**

1. **호가 스냅샷 식별자가 없다.** BBO 한 건에 id 가 없어서 「이 두 체결이 **같은 한 호가**에서 나왔다」를 응답만으로 단정할 수 없다. `published_at` 이 밀리초까지 같다는 것이 현재의 최선이고, 그건 정황이지 식별이 아니다.
2. **접수 시점의 호가가 응답에 없다.** `reference_px` 는 중간값 하나이고 bid/ask 가 따로 안 나온다. 미체결로 끝난 팔(14편 비교군)은 **자기가 어떤 호가를 봤는지 응답 어디에도 안 남는다.**
3. **`client_tracking_id` 로 실험 전체를 되찾을 수 없다** *(실행 시점 기준 — 환경 고지 §동시 편집 참조)*. 실측: `GET /v1/forward-tests?q=cf-04-stoploss-width` → **0건**. 그 시점의 `list_page` 의 `q` 는 `test_id`·`symbol`·`memo`·`tags` 만 봤다. `client_tracking_id` 필터는 **한 `test_id` 안의 `/orders`** 에만 있다(`weltiq/api/forward_tests.py:270-274`). 시험 매수는 한 건이 곧 한 묶음이라 **여러 팔을 잇는 추적 ID 가 교차 조회로는 무용지물**이었다. 실제로 실험을 되찾은 것은 **태그**다 — `GET /v1/forward-tests?tag=a2-04-04` → **3건** (정확히 04편 세 팔).

   → **이 실행 직후(13:29:13) 같은 작업 트리에서 이 칸이 열렸다** — `list_page(tracking=…)` 정확 일치와 `q` 의 `client_tracking_id` 확장. 나는 그 코드를 돌리지 않았으므로 **여기서는 「열렸다」고만 적고 실측으로 주장하지 않는다.** 위 0건은 열리기 전의 사실이다.

---

## 레시피 표

| 편 | 바꾼 칸 | 대조군 수 | 무엇이 측정되나 | 한도 비용 |
|---|---|---|---|---|
| **04 freqtrade** | `exit_plan.stop_loss` (손절 폭) | **3** (기록 −0.05% · 합성 −0.10% · 기록 폭 −0.20%) | 같은 체결·같은 호가에서 **어느 손절선이 발동하는가** — `exit_trigger`·`exit_trigger_px`·`close_reason`·소요 시간. 손익 차는 호가가 더 움직여야 난다 | **3회** |
| **14 QuantDinger** | `limit_price` (두 최적점이 낸 진입가) | **2** | 같은 호가에서 **지정가 한 칸이 체결/미체결을 가르는가**. 미체결 팔은 `close_after_seconds` 시계가 시작조차 안 한다. **격자 파라미터 자체는 대조 불가** — 도구가 거래별 레벨을 안 내놓고 우리 문법 상한은 200 | **2회** |
| **15 Moss** | `exit_plan.take_profit` (`tp_rr_ratio` 3.0→3.3) | **2** | **비용을 보고 올린 rr 이 그 근거였던 거래를 죽이는가** — 시장이 실제로 간 곳에 3.0 은 닿고 3.3 은 91.95 못 미친다 | **2회** |
| **23 arena** | `venue` (= 수수료 프로필) | **4** (10bp · 5bp · 5.5bp · 10bp) | 같은 체결가·같은 청산가에서 **요율만으로 순손익 부호가 뒤집히는가** (총손익 12.983bp 고정, 순 −7.03 / +2.98 / +1.98 / −7.03bp). **주의: venue 는 로트·최소금액도 같이 바꿔 수량이 13배 갈린다** | **4회** |
| (측정) 동시 발주 | `exit_plan.stop_loss` | **6** | 동시 발주 상한 — 6/6 201, 0.02초, 접수 분포 6.5ms, 막히는 코드 없음 | **6회** |
| (측정) 멱등 | 없음 / 본문 한 칸 | 2 | 재전송 200·0회 / 다른 본문 409·0회 | **0회** |

**일반 규칙: 대조군 N개 = 한도 N회. 청산·재전송·거절은 0회.**

---

## 마감

| | |
|---|---|
| 종료 순서 | 케이스 종료 → `axis-b-evidence.json` 기록 → SIGINT → uvicorn 종료 → `pg_ctl -m fast stop` (`waiting for server to shut down.... done / server stopped`) → `tempfile.TemporaryDirectory` 컨텍스트 종료로 임시 디렉터리 삭제 |
| 잔존 프로세스 | 없음 — `pgrep -f weltiq-cfb` 0건 |
| 잔존 포트 | 없음 — 8912·55552 모두 LISTEN 0건 |
| 잔존 디렉터리 | 없음 — `/tmp/weltiq-cfb-*` 0건 |
| 운영 영향 | 없음 — 로컬 엔진(8722~8724)·DB `weltiq_r1_claude` 미접속. 커밋하지 않았다 |
