diff --git a/src/gas_adapter_parts/gdc_02_account_satellite.gs b/src/gas_adapter_parts/gdc_02_account_satellite.gs index f0eb420..21acf83 100644 --- a/src/gas_adapter_parts/gdc_02_account_satellite.gs +++ b/src/gas_adapter_parts/gdc_02_account_satellite.gs @@ -2002,6 +2002,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; @@ -2028,6 +2060,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; @@ -2040,9 +2081,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'; @@ -2070,6 +2116,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 컬럼