diff --git a/frontend/src/lib/api/types.ts b/frontend/src/lib/api/types.ts
index 6948542..0770392 100644
--- a/frontend/src/lib/api/types.ts
+++ b/frontend/src/lib/api/types.ts
@@ -149,7 +149,7 @@ export interface WatchlistItem {
export interface IndexQuote {
name: string
- value: number
+ price: number
change: number
changeRate: number
}
diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts
index 71ef64b..3ceab12 100644
--- a/frontend/src/lib/utils.ts
+++ b/frontend/src/lib/utils.ts
@@ -39,16 +39,16 @@ export function formatDate(iso: string): string {
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
}
-// 전일대비 부호 문자 (2=상승, 3=보합, 5=하락)
+// 전일대비 부호 문자 (1=상한가, 2=상승, 3=보합, 4=하한가, 5=하락)
export function sigToArrow(sig: string): string {
- if (sig === '2') return '▲'
- if (sig === '5') return '▼'
+ if (sig === '1' || sig === '2') return '▲'
+ if (sig === '4' || sig === '5') return '▼'
return '-'
}
// 전일대비 부호에 따른 클래스
export function sigClass(sig: string): string {
- if (sig === '2') return 'text-red-400'
- if (sig === '5') return 'text-blue-400'
+ if (sig === '1' || sig === '2') return 'text-red-400'
+ if (sig === '4' || sig === '5') return 'text-blue-400'
return 'text-gray-400'
}
diff --git a/frontend/src/routes/(app)/+page.svelte b/frontend/src/routes/(app)/+page.svelte
index 58c2bf1..2b03475 100644
--- a/frontend/src/routes/(app)/+page.svelte
+++ b/frontend/src/routes/(app)/+page.svelte
@@ -296,7 +296,7 @@
{#each indices as idx}
{idx.name}
-
{idx.value.toLocaleString('ko-KR', { maximumFractionDigits: 2 })}
+
{idx.price.toLocaleString('ko-KR', { maximumFractionDigits: 2 })}
{formatRate(idx.changeRate)}
{/each}
diff --git a/frontend/src/routes/(app)/kospi200/+page.svelte b/frontend/src/routes/(app)/kospi200/+page.svelte
index 2b8c68a..4fe28e8 100644
--- a/frontend/src/routes/(app)/kospi200/+page.svelte
+++ b/frontend/src/routes/(app)/kospi200/+page.svelte
@@ -97,7 +97,7 @@
{stock.curPrc.toLocaleString()}
- {sigToArrow(stock.predPreSig)} {stock.predPre.toLocaleString()}
+ {sigToArrow(stock.predPreSig)} {Math.abs(stock.predPre).toLocaleString()}
|
{formatRate(stock.fluRt)}
diff --git a/frontend/src/routes/(app)/theme/+page.svelte b/frontend/src/routes/(app)/theme/+page.svelte
index ddb0d3e..3598dc5 100644
--- a/frontend/src/routes/(app)/theme/+page.svelte
+++ b/frontend/src/routes/(app)/theme/+page.svelte
@@ -190,7 +190,7 @@
{stock.curPrc.toLocaleString()}
|
- {sigToArrow(stock.fluSig)}{stock.predPre.toLocaleString()}
+ {sigToArrow(stock.fluSig)}{Math.abs(stock.predPre).toLocaleString()}
|
{formatRate(stock.fluRt)}
diff --git a/services/kiwoom_service.go b/services/kiwoom_service.go
index f63dab6..a88338f 100644
--- a/services/kiwoom_service.go
+++ b/services/kiwoom_service.go
@@ -219,12 +219,11 @@ func (k *KiwoomClient) fetchPrice(stkCd string) (*models.StockPrice, error) {
if result.ReturnCode != 0 {
return nil, fmt.Errorf("현재가 조회 실패: %s", result.ReturnMsg)
}
-
price := &models.StockPrice{
Code: displayCode,
Name: result.StkNm,
CurrentPrice: absParseIntSafe(result.CurPrc),
- ChangePrice: parseIntSafe(result.PredPre),
+ ChangePrice: signedChange(result.PredPre, result.FluRt),
ChangeRate: parseFloatSafe(result.FluRt),
Volume: absParseIntSafe(result.TrdeQty),
High: absParseIntSafe(result.HighPric),
@@ -451,7 +450,7 @@ func (k *KiwoomClient) GetTopVolumeStocks(market string, count int) ([]models.St
Code: row.StkCd,
Name: row.StkNm,
CurrentPrice: absParseIntSafe(row.CurPrc),
- ChangePrice: parseIntSafe(row.PredPre),
+ ChangePrice: signedChange(row.PredPre, row.FluRt),
ChangeRate: parseFloatSafe(row.FluRt),
Volume: absParseIntSafe(row.TrdeQty),
Market: mktName,
@@ -559,7 +558,7 @@ func (k *KiwoomClient) GetTopFluctuation(market string, ascending bool, count in
Code: row.StkCd,
Name: row.StkNm,
CurrentPrice: absParseIntSafe(row.CurPrc),
- ChangePrice: parseIntSafe(row.PredPre),
+ ChangePrice: signedChange(row.PredPre, row.FluRt),
ChangeRate: parseFloatSafe(row.FluRt),
Volume: absParseIntSafe(row.NowTrdeQty),
CntrStr: parseFloatSafe(row.CntrStr),
@@ -588,6 +587,27 @@ func absParseIntSafe(s string) int64 {
return n
}
+// signedChange 전일대비를 절댓값으로 파싱 후 등락률 부호에 맞춰 부호 결정
+// 키움 API의 pred_pre 필드는 가격 필드처럼 부호가 방향 표시용이므로 flu_rt 기준으로 부호 결정
+func signedChange(predPre string, fluRt string) int64 {
+ n := absParseIntSafe(predPre)
+ rate := parseFloatSafe(fluRt)
+ if rate < 0 {
+ return -n
+ }
+ return n
+}
+
+// signedChangeBySig 전일대비를 절댓값으로 파싱 후 flu_sig(등락기호) 기준으로 부호 결정
+// flu_sig: 1=상한가, 2=상승, 3=보합, 4=하한가, 5=하락
+func signedChangeBySig(predPre string, fluSig string) int64 {
+ n := absParseIntSafe(predPre)
+ if fluSig == "4" || fluSig == "5" {
+ return -n
+ }
+ return n
+}
+
func parseFloatSafe(s string) float64 {
s = strings.ReplaceAll(s, ",", "")
s = strings.TrimPrefix(s, "+")
diff --git a/services/kiwoom_ws_service.go b/services/kiwoom_ws_service.go
index 44997a6..d5cc5f4 100644
--- a/services/kiwoom_ws_service.go
+++ b/services/kiwoom_ws_service.go
@@ -434,11 +434,17 @@ func (k *KiwoomWSClient) reconnect() {
func parseRealPrice(code string, v map[string]string) *models.StockPrice {
normalized := strings.TrimPrefix(code, "A")
normalized = strings.SplitN(normalized, "_", 2)[0] // _NX, _AL 등 접미사 제거
+ // 전일대비(v["11"])는 절댓값으로 파싱 후, 등락률(v["12"]) 부호에 맞춰 부호 결정
+ changeAbs := absInt(parseWSInt(v["11"]))
+ changeRate := parseWSFloat(v["12"])
+ if changeRate < 0 {
+ changeAbs = -changeAbs
+ }
return &models.StockPrice{
Code: normalized,
CurrentPrice: absInt(parseWSInt(v["10"])),
- ChangePrice: parseWSInt(v["11"]),
- ChangeRate: parseWSFloat(v["12"]),
+ ChangePrice: changeAbs,
+ ChangeRate: changeRate,
Volume: absInt(parseWSInt(v["13"])),
TradeMoney: absInt(parseWSInt(v["14"])),
TradeVolume: absInt(parseWSInt(v["15"])),
@@ -458,11 +464,17 @@ func parseRealPrice(code string, v map[string]string) *models.StockPrice {
func parseExpectedPrice(code string, v map[string]string) *models.StockPrice {
normalized := strings.TrimPrefix(code, "A")
normalized = strings.SplitN(normalized, "_", 2)[0]
+ // 전일대비(v["11"])는 절댓값으로 파싱 후, 등락률(v["12"]) 부호에 맞춰 부호 결정
+ expChangeAbs := absInt(parseWSInt(v["11"]))
+ expChangeRate := parseWSFloat(v["12"])
+ if expChangeRate < 0 {
+ expChangeAbs = -expChangeAbs
+ }
return &models.StockPrice{
Code: normalized,
CurrentPrice: absInt(parseWSInt(v["10"])),
- ChangePrice: parseWSInt(v["11"]),
- ChangeRate: parseWSFloat(v["12"]),
+ ChangePrice: expChangeAbs,
+ ChangeRate: expChangeRate,
TradeVolume: absInt(parseWSInt(v["15"])),
Volume: absInt(parseWSInt(v["13"])),
TradeTime: v["20"],
diff --git a/services/kospi200_service.go b/services/kospi200_service.go
index 47b1d9f..55ba625 100644
--- a/services/kospi200_service.go
+++ b/services/kospi200_service.go
@@ -85,7 +85,7 @@ func (s *Kospi200Service) GetStocks() ([]models.Kospi200Stock, error) {
Name: s.StkNm,
CurPrc: absParseIntSafe(s.CurPrc),
PredPreSig: s.PredPreSig,
- PredPre: parseIntSafe(s.PredPre),
+ PredPre: signedChangeBySig(s.PredPre, s.PredPreSig),
FluRt: parseFloatSafe(s.FluRt),
Volume: absParseIntSafe(s.NowTrdeQty),
Open: absParseIntSafe(s.OpenPric),
diff --git a/services/theme_service.go b/services/theme_service.go
index 2fa7932..bb41635 100644
--- a/services/theme_service.go
+++ b/services/theme_service.go
@@ -109,8 +109,8 @@ func (s *ThemeService) GetThemeStocks(themeCode, dateTp string) (*models.ThemeDe
}
var result struct {
- FluRt string `json:"flu_rt"`
- DtPrftRt string `json:"dt_prft_rt"`
+ FluRt string `json:"flu_rt"`
+ DtPrftRt string `json:"dt_prft_rt"`
ThemaCompStk []struct {
StkCd string `json:"stk_cd"`
StkNm string `json:"stk_nm"`
@@ -136,7 +136,7 @@ func (s *ThemeService) GetThemeStocks(themeCode, dateTp string) (*models.ThemeDe
Name: s.StkNm,
CurPrc: absParseIntSafe(s.CurPrc),
FluSig: s.FluSig,
- PredPre: parseIntSafe(s.PredPre),
+ PredPre: signedChangeBySig(s.PredPre, s.FluSig),
FluRt: parseFloatSafe(strings.TrimPrefix(s.FluRt, "+")),
})
}
|