Files
trex-core/docs/data-model.md
T
genichinandClaude Opus 4.8 97d58318db Deliver BAT-004: broker execution + KIS adapter + durable handoff
Implement REQ-011~015 (dcy-003): the order-execution layer on top of the
BAT-002 slot-core daemon, connecting intents to real orders.
- application: BrokerPort (submit/poll_fill/cancel) + ExecutionService
  (claim -> submit -> poll -> transition -> rollback -> reconcile)
- adapters/broker: PaperBroker (deterministic async double) and KISBroker
  (KIS Open API: token, order-cash, inquire-daily-ccld, cancel; VTS sandbox
  tr_ids; live account gated behind allow_live)
- persistence: option-A execution queue (find_pending_for_dispatch FOR
  UPDATE SKIP LOCKED, mark_dispatched idempotency guard, clear_dispatch)
- runtime: background execution loop in the daemon lifespan + startup
  reconcile; config selects paper|kis

Verification (real KIS VTS 모의투자 + PostgreSQL): 92 passed, ruff clean,
domain import sweep shows zero broker/web/db deps, buy->holding /
sell->closed / reject->idle, idempotent dispatch (exactly one order),
reconcile after crash creates no duplicate order, KIS sandbox token+submit
round-trip, and a daemon E2E through the background loop. Align the four
baseline docs. BAT-004 -> release-candidate; REQ-011~015 -> Implemented.

KIS live-account go-live, partial-fill accrual, option-B outbox, connection
pooling, and the safety floor remain deferred to follow-up Discoveries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:46:17 +09:00

6.6 KiB

Trex Core Data Model

  • Baseline Mode: mixed
  • Baseline Seed: .stage-pilot/bootstrap/baseline.yaml
  • Status: draft
  • Owner: project maintainers
  • Last Updated (KST): 2026-06-03
  • Source Discovery / Batch: bootstrap-baseline (pre-Discovery)

Project Summary

  • trex 제품군의 공용 베이스로, 첫 도메인으로 trex-orbit 의 일일 거래 슬롯 생명주기(slot) 순수 도메인을 storage-agnostic 하게 이식한 코어다.

Primary Domain

  • 자동매매 일일 거래 슬롯 생명주기 도메인 (equity trading slot lifecycle)

Primary Persistence Backend

  • PostgreSQL (BAT-002, REQ-006) — 코어 데몬의 durable 단일 writer. 도메인은 여전히 storage-agnostic(SlotRepository Protocol); in-memory 어댑터는 테스트용으로 잔존. 슬라이스 1 테이블: daily_slot / daily_symbol_entries / slot_transition_log / intent_log (daily_slot_archive·prune 은 범위 밖).

Purpose

  • This document captures the approved cross-cutting data model baseline for the project.
  • It is a shared reference for REQ drafting, batch design, implementation, verification, migration planning, and handoff.

Scope

  • Covers core entities, relationships, states, persistence mappings, and shared consistency rules.
  • Does not duplicate full functional acceptance criteria already owned by REQ documents.
  • Does not replace ORM definitions, migration files, or generated schema artifacts.

Model Summary

  • Slot :: 하나의 일일 거래 슬롯의 현재 생명주기 상태/점유 정보(source of truth)
  • SlotTransitionRecord :: 슬롯 상태 전이의 append-only 감사 기록
  • daily_symbol_entries (카운터) :: (trading_date, symbol) 별 재진입 횟수(결정 입력)
  • SlotCapacity (계산 스냅샷) :: idle/holding/pending + scarcity_ratio (영속 엔티티 아님)

Entity: Slot

  • Purpose: 하나의 일일 거래 슬롯의 현재 생명주기 상태와 점유 정보를 담는 source of truth.
  • Source of Truth: daily_slot (향후 테이블) / 현재는 in-memory dict
  • Lifecycle: idle -> pending_buy -> holding -> pending_sell -> closed -> (recovery) idle ; 모든 비-error 상태 -> error ; error -> {idle, holding}

Key Fields

  • slot_id :: UUID :: 슬롯 식별자(PK)
  • trading_date :: date :: 거래일
  • status :: SlotState :: 6 상태(idle/pending_buy/holding/pending_sell/closed/error) 중 현재 상태
  • symbol :: str? :: 점유 종목
  • qty / avg_price / entry_price :: numeric? :: 수량 / 평단 / 진입가
  • allocated_capital :: numeric? :: 배정 자본
  • order_id / broker_order_id :: str? :: 주문 식별자(자유 주석 / 브로커 핸들)
  • strategy_id / sell_strategy_id :: str? :: 진입/청산 전략 식별
  • portfolio_id :: str? :: 포트폴리오 식별
  • forced_close_at :: datetime? :: 강제 청산 마감선
  • created_at / updated_at :: datetime? :: 생성/갱신 시각

Relationships

  • daily_symbol_entries :: closed->idle 복구 시 (trading_date, symbol) 카운트 +1
  • slot_transition_log :: 매 전이마다 append-only 기록 1행

State Rules

  • 8 전이 패밀리에 없는 전이는 거부한다.
  • 전이 전 current status == from_state 여야 한다(레이스 감지).
  • closed->idle / pending_buy->idle 복구 시 점유 필드(symbol/qty/.../forced_close_at)를 초기화한다.

Entity: SlotTransitionRecord

  • Purpose: 슬롯 상태 전이의 append-only 감사 기록.
  • Source of Truth: slot_transition_log (향후 테이블) / 현재는 in-memory list
  • Lifecycle: append-only (UPDATE/DELETE 금지)

Key Fields

  • slot_id :: UUID :: 대상 슬롯
  • from_state / to_state :: SlotState :: 전이 전후 상태
  • ts :: datetime :: 전이 시각(UTC)
  • reason :: str :: 전이 사유
  • actor :: str :: 전이 주체(시스템 워커 / 운영자)
  • extra :: dict :: 부가 컨텍스트(예: symbol)

Relationships

  • Slot :: slot_id 로 연결

State Rules

  • 오직 INSERT 만 허용한다(append-only).

Entity: intent_log (BAT-002)

  • Purpose: HTTP 로 제출된 buy/sell intent 의 멱등 dedup 게이트 + audit. intent_id UNIQUE 가 at-least-once 재전송의 슬롯 중복 전이를 차단한다(dcy-002 OQ-1).
  • Source of Truth: intent_log (PostgreSQL) / 테스트는 in-memory IntentStore
  • Lifecycle: processing -> admitted | rejected

Key Fields

  • intent_id :: TEXT PK :: 멱등키(전략 데몬 발급)
  • intent_type :: TEXT :: buy | sell
  • payload :: JSONB :: 제출 본문 스냅샷
  • status :: TEXT :: processing/admitted/rejected
  • slot_id :: UUID? :: 수락 시 전이된 슬롯
  • reason :: TEXT? :: 거부 사유
  • created_at / updated_at :: TIMESTAMPTZ

State Rules

  • try_insert 는 INSERT ... ON CONFLICT DO NOTHING(dedup 게이트). 중복 intent_id 는 재전이 없이 기존 decision 반환.
  • 완전 비동기 outbox(상태머신 + 소비 루프)로의 승격은 브로커 집행 Discovery 로 Deferred(이 테이블이 전구체).

Shared Consistency Rules

  • (trading_date, symbol) 재진입 카운트는 closed->idle 복구와 원자적으로 증가한다.
  • 모든 상태 변경과 전이 로그 append 는 동일 advisory-locked 트랜잭션 안에서 일어난다.
  • 재진입 정책 결정 입력은 daily_symbol_entries 카운터에서 읽고, slot_transition_log(감사 전용)를 join 하지 않는다.

Persistence / Integration Notes

  • 현재는 InMemorySlotRepository(threading.Lock 으로 advisory lock 모사)만 제공한다.
  • 향후 PostgreSQL 구현 시 plan.md 부록 A 의 컬럼 계약(타입 포함)을 만족해야 한다.
  • daily_symbol_entries PK = (trading_date, symbol); slot_transition_log 는 append-only 시퀀스.

Current Gaps / Planned Changes

  • daily_slot / daily_symbol_entries / slot_transition_log 의 물리 스키마(DDL)는 미이식 — 영속화 단계에서 작성.
  • daily_slot_archive(EOD 아카이브)와 retention prune 은 trex-orbit 인프라 기능으로, 이번 순수 도메인 범위 밖.
  • SlotState/필드 계약을 코드와 문서 사이에서 드리프트 없이 유지할 방법은 첫 Discovery 에서 정의(plan.md OQ-4).

Update Triggers

  • Update this document when a core entity, key field, or relationship changes.
  • Update this document when lifecycle or persistence behavior changes.
  • Update this document when a batch introduces a migration, backfill, or breaking data assumption.

Change Log

  • 2026-06-03 :: bootstrap-baseline 으로 초기 데이터 모델 baseline 생성(Slot + SlotTransitionRecord + 재진입 카운터).
  • 2026-06-03 :: BAT-002 — PostgreSQL 영속화 확정 + intent_log 엔티티 추가(REQ-006/007/009).
  • 2026-06-04 :: BAT-004 — 브로커 집행 레이어 반영(BrokerPort/paper·KIS 어댑터, execution 루프, broker_order_id 실행큐·멱등, reconciliation) (REQ-011~015).