diff --git a/src/arbitrade/api/routes.py b/src/arbitrade/api/routes.py index 69b7618..a7fcaae 100644 --- a/src/arbitrade/api/routes.py +++ b/src/arbitrade/api/routes.py @@ -899,6 +899,25 @@ async def dashboard_audit(request: Request) -> HTMLResponse: ) +@router.get("/dashboard/config/pairings", response_class=HTMLResponse) +async def dashboard_config_pairings_page( + request: Request, + search: str | None = None, + enabled: str | None = None, +) -> HTMLResponse: + """Standalone pairings management page.""" + return templates.TemplateResponse( + request=request, + name="pairings.html", + context={ + "title": "Currency Pairings", + "request": request, + "search": search or "", + "enabled": enabled or "all", + }, + ) + + @router.get("/dashboard/config", response_class=HTMLResponse) async def dashboard_config_page(request: Request) -> HTMLResponse: d_context = await _dashboard_config_context(request) @@ -1447,19 +1466,20 @@ async def dashboard_api_pairings_toggle(request: Request) -> HTMLResponse: ) -@router.post("/dashboard/api/pairings/sync") -async def dashboard_api_pairings_sync(request: Request) -> JSONResponse: - """Trigger a re-sync of pairings from Kraken.""" - kraken_client = request.app.state.kraken_client +@router.post("/dashboard/api/pairings/sync", response_class=HTMLResponse) +async def dashboard_api_pairings_sync(request: Request) -> HTMLResponse: + """Sync pairings from Kraken and return refreshed table.""" + from arbitrade.config.pairing_sync import sync_pairings_from_kraken + store = request.app.state.store - summary = await sync_pairings_from_kraken(kraken_client, store) - - await _record_audit( - request, - actor="dashboard_user", - event_type="dashboard.pairings.sync", - decision="approved", - payload=summary, # type: ignore + kraken = getattr(request.app.state, "kraken_client", None) + if kraken is not None: + await sync_pairings_from_kraken(kraken, store) + repo = _pairing_repo(request) + pairings = await repo.list_pairings() + pairings.sort(key=lambda p: (p.base_asset, p.quote_asset)) + return templates.TemplateResponse( + request=request, + name="partials/pairings_table.html", + context={"request": request, "pairings": pairings}, ) - - return JSONResponse(summary) diff --git a/src/arbitrade/market_data/order_book.py b/src/arbitrade/market_data/order_book.py index a4ba86a..a95803b 100644 --- a/src/arbitrade/market_data/order_book.py +++ b/src/arbitrade/market_data/order_book.py @@ -86,7 +86,8 @@ class OrderBook: BookLevel(price=price, volume=self._bids[price]) for price in reversed(bid_keys[-depth:]) ] - asks = [BookLevel(price=price, volume=self._asks[price]) for price in ask_keys[:depth]] + asks = [BookLevel(price=price, volume=self._asks[price]) + for price in ask_keys[:depth]] return bids, asks def compute_checksum(self, depth: int = 10) -> int: diff --git a/src/arbitrade/web/templates/_header.html b/src/arbitrade/web/templates/_header.html index b7a5d85..7e42202 100644 --- a/src/arbitrade/web/templates/_header.html +++ b/src/arbitrade/web/templates/_header.html @@ -5,9 +5,10 @@ {% set nav_links = [ {"url": "/dashboard", "label": "Dashboard", "class": "secondary"}, {"url": "/dashboard/config", "label": "Config", "class": - "secondary"}, {"url": "/dashboard/backtesting", "label": "Backtesting", - "class": "secondary"}, {"url": "/dashboard/health", "label": "Health", - "class": "secondary"}, ] %} + "secondary"}, {"url": "/dashboard/config/pairings", "label": "Pairings", + "class": "secondary"}, {"url": "/dashboard/backtesting", "label": + "Backtesting", "class": "secondary"}, {"url": "/dashboard/health", "label": + "Health", "class": "secondary"}, ] %}
diff --git a/src/arbitrade/web/templates/config/kraken.html b/src/arbitrade/web/templates/config/kraken.html new file mode 100644 index 0000000..73226e9 --- /dev/null +++ b/src/arbitrade/web/templates/config/kraken.html @@ -0,0 +1,93 @@ +