Cache-first čitanje klines-a u svim generatorima, sa Binance fallback-om. 5/5 determinizam test, 148x ubrzanje na kratkim upitima.
KlinesProvider je sad default put za kline reads u svim generatorima preko _build_context.get_klines. Cache-first sa Binance fallback-om za rupe.
src/klines_provider.py (novi modul, ~250 lines)API:
provider = KlinesProvider(analyzer, db_path='database/klines_cache.db')
df = provider.get(symbol, interval, start_dt, end_dt)Karakteristike:
threading.Lock za writes)enable_fallback=False → testing mod (samo cache, bez Binance-a)enable_writes=False → read-only modcache_available property — gracefully False ako cache db ne postoji_read_cache: ignoriše rows gde close_time/1000 > strftime('%s', fetched_at) (open-at-fetch candles)INSERT OR REPLACE (umesto OR IGNORE) — stale partial rows mogu biti overwritovanesrc/generator_manager.py izmene# __init__:
self.klines_provider: KlinesProvider | None = None
if os.environ.get('CRYPTO_KLINES_PROVIDER_DISABLE') != '1':
self.klines_provider = KlinesProvider(self.analyzer)
# _build_context.get_klines:
def get_klines(symbol, tf, start_dt, end_dt):
provider = self.klines_provider
if provider is not None:
df = provider.get(symbol, tf, start_dt, end_dt)
if df is not None and not df.empty:
return df
return self._get_klines_range(symbol, tf, start_dt, end_dt)Sigurnosni mehanizmi:
CRYPTO_KLINES_PROVIDER_DISABLE=1 → potpun bypass na originalni put_get_klines_rangetools/history_cache/build_klines_cache.py fixclose_time_ms > now_ms)INSERT OR REPLACE umesto OR IGNOREtools/history_cache/clean_stale_open_candles.py (one-shot cleanup)Posle bulk fetch-a, otkriveno je 150 stale rows (svi koji su bili open-at-fetch):
Sve obrisano. Provider će ih ponovo povući iz Binance-a kad budu zatraženi.
tools/analysis/faza2_klines_equivalence.py)Poredi KlinesProvider.get() vs _get_klines_range() (originalni Binance put) za 5 slučajeva:
| Symbol | TF | Days | Rows | Result |
|---|---|---|---|---|
| BTCUSDT | 4h | 60 | 360 | OK identical |
| ETHUSDT | 1h | 7 | 168 | OK identical |
| SOLUSDT | 15m | 3 | 288 | OK identical |
| BTCUSDT | 1d | 365 | 365 | OK identical |
| AAVEUSDT | 4h | 30 | 180 | OK identical |
5/5 PASS. Numerička greška < 1e-6 na svim OHLCV+volume kolonama.
Important: test koristi boundary - 1s da isključi tekući (još otvoren) candle. Otkrio je da open-at-fetch candles bili problematični → fix iznad.
tools/analysis/faza2_benchmark.py)| Symbol | TF | Days | Rows | Provider | Binance | Speedup |
|---|---|---|---|---|---|---|
| BTCUSDT | 4h | 30 | 180 | 9.7ms | 1451ms | 148x |
| BTCUSDT | 4h | 365 | 2190 | 1603ms | 1333ms | 0.8x |
| SOLUSDT | 1h | 30 | 720 | 413ms | 616ms | 1.5x |
| AAVEUSDT | 15m | 7 | 672 | 673ms | 605ms | 0.9x |
Sve match-ovi rows (OK marker). Performance:
_read_cache znači da live mod uvek dobija fresh vrednost za otvoreni candle (provider re-fetches)CRYPTO_KLINES_PROVIDER_DISABLE=1 → eksplicitni bypassklines_features tabela sa precomputed indikatorima (Faza 4) — najveci speedup za RSI/ADX/EMA/BB/Supertrend heavy generatore~/crypto_scanner/database/klines_cache.db)src/klines_provider.py, tools/analysis/faza2_klines_equivalence.py, tools/analysis/faza2_benchmark.py, tools/history_cache/clean_stale_open_candles.pysrc/generator_manager.py (KlinesProvider hook), tools/history_cache/build_klines_cache.py (skip open candles + REPLACE)database/klines_cache.db na .88 (bind-mountovan, 2.2GB, 13.6M redova, 5y × 68 simbola × 4 intervala)Izvor: crypto_scanner/reports/analysis/2026-05-20_faza2_klines_provider.md