Add configurable data providers and localize frontend UI
This commit is contained in:
@@ -17,6 +17,7 @@ from backend.core.pipeline import TradingPipeline
|
||||
from backend.core.state_sync import StateSync
|
||||
from backend.services.market import MarketService
|
||||
from backend.services.storage import StorageService
|
||||
from backend.data.provider_router import get_provider_router
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -60,10 +61,14 @@ class Gateway:
|
||||
|
||||
# Session tracking for live returns
|
||||
self._session_start_portfolio_value: Optional[float] = None
|
||||
self._provider_router = get_provider_router()
|
||||
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
|
||||
async def start(self, host: str = "0.0.0.0", port: int = 8766):
|
||||
"""Start gateway server"""
|
||||
logger.info(f"Starting gateway on {host}:{port}")
|
||||
self._loop = asyncio.get_running_loop()
|
||||
self._provider_router.add_listener(self._on_provider_usage_changed)
|
||||
|
||||
# Initialize terminal dashboard
|
||||
self._dashboard.set_config(
|
||||
@@ -77,6 +82,7 @@ class Gateway:
|
||||
initial_cash=self.storage.initial_cash,
|
||||
start_date=self._backtest_start_date or "",
|
||||
end_date=self._backtest_end_date or "",
|
||||
data_sources=self._provider_router.get_usage_snapshot(),
|
||||
)
|
||||
self._dashboard.start()
|
||||
|
||||
@@ -88,6 +94,10 @@ class Gateway:
|
||||
"is_mock_mode",
|
||||
self.config.get("mock_mode", False),
|
||||
)
|
||||
self.state_sync.update_state(
|
||||
"data_sources",
|
||||
self._provider_router.get_usage_snapshot(),
|
||||
)
|
||||
|
||||
# Load and display existing portfolio state if available
|
||||
summary = self.storage.load_file("summary")
|
||||
@@ -130,6 +140,21 @@ class Gateway:
|
||||
)
|
||||
await asyncio.Future()
|
||||
|
||||
def _on_provider_usage_changed(self, snapshot: Dict[str, Any]):
|
||||
"""Handle provider routing updates from the shared router."""
|
||||
self.state_sync.update_state("data_sources", snapshot)
|
||||
self._dashboard.update(data_sources=snapshot)
|
||||
if self._loop and self._loop.is_running():
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
self.broadcast(
|
||||
{
|
||||
"type": "data_sources_update",
|
||||
"data_sources": snapshot,
|
||||
},
|
||||
),
|
||||
self._loop,
|
||||
)
|
||||
|
||||
@property
|
||||
def state(self) -> Dict[str, Any]:
|
||||
return self.state_sync.state
|
||||
@@ -149,6 +174,9 @@ class Gateway:
|
||||
state_payload = self.state_sync.get_initial_state_payload(
|
||||
include_dashboard=True,
|
||||
)
|
||||
state_payload["data_sources"] = (
|
||||
self._provider_router.get_usage_snapshot()
|
||||
)
|
||||
# Include market status in initial state
|
||||
state_payload[
|
||||
"market_status"
|
||||
|
||||
@@ -10,6 +10,8 @@ from typing import Any, Callable, Dict, List, Optional
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import pandas_market_calendars as mcal
|
||||
from backend.config.data_config import get_data_source
|
||||
from backend.data.provider_utils import normalize_symbol
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -40,7 +42,7 @@ class MarketService:
|
||||
backtest_start_date: Optional[str] = None,
|
||||
backtest_end_date: Optional[str] = None,
|
||||
):
|
||||
self.tickers = tickers
|
||||
self.tickers = [normalize_symbol(ticker) for ticker in tickers]
|
||||
self.poll_interval = poll_interval
|
||||
self.mock_mode = mock_mode
|
||||
self.backtest_mode = backtest_mode
|
||||
@@ -123,11 +125,16 @@ class MarketService:
|
||||
def _start_real_mode(self):
|
||||
from backend.data.polling_price_manager import PollingPriceManager
|
||||
|
||||
if not self.api_key:
|
||||
provider = get_data_source()
|
||||
if provider == "local_csv":
|
||||
provider = "yfinance"
|
||||
|
||||
if provider == "finnhub" and not self.api_key:
|
||||
raise ValueError("API key required for live mode")
|
||||
self._price_manager = PollingPriceManager(
|
||||
api_key=self.api_key,
|
||||
poll_interval=self.poll_interval,
|
||||
provider=provider,
|
||||
)
|
||||
self._price_manager.add_price_callback(self._make_price_callback())
|
||||
self._price_manager.subscribe(self.tickers)
|
||||
|
||||
Reference in New Issue
Block a user