Skip to content

Commit b59352b

Browse files
authored
fix(data): preserve K-line price precision (#224)
1 parent 615d90c commit b59352b

2 files changed

Lines changed: 62 additions & 6 deletions

File tree

backend_api_python/app/data_sources/base.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@ def format_kline(
7373
close: float,
7474
volume: float
7575
) -> Dict[str, Any]:
76-
"""Normalize one K-line row."""
76+
"""Normalize one K-line row while preserving provider price precision; volume keeps two decimals."""
7777
return {
7878
'time': timestamp,
79-
'open': round(float(open_price), 4),
80-
'high': round(float(high), 4),
81-
'low': round(float(low), 4),
82-
'close': round(float(close), 4),
79+
'open': float(open_price),
80+
'high': float(high),
81+
'low': float(low),
82+
'close': float(close),
8383
'volume': round(float(volume), 2)
8484
}
8585

@@ -173,4 +173,3 @@ def log_result(
173173
)
174174
else:
175175
logger.warning(f"{self.name}: no data for {symbol}")
176-
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""Regression coverage for generic K-line normalization."""
2+
3+
import math
4+
5+
import pytest
6+
7+
from app.data_sources.base import BaseDataSource
8+
9+
10+
class _TestDataSource(BaseDataSource):
11+
"""Concrete shell for exercising the shared normalization method."""
12+
13+
def get_kline(self, symbol, timeframe, limit, before_time=None, after_time=None):
14+
return []
15+
16+
17+
@pytest.fixture
18+
def data_source():
19+
return _TestDataSource()
20+
21+
22+
@pytest.mark.parametrize(
23+
"price",
24+
[0.01038, 0.001038, 123.456789],
25+
)
26+
def test_format_kline_preserves_source_price_precision(data_source, price):
27+
row = data_source.format_kline(1_700_000_000, price, price, price, price, 12.3456)
28+
29+
assert row["open"] == price
30+
assert row["high"] == price
31+
assert row["low"] == price
32+
assert row["close"] == price
33+
34+
35+
def test_format_kline_keeps_timestamp_and_existing_volume_normalization(data_source):
36+
row = data_source.format_kline(
37+
1_700_000_123,
38+
10.123456,
39+
10.234567,
40+
10.012345,
41+
10.200001,
42+
9876.54321,
43+
)
44+
45+
assert row["time"] == 1_700_000_123
46+
assert row["volume"] == 9876.54
47+
48+
49+
def test_format_kline_preserves_nan_price_behavior(data_source):
50+
row = data_source.format_kline(1, math.nan, 2.0, 1.0, 1.5, 0.0)
51+
52+
assert math.isnan(row["open"])
53+
54+
55+
def test_format_kline_rejects_non_numeric_prices(data_source):
56+
with pytest.raises(ValueError):
57+
data_source.format_kline(1, "not-a-price", 2.0, 1.0, 1.5, 0.0)

0 commit comments

Comments
 (0)