Describe the bug
backend_api_python/app/data_sources/base.py format_kline rounds every OHLC price with round(float(x), 4). Exchange tick sizes are not a fixed 4 decimals: several Binance perpetual symbols trade at 5–6 decimal ticks (verified from fapi.binance.com/exchangeInfo):
| symbol |
PRICE_FILTER tickSize |
| TUT/USDT:USDT |
0.0000100 (5 dp) |
| TAG/USDT:USDT |
0.0000010 (6 dp) |
| JCT/USDT:USDT |
0.0000010 (6 dp) |
| CYS/USDT:USDT / BEAT/USDT:USDT |
0.0001000 (4 dp, unaffected) |
So for low-priced symbols the persisted price loses 1–2 decimal places versus real quotes. Every consumer of get_kline — Strategy V2 backtests, indicators, AI features, charts — then works on prices that differ from the market. Price-threshold logic (e.g. breakout close > prior_high) fires on the wrong bars for these symbols.
Steps to reproduce
- Fetch one bar via ccxt directly:
exchange.fetch_ohlcv('TUT/USDT:USDT', '5m') → close 0.01038 (5 dp).
- Fetch the same bar via
DataSourceFactory.get_kline(market='Crypto', symbol='TUT/USDT', timeframe='5m', market_type='swap') → close 0.0104 (4 dp, rounded).
- Run any Strategy V2 breakout backtest on a universe that includes low-priced perps; compare full-precision frames vs the rounded frames → different entry bars, trade counts, and per-symbol PnL.
Expected behavior
K-line prices should preserve the exchange's actual tick precision (or round to the per-symbol PRICE_FILTER.tickSize), not a fixed 4 decimals.
Deployment method
Docker Compose
Relevant logs
ccxt fetch_ohlcv('TUT/USDT:USDT','5m') 2026-02-25T16:10:00Z close=0.01038
get_kline TUT/USDT swap same bar close=0.0104
Describe the bug
backend_api_python/app/data_sources/base.pyformat_klinerounds every OHLC price withround(float(x), 4). Exchange tick sizes are not a fixed 4 decimals: several Binance perpetual symbols trade at 5–6 decimal ticks (verified fromfapi.binance.com/exchangeInfo):0.0000100(5 dp)0.0000010(6 dp)0.0000010(6 dp)0.0001000(4 dp, unaffected)So for low-priced symbols the persisted price loses 1–2 decimal places versus real quotes. Every consumer of
get_kline— Strategy V2 backtests, indicators, AI features, charts — then works on prices that differ from the market. Price-threshold logic (e.g. breakoutclose > prior_high) fires on the wrong bars for these symbols.Steps to reproduce
exchange.fetch_ohlcv('TUT/USDT:USDT', '5m')→ close0.01038(5 dp).DataSourceFactory.get_kline(market='Crypto', symbol='TUT/USDT', timeframe='5m', market_type='swap')→ close0.0104(4 dp, rounded).Expected behavior
K-line prices should preserve the exchange's actual tick precision (or round to the per-symbol
PRICE_FILTER.tickSize), not a fixed 4 decimals.Deployment method
Docker Compose
Relevant logs