diff --git a/app/execution/kis_client.py b/app/execution/kis_client.py index 99727ce..d4d52c4 100644 --- a/app/execution/kis_client.py +++ b/app/execution/kis_client.py @@ -48,6 +48,12 @@ class KISClient: # 토큰 관련 self._access_token : Optional[str] = None self._token_expires_at: Optional[datetime] = None + # 토큰 파일 캐시 경로 (재시작 시 재사용) + mode_tag = "mock" if self.is_mock else "real" + self._token_cache_file = os.path.join( + os.path.dirname(__file__), "..", "..", "data", f"kis_token_{mode_tag}.json" + ) + self._load_token_from_file() # rate limit: 모의투자 1건/초, 실거래 5건/초 self._rate_limit = 1 if self.is_mock else 5 @@ -71,6 +77,32 @@ class KISClient: # 토큰 관리 # ───────────────────────────────────────── + def _load_token_from_file(self): + """재시작 시 파일 캐시에서 토큰 복원""" + try: + if os.path.exists(self._token_cache_file): + with open(self._token_cache_file, encoding="utf-8") as f: + cached = json.load(f) + expires_at = datetime.fromisoformat(cached["expires_at"]) + if datetime.now() < expires_at - timedelta(minutes=30): + self._access_token = cached["access_token"] + self._token_expires_at = expires_at + logger.info("KIS 토큰 파일 캐시 복원 완료") + except Exception: + pass + + def _save_token_to_file(self): + """토큰을 파일에 저장 (재시작 시 재사용)""" + try: + os.makedirs(os.path.dirname(self._token_cache_file), exist_ok=True) + with open(self._token_cache_file, "w", encoding="utf-8") as f: + json.dump({ + "access_token": self._access_token, + "expires_at": self._token_expires_at.isoformat(), + }, f) + except Exception: + pass + async def get_access_token(self) -> str: """액세스 토큰 발급/갱신 (만료 30분 전 자동 갱신)""" now = datetime.now() @@ -96,6 +128,7 @@ class KISClient: self._access_token = data["access_token"] # 유효기간 24시간 self._token_expires_at = now + timedelta(hours=24) + self._save_token_to_file() logger.info("KIS 액세스 토큰 발급/갱신 완료") return self._access_token