From 57be399f2a948a0d12d94f0236b2e8a2a3958a04 Mon Sep 17 00:00:00 2001 From: gavindiaz Date: Wed, 8 Jul 2026 06:59:22 +0000 Subject: [PATCH] Add tests for watch_ticker and watch_ohlcv --- tests/test_watch.py | 98 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 tests/test_watch.py diff --git a/tests/test_watch.py b/tests/test_watch.py new file mode 100644 index 0000000..1fc7b72 --- /dev/null +++ b/tests/test_watch.py @@ -0,0 +1,98 @@ +"""Tests for watch_ticker and watch_ohlcv (polling-based watching).""" + +import asyncio +import time + +import responses +import pytest + +import mt5bridge_ccxt + + +class TestWatchTicker: + @responses.activate + def test_returns_immediately_when_changed(self, exchange_config, mock_ticker): + # Two different ticks to simulate change + responses.add( + responses.GET, + "http://mock-mt5bridge:8080/symbols/XAUUSDc/tick", + json=mock_ticker, status=200, + ) + mock_ticker2 = dict(mock_ticker) + mock_ticker2["data"] = [dict(mock_ticker["data"][0])] + mock_ticker2["data"][0]["bid"] = 4181.0 # price changed + mock_ticker2["data"][0]["ask"] = 4181.5 + responses.add( + responses.GET, + "http://mock-mt5bridge:8080/symbols/XAUUSDc/tick", + json=mock_ticker2, status=200, + ) + + ex = mt5bridge_ccxt.mt5bridge(exchange_config) + result = asyncio.run( + ex.watch_ticker("XAU/USD", params={"poll_interval_ms": 50}) + ) + assert result["symbol"] == "XAU/USD" + assert result["bid"] in (4180.5, 4181.0) + + @responses.activate + def test_returns_after_max_wait_even_if_unchanged(self, exchange_config, mock_ticker): + # Same tick twice → no change + responses.add( + responses.GET, + "http://mock-mt5bridge:8080/symbols/XAUUSDc/tick", + json=mock_ticker, status=200, + ) + responses.add( + responses.GET, + "http://mock-mt5bridge:8080/symbols/XAUUSDc/tick", + json=mock_ticker, status=200, + ) + + ex = mt5bridge_ccxt.mt5bridge(exchange_config) + start = time.time() + result = asyncio.run( + ex.watch_ticker( + "XAU/USD", + params={"poll_interval_ms": 50, "max_wait_ms": 200}, + ) + ) + elapsed = time.time() - start + # Should return after ~200ms even though nothing changed + assert elapsed >= 0.2 + assert elapsed < 1.0 # but not much more + assert result["bid"] == 4180.5 + + +class TestWatchOHLCV: + @responses.activate + def test_returns_new_bar(self, exchange_config, mock_bars): + # Second call returns a new bar + mock_bars2 = { + "data": [ + *mock_bars["data"], + {"time": "2026-07-08T13:00:00", "open": 4184.0, "high": 4188.0, + "low": 4183.0, "close": 4186.0, "tick_volume": 90, "spread": 5, + "real_volume": 45.0}, + ], + "count": 3, "format": "json", + } + responses.add( + responses.GET, + "http://mock-mt5bridge:8080/rates/from-pos", + json=mock_bars, status=200, + ) + responses.add( + responses.GET, + "http://mock-mt5bridge:8080/rates/from-pos", + json=mock_bars2, status=200, + ) + + ex = mt5bridge_ccxt.mt5bridge(exchange_config) + result = asyncio.run( + ex.watch_ohlcv("XAU/USD", "1h", limit=2, + params={"poll_interval_ms": 50, "max_wait_ms": 500}) + ) + assert len(result) >= 2 + # New bar should be at the end with time 13:00 + assert result[-1][0] == ex._parse_datetime("2026-07-08T13:00:00")