first commit
This commit is contained in:
106
services/kospi200_service.go
Normal file
106
services/kospi200_service.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"stocksearch/models"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Kospi200Service 코스피200 종목 조회 서비스
|
||||
type Kospi200Service struct {
|
||||
kiwoom *KiwoomClient
|
||||
cache *CacheService
|
||||
}
|
||||
|
||||
var kospi200Svc *Kospi200Service
|
||||
|
||||
// GetKospi200Service 코스피200 서비스 싱글턴 반환
|
||||
func GetKospi200Service() *Kospi200Service {
|
||||
if kospi200Svc == nil {
|
||||
kospi200Svc = &Kospi200Service{
|
||||
kiwoom: GetKiwoomClient(),
|
||||
cache: GetCacheService(),
|
||||
}
|
||||
}
|
||||
return kospi200Svc
|
||||
}
|
||||
|
||||
// GetStocks ka20002: 코스피200 구성종목 전체 조회 (연속조회, 캐시 1분)
|
||||
func (s *Kospi200Service) GetStocks() ([]models.Kospi200Stock, error) {
|
||||
const cacheKey = "kospi200_stocks"
|
||||
if cached, ok := s.cache.Get(cacheKey); ok {
|
||||
if stocks, ok := cached.([]models.Kospi200Stock); ok {
|
||||
return stocks, nil
|
||||
}
|
||||
}
|
||||
|
||||
var all []models.Kospi200Stock
|
||||
contYn, nextKey := "N", ""
|
||||
|
||||
for {
|
||||
body, nextContYn, nextNextKey, err := s.kiwoom.postPaged(
|
||||
"ka20002", "/api/dostk/sect",
|
||||
map[string]string{
|
||||
"mrkt_tp": "0", // 코스피
|
||||
"inds_cd": "201", // KOSPI200
|
||||
"stex_tp": "1", // KRX
|
||||
},
|
||||
contYn, nextKey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("코스피200 조회 실패: %w", err)
|
||||
}
|
||||
|
||||
var result struct {
|
||||
IndsStkpc []struct {
|
||||
StkCd string `json:"stk_cd"`
|
||||
StkNm string `json:"stk_nm"`
|
||||
CurPrc string `json:"cur_prc"`
|
||||
PredPreSig string `json:"pred_pre_sig"`
|
||||
PredPre string `json:"pred_pre"`
|
||||
FluRt string `json:"flu_rt"`
|
||||
NowTrdeQty string `json:"now_trde_qty"`
|
||||
OpenPric string `json:"open_pric"`
|
||||
HighPric string `json:"high_pric"`
|
||||
LowPric string `json:"low_pric"`
|
||||
} `json:"inds_stkpc"`
|
||||
ReturnCode int `json:"return_code"`
|
||||
ReturnMsg string `json:"return_msg"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return nil, fmt.Errorf("코스피200 응답 파싱 실패: %w", err)
|
||||
}
|
||||
if result.ReturnCode != 0 {
|
||||
return nil, fmt.Errorf("코스피200 조회 실패: %s", result.ReturnMsg)
|
||||
}
|
||||
|
||||
for _, s := range result.IndsStkpc {
|
||||
// 종목코드·종목명이 없는 행은 건너뜀
|
||||
if s.StkCd == "" || s.StkNm == "" {
|
||||
continue
|
||||
}
|
||||
all = append(all, models.Kospi200Stock{
|
||||
Code: s.StkCd,
|
||||
Name: s.StkNm,
|
||||
CurPrc: absParseIntSafe(s.CurPrc),
|
||||
PredPreSig: s.PredPreSig,
|
||||
PredPre: parseIntSafe(s.PredPre),
|
||||
FluRt: parseFloatSafe(s.FluRt),
|
||||
Volume: absParseIntSafe(s.NowTrdeQty),
|
||||
Open: absParseIntSafe(s.OpenPric),
|
||||
High: absParseIntSafe(s.HighPric),
|
||||
Low: absParseIntSafe(s.LowPric),
|
||||
})
|
||||
}
|
||||
|
||||
// 연속조회 종료 조건
|
||||
if nextContYn != "Y" || nextNextKey == "" {
|
||||
break
|
||||
}
|
||||
contYn, nextKey = nextContYn, nextNextKey
|
||||
}
|
||||
|
||||
s.cache.Set(cacheKey, all, time.Minute)
|
||||
return all, nil
|
||||
}
|
||||
Reference in New Issue
Block a user