Metadata-Version: 2.4
Name: rawr-dashboard
Version: 0.1.2
Summary: RAWR Dashboard — bento module board for journal, P&L, and indicators.
Project-URL: Homepage, https://github.com/snowjang24/rawr-tools
Project-URL: Repository, https://github.com/snowjang24/rawr-tools
Project-URL: Documentation, https://github.com/snowjang24/rawr-tools/tree/main/packages/rawr-dashboard#readme
Project-URL: Issues, https://github.com/snowjang24/rawr-tools/issues
Requires-Python: >=3.12
Requires-Dist: click>=8.0
Requires-Dist: fastapi>=0.110
Requires-Dist: pydantic>=2.0
Requires-Dist: rawr-tools
Requires-Dist: uvicorn[standard]>=0.29
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# rawr-dashboard

A RAWR plugin that adds a local bento-board web UI for trade journalling, portfolio reviews, P&L tracking, and indicator tiles — plus MCP tools so an AI agent can write to the journal directly.

## Install

```bash
pip install rawr-dashboard
```

The package bundles the pre-built SPA (no Node.js needed at runtime).

## Usage

### Serve the dashboard

```bash
rawr dashboard serve            # opens http://127.0.0.1:8800/ in your browser
rawr dashboard serve --port 9000 --no-open
```

### Import KIS executions

```bash
rawr dashboard sync             # idempotent — safe to run repeatedly
```

## 한국 시장 관찰 모니터

`rawr dashboard monitor`는 한국 주식/ETF 시장을 로컬에서 관찰하고 후보와 주문 프리뷰를 저장하는 preview-only 기능입니다. 이 기능은 실주문을 제출하지 않습니다.

```bash
rawr dashboard monitor doctor
rawr dashboard monitor run-once
rawr dashboard monitor start --interval-minutes 10
rawr dashboard monitor status
rawr dashboard monitor logs --tail 100
rawr dashboard monitor stop
```

- 기본 주기는 10분입니다.
- 허용 주기는 5-15분입니다.
- 백그라운드 로그 기본 경로는 `~/.rawr/rawr-dashboard-monitor.log`입니다.
- 다른 로그 파일을 쓰려면 `rawr dashboard monitor start --log-file ./monitor.log`를 사용합니다.
- 후보별 주문 프리뷰는 `preview_only=true`, `live_order_submitted=false`를 포함합니다.
- 웹 대시보드는 `rawr dashboard serve`로 실행합니다.
- 실거래 검토는 기존 RAWR order preview와 policy gate를 별도로 거쳐야 합니다.

### OHLCV cache refresh

모니터와 백테스트는 로컬 `ohlcv_cache`를 읽습니다. 새 DB이거나 캐시가 비어 있으면 먼저 가격 캐시를 채웁니다.

```bash
rawr dashboard monitor cache refresh \
  --tickers 005930,000660 \
  --days 260 \
  --provider krx
```

파일 입력도 지원합니다.

```bash
rawr dashboard monitor cache refresh \
  --tickers-file ./watchlist.txt \
  --days 260 \
  --provider krx
```

`--provider krx`는 RAWR의 KRX OpenAPI 설정을 사용합니다. 미국 티커나 지수 ETF를 캐시할 때는 `--provider yfinance`를 사용할 수 있습니다. 이 명령은 `ohlcv_cache`만 갱신하며 후보, 알림, 주문 프리뷰, 실주문을 만들지 않습니다.

캐시 준비 상태는 `rawr dashboard monitor doctor`의 `cache_status`, `cache_ready`,
`cache_universe_source` 출력으로 확인할 수 있습니다. 같은 값은
`GET /api/monitor/cache/status`와 웹 대시보드의 시장 관찰 타일 `캐시 상태` 패널에도
노출됩니다. 관심종목이 비어 있으면 최근 캐시된 종목을 fallback universe로 사용하고,
관심종목이 있으면 관심종목 중 캐시가 있는 종목만 스캔 준비 상태로 봅니다.

### Phase 1: Swing CCI rebound

현재 모니터의 첫 전략은 `swing_cci_rebound`입니다. 이 전략은 외부 지표를 호출하지 않고 로컬 `ohlcv_cache`의 가격/거래량 데이터만 사용합니다.

- 개별 종목 CCI(20)가 `-200` 이하까지 밀린 뒤 회복을 시작해야 합니다.
- 최신 종가가 전일 종가보다 높아야 합니다.
- ATR(14)와 최근 스윙 저점으로 손절가를 계산합니다.
- 목표가는 진입가 기준 2R 지점으로 계산합니다.
- 50/200일 이동평균 데이터가 충분하면 후보 evidence에 추세 상태를 함께 기록합니다.

CNN Fear & Greed Index, Nasdaq CCI, S&P500 breadth 같은 외부 시장 필터는 Phase 2 범위입니다. 외부 지표가 붙기 전까지 Phase 1은 종목 단위 반등 후보를 preview-only로 골라내는 역할에 집중합니다.

### Phase 2A: Market regime gate

`swing_cci_rebound` 후보에 시장 레짐 조건을 강제로 붙이고 싶으면, 먼저 레짐 snapshot을 캐시에 저장한 뒤 `--require-market-regime` 옵션을 사용합니다.

```bash
rawr dashboard monitor regime set \
  --as-of 2026-06-12T09:00:00+09:00 \
  --nasdaq-cci20 -230 \
  --cnn-fgi 18 \
  --sp500-above-50dma-pct 16 \
  --nasdaq-ma50 18000 \
  --nasdaq-ma200 17000 \
  --source manual

rawr dashboard monitor regime status
rawr dashboard monitor run-once --require-market-regime
rawr dashboard monitor start --require-market-regime
```

게이트 조건은 다음과 같습니다.

- Nasdaq CCI(20) `<= -200`
- CNN FGI `<= 25`
- S&P500 50일선 위 종목 비율 `<= 20`
- Nasdaq 50일 이동평균 `>` 200일 이동평균

`--require-market-regime`을 켰는데 snapshot이 없거나 24시간보다 오래됐거나 조건을 통과하지 못하면 신규 `swing_cci_rebound` 후보는 저장하지 않습니다. Phase 2A는 캐시/게이트 단계이며, CNN/Barchart/yfinance 자동 수집기는 후속 Phase 2B 범위입니다.

### Phase 2B: Regime refresh

CNN FGI와 Nasdaq 가격 지표는 자동으로 가져오고, S&P500 breadth 값은 직접 입력해서 snapshot을 갱신할 수 있습니다.

```bash
rawr dashboard monitor regime refresh \
  --sp500-above-50dma-pct 16 \
  --nasdaq-ticker '^IXIC'
```

이 명령은 다음 값을 저장합니다.

- CNN Fear & Greed Index
- Nasdaq CCI(20)
- Nasdaq 50일/200일 이동평균
- 사용자가 입력한 S&P500 50일선 위 종목 비율

`regime refresh`는 snapshot만 저장합니다. 후보 스캔이나 주문 프리뷰를 만들지 않고, 실주문도 제출하지 않습니다. Barchart breadth 자동 연동은 API/권한 확인이 필요한 후속 단계입니다.

### Phase 2C: S&P500 breadth calculation

S&P500 breadth 값을 직접 입력하지 않고, 티커 목록으로부터 50일 이동평균 위 종목 비율을 계산할 수도 있습니다.

```bash
rawr dashboard monitor regime refresh \
  --sp500-tickers AAPL,MSFT,NVDA,AMZN,META \
  --nasdaq-ticker '^IXIC'
```

파일 입력도 지원합니다.

```bash
rawr dashboard monitor regime refresh \
  --sp500-tickers-file ./sp500.txt
```

`sp500.txt`는 쉼표 또는 줄바꿈으로 구분된 티커 목록을 담으면 됩니다.

```text
AAPL
MSFT
NVDA,AMZN,META
```

수동 breadth 값, `--sp500-tickers`, `--sp500-tickers-file` 중 정확히 하나만 사용해야 합니다. 티커 기반 계산은 각 종목의 OHLCV가 최소 50개 이상 있어야 하며, 부족하면 snapshot을 저장하지 않습니다. RAWR는 S&P500 구성종목 목록을 내장하지 않습니다. 구성종목은 시간이 지나며 바뀌므로 최신 목록은 사용자가 관리해야 합니다.

### Phase 3A: Swing strategy backtest

캐시된 OHLCV로 `swing_cci_rebound` 전략을 간단히 검증할 수 있습니다.

```bash
rawr dashboard monitor backtest 005930 --days 260 --max-hold-bars 20
```

백테스트 규칙은 다음과 같습니다.

- 신호 발생 봉의 종가로 진입한 것으로 계산합니다.
- Phase 1의 ATR/스윙저점 손절가와 2R 목표가를 사용합니다.
- 이후 봉에서 손절가 또는 목표가에 닿으면 청산합니다.
- 같은 봉에서 손절과 목표가가 모두 닿으면 보수적으로 손절을 먼저 적용합니다.
- `--max-hold-bars` 안에 닿지 않으면 시간청산합니다.
- 겹치는 포지션은 열지 않습니다.

이 명령은 연구용입니다. `ohlcv_cache`를 읽기만 하며 후보, 알림, 주문 프리뷰, 실주문을 만들지 않습니다.

### Phase 3B: Backtest API and dashboard view

같은 백테스트 결과는 웹 API로도 확인할 수 있습니다.

```bash
GET /api/monitor/backtest/005930?days=260&max_hold_bars=20
```

`monitor_board` 타일 데이터에는 최근 후보 종목의 `backtests` 요약이 포함됩니다. 웹 대시보드의 시장 관찰 타일은 거래 수, 승률, 총 R, 평균 R, 최대 낙폭 R을 표시합니다. 타일 config에 `strategy_id`를 넣으면 같은 응답의 `strategy_validation`에 해당 전략의 최신 검증 상태가 포함됩니다. `strategy_id`가 없으면 저장된 최신 검증 report를 자동으로 사용합니다. 시장 관찰 타일의 `검증 게이트` 패널에는 stage, pass/fail/not-run 수, attention check, 19개 검증 항목의 우선순위 체크리스트가 렌더링됩니다. 상태는 `not_configured`, `missing_strategy`, `missing_report`, `ok` 중 하나이며, `ok`일 때는 `failed_checks`, `warning_checks`, `not_run_required_checks`, `attention_checks` summary와 `checks` 상세 목록이 들어갑니다. 타일 조회 경로는 캐시와 저장된 검증 report를 읽기만 하며 후보, 알림, 주문 프리뷰, 실주문을 만들지 않습니다.

시장 관찰 타일의 `백테스트 검증` 버튼은 현재 후보 첫 종목 또는 백테스트 요약 첫 종목으로
`POST /api/monitor/strategies/{strategy_id}/validate-backtest`를 호출해 최신 검증 report를 저장하고
타일 데이터를 다시 불러옵니다. 이 동작도 연구/검증용이며 실주문을 제출하지 않습니다.

최근 스캔 이력은 `GET /api/monitor/cycles?limit=20`로 조회할 수 있습니다. 같은 데이터는
시장 관찰 타일의 `최근 스캔` 패널에 표시되며, 각 사이클의 성공/오류 상태, 완료 시각,
universe/candidate/notification 수, 에러 메시지를 보여줍니다.
시장 관찰 타일의 `1회 스캔` 버튼은 preview-only `POST /api/monitor/run-once`를 호출한 뒤
해당 타일 데이터를 다시 불러옵니다.
타일 config에 `require_strategy_validation`, `strategy_id`, `min_strategy_stage`,
`require_market_regime`, `market_regime_max_age_minutes`가 있으면 버튼도 같은 게이트 조건을
API body로 넘깁니다.
API 호출 시 JSON body로 `require_strategy_validation`, `strategy_id`, `min_strategy_stage`,
`require_market_regime`, `market_regime_max_age_minutes`를 넘기면 CLI의 게이트 옵션과 같은
조건으로 1회 스캔을 실행할 수 있습니다. `require_strategy_validation=true`일 때
`strategy_id`가 비어 있으면 요청은 422 validation error로 거절됩니다.
타일은 30초마다 자동으로 다시 불러와 상태, 최근 스캔, 로그 tail을 갱신합니다. 이 자동
갱신은 데이터를 다시 읽기만 하며 스캔이나 주문을 실행하지 않습니다.

백그라운드 worker 로그 tail은 `GET /api/monitor/logs?tail=100`로 조회할 수 있습니다. 이
엔드포인트는 `RAWR_DASHBOARD_MONITOR_LOG` 또는 기본
`~/.rawr/rawr-dashboard-monitor.log`만 읽으며, 시장 관찰 타일의 `실행 로그` 패널에도
같은 tail이 표시됩니다.

### Phase 4A: Strategy validation model and CLI

전략 아이디어를 바로 모니터/자동매매에 연결하지 않고, 먼저 19개 검증 항목을 통과해야 하는 모델, CLI 저장 흐름, 백테스트 기반 자동 검증, 웹 대시보드 표시를 추가했습니다.

- 전략 발견 방식: 가격/거래량 패턴, 공개 팩터, 기술적 지표 조합, 신규 공식 팩터, AI 팩터 모델
- 검증 항목: 데이터 검증, 과최적화, walk-forward, out-of-sample, 몬테카를로, 스트레스, 거래비용, 용량, 켈리, MDD, Sharpe, Sortino, Calmar, Profit Factor, Recovery Factor, 파산확률, regime, 상관관계, factor exposure
- 단계: `research_only` -> `backtest_passed` -> `walk_forward_passed` -> `paper_ready` -> `limited_live_ready`
- 안전장치: 모든 전략 후보는 `preview_only=true`, `live_order_submitted=false`를 유지합니다.

전략 등록:

```bash
rawr dashboard monitor strategy create \
  --strategy-id swing-cci-regime-v1 \
  --name "Swing CCI Regime V1" \
  --discovery-method technical_indicator_combo \
  --universe NASDAQ100 \
  --universe SP500 \
  --entry-rule "nasdaq_cci20 <= -200" \
  --entry-rule "stock_cci20 <= -200" \
  --exit-rule "direction_invalidated_at_minus_5pct" \
  --indicator CCI20 \
  --indicator CNN_FGI
```

검증 결과 저장:

```bash
rawr dashboard monitor strategy validate swing-cci-regime-v1 \
  --check data_validation=pass \
  --check overfitting_validation=pass \
  --check trading_cost_simulation=pass \
  --check max_drawdown_limit=pass \
  --check sharpe_ratio=pass \
  --check sortino_ratio=pass \
  --check calmar_ratio=pass \
  --check profit_factor=pass \
  --message "backtest gate passed"
```

캐시된 OHLCV 백테스트 결과로 일부 검증 항목을 자동 저장:

```bash
rawr dashboard monitor strategy validate-backtest swing-cci-regime-v1 005930 \
  --days 260 \
  --max-hold-bars 20 \
  --min-bars 120 \
  --min-trades 1 \
  --max-drawdown-r 3 \
  --min-profit-factor 1.5 \
  --min-recovery-factor 1.0 \
  --cost-per-trade-r 0.05 \
  --min-sharpe-ratio 0.5 \
  --min-sortino-ratio 0.5 \
  --min-calmar-ratio 1.0 \
  --sensitivity-offset -5 \
  --sensitivity-offset 0 \
  --sensitivity-offset 5 \
  --min-sensitivity-pass-rate 0.67 \
  --out-of-sample-fraction 0.3 \
  --min-oos-trades 1 \
  --walk-forward-windows 3 \
  --min-window-trades 1 \
  --min-walk-forward-pass-rate 0.67 \
  --monte-carlo-paths 500 \
  --monte-carlo-seed 7 \
  --min-monte-carlo-profit-probability 0.55 \
  --max-monte-carlo-drawdown-r 3 \
  --ruin-drawdown-r 3 \
  --max-risk-of-ruin-probability 0.05 \
  --stress-r-haircut 0.25 \
  --stress-loss-multiplier 1.5 \
  --min-stress-total-r 0 \
  --max-stress-drawdown-r 3 \
  --min-kelly-trades 5 \
  --kelly-fraction-multiplier 0.25 \
  --max-kelly-fraction 0.05 \
  --capacity-capital-krw 1000000 \
  --capacity-target-position-fraction 0.2 \
  --capacity-max-participation-rate 0.01 \
  --capacity-lookback-bars 20 \
  --min-capacity-multiple 1 \
  --market-regime-max-age-minutes 1440 \
  --market-regime-cnn-fgi-max 25 \
  --market-regime-sp500-above-50dma-pct-max 20 \
  --market-regime-nasdaq-cci20-max -200 \
  --correlation 0.21 \
  --correlation -0.18 \
  --max-absolute-correlation 0.7 \
  --min-correlation-samples 2 \
  --factor-exposure momentum=0.22 \
  --factor-exposure volatility=-0.14 \
  --max-absolute-factor-exposure 0.7 \
  --min-factor-exposure-count 2
```

`validate-backtest`는 `data_validation`, `max_drawdown_limit`, `profit_factor`, `recovery_factor`, `overfitting_validation`, `out_of_sample_test`, `walk_forward_analysis`, `capacity_analysis`, `market_regime_test`를 계산합니다. `data_validation`은 최소 OHLCV/거래 샘플 수와 함께 캐시 OHLCV의 날짜 형식, 날짜 중복, 비증가 순서를 검사하고 해당 카운트를 metrics에 남깁니다. `--correlation` 값을 하나 이상 주면 `correlation_analysis`도 계산하고, `--factor-exposure name=value`를 하나 이상 주면 `factor_exposure_analysis`도 계산합니다. `overfitting_validation`은 `max_hold_bars` 주변값을 함께 돌려 민감도를 확인합니다. `out_of_sample_test`는 캐시된 전체 기간의 뒤쪽 비율을 검증 구간으로 분리하고, `walk_forward_analysis`는 전체 기간을 연속 구간으로 나눠 각 구간의 거래 결과를 확인합니다. 현재 walk-forward는 파라미터를 구간마다 재최적화하지 않는 fixed-rule proxy입니다.

`--cost-per-trade-r`가 0보다 크면 거래별 R multiple에서 비용을 차감해 `trading_cost_simulation`, trade-level Sharpe proxy, Sortino proxy, Calmar proxy도 pass/fail로 저장합니다. 비용을 지정하지 않으면 `trading_cost_simulation`은 `warning`으로 남습니다. `monte_carlo_simulation`과 `risk_of_ruin`은 비용 차감 후 trade R multiple을 seed 기반 bootstrap으로 재표본추출해 계산합니다. `stress_test`는 trade R에 haircut과 손실 확대를 적용하는 adverse-assumption 방식이며, `kelly_sizing_review`는 승률과 평균 이익/손실 R로 raw Kelly와 capped fractional Kelly를 저장합니다. `capacity_analysis`는 캐시 OHLCV의 `close * volume` 평균 거래대금과 목표 포지션 금액을 비교합니다. `market_regime_test`는 최신 market-regime snapshot을 기존 `MarketRegimeGate`로 평가하며, snapshot이 없거나 오래됐으면 `missing_market_regime`으로 실패합니다. `correlation_analysis`와 `factor_exposure_analysis`는 외부에서 계산한 보유종목/벤치마크/다른 전략 대비 상관계수와 팩터 노출값을 명시 입력으로 받아 검증합니다.

상태 확인:

```bash
rawr dashboard monitor strategy status swing-cci-regime-v1
```

상태 출력은 최신 report의 집계와 함께 `failed_checks`, `warning_checks`, `not_run_required_checks`, `attention_checks`를 표시합니다. `attention_checks`는 실패, 경고, 아직 실행하지 않은 필수 검증을 canonical 순서로 합친 운영용 점검 목록입니다.

웹/API에서도 최신 report와 같은 summary를 조회할 수 있습니다.

```bash
GET /api/monitor/strategies/swing-cci-regime-v1/validation-report
```

웹/API에서 백테스트 검증을 실행하고 저장할 수도 있습니다. 요청 바디의 임계값 필드는 CLI
`validate-backtest` 옵션과 같은 의미입니다.

```bash
POST /api/monitor/strategies/swing-cci-regime-v1/validate-backtest
{
  "code": "005930",
  "days": 260,
  "max_hold_bars": 20,
  "min_bars": 120,
  "cost_per_trade_r": 0.05,
  "correlation_coefficients": [0.21, -0.18],
  "factor_exposures": {
    "momentum": 0.22,
    "volatility": -0.14
  }
}
```

응답은 저장된 report id, backtest summary, 최신 validation report, operator summary를 함께 반환합니다.

저장된 전략 검증 상태를 모니터 스캔에 강제로 적용:

```bash
rawr dashboard monitor run-once \
  --require-strategy-validation \
  --strategy-id swing-cci-regime-v1 \
  --min-strategy-stage paper_ready
```

백그라운드 모니터에도 같은 게이트를 적용할 수 있습니다.

```bash
rawr dashboard monitor start \
  --require-strategy-validation \
  --strategy-id swing-cci-regime-v1 \
  --min-strategy-stage paper_ready
```

`--require-strategy-validation`을 켰는데 저장된 최신 report가 없거나, report stage가 `--min-strategy-stage`보다 낮거나, blocker가 있으면 후보를 저장하지 않습니다.

설계 문서는 `docs/superpowers/specs/2026-06-14-quant-strategy-validation-design.md`, `docs/superpowers/specs/2026-06-14-quant-strategy-validation-persistence-design.md`, `docs/superpowers/specs/2026-06-14-monitor-strategy-validation-gate-design.md`, `docs/superpowers/specs/2026-06-14-strategy-backtest-validation-design.md`, `docs/superpowers/specs/2026-06-14-backtest-risk-cost-validation-design.md`, `docs/superpowers/specs/2026-06-14-backtest-overfitting-sensitivity-design.md`, `docs/superpowers/specs/2026-06-14-strategy-validation-visibility-design.md`, `docs/superpowers/specs/2026-06-14-monitor-board-strategy-validation-design.md`에 있습니다. 구현 계획은 `docs/superpowers/plans/2026-06-14-quant-strategy-validation.md`, `docs/superpowers/plans/2026-06-14-quant-strategy-validation-persistence.md`, `docs/superpowers/plans/2026-06-14-monitor-strategy-validation-gate.md`, `docs/superpowers/plans/2026-06-14-strategy-backtest-validation.md`, `docs/superpowers/plans/2026-06-14-backtest-risk-cost-validation.md`, `docs/superpowers/plans/2026-06-14-backtest-overfitting-sensitivity.md`, `docs/superpowers/plans/2026-06-14-strategy-validation-visibility.md`, `docs/superpowers/plans/2026-06-14-monitor-board-strategy-validation.md`에 있습니다.

## Dev flow

The SPA source lives under `apps/dashboard/` (Vite + React). To rebuild it:

```bash
pnpm --dir apps/dashboard build   # writes to src/rawr_dashboard/web/static/
```

To rebuild the Python wheel with the fresh SPA:

```bash
python -m build --wheel packages/rawr-dashboard
```

> **Always build the SPA first.** The wheel force-includes whatever is in
> `web/static/`; if you skip the `pnpm build` step the wheel ships without a UI
> and `rawr dashboard serve` returns 404 at `/`.

## Data model

| Layer | File | Purpose |
|-------|------|---------|
| Models | `models.py` | `JournalEntry`, `Annotation`, `CalendarItem` (Pydantic) |
| Core | `core/journal.py` | `JournalService` — create/close entry, upsert annotation |
| Core | `core/reviews.py` | `ReviewService` — store portfolio reviews in RAWR memory events |
| Core | `core/sync.py` | `KisSyncService` — import KIS executions (idempotent) |
| Core | `core/board.py` | `BoardService` — module/board layout CRUD |
| Web | `web/app.py` | FastAPI app factory |
| Web | `web/deps.py` | `get_db()` — shared `RawrDB` instance |
| CLI | `cli.py` | `dashboard` Click group; `get_cli_plugin()`, `get_mcp_plugin()` |

## Built-in review workflow

The default board includes:

- `portfolio_reviews` — writes recurring portfolio reviews to RAWR `memory_events`.
- `trade_entry` — records manual buy/sell journal entries to the shared `journal` table.

API endpoints:

```bash
GET  /api/reviews
POST /api/reviews
GET  /api/journal
POST /api/journal
```

## MCP tools (agent write access)

When RAWR's MCP server is running, an AI agent can call these tools:

### `dashboard_record_trade`

Record a new open trade in the journal.

| Parameter | Type | Description |
|-----------|------|-------------|
| `code` | `str` | Ticker symbol |
| `name` | `str` | Company / asset name |
| `side` | `str` | `"buy"` or `"sell"` |
| `qty` | `int` | Quantity |
| `entry_price` | `float` | Entry price |
| `reason` | `str` | Trade rationale (optional) |
| `strategy` | `str` | Strategy tag (optional) |
| `currency` | `str` | Default `"KRW"` |

Returns `{"journal_id": int, "status": "open"}`.

### `dashboard_close_trade`

Close an open journal entry with its realized outcome.

| Parameter | Type | Description |
|-----------|------|-------------|
| `journal_id` | `int` | ID returned by `dashboard_record_trade` |
| `exit_price` | `float` | Exit price |
| `outcome_pnl` | `float` | Realized P&L |
| `outcome_pct` | `float` | Return % |

Returns `{"journal_id": int, "updated": bool, "status": "closed" | "not_found"}` — `updated` is `false` (status `"not_found"`) when no entry matched the id.

### `dashboard_annotate_trade`

Attach a reflection note to a trade entry.

| Parameter | Type | Description |
|-----------|------|-------------|
| `journal_id` | `int` | Target entry |
| `tags` | `list[str]` | Freeform tags (optional) |
| `confidence` | `int` | Conviction level 1–5 (optional) |
| `emotion` | `str` | Emotional state note (optional) |
| `discipline_checklist` | `dict` | Key→bool checklist (optional) |
| `mistakes` | `str` | Post-trade mistake notes (optional) |

Returns `{"journal_id": int, "annotated": true}`.

### `dashboard_sync_kis`

Pull KIS executions into the journal (idempotent).

Returns `{"created": int, "skipped": int}`.
