From a9e805be056174ac5c8322023b7500798e3fee15 Mon Sep 17 00:00:00 2001 From: kyu Date: Sat, 6 Jun 2026 15:45:46 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9E=90=EB=8F=99=EB=A7=A4=EB=A7=A4=20?= =?UTF-8?q?=EC=9E=90=EB=B3=B8=EA=B8=88=20=EC=84=A4=EC=A0=95=EA=B0=92=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20(=ED=95=98=EB=93=9C=EC=BD=94=EB=94=A9=20?= =?UTF-8?q?=E2=82=A91=EC=B2=9C=EB=A7=8C=20=EC=A0=9C=EA=B1=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 손실%·포지션사이즈 기준 자본금을 .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) --- docker-compose.yml | 1 + score-engine/main.py | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 959b7e8..9e815b4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -199,6 +199,7 @@ services: ECOS_API_KEY: "${ECOS_API_KEY:-}" GEMINI_API_KEY: "${GEMINI_API_KEY:-}" GEMINI_MODEL: "${GEMINI_MODEL:-gemini-2.5-pro}" + TRADE_DEFAULT_CAPITAL: "${TRADE_DEFAULT_CAPITAL:-10000000}" TZ: "Asia/Seoul" networks: trading-net: diff --git a/score-engine/main.py b/score-engine/main.py index bdb26ea..8625915 100644 --- a/score-engine/main.py +++ b/score-engine/main.py @@ -5993,7 +5993,9 @@ TRADE_SETTINGS = { "min_conviction": 4, # Gemini 확신도 ≥4 "require_agreement": True, # 두 LLM 일치 필수 "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, "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}") async def trade_propose(code: str, - capital: int = Query(default=10_000_000, ge=1_000_000)): - """수동 매수 신호 평가 + confirm 요청 (자동 cron으로도 호출됨).""" + capital: int | None = Query(default=None, ge=1_000_000)): + """수동 매수 신호 평가 + confirm 요청 (자동 cron으로도 호출됨). + capital 미지정 시 설정 자본금(TRADE_SETTINGS['default_capital']) 사용.""" + cap = capital or TRADE_SETTINGS["default_capital"] 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}") @@ -6183,9 +6187,11 @@ async def trade_orders_list(status: str = Query(default=""), @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)): - """모든 강력매수 종목 평가 → 통과 종목 표시 (또는 자동 proposal).""" + """모든 강력매수 종목 평가 → 통과 종목 표시 (또는 자동 proposal). + capital 미지정 시 설정 자본금(TRADE_SETTINGS['default_capital']) 사용.""" + cap = capital or TRADE_SETTINGS["default_capital"] async with pg_pool.acquire() as conn: codes = [r["stock_code"] for r in await conn.fetch(""" 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) results.append({"code": c, **sig}) 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}