fix: 로그 분석으로 찾은 버그 4건 (과다매도·수량 0 오염·LSTM 무력화·sync 충돌)
1) DT 분할매도가 ActiveTrade.quantity를 갱신하지 않아 재기동 복원 시 원래 수량이 되살아남 → 잔량 4주인데 7주 매도되어 같은 종목 스윙 보유분 3주까지 청산됨(2026-09-23 LG씨엔에스). 2) reflect_sell이 '전략 포지션 잔량'을 Portfolio 행 잔량으로 사용 → DT 전량청산이 스윙 보유분까지 0으로 만듦. 행 잔량은 항상 (행 수량 - 매도 수량)으로 계산. 3) LSTM 체크포인트에 numpy 배열이 들어가 weights_only=True 로드가 매번 실패 → 앙상블에서 LSTM이 조용히 빠진 채 예측 중이었음. 저장을 list로 바꾸고, 기존 파일은 MODEL_DIR 내부일 때만 완화 재시도. 4) 수동 매도(행 삭제)와 sync 동시 실행 시 StaleDataError로 sync 전체 실패 → 전량 매도는 행 삭제 대신 수량 0, sync는 충돌 시 실패 기록 없이 다음 주기 재시도. 추가로 비강제 sync는 락 점유 중이면 30초 대기 없이 캐시 반환. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -170,8 +170,10 @@ class StockLSTM:
|
||||
return
|
||||
torch.save({
|
||||
"model_state": self.model.state_dict(),
|
||||
"seq_mean": self.seq_mean,
|
||||
"seq_std": self.seq_std,
|
||||
# numpy 배열을 그대로 저장하면 weights_only=True 로드가 거부된다
|
||||
# (2026-09-23: LSTM이 매번 로드 실패해 앙상블에서 조용히 빠져 있었음) → list 로 저장
|
||||
"seq_mean": self.seq_mean.tolist() if self.seq_mean is not None else None,
|
||||
"seq_std": self.seq_std.tolist() if self.seq_std is not None else None,
|
||||
"config": {
|
||||
"input_size": self.input_size,
|
||||
"hidden_size": self.hidden_size,
|
||||
@@ -193,9 +195,23 @@ class StockLSTM:
|
||||
except TypeError:
|
||||
# PyTorch < 2.0: weights_only 파라미터 미지원
|
||||
checkpoint = torch.load(path, map_location=self.device) # noqa: S614
|
||||
except Exception as _wo_err:
|
||||
# 구 체크포인트(numpy 배열 포함)는 weights_only=True 로 못 읽는다.
|
||||
# 우리 학습 산출물(MODEL_DIR 내부)일 때만 완화해서 재시도한다.
|
||||
try:
|
||||
_inside = Path(path).resolve().is_relative_to(MODEL_DIR.resolve())
|
||||
except Exception:
|
||||
_inside = False
|
||||
if not _inside:
|
||||
raise
|
||||
logger.warning(
|
||||
f"LSTM 체크포인트 weights_only 로드 실패 → 자체 학습 산출물로 재시도: {_wo_err}"
|
||||
)
|
||||
checkpoint = torch.load(path, map_location=self.device, weights_only=False) # noqa: S614
|
||||
self.model.load_state_dict(checkpoint["model_state"])
|
||||
self.seq_mean = checkpoint["seq_mean"]
|
||||
self.seq_std = checkpoint["seq_std"]
|
||||
_mean, _std = checkpoint["seq_mean"], checkpoint["seq_std"]
|
||||
self.seq_mean = None if _mean is None else np.asarray(_mean, dtype=np.float32)
|
||||
self.seq_std = None if _std is None else np.asarray(_std, dtype=np.float32)
|
||||
self.model.eval()
|
||||
return True
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user