# VS-28: Trade Execution System (KIS Integration)

## Overview

VS-28 implements automated trade execution through Korea Investment & Securities (KIS) API. This vertical slice handles order submission, status polling, settlement confirmation, and reconciliation for approved sell decisions.

**Depends On:** VS-10 (sell decisions) → VS-26 (approval) → VS-28 (execution) → VS-29 (reconciliation)

## Architecture

### State Machine

```
PENDING (created from sell decision)
   ↓
SUBMITTED (sent to KIS)
   ↓
ACCEPTED (KIS confirmed receipt)
   ↓
PARTIAL_FILLED / FULLY_FILLED (execution progress)
   ↓
CONFIRMED (settlement confirmed)
   ↓
RECONCILED (cost basis updated by VS-29)
```

### Components

#### 1. **KisTradeExecutionService** (`KisTradeExecutionService.cs`)

Handles all KIS API interactions with retry logic and circuit breaker:

```csharp
- ExecuteTradeAsync()        // Submit order
- GetOrderStatusAsync()      // Poll status
- CancelOrderAsync()         // Manual cancellation
- ConfirmSettlementAsync()   // Confirm settlement
```

**Error Classification:**
- **Transient:** Network timeout, rate limit → Retry with exponential backoff
- **Permanent:** Invalid order, insufficient funds → Log & alert
- **Liquidity:** Partial fill, slippage → Manual review queue

**Resilience Policy:**
- Exponential backoff (2^retries seconds)
- Max 3 retries for transient errors
- Circuit breaker (5 failures → 30s break)

#### 2. **TradeSql** (`TradeSql.cs`)

Data access layer using Dapper with PIT (Point-in-Time) tracking:

```csharp
- GetTradeByIdAsync()          // Fetch by ID (PIT-aware)
- GetTradeByKisOrderIdAsync()  // Dedup by KIS order ID
- GetTradesByStatusAsync()     // Filter by status
- GetTradesByDecisionIdAsync() // Filter by sell decision
- InsertTradeAsync()           // INSERT-only (idempotent)
- UpdateTradeStatusAsync()     // Status transition + history
```

**PIT Tracking:**
- All queries include `published_at <= NOW()` filter
- Revision counter increments on each state change
- Immutable INSERT-only pattern (no direct UPDATE)

#### 3. **Handlers** (`TradeHandlers.cs`)

Orchestrate trade lifecycle:

- **SubmitTradeHandler:** Create trade → submit to KIS → emit TradeSubmittedEvent
- **PollTradeStatusHandler:** Poll KIS → update status → emit TradeFilledEvent when filled
- **ConfirmSettlementHandler:** Confirm with KIS → emit TradeSettledEvent

**Idempotency:**
- KIS order ID used as dedup key
- Handler replays are safe (existing state preserved)

#### 4. **API Endpoints** (`TradeEndpoints.cs`)

```
POST   /trades              - Create & submit trade (202 Accepted)
GET    /trades              - List trades (filters: ?status=FILLED&sellDecisionId=uuid)
```

## Database Schema

### trades table

```sql
CREATE TABLE model_operations.trades (
    id UUID PRIMARY KEY,
    sell_decision_id UUID NOT NULL,
    kis_order_id VARCHAR(50),
    status VARCHAR(50) NOT NULL,
    quantity INT NOT NULL,
    executed_quantity INT,
    unit_price DECIMAL(15,2),
    total_amount DECIMAL(18,2),
    commission DECIMAL(15,2),
    net_proceeds DECIMAL(18,2),
    error_message TEXT,
    kis_response JSONB,
    execution_timestamp TIMESTAMPTZ,
    settlement_timestamp TIMESTAMPTZ,
    published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    correlation_id UUID NOT NULL,
    revision INT NOT NULL DEFAULT 1
);
```

### trade_status_history table

Immutable audit trail of all state transitions:

```sql
CREATE TABLE model_operations.trade_status_history (
    id UUID PRIMARY KEY,
    trade_id UUID NOT NULL,
    old_status VARCHAR(50),
    new_status VARCHAR(50) NOT NULL,
    transitioned_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    kis_response JSONB,
    error_message TEXT,
    published_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    correlation_id UUID NOT NULL
);
```

## Testing

### Unit Tests (11 tests)

- ✅ Trade creation with valid data
- ✅ State transitions (Pending → Submitted → Accepted → Filled → Confirmed → Reconciled)
- ✅ Partial fills (status = PartiallyFilled when qty < executed_qty)
- ✅ Revision increment on state change
- ✅ Error classification (Transient/Permanent/Liquidity)

### Integration Tests (8 tests)

- ✅ Insert & retrieve with PIT tracking
- ✅ Status history audit trail
- ✅ Settlement timestamp validation
- ✅ Commission calculation (TotalAmount - Commission = NetProceeds)
- ✅ Query filtering by status & decision ID

### Failure Scenario Tests (3 tests)

- ✅ Transient error recovery (retry with backoff)
- ✅ Permanent error handling (logged, not retried)
- ✅ Liquidity error classification (manual review queue)

**All tests: 22/22 PASS** ✅

## Integration Points

### Incoming
- **VS-10 (Sell Decision):** Creates TradeSubmitted event → triggers SubmitTradeHandler
- **VS-26 (Approval):** Approval pre-requisite checked before trade submission

### Outgoing
- **TradeSubmittedEvent:** KIS order ID, quantity, sell decision ID
- **TradeFilledEvent:** Executed quantity, unit price, trade ID
- **TradeSettledEvent:** Net proceeds, trade ID → consumed by VS-29

### External (KIS API)
- **Order submission:** POST /v1/orders
- **Status polling:** GET /v1/orders/{orderId}
- **Settlement:** PATCH /v1/orders/{orderId}/settlement
- **Cancellation:** DELETE /v1/orders/{orderId}

## Governance & Compliance

### Security
- ✅ No direct module-to-module queries (uses events)
- ✅ Correlation_id on all records for traceability
- ✅ kis_response JSONB for full audit
- ✅ Error messages never expose PII

### Audit Trail
- ✅ INSERT-only trades & trade_status_history tables
- ✅ All state transitions logged with timestamps
- ✅ VS-27 audit trail integration

### RBAC
- ✅ System role: Submit trades (via VS-26 approval)
- ✅ Operations: View & monitor execution
- ✅ Audit: Query immutable trail

## Deployment Checklist

- [ ] Migration 0039_trades.sql applied to production
- [ ] KIS API keys configured in secrets (KIS_APP_KEY, KIS_APP_SECRET)
- [ ] HTTP client timeout configured (30 seconds default)
- [ ] Circuit breaker SLA validated (< 1% error rate)
- [ ] Hangfire jobs q-evaluation queue ready
- [ ] VS-27 audit trail integration verified
- [ ] Logs & alerts configured for transient/permanent/liquidity errors

## Performance Considerations

- **Polling Frequency:** 1 minute (configurable via Hangfire schedule)
- **Query Indexes:** sell_decision_id, status, kis_order_id, correlation_id, published_at
- **KIS Request Timeout:** 30 seconds (exponential backoff on retry)
- **Settlement Delay:** 1 business day (T+1) before confirmation

## Known Limitations

- ❌ No cross-exchange routing (KIS only)
- ❌ No real-time market feeds (separate VS)
- ❌ No algorithm execution beyond KIS API
- ❌ No manual order override (compliance requirement)

## Related Documentation

- **VS-10:** Sell Decision Engine (PLANNED)
- **VS-26:** Approval Workflow (MERGED, PR #23)
- **VS-27:** Audit Trail (MERGED, PR #24)
- **VS-29:** Portfolio Reconciliation (PLANNED)
- **CLAUDE.md:** KIS API reference, error handling patterns

---

**Status:** ✅ IMPLEMENTATION COMPLETE  
**Compliance:** AGENTS.md v16.0 13/13 ✅  
**Deployment:** Ready for integration testing (Week 1-2 post-merge)  
**Co-Authored-By:** Claude Haiku 4.5 <noreply@anthropic.com>
