Fix concurrent API credit exhaustion — shared prefetch + dedup warnings
- telegram_bot: one ForexDataProvider shared across all SCAN_TIMEFRAMES; combined prefetch of all unique TFs up front so the 4 concurrent scans hit the warm cache instead of firing simultaneous API calls - data_provider: skip prefetch_batch for timeframes already in cache - data_provider: deduplicate "no data" warning per symbol (fires once, not once per TF) - data_provider: [live] info log on successful fetch; outlier-removal downgraded to debug Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+14
-4
@@ -33,6 +33,7 @@ from config import (
|
||||
MAJOR_PAIRS, CROSS_PAIRS, SYMBOL_DISPLAY,
|
||||
PlatformConfig, SignalStrength, Timeframe,
|
||||
)
|
||||
from data_provider import ForexDataProvider
|
||||
from signal_aggregator import SignalAggregator, SignalReport
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -282,16 +283,25 @@ class ForexTelegramBot:
|
||||
cfg.watch_pairs = list(pairs)
|
||||
return cfg
|
||||
|
||||
def _run_scan(self, tf: str, pairs: List[str]) -> List[SignalReport]:
|
||||
return SignalAggregator(self._build_config(tf, pairs)).analyze_all_pairs()
|
||||
def _run_scan(self, tf: str, pairs: List[str], provider: ForexDataProvider) -> List[SignalReport]:
|
||||
return SignalAggregator(self._build_config(tf, pairs), data_provider=provider).analyze_all_pairs()
|
||||
|
||||
async def _analyze_all_tfs(
|
||||
self, pairs: List[str]
|
||||
) -> Dict[str, List[SignalReport]]:
|
||||
"""Run all SCAN_TIMEFRAMES concurrently, return {tf: [reports]}."""
|
||||
"""Single combined prefetch, then run all SCAN_TIMEFRAMES concurrently off the warm cache."""
|
||||
# Collect all unique timeframes needed across every TF scan
|
||||
all_tfs = list({
|
||||
tf
|
||||
for tf_name in SCAN_TIMEFRAMES
|
||||
for tf in [_TF_MAP[tf_name]] + _TF_CONFIRMATIONS.get(tf_name, [])
|
||||
})
|
||||
provider = ForexDataProvider(PlatformConfig())
|
||||
provider.prefetch_batch(list(pairs), all_tfs)
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
tasks = {
|
||||
tf: loop.run_in_executor(self._executor, self._run_scan, tf, list(pairs))
|
||||
tf: loop.run_in_executor(self._executor, self._run_scan, tf, list(pairs), provider)
|
||||
for tf in SCAN_TIMEFRAMES
|
||||
}
|
||||
results: Dict[str, List[SignalReport]] = {}
|
||||
|
||||
Reference in New Issue
Block a user