From 1e8542f6c721fe700892ee4c204b5204b943b740 Mon Sep 17 00:00:00 2001 From: gahusb Date: Tue, 12 May 2026 14:19:36 +0900 Subject: [PATCH] =?UTF-8?q?feat(stock):=20GatePanel=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=20=ED=8F=BC=20+=20GlobalControls=20(TopN/ATR/RR=20+=203?= =?UTF-8?q?=EB=B2=84=ED=8A=BC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stock/screener/components/GatePanel.jsx | 40 ++++++++++++++++++- .../screener/components/GlobalControls.jsx | 39 ++++++++++++++++-- 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/pages/stock/screener/components/GatePanel.jsx b/src/pages/stock/screener/components/GatePanel.jsx index ab0aa7e..1fb568d 100644 --- a/src/pages/stock/screener/components/GatePanel.jsx +++ b/src/pages/stock/screener/components/GatePanel.jsx @@ -1,3 +1,41 @@ export default function GatePanel({ meta, value, onChange }) { - return

{meta?.label ?? '게이트'}

TODO: 게이트 파라미터 폼 (Task 4.5)

; + if (!meta) return null; + const props = meta.param_schema?.properties || {}; + return ( +
+

{meta.label}

+

+ 통과 조건 — 통과한 종목만 점수 노드에 전달 +

+ {Object.entries(props).map(([key, prop]) => ( + onChange({ ...value, [key]: v })} /> + ))} +
+ ); +} + +function GateField({ paramKey, prop, value, onChange }) { + if (prop.type === 'integer') { + return ( +
+ + onChange(parseInt(e.target.value, 10))} + style={{ flex: 1 }} /> +
+ ); + } + if (prop.type === 'boolean') { + return ( +
+ +
+ ); + } + return null; } diff --git a/src/pages/stock/screener/components/GlobalControls.jsx b/src/pages/stock/screener/components/GlobalControls.jsx index dd8990c..b55c9aa 100644 --- a/src/pages/stock/screener/components/GlobalControls.jsx +++ b/src/pages/stock/screener/components/GlobalControls.jsx @@ -2,9 +2,42 @@ export default function GlobalControls({ settings, setSettings, onRun, onSave, o return (

실행 옵션

- - - +
+ + setSettings({ ...settings, top_n: parseInt(e.target.value, 10) })} + min={5} max={100} style={{ width: 80 }} /> +
+
+ + setSettings({ ...settings, atr_window: parseInt(e.target.value, 10) })} + min={5} max={50} style={{ width: 80 }} /> +
+
+ + setSettings({ ...settings, atr_stop_mult: parseFloat(e.target.value) })} + min={0.5} max={5} style={{ width: 80 }} /> +
+
+ + setSettings({ ...settings, rr_ratio: parseFloat(e.target.value) })} + min={1} max={10} style={{ width: 80 }} /> +
+ + +
); }