Skip to content

Commit 6acab59

Browse files
committed
test(dataflows): add unit tests for binance vendor
1 parent 4d0782a commit 6acab59

1 file changed

Lines changed: 108 additions & 0 deletions

File tree

tests/test_binance_vendor.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""Binance vendor: native OHLCV data for crypto assets.
2+
3+
Covers symbol resolution, date-boundary inclusivity (#binance-pagination),
4+
pagination past the 1000-candle-per-request cap, and the
5+
NoMarketDataError contract for unrecognized symbols / empty responses.
6+
"""
7+
import pytest
8+
9+
import tradingagents.dataflows.binance as binance
10+
11+
12+
class _FakeResponse:
13+
def __init__(self, payload):
14+
self._payload = payload
15+
16+
def raise_for_status(self):
17+
pass
18+
19+
def json(self):
20+
return self._payload
21+
22+
23+
def _kline_row(date_str, price=50000.0, volume=100.0):
24+
"""Build one Binance-shaped kline row for a given date."""
25+
import pandas as pd
26+
open_ms = int(pd.Timestamp(date_str, tz="UTC").timestamp() * 1000)
27+
return [
28+
open_ms, str(price), str(price + 10), str(price - 10), str(price + 5),
29+
str(volume), open_ms + 86399999, "0", 1, "0", "0", "0",
30+
]
31+
32+
33+
@pytest.mark.unit
34+
def test_unrecognized_symbol_raises_no_market_data_error():
35+
with pytest.raises(binance.NoMarketDataError):
36+
binance.get_binance_stock("NOTACOIN-USD", "2026-06-01", "2026-06-10")
37+
38+
39+
@pytest.mark.unit
40+
def test_empty_response_raises_no_market_data_error(monkeypatch):
41+
monkeypatch.setattr(
42+
binance.requests, "get",
43+
lambda *a, **k: _FakeResponse([]),
44+
)
45+
with pytest.raises(binance.NoMarketDataError):
46+
binance.get_binance_stock("BTC-USD", "2026-06-01", "2026-06-10")
47+
48+
49+
@pytest.mark.unit
50+
def test_normal_path_returns_expected_format(monkeypatch):
51+
rows = [_kline_row(d) for d in
52+
["2026-06-01", "2026-06-02", "2026-06-03"]]
53+
monkeypatch.setattr(
54+
binance.requests, "get",
55+
lambda *a, **k: _FakeResponse(rows),
56+
)
57+
result = binance.get_binance_stock("BTC-USD", "2026-06-01", "2026-06-03")
58+
assert "Total records: 3" in result
59+
assert "2026-06-03" in result # end_date must be included
60+
assert "BTCUSDT" in result
61+
62+
63+
@pytest.mark.unit
64+
def test_end_date_inclusive_even_at_batch_boundary(monkeypatch):
65+
# Simulate Binance returning one extra day past end_date (the buffered
66+
# request); the vendor must locally filter it out.
67+
rows = [_kline_row(d) for d in
68+
["2026-06-01", "2026-06-02", "2026-06-03"]] # 06-03 is the buffer day
69+
monkeypatch.setattr(
70+
binance.requests, "get",
71+
lambda *a, **k: _FakeResponse(rows),
72+
)
73+
result = binance.get_binance_stock("BTC-USD", "2026-06-01", "2026-06-02")
74+
assert "Total records: 2" in result
75+
assert "2026-06-03" not in result # buffer day must be filtered out
76+
77+
78+
@pytest.mark.unit
79+
def test_pagination_stops_when_batch_smaller_than_limit(monkeypatch):
80+
calls = []
81+
82+
def fake_get(url, params=None, **kwargs):
83+
calls.append(params)
84+
# First call: full page (simulated as MAX_LIMIT rows) triggers a
85+
# second call; second call returns fewer rows, ending pagination.
86+
if len(calls) == 1:
87+
return _FakeResponse(
88+
[_kline_row(f"2020-01-{d:02d}") for d in range(1, 32)]
89+
* (binance._MAX_LIMIT // 31 + 1)
90+
)
91+
return _FakeResponse([_kline_row("2026-06-01")])
92+
93+
monkeypatch.setattr(binance.requests, "get", fake_get)
94+
binance.get_binance_stock("BTC-USD", "2020-01-01", "2026-06-01")
95+
assert len(calls) == 2 # confirms pagination actually looped
96+
97+
98+
@pytest.mark.unit
99+
def test_symbol_resolution_uses_usdt_pair(monkeypatch):
100+
captured = {}
101+
102+
def fake_get(url, params=None, **kwargs):
103+
captured.update(params)
104+
return _FakeResponse([_kline_row("2026-06-01")])
105+
106+
monkeypatch.setattr(binance.requests, "get", fake_get)
107+
binance.get_binance_stock("BTC-USD", "2026-06-01", "2026-06-01")
108+
assert captured["symbol"] == "BTCUSDT"

0 commit comments

Comments
 (0)