From d9e3a43e618a40346da83748a9e1476eb7ecf1bf Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sat, 13 Jun 2026 14:05:12 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20WBS-2.2=20US=20=EC=A3=BC=EC=8B=9D=20?= =?UTF-8?q?=EA=B0=80=EA=B2=A9=20settings=20=EC=88=98=EB=8F=99=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20->=20=EC=9E=90=EB=8F=99=20Weight=5FPct=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdc_02_account_satellite.gs | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/gas_adapter_parts/gdc_02_account_satellite.gs b/src/gas_adapter_parts/gdc_02_account_satellite.gs index 8b94192..5fc4766 100644 --- a/src/gas_adapter_parts/gdc_02_account_satellite.gs +++ b/src/gas_adapter_parts/gdc_02_account_satellite.gs @@ -1998,6 +1998,38 @@ function parseAccountSnapshot_(ss, totalAssetKrw, dfMap) { var sheet = ss.getSheetByName(AS_SHEET_NAME); if (!sheet) { Logger.log('[HARNESS] account_snapshot 시트 없음'); return result; } + // ── 환율(USD_KRW) 로드 ────────────────────────────────────────────────── + var usdKrw = 1400; // default fallback + try { + var macroSheet = ss.getSheetByName("macro"); + if (macroSheet) { + var mData = macroSheet.getDataRange().getValues(); + var headerRowIdx = 0; + for (var r = 0; r < Math.min(5, mData.length); r++) { + var row = mData[r] ?? []; + if (row.indexOf("Symbol") >= 0 && row.indexOf("Name") >= 0) { + headerRowIdx = r; + break; + } + } + var nameIdx = mData[headerRowIdx].indexOf("Name"); + var closeIdx = mData[headerRowIdx].indexOf("Close"); + if (nameIdx >= 0 && closeIdx >= 0) { + for (var i = headerRowIdx + 1; i < mData.length; i++) { + if (String(mData[i][nameIdx]).trim() === "USD_KRW") { + var val = parseFloat(mData[i][closeIdx]); + if (Number.isFinite(val) && val > 0) { + usdKrw = val; + break; + } + } + } + } + } + } catch (e) { + Logger.log('[WARN] parseAccountSnapshot_ 환율 로드 실패: ' + e.message); + } + var data = sheet.getDataRange().getValues(); if (data.length <= AS_HEADER_ROW_IDX) return result; @@ -2024,6 +2056,15 @@ function parseAccountSnapshot_(ss, totalAssetKrw, dfMap) { var d2Cash = numCol_(row, c, 'settlement_cash_d2'); var openOrder = numCol_(row, c, 'open_order_amount'); var mktValue = numCol_(row, c, 'market_value'); + var ticker = normTicker_(c['ticker'] !== undefined ? row[c['ticker']] : ''); + var isUsTicker = /^[A-Z]+$/.test(ticker); + + if (isUsTicker) { + var currPrice = numCol_(row, c, 'current_price'); + if (currPrice > 0 && holdingQty > 0) { + mktValue = Math.round(currPrice * holdingQty * usdKrw); + } + } if (!isRestrictedAcct) { if (immCash > 0) result.immediateCashKrw += immCash; @@ -2036,9 +2077,14 @@ function parseAccountSnapshot_(ss, totalAssetKrw, dfMap) { if (holdingQty <= 0 || userConfirmed !== 'Y') continue; // 보유 포지션 처리 - var ticker = normTicker_(c['ticker'] !== undefined ? row[c['ticker']] : ''); var avgCost = numCol_(row, c, 'average_cost'); + if (isUsTicker && avgCost > 0) { + avgCost = round2_(avgCost * usdKrw); + } var stopPrice = numCol_(row, c, 'stop_price'); + if (isUsTicker && stopPrice > 0) { + stopPrice = round2_(stopPrice * usdKrw); + } var dfRow = dfMap[ticker] || {}; var atr20 = dfRow.atr20 || 0; var stopSrc = 'MANUAL'; @@ -2066,6 +2112,10 @@ function parseAccountSnapshot_(ss, totalAssetKrw, dfMap) { // stop_price 이탈 감지 var close = dfRow.close || 0; + if (isUsTicker) { + var currPrice = numCol_(row, c, 'current_price'); + close = currPrice > 0 ? round2_(currPrice * usdKrw) : round2_(close * usdKrw); + } var stopBreach = close > 0 && stopPrice > 0 && close <= stopPrice; // weight_pct: settings의 total_asset 기준으로 계산, 없으면 account_snapshot 컬럼