feat(rel-006): dcy-022/023 + BAT-032~034 — 실행 정책·qty 검증·allocated_capital 제거 통합

BAT-032 (dcy-022): timeout_sec/slippage_pct 실행 정책, 미체결 자동 취소,
보호 지정가, `trex-core cancel` 백스톱. 마이그레이션 012.
BAT-033: `trex-core enter --qty` 필수 검증 — 미지정 시 RPC 전 즉시 오류.
BAT-034 (dcy-023): allocated_capital 죽은 필드 전 경로 제거 (domain·intent·
persistence·snapshot·CLI). 마이그레이션 013(비가역 DROP). 외부 발신자
unknown key 무시 수신 의미론 적용.
REL-006 confirmed: BAT-026~034 통합 릴리즈, pre-release smoke 증거 포함.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 07:42:03 +09:00
co-authored by Claude Sonnet 4.6
parent 5ee5f7f4e2
commit fb05a73130
56 changed files with 3151 additions and 103 deletions
+26 -22
View File
@@ -28,9 +28,10 @@ from trex_core.domain.slot import Slot, SlotNotFoundError, SlotState, SlotTransi
_SLOT_COLUMNS = (
"slot_id, status, symbol, qty, avg_price, limit_price, "
"allocated_capital, order_id, strategy_id, broker_order_id, portfolio_id, "
"order_id, strategy_id, broker_order_id, portfolio_id, "
"sell_strategy_id, forced_close_at, stop_loss_price, take_profit_price, "
"created_at, updated_at, instance_key, retired_at"
"created_at, updated_at, instance_key, retired_at, "
"timeout_sec, slippage_pct"
)
@@ -166,18 +167,19 @@ class PostgreSQLSlotRepository:
with conn.cursor() as cur:
cur.execute(
"UPDATE daily_slot SET status=%s, symbol=%s, qty=%s, avg_price=%s, "
"limit_price=%s, allocated_capital=%s, order_id=%s, strategy_id=%s, "
"limit_price=%s, order_id=%s, strategy_id=%s, "
"broker_order_id=%s, portfolio_id=%s, sell_strategy_id=%s, "
"forced_close_at=%s, stop_loss_price=%s, take_profit_price=%s, "
"instance_key=%s, retired_at=%s, "
"instance_key=%s, retired_at=%s, timeout_sec=%s, slippage_pct=%s, "
"updated_at=%s WHERE slot_id=%s",
(
slot.status.value, slot.symbol, slot.qty, slot.avg_price,
slot.limit_price, slot.allocated_capital, slot.order_id,
slot.limit_price, slot.order_id,
slot.strategy_id, slot.broker_order_id, slot.portfolio_id,
slot.sell_strategy_id, slot.forced_close_at,
slot.stop_loss_price, slot.take_profit_price,
slot.instance_key, slot.retired_at,
slot.timeout_sec, slot.slippage_pct,
slot.updated_at or datetime.now(tz=timezone.utc), slot.slot_id,
),
)
@@ -266,10 +268,11 @@ class PostgreSQLSlotRepository:
f = lambda v: float(v) if v is not None else None # noqa: E731
d = lambda v: Decimal(str(v)) if v is not None else None # noqa: E731
# Column order: slot_id(0) status(1) symbol(2) qty(3) avg_price(4)
# limit_price(5) allocated_capital(6) order_id(7) strategy_id(8)
# broker_order_id(9) portfolio_id(10) sell_strategy_id(11)
# forced_close_at(12) stop_loss_price(13) take_profit_price(14)
# created_at(15) updated_at(16) instance_key(17) retired_at(18)
# limit_price(5) order_id(6) strategy_id(7)
# broker_order_id(8) portfolio_id(9) sell_strategy_id(10)
# forced_close_at(11) stop_loss_price(12) take_profit_price(13)
# created_at(14) updated_at(15) instance_key(16) retired_at(17)
# timeout_sec(18) slippage_pct(19) [dcy-022/REQ-068]
return Slot(
slot_id=row[0] if isinstance(row[0], UUID) else UUID(str(row[0])),
status=SlotState(row[1]),
@@ -277,19 +280,20 @@ class PostgreSQLSlotRepository:
qty=f(row[3]),
avg_price=f(row[4]),
limit_price=f(row[5]),
allocated_capital=f(row[6]),
order_id=row[7],
strategy_id=row[8],
broker_order_id=row[9],
portfolio_id=row[10],
sell_strategy_id=row[11],
forced_close_at=row[12],
stop_loss_price=d(row[13]),
take_profit_price=d(row[14]),
created_at=row[15],
updated_at=row[16],
instance_key=row[17] if row[17] is not None else "default",
retired_at=row[18],
order_id=row[6],
strategy_id=row[7],
broker_order_id=row[8],
portfolio_id=row[9],
sell_strategy_id=row[10],
forced_close_at=row[11],
stop_loss_price=d(row[12]),
take_profit_price=d(row[13]),
created_at=row[14],
updated_at=row[15],
instance_key=row[16] if row[16] is not None else "default",
retired_at=row[17],
timeout_sec=int(row[18]) if row[18] is not None else None,
slippage_pct=f(row[19]),
)