101 lines
4.2 KiB
Python
101 lines
4.2 KiB
Python
|
|
import sys
|
||
|
|
import os
|
||
|
|
import json
|
||
|
|
import math
|
||
|
|
import signal
|
||
|
|
from unittest.mock import MagicMock, patch
|
||
|
|
|
||
|
|
if not hasattr(signal, 'SIGHUP'):
|
||
|
|
signal.SIGHUP = 1
|
||
|
|
|
||
|
|
# Configure pathing for local test execution
|
||
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../nautilus_dolphin')))
|
||
|
|
|
||
|
|
from nautilus_dolphin.nautilus.adaptive_circuit_breaker import AdaptiveCircuitBreaker, ACBConfig
|
||
|
|
|
||
|
|
# 1. TEST ACB INTERNAL FUNCTIONING (Internal Logic Validity)
|
||
|
|
def test_acb_internal_functioning():
|
||
|
|
print("\n--- Running ACBv6 Internal Unit Tests ---")
|
||
|
|
acb = AdaptiveCircuitBreaker()
|
||
|
|
|
||
|
|
# Simulate a HZ snapshot with some bearish values
|
||
|
|
mock_snapshot = {
|
||
|
|
'funding_btc': -0.0002, # Very Bearish -> 1 signal
|
||
|
|
'dvol_btc': 85.0, # Extreme -> 1 signal
|
||
|
|
'fng': 20.0, # Extreme Fear -> 1 signal
|
||
|
|
'taker': 0.7, # Very high selling -> 1 signal
|
||
|
|
'_staleness_s': {'funding_btc': 100}
|
||
|
|
}
|
||
|
|
|
||
|
|
# Calculate boost from these factors (which should generate max signal count = 4.0)
|
||
|
|
info = acb.get_dynamic_boost_from_hz("2026-04-10", mock_snapshot, w750_velocity=0.005)
|
||
|
|
|
||
|
|
assert info['cut'] == 0.0, "ACBv6 inverse mode should never cut position"
|
||
|
|
assert info['signals'] == 4.0, f"Expected 4.0 signals, got {info['signals']}"
|
||
|
|
|
||
|
|
# Mathematical confirmation of log_0.5 inverse boost curve expectations
|
||
|
|
expected_boost = 1.0 + 0.5 * math.log1p(info['signals']) # 1.0 + 0.5 * ln(5) == 1.804
|
||
|
|
assert math.isclose(info['boost'], expected_boost, rel_tol=1e-3), (
|
||
|
|
f"Boost math failure. Expected '{expected_boost:.3f}', got '{info['boost']:.3f}'"
|
||
|
|
)
|
||
|
|
|
||
|
|
# Test w750 velocity fallback/caching
|
||
|
|
# Should be pre-cached now
|
||
|
|
assert acb._w750_vel_cache["2026-04-10"] == 0.005, "w750_velocity should be correctly stored"
|
||
|
|
|
||
|
|
print(f"ACB internal functions properly handle HZ conversion and log_0.5 boost (Yields ~{expected_boost:.3f}x leverage multiplier on 4-signal stress).")
|
||
|
|
|
||
|
|
# 2. TEST NAUTILUS EVENT TRADER WIRING (Structural Pipeline Validation)
|
||
|
|
def test_trader_acb_wiring():
|
||
|
|
print("\n--- Running DolphinLiveTrader ACB Wiring Tests ---")
|
||
|
|
|
||
|
|
# We must patch thread pools and hz client to test DolphinLiveTrader in isolation
|
||
|
|
with patch('concurrent.futures.ThreadPoolExecutor'):
|
||
|
|
with patch('prod.nautilus_event_trader.create_d_liq_engine'):
|
||
|
|
# Mock the Linux-only exit handler module so it imports locally on Windows
|
||
|
|
mock_exit = MagicMock()
|
||
|
|
sys.modules['dolphin_exit_handler'] = mock_exit
|
||
|
|
import prod.nautilus_event_trader as net
|
||
|
|
|
||
|
|
# Instantiate trader
|
||
|
|
trader = net.DolphinLiveTrader()
|
||
|
|
|
||
|
|
# Setup mock engine
|
||
|
|
trader.eng = MagicMock()
|
||
|
|
trader.current_day = "2026-04-10"
|
||
|
|
trader.eng_lock = MagicMock()
|
||
|
|
trader.acb = MagicMock()
|
||
|
|
|
||
|
|
# Trigger exF listener manually
|
||
|
|
mock_exf_snapshot = json.dumps({'dvol_btc': 55.0, 'taker': 0.8})
|
||
|
|
|
||
|
|
class MockEvent:
|
||
|
|
def __init__(self, val): self.value = val
|
||
|
|
|
||
|
|
trader.last_w750_vel = 0.001
|
||
|
|
trader.on_exf_update(MockEvent(mock_exf_snapshot))
|
||
|
|
|
||
|
|
# Ensure acb.get_dynamic_boost_from_hz was called with parameters
|
||
|
|
trader.acb.get_dynamic_boost_from_hz.assert_called_once_with(
|
||
|
|
date_str="2026-04-10",
|
||
|
|
exf_snapshot={'dvol_btc': 55.0, 'taker': 0.8},
|
||
|
|
w750_velocity=0.001
|
||
|
|
)
|
||
|
|
|
||
|
|
# Ensure engine.update_acb_boost was called
|
||
|
|
if hasattr(trader.eng, 'update_acb_boost'):
|
||
|
|
trader.eng.update_acb_boost.assert_called_once()
|
||
|
|
|
||
|
|
print("ACB pipeline successfully routes live EXF data into the engine loop.")
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
try:
|
||
|
|
test_acb_internal_functioning()
|
||
|
|
test_trader_acb_wiring()
|
||
|
|
print("\nALL UNIT TESTS PASSED SUCCESSFULLY! ACBv6 is securely wired.")
|
||
|
|
except AssertionError as e:
|
||
|
|
print(f"FAILED: {e}")
|
||
|
|
except Exception as e:
|
||
|
|
print(f"ERROR: {e}")
|