Files
DOLPHIN/nautilus_dolphin/tests/test_signal_bridge.py

154 lines
5.2 KiB
Python
Raw Normal View History

"""Tests for SignalBridgeActor.
Uses TestClock pattern from Nautilus to properly initialize Actor components.
"""
import pytest
from unittest.mock import Mock, patch, PropertyMock
from nautilus_dolphin.nautilus.signal_bridge import SignalBridgeActor, SignalBridgeConfig
class TestSignalBridgeTimestampParsing:
"""Test timestamp parsing without full Nautilus initialization."""
def test_parse_timestamp_ns_from_seconds(self):
"""Test timestamp conversion from seconds."""
config = SignalBridgeConfig(redis_url='redis://localhost')
actor = SignalBridgeActor(config)
ts_sec = 1234567890
ts_ns = actor._parse_timestamp_ns(ts_sec)
assert ts_ns == 1234567890 * 1_000_000_000
def test_parse_timestamp_ns_from_milliseconds(self):
"""Test timestamp conversion from milliseconds."""
config = SignalBridgeConfig(redis_url='redis://localhost')
actor = SignalBridgeActor(config)
ts_ms = 1234567890123
ts_ns = actor._parse_timestamp_ns(ts_ms)
assert ts_ns == 1234567890123 * 1_000
def test_parse_timestamp_ns_from_nanoseconds(self):
"""Test timestamp already in nanoseconds."""
config = SignalBridgeConfig(redis_url='redis://localhost')
actor = SignalBridgeActor(config)
ts_ns = 1234567890123456789
result = actor._parse_timestamp_ns(ts_ns)
assert result == ts_ns
class TestSignalBridgeWithNautilus:
"""Test SignalBridgeActor with proper Nautilus initialization."""
@pytest.fixture
def nautilus_actor(self):
"""Create a properly initialized SignalBridgeActor with mocked clock."""
from nautilus_trader.common.component import TestClock
config = SignalBridgeConfig(
redis_url='redis://localhost',
max_signal_age_sec=10
)
actor = SignalBridgeActor(config)
# Create TestClock and patch the clock property
clock = TestClock()
# Use patch to mock the clock property
with patch.object(
type(actor),
'clock',
new_callable=PropertyMock
) as mock_clock:
mock_clock.return_value = clock
yield actor, clock
def test_validate_signal_missing_fields(self, nautilus_actor):
"""Test signal validation rejects missing fields."""
actor, clock = nautilus_actor
signal = {'timestamp': 1234567890, 'asset': 'BTCUSDT'}
assert not actor._validate_signal(signal)
def test_validate_signal_valid(self, nautilus_actor):
"""Test signal validation accepts valid signal."""
actor, clock = nautilus_actor
# Set clock to be after signal timestamp
clock.set_time(1234567890 * 1_000_000_000 + 5_000_000_000)
signal = {
'timestamp': 1234567890,
'asset': 'BTCUSDT',
'direction': 'SHORT',
'vel_div': -0.025,
'strength': 0.75
}
assert actor._validate_signal(signal)
def test_validate_signal_stale(self, nautilus_actor):
"""Test signal validation rejects stale signals."""
actor, clock = nautilus_actor
# Set clock to be much later than signal (older than max_signal_age_sec)
clock.set_time(1234567890 * 1_000_000_000 + 20_000_000_000) # 20s later
signal = {
'timestamp': 1234567890,
'asset': 'BTCUSDT',
'direction': 'SHORT',
'vel_div': -0.025,
'strength': 0.75
}
assert not actor._validate_signal(signal)
def test_validate_signal_future(self, nautilus_actor):
"""Test signal validation rejects future signals."""
actor, clock = nautilus_actor
# Set clock to be before signal timestamp
clock.set_time(1234567890 * 1_000_000_000 - 1_000_000_000)
signal = {
'timestamp': 1234567890,
'asset': 'BTCUSDT',
'direction': 'SHORT',
'vel_div': -0.025,
'strength': 0.75
}
assert not actor._validate_signal(signal)
class TestSignalBridgeConfig:
"""Test SignalBridgeConfig initialization."""
def test_default_config(self):
"""Test default configuration values."""
config = SignalBridgeConfig()
assert config.redis_url == "redis://localhost:6379"
assert config.stream_key == "dolphin:signals:stream"
assert config.max_signal_age_sec == 10
def test_custom_config(self):
"""Test custom configuration values."""
config = SignalBridgeConfig(
redis_url="redis://custom:6380",
stream_key="custom:stream",
max_signal_age_sec=30
)
assert config.redis_url == "redis://custom:6380"
assert config.stream_key == "custom:stream"
assert config.max_signal_age_sec == 30