모의투자 투자금·종목별 관리 설계
상용 주식/HTS 프로그램(키움 영웅문 모의, NH/미래 HTS 모의, TradingView Paper 등)에서 통상 제공하는 계좌·투자금·종목별 배분·수익률·거래내역 구조를 기준으로, goldenChart 현재 구현(as-is) 과 목표(to-be) 를 정리한 설계서입니다.
1. 목표
| 목표 |
설명 |
| 투자금 단일 원천 |
모의 계좌의 현금·총자산·초기자본·실현/평가 손익을 DB에서 일관되게 관리 |
| 종목별 투자 한도 |
종목마다 최대 투자금(또는 비율)을 두고 매수 시 한도 초과 방지 |
| 투자금 설정 vs 관리 분리 |
설정(규칙·초기화) 화면과 운영(잔고·보유·체결) 화면 역할 분리 |
| 종목별 매수/매도 |
수동 주문·전략 자동매매가 동일 계좌·동일 한도 규칙을 따름 |
| 가상매매 연동 |
가상투자 대시보드·모의투자 메뉴가 동일 gc_paper_* 계좌 를 참조 |
2. 현재 구현 (As-Is)
2.1 DB (V18)
2.2 API
| 메서드 |
경로 |
용도 |
| GET/POST |
/api/paper/summary |
계좌 요약·보유·평가손익(markPrices 선택) |
| GET |
/api/paper/trades |
체결 목록 |
| POST |
/api/paper/orders |
즉시 체결 주문 |
| POST |
/api/paper/reset |
계좌 초기화 |
2.3 화면
| 화면 |
위치 |
역할 |
| 가상매매 설정 |
설정 → 가상매매 |
초기자본·수수료·자동매매 (전역) |
| 모의투자 설정 탭 |
모의투자 좌측 |
위와 동일 항목 + 계좌 초기화 |
| 모의투자 대시보드 |
메뉴 모의투자 |
KPI·보유·체결·차트·수동 매수/매도 |
| 가상투자 |
메뉴 가상투자 |
전략 모니터링 + placePaperOrder 자동/수동 |
2.4 부족한 점 (Gap)
- 종목별 투자금 한도 없음 → 전역
paper_auto_trade_budget_pct 만 존재
- 현금 변동 원장(입금/출금/수수료/초기화) 미분리 →
cash_after 만 체결에 기록
- 일별 자산 스냅샷 없음 → 수익률 차트는 프론트가 체결만 재구성
- 미체결 주문 없음 → 모두 즉시 체결
- 종목별 실현손익·회전율 집계 테이블 없음
- 투자금 설정 이 설정 앱 + 모의투자에 이중 노출
3. 상용 모의투자 벤치마크
| 영역 |
통상 기능 |
goldenChart 매핑 |
| 계좌 개설 |
초기 예탁금 설정 |
paper_initial_capital + gc_paper_account |
| 계좌 초기화 |
잔고·보유·내역 리셋 |
POST /paper/reset (유지·이력 테이블 추가 권장) |
| 예수금/주문가능 |
현금, D+0 가용 |
cash_balance − reserved_cash |
| 종목별 매수한도 |
종목당 상한 또는 비중 상한 |
신규 gc_paper_symbol_allocation |
| 보유종목 |
수량·평단·평가·손익률·비중 |
gc_paper_position + summary API 확장 |
| 체결내역 |
일자·종목·매수/매도·가격·수량·수수료 |
gc_paper_trade (필터·페이징 추가) |
| 자산추이 |
일별 총자산 그래프 |
신규 gc_paper_daily_snapshot |
| 원장/자금변동 |
입출금·수수료·배당·이자 |
신규 gc_paper_cash_ledger |
| 수동 주문 |
지정가/시장가·수량·금액 |
TradeOrderPanel + /paper/orders |
| 자동매매 |
전략 시그널 연동 |
STOMP 시그널 → placePaperOrder |
4. DB 설계 (To-Be)
4.1 ER 개요
4.2 테이블 상세
(기존 확장) gc_paper_account
| 컬럼 |
타입 |
설명 |
id |
BIGINT PK |
|
user_id / device_id |
|
기존 |
cash_balance |
DECIMAL(20,2) |
예수금 |
reserved_cash |
DECIMAL(20,2) NEW |
미체결·예약 금액 합 (Phase 2) |
realized_pnl |
DECIMAL(20,2) |
누적 실현손익 |
initial_capital_snapshot |
DECIMAL(20,2) NEW |
마지막 초기화 시점 기준 초기자본 |
reset_count |
INT NEW |
초기화 횟수 |
last_reset_at |
DATETIME NEW |
|
status |
VARCHAR(20) NEW |
ACTIVE | FROZEN |
created_at / updated_at |
|
|
파생 지표(API 계산, 컬럼 비저장 권장)
orderable_cash = cash_balance − reserved_cash
stock_eval_amount = Σ(보유 수량 × markPrice)
total_asset = cash_balance + stock_eval_amount
unrealized_pnl = stock_eval_amount − Σ(수량 × 평단)
total_return_pct = (total_asset − initial_capital_snapshot) / initial_capital_snapshot × 100
(신규) gc_paper_symbol_allocation — 종목별 투자금 설정
상용 HTS의 종목별 매수 한도 / 관심종목 투자비중 에 해당.
| 컬럼 |
타입 |
설명 |
id |
BIGINT PK |
|
account_id |
BIGINT FK |
|
symbol |
VARCHAR(50) |
KRW-BTC 등 |
korean_name |
VARCHAR(100) |
|
max_invest_krw |
DECIMAL(20,2) |
종목 최대 투자금(상한) |
budget_pct |
DECIMAL(8,4) NULL |
총자산 대비 % (max와 택1 또는 min 적용) |
strategy_id |
BIGINT NULL |
연결 전략(가상투자 카드와 동기) |
is_active |
TINYINT(1) |
0이면 신규 매수 차단 |
pinned |
TINYINT(1) |
관심 고정 |
sort_order |
INT |
UI 정렬 |
created_at / updated_at |
|
|
UK: (account_id, symbol)
파생(체결·보유 기준 계산)
| 필드 |
계산 |
invested_krw |
보유 평가금 또는 quantity × avg_price |
available_buy_krw |
max_invest_krw − invested_krw (음수면 0) |
symbol_return_pct |
(평가 − 원가) / 원가 × 100 |
weight_pct |
eval_amount / total_asset × 100 |
(기존 유지) gc_paper_position
| 컬럼 |
비고 |
quantity, avg_price |
평단가 가중평균 유지 (기존 로직) |
(선택) first_buy_at |
최초 매수 시각 — 통계용 |
(기존 확장) gc_paper_trade
| 컬럼 |
타입 |
설명 |
| 기존 컬럼 |
|
|
realized_pnl_delta |
DECIMAL(20,2) NULL NEW |
매도 시 해당 체결 실현손익 |
position_qty_after |
DECIMAL(30,12) NULL NEW |
체결 후 잔량 |
note |
VARCHAR(200) NULL NEW |
메모 |
인덱스 추가: (account_id, symbol, created_at), (account_id, created_at DESC)
(신규) gc_paper_cash_ledger — 자금 변동 원장
| 컬럼 |
타입 |
설명 |
id |
BIGINT PK |
|
account_id |
BIGINT FK |
|
entry_type |
VARCHAR(30) |
아래 enum |
amount |
DECIMAL(20,2) |
+입금 / −출금 |
cash_before |
DECIMAL(20,2) |
|
cash_after |
DECIMAL(20,2) |
|
ref_trade_id |
BIGINT NULL |
체결 연결 |
symbol |
VARCHAR(50) NULL |
|
created_at |
DATETIME |
|
entry_type enum
INITIAL — 계좌 생성·초기화 시 초기 예탁
BUY_SETTLE — 매수 결제
SELL_SETTLE — 매도 입금
FEE — 수수료 (체결에 포함 시 생략 가능)
ADJUST — 관리자/시스템 조정
RESET — 초기화 전 스냅샷 역산용
(신규) gc_paper_daily_snapshot — 일별 자산 (수익률 차트)
| 컬럼 |
타입 |
설명 |
id |
BIGINT PK |
|
account_id |
BIGINT FK |
|
snapshot_date |
DATE |
KST 기준 |
cash_balance |
DECIMAL(20,2) |
|
stock_eval_amount |
DECIMAL(20,2) |
EOD 시세 기준 |
total_asset |
DECIMAL(20,2) |
|
daily_pnl |
DECIMAL(20,2) |
전일 대비 |
daily_return_pct |
DECIMAL(10,4) |
|
cumulative_return_pct |
DECIMAL(10,4) |
초기자본 대비 |
UK: (account_id, snapshot_date) — 스케줄러: 매일 00:05 KST 또는 마지막 틱 후
(신규) gc_paper_reset_log — 초기화 이력
| 컬럼 |
설명 |
account_id, reset_at, initial_capital, cash_before, positions_json, reason |
감사·복구 |
(Phase 2, 선택) gc_paper_order — 미체결 주문
지정가·예약 매수 등 확장 시. 현재는 즉시 체결 유지하고 Phase 2로 미룸.
4.3 전역 설정 (gc_app_settings — 기존 유지)
| 컬럼 |
용도 |
paper_trading_enabled |
모의투자 마스터 스위치 |
paper_initial_capital |
초기화·신규 계좌 기본 예탁금 |
paper_fee_rate_pct / paper_slippage_pct / paper_min_order_krw |
|
paper_auto_trade_enabled / paper_auto_trade_budget_pct |
전역 자동매수 시 가용현금 % |
규칙 우선순위 (매수 가능 금액)
4.4 마이그레이션 제안
| 파일 |
내용 |
V51__paper_investment_management.sql |
account 확장, symbol_allocation, cash_ledger, daily_snapshot, reset_log, trade 인덱스 |
| 데이터 백필 |
기존 account → initial_capital_snapshot = app.initial_capital; allocation은 보유 종목만 max=초기자본으로 seed |
5. 화면 설계
5.1 메뉴·정보 구조
역할 분리 원칙
| 화면 |
사용자 질문 |
| 투자금 설정 |
“얼마로 시작하고, 수수료·자동매매·종목당 한도는?” |
| 투자금 관리 |
“지금 얼마 벌었고, 종목별로 얼마 묶여 있나?” |
| 거래/주문 |
“이 종목 사고/팔려면?” |
5.2 투자금 설정 화면 (PaperInvestmentSettingsPage 또는 설정 탭 통합)
레이아웃 (1열 폼 + 위험 작업 하단)
- 저장:
gc_app_settings + (선택) 계좌 initial_capital_snapshot 동기
- 초기화:
POST /paper/reset + gc_paper_reset_log + ledger RESET
5.3 투자금 관리 화면 (PaperInvestmentManage — 모의투자 메인 상단/탭)
상용 HTS “계좌평가 / 잔고” 패널에 해당
행 동작
- 행 클릭 → 차트/주문 패널 종목 전환
- 한도 편집 →
PATCH /paper/allocations/{symbol}
- 비활성 토글 → 해당 종목 신규 매수 차단
5.4 모의투자 대시보드 (기존 PaperTradingPage 개편)
- 좌측 설정 → §5.2 로 링크 또는 임베드
- 중앙 투자금 관리 → §5.3
- 우측 TradeOrderPanel — 종목별
available_buy_krw 표시
5.5 거래내역 화면
| 컬럼 |
설명 |
| 체결시각 |
|
| 종목 |
|
| 구분 |
매수(빨강) / 매도(파랑) — --gc-trade-buy/sell |
| 가격·수량·금액 |
|
| 수수료 |
|
| 실현손익 |
매도 행만 |
| 출처 |
MANUAL / STRATEGY |
| 체결 후 예수금 |
cash_after |
필터: 기간, 종목, side, source · 페이징 API
5.6 가상투자와의 동기화
| 가상투자 UI |
DB 매핑 |
| 투자대상 목록 |
gc_paper_symbol_allocation (symbol, strategy_id, pinned) |
| 카드 매수/매도 |
/paper/orders + 한도 검증 |
| 자동매매 |
paper_auto_trade_* + 종목 max_invest_krw |
권장: 가상투자 targets 저장 시 백엔드 PUT /paper/allocations/bulk 로 동기화 (localStorage는 캐시만).
6. 기능 설계
6.1 API (신규·확장)
| 메서드 |
경로 |
설명 |
| GET |
/paper/summary |
기존 + orderableCash, initialCapitalSnapshot, allocations[] |
| GET |
/paper/allocations |
종목별 한도·투입·가용·수익률 |
| PUT |
/paper/allocations |
bulk upsert (가상투자 동기) |
| PATCH |
/paper/allocations/{symbol} |
단일 종목 한도 수정 |
| GET |
/paper/trades |
?symbol=&side=&from=&to=&page= |
| GET |
/paper/ledger |
자금 원장 |
| GET |
/paper/snapshots/daily |
자산 추이 |
| POST |
/paper/orders |
한도·orderable 검증 추가 |
| POST |
/paper/reset |
reset_log + ledger + allocation 정책에 따라 재생성 |
6.2 매수 검증 플로우
6.3 매도 검증
- 보유
quantity ≥ 매도 수량
- 전량 매도 시
realized_pnl_delta 계산 → account.realized_pnl 누적
- (선택) 매도 후에도 allocation 행 유지,
invested_krw=0
6.4 일별 스냅샷 배치
- 대상:
paper_trading_enabled 이고 당일 체결/시세 변동 있는 계좌
- 입력: EOD mark prices (Ta4jStorage 또는 REST)
- UPSERT
gc_paper_daily_snapshot
6.5 종목별 수익률 정의 (화면 표기 통일)
| 지표 |
정의 |
| 종목 평가수익률 |
(mark×qty − avg×qty) / (avg×qty) × 100 |
| 종목 실현손익 |
해당 종목 매도 체결의 realized_pnl_delta 합 |
| 계좌 총수익률 |
(total_asset − initial_capital_snapshot) / initial × 100 |
| 당일 수익률 |
daily_snapshot.daily_return_pct |
7. 서비스·모듈 구조 (백엔드)
8. 구현 단계 (로드맵)
| 단계 |
범위 |
산출물 |
| P0 |
DB V51 + allocation CRUD + 매수 한도 검증 |
마이그레이션, API, 단위 테스트 |
| P1 |
투자금 관리 UI (보유+한도+KPI) |
PaperTradingPage 탭, bulk sync 가상투자 |
| P2 |
cash_ledger + 거래내역 필터/페이징 |
원장 화면 |
| P3 |
daily_snapshot + 자산추이 차트 |
스케줄러 |
| P4 |
(선택) 미체결 주문 |
gc_paper_order |
9. goldenChart 적용 시 유의사항
- 단일 계좌:
device_id 기준 1계좌 유지 (상용 모의도 대부분 1:1).
- 평가 시세: summary는
POST /paper/summary + markPrices 패턴 유지.
- 색상: 매수
#ef5350, 매도 #4dabf7 (--gc-trade-buy/sell).
- 전략 평가와 분리: Ta4j 시그널은
gc_paper_* 체결만 변경; 전략 DSL 평가는 기존 백엔드 단일 경로 유지.
- 설정 이중화 해소:
SettingsPage 가상매매 = 전역 기본값, 모의투자 좌측 설정 = 동일 API 바인딩 또는 “설정으로 이동” 링크만.
10. 요약
| 계층 |
설계 요지 |
| DB |
계좌 + 종목별 allocation + cash 원장 + 일별 스냅샷 + 체결 확장 |
| 투자금 설정 |
전역 규칙·초기자본·초기화 (app_settings + reset_log) |
| 투자금 관리 |
총자산·예수금·종목별 한도/투입/수익률·비중 |
| 매수/매도 |
가용현금 ∧ 종목한도 ∧ (자동매매 %) 검증 후 체결 |
| 거래내역 |
paper_trade + ledger, 필터·페이징 |
현재 V18 스키마는 MVP 체결·보유 에 적합하고, 상용 수준의 종목별 투자금·원장·일별 성과 는 §4.4 V51 마이그레이션과 §8 P0~P3 순으로 확장하는 것을 권장합니다.