feat: 자동매매 자본금 설정값 분리 (하드코딩 ₩1천만 제거)
trading/pipeline/head This commit looks good

손실%·포지션사이즈 기준 자본금을 .env TRADE_DEFAULT_CAPITAL로 설정 가능하게 분리.
- TRADE_SETTINGS['default_capital']을 env에서 로드(미설정 시 1천만)
- /trade/propose·/trade/scan의 하드코딩 Query default 제거 → 설정값 폴백
- docker-compose score-engine에 TRADE_DEFAULT_CAPITAL 전달
- 런타임 변경은 기존 POST /trade/settings 그대로 (재시작 시 env로 복귀)
- /performance/simulation의 capital은 what-if 입력값이라 유지

검증: 컨테이너 env 인식·/trade/settings 반영·런타임 override(5천만)·healthy 확인.
실잔고(키움) 자동연동은 계좌번호 미설정으로 별도 과제.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
kyu
2026-06-06 15:45:46 +09:00
parent 73575d1ee8
commit a9e805be05
2 changed files with 14 additions and 7 deletions
+1
View File
@@ -199,6 +199,7 @@ services:
ECOS_API_KEY: "${ECOS_API_KEY:-}" ECOS_API_KEY: "${ECOS_API_KEY:-}"
GEMINI_API_KEY: "${GEMINI_API_KEY:-}" GEMINI_API_KEY: "${GEMINI_API_KEY:-}"
GEMINI_MODEL: "${GEMINI_MODEL:-gemini-2.5-pro}" GEMINI_MODEL: "${GEMINI_MODEL:-gemini-2.5-pro}"
TRADE_DEFAULT_CAPITAL: "${TRADE_DEFAULT_CAPITAL:-10000000}"
TZ: "Asia/Seoul" TZ: "Asia/Seoul"
networks: networks:
trading-net: trading-net:
+13 -7
View File
@@ -5993,7 +5993,9 @@ TRADE_SETTINGS = {
"min_conviction": 4, # Gemini 확신도 ≥4 "min_conviction": 4, # Gemini 확신도 ≥4
"require_agreement": True, # 두 LLM 일치 필수 "require_agreement": True, # 두 LLM 일치 필수
"min_diagnosis_score": 3, # 5가지 진단 ≥3 "min_diagnosis_score": 3, # 5가지 진단 ≥3
"default_capital": 10_000_000, # 자본금: .env TRADE_DEFAULT_CAPITAL로 설정(미설정 시 1천만). 손실%·포지션사이즈 기준값.
# 런타임 변경은 POST /trade/settings?default_capital=... (재시작 시 env 값으로 복귀).
"default_capital": int(os.getenv("TRADE_DEFAULT_CAPITAL", "10000000")),
# 매도 신호 임계값 # 매도 신호 임계값
"stop_loss_pct": -8.0, "stop_loss_pct": -8.0,
"take_profit_pct": 15.0, "take_profit_pct": 15.0,
@@ -6147,10 +6149,12 @@ async def propose_buy_order(conn, code: str, capital: int = None) -> dict:
@app.post("/trade/propose/{code}") @app.post("/trade/propose/{code}")
async def trade_propose(code: str, async def trade_propose(code: str,
capital: int = Query(default=10_000_000, ge=1_000_000)): capital: int | None = Query(default=None, ge=1_000_000)):
"""수동 매수 신호 평가 + confirm 요청 (자동 cron으로도 호출됨).""" """수동 매수 신호 평가 + confirm 요청 (자동 cron으로도 호출됨).
capital 미지정 설정 자본금(TRADE_SETTINGS['default_capital']) 사용."""
cap = capital or TRADE_SETTINGS["default_capital"]
async with pg_pool.acquire() as conn: async with pg_pool.acquire() as conn:
return await propose_buy_order(conn, code, capital) return await propose_buy_order(conn, code, cap)
@app.post("/trade/cancel/{order_id}") @app.post("/trade/cancel/{order_id}")
@@ -6183,9 +6187,11 @@ async def trade_orders_list(status: str = Query(default=""),
@app.post("/trade/scan") @app.post("/trade/scan")
async def trade_scan(capital: int = Query(default=10_000_000), async def trade_scan(capital: int | None = Query(default=None),
auto_propose: bool = Query(default=False)): auto_propose: bool = Query(default=False)):
"""모든 강력매수 종목 평가 → 통과 종목 표시 (또는 자동 proposal).""" """모든 강력매수 종목 평가 → 통과 종목 표시 (또는 자동 proposal).
capital 미지정 설정 자본금(TRADE_SETTINGS['default_capital']) 사용."""
cap = capital or TRADE_SETTINGS["default_capital"]
async with pg_pool.acquire() as conn: async with pg_pool.acquire() as conn:
codes = [r["stock_code"] for r in await conn.fetch(""" codes = [r["stock_code"] for r in await conn.fetch("""
SELECT stock_code FROM stock_scores SELECT stock_code FROM stock_scores
@@ -6198,7 +6204,7 @@ async def trade_scan(capital: int = Query(default=10_000_000),
sig = await evaluate_buy_signal(conn, c) sig = await evaluate_buy_signal(conn, c)
results.append({"code": c, **sig}) results.append({"code": c, **sig})
if auto_propose and sig["ok"]: if auto_propose and sig["ok"]:
await propose_buy_order(conn, c, capital) await propose_buy_order(conn, c, cap)
return {"evaluated": len(results), "results": results} return {"evaluated": len(results), "results": results}