Files
Bithumb/tests/test_candle_bars.py
dsyoon 72de8d534e feat(vol_breakout): 15m 현물 롱 라이브·모니터·cron 운영 추가
vol_breakout 멀티종목 tick, vol_live HTML 모니터, 마감 봉만 저장하는 캔들 다운로드,
텔레그램 체결 알림, cron/watch 감시 스크립트 및 테스트를 포함한다.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 08:31:14 +09:00

74 lines
2.3 KiB
Python

"""캔들 봉 마감·다운로드 필터."""
from __future__ import annotations
from datetime import datetime, timedelta
from bithumb.data.candle_bars import (
is_closed_candle,
last_closed_bar_open,
only_closed_candles,
)
def test_is_closed_candle_15m() -> None:
"""15분봉은 마감 시각 이후에만 closed."""
bar_open = datetime(2026, 6, 27, 16, 15, 0)
assert not is_closed_candle(
bar_open, 15, now=datetime(2026, 6, 27, 16, 29, 59)
)
assert is_closed_candle(
bar_open, 15, now=datetime(2026, 6, 27, 16, 30, 0)
)
def test_only_closed_candles_filters_forming_bar() -> None:
"""API 배치에서 진행 중 봉은 제외."""
rows = [
("2026-06-27 16:00:00", 100.0, 110.0, 95.0, 105.0, 1.0),
("2026-06-27 16:15:00", 105.0, 105.0, 105.0, 105.0, 0.1),
]
now = datetime(2026, 6, 27, 16, 20, 0)
closed = only_closed_candles(rows, 15, now=now)
assert len(closed) == 1
assert closed[0][0] == "2026-06-27 16:00:00"
def test_last_closed_bar_open() -> None:
"""진행 중인 16:15~16:30 봉 기준 최근 마감은 16:00."""
now = datetime(2026, 6, 27, 16, 20, 0)
assert last_closed_bar_open(now, 15) == datetime(2026, 6, 27, 16, 0, 0)
now = datetime(2026, 6, 27, 16, 30, 0)
assert last_closed_bar_open(now, 15) == datetime(2026, 6, 27, 16, 15, 0)
def test_only_closed_candles_keeps_all_historical() -> None:
"""과거 봉은 모두 마감으로 간주."""
rows = [
("2026-06-26 20:00:00", 1.0, 2.0, 0.5, 1.5, 10.0),
("2026-06-26 20:15:00", 1.5, 2.5, 1.0, 2.0, 8.0),
]
now = datetime(2026, 6, 27, 22, 0, 0)
assert len(only_closed_candles(rows, 15, now=now)) == 2
def test_delete_incomplete_tail(tmp_path) -> None:
"""미마감 최신 봉이 DB에서 제거된다."""
from bithumb.data.candle_store import CandleStore
db = tmp_path / "t.db"
store = CandleStore(db)
rows = [
("2026-06-27 16:00:00", 100.0, 110.0, 95.0, 105.0, 1.0),
("2026-06-27 16:15:00", 105.0, 105.0, 105.0, 105.0, 0.1),
]
store.upsert_rows("NEAR", "NEAR", 15, rows)
deleted = store.delete_incomplete_tail(
"NEAR", 15, now=datetime(2026, 6, 27, 16, 20, 0)
)
assert deleted == 1
_, _, db_max = store.get_range("NEAR", 15)
assert db_max == datetime(2026, 6, 27, 16, 0, 0)
store.close()