215 lines
6.4 KiB
Python
215 lines
6.4 KiB
Python
"""Tests for candle models."""
|
|
|
|
import pytest
|
|
|
|
from exchange_data_manager.candles.models import Candle, CandleRequest
|
|
|
|
|
|
class TestCandle:
|
|
"""Tests for Candle dataclass."""
|
|
|
|
def test_create_candle(self):
|
|
"""Test creating a candle."""
|
|
candle = Candle(
|
|
time=1709337600,
|
|
open=50000.0,
|
|
high=51000.0,
|
|
low=49500.0,
|
|
close=50500.0,
|
|
volume=100.5,
|
|
)
|
|
|
|
assert candle.time == 1709337600
|
|
assert candle.open == 50000.0
|
|
assert candle.high == 51000.0
|
|
assert candle.low == 49500.0
|
|
assert candle.close == 50500.0
|
|
assert candle.volume == 100.5
|
|
assert candle.closed is True
|
|
|
|
def test_candle_closed_default(self):
|
|
"""Test that closed defaults to True."""
|
|
candle = Candle(
|
|
time=1709337600,
|
|
open=50000.0,
|
|
high=50000.0,
|
|
low=50000.0,
|
|
close=50000.0,
|
|
volume=0.0,
|
|
)
|
|
assert candle.closed is True
|
|
|
|
def test_candle_not_closed(self):
|
|
"""Test creating an unclosed candle."""
|
|
candle = Candle(
|
|
time=1709337600,
|
|
open=50000.0,
|
|
high=50000.0,
|
|
low=50000.0,
|
|
close=50000.0,
|
|
volume=0.0,
|
|
closed=False,
|
|
)
|
|
assert candle.closed is False
|
|
|
|
def test_to_dict(self):
|
|
"""Test converting candle to dictionary."""
|
|
candle = Candle(
|
|
time=1709337600,
|
|
open=50000.0,
|
|
high=51000.0,
|
|
low=49500.0,
|
|
close=50500.0,
|
|
volume=100.5,
|
|
)
|
|
|
|
result = candle.to_dict()
|
|
|
|
assert result == {
|
|
"time": 1709337600,
|
|
"open": 50000.0,
|
|
"high": 51000.0,
|
|
"low": 49500.0,
|
|
"close": 50500.0,
|
|
"volume": 100.5,
|
|
"closed": True,
|
|
}
|
|
|
|
def test_from_dict(self):
|
|
"""Test creating candle from dictionary."""
|
|
data = {
|
|
"time": 1709337600,
|
|
"open": 50000.0,
|
|
"high": 51000.0,
|
|
"low": 49500.0,
|
|
"close": 50500.0,
|
|
"volume": 100.5,
|
|
}
|
|
|
|
candle = Candle.from_dict(data)
|
|
|
|
assert candle.time == 1709337600
|
|
assert candle.open == 50000.0
|
|
assert candle.high == 51000.0
|
|
assert candle.low == 49500.0
|
|
assert candle.close == 50500.0
|
|
assert candle.volume == 100.5
|
|
|
|
def test_from_ccxt(self):
|
|
"""Test creating candle from ccxt OHLCV format."""
|
|
# ccxt format: [timestamp_ms, open, high, low, close, volume]
|
|
ohlcv = [1709337600000, 50000.0, 51000.0, 49500.0, 50500.0, 100.5]
|
|
|
|
candle = Candle.from_ccxt(ohlcv)
|
|
|
|
# Time should be converted from ms to seconds
|
|
assert candle.time == 1709337600
|
|
assert candle.open == 50000.0
|
|
assert candle.high == 51000.0
|
|
assert candle.low == 49500.0
|
|
assert candle.close == 50500.0
|
|
assert candle.volume == 100.5
|
|
assert candle.closed is True
|
|
|
|
def test_timestamp_ms_property(self):
|
|
"""Test timestamp_ms property."""
|
|
candle = Candle(
|
|
time=1709337600,
|
|
open=50000.0,
|
|
high=50000.0,
|
|
low=50000.0,
|
|
close=50000.0,
|
|
volume=0.0,
|
|
)
|
|
assert candle.timestamp_ms == 1709337600000
|
|
|
|
def test_datetime_property(self):
|
|
"""Test datetime property."""
|
|
candle = Candle(
|
|
time=1709337600,
|
|
open=50000.0,
|
|
high=50000.0,
|
|
low=50000.0,
|
|
close=50000.0,
|
|
volume=0.0,
|
|
)
|
|
dt = candle.datetime
|
|
assert dt.year == 2024
|
|
assert dt.month == 3
|
|
assert dt.day == 2 # 1709337600 = 2024-03-02 00:00:00 UTC
|
|
|
|
|
|
class TestCandleRequest:
|
|
"""Tests for CandleRequest dataclass."""
|
|
|
|
def test_create_request(self):
|
|
"""Test creating a candle request."""
|
|
request = CandleRequest(
|
|
exchange="binance",
|
|
symbol="BTC/USDT",
|
|
timeframe="5m",
|
|
)
|
|
|
|
assert request.exchange == "binance"
|
|
assert request.symbol == "BTC/USDT"
|
|
assert request.timeframe == "5m"
|
|
assert request.start is None
|
|
assert request.end is None
|
|
assert request.limit is None
|
|
|
|
def test_create_request_with_range(self):
|
|
"""Test creating a candle request with time range."""
|
|
request = CandleRequest(
|
|
exchange="binance",
|
|
symbol="BTC/USDT",
|
|
timeframe="1h",
|
|
start=1709251200,
|
|
end=1709337600,
|
|
limit=100,
|
|
)
|
|
|
|
assert request.start == 1709251200
|
|
assert request.end == 1709337600
|
|
assert request.limit == 100
|
|
|
|
def test_cache_key_property(self):
|
|
"""Test cache key generation."""
|
|
request = CandleRequest(
|
|
exchange="Binance", # Mixed case
|
|
symbol="btc/usdt", # Lowercase
|
|
timeframe="5M", # Uppercase
|
|
)
|
|
|
|
# Should be normalized
|
|
assert request.cache_key == "binance:BTC/USDT:5m"
|
|
|
|
def test_cache_key_different_symbols(self):
|
|
"""Test that different symbols produce different keys."""
|
|
request1 = CandleRequest(exchange="binance", symbol="BTC/USDT", timeframe="5m")
|
|
request2 = CandleRequest(exchange="binance", symbol="ETH/USDT", timeframe="5m")
|
|
|
|
assert request1.cache_key != request2.cache_key
|
|
|
|
def test_cache_key_different_timeframes(self):
|
|
"""Test that different timeframes produce different keys."""
|
|
request1 = CandleRequest(exchange="binance", symbol="BTC/USDT", timeframe="5m")
|
|
request2 = CandleRequest(exchange="binance", symbol="BTC/USDT", timeframe="1h")
|
|
|
|
assert request1.cache_key != request2.cache_key
|
|
|
|
def test_symbol_normalization(self):
|
|
"""Test that symbols are normalized."""
|
|
# Lowercase should be uppercased
|
|
request = CandleRequest(exchange="binance", symbol="btc/usdt", timeframe="5m")
|
|
assert request.symbol == "BTC/USDT"
|
|
|
|
def test_symbol_separator_added(self):
|
|
"""Test that separator is added to symbols without one."""
|
|
request = CandleRequest(exchange="binance", symbol="BTCUSDT", timeframe="5m")
|
|
assert request.symbol == "BTC/USDT"
|
|
|
|
def test_exchange_normalization(self):
|
|
"""Test that exchange is normalized to lowercase."""
|
|
request = CandleRequest(exchange="BINANCE", symbol="BTC/USDT", timeframe="5m")
|
|
assert request.exchange == "binance"
|