feat: 봇 시작 시 과거 캔들 200개 프리로드 (즉시 신호 계산 가능)
Made-with: Cursor
This commit is contained in:
@@ -45,11 +45,37 @@ class KlineStream:
|
||||
df.set_index("timestamp", inplace=True)
|
||||
return df
|
||||
|
||||
async def _preload_history(self, client: AsyncClient, limit: int = 200):
|
||||
"""REST API로 과거 캔들 데이터를 버퍼에 미리 채운다."""
|
||||
logger.info(f"과거 캔들 {limit}개 로드 중...")
|
||||
loop = asyncio.get_event_loop()
|
||||
klines = await loop.run_in_executor(
|
||||
None,
|
||||
lambda: client.futures_klines(
|
||||
symbol=self.symbol.upper(),
|
||||
interval=self.interval,
|
||||
limit=limit,
|
||||
),
|
||||
)
|
||||
# 마지막 캔들은 아직 닫히지 않았을 수 있으므로 제외
|
||||
for k in klines[:-1]:
|
||||
self.buffer.append({
|
||||
"timestamp": k[0],
|
||||
"open": float(k[1]),
|
||||
"high": float(k[2]),
|
||||
"low": float(k[3]),
|
||||
"close": float(k[4]),
|
||||
"volume": float(k[5]),
|
||||
"is_closed": True,
|
||||
})
|
||||
logger.info(f"과거 캔들 {len(self.buffer)}개 로드 완료 — 즉시 신호 계산 가능")
|
||||
|
||||
async def start(self, api_key: str, api_secret: str):
|
||||
client = await AsyncClient.create(
|
||||
api_key=api_key,
|
||||
api_secret=api_secret,
|
||||
)
|
||||
await self._preload_history(client)
|
||||
bm = BinanceSocketManager(client)
|
||||
stream_name = f"{self.symbol}@kline_{self.interval}"
|
||||
logger.info(f"WebSocket 스트림 시작: {stream_name}")
|
||||
|
||||
@@ -44,3 +44,23 @@ async def test_callback_called_on_closed_candle():
|
||||
}
|
||||
stream.handle_message(raw_msg)
|
||||
assert len(received) == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_preload_history_fills_buffer():
|
||||
stream = KlineStream(symbol="XRPUSDT", interval="1m", buffer_size=200)
|
||||
|
||||
# REST API 응답 형식: [open_time, open, high, low, close, volume, ...]
|
||||
fake_klines = [
|
||||
[1700000000000 + i * 60000, "0.5", "0.51", "0.49", "0.505", "100000",
|
||||
0, "0", "0", "0", "0", "0"]
|
||||
for i in range(201) # 201개 반환 → 마지막 1개 제외 → 200개 버퍼
|
||||
]
|
||||
|
||||
mock_client = MagicMock()
|
||||
mock_client.futures_klines.return_value = fake_klines
|
||||
|
||||
await stream._preload_history(mock_client, limit=200)
|
||||
|
||||
assert len(stream.buffer) == 200
|
||||
assert stream.get_dataframe() is not None
|
||||
|
||||
Reference in New Issue
Block a user