feat: Implement pairing synchronization from Kraken and enhance market data feed

- Added `sync_pairings_from_kraken` function to fetch and upsert asset pairs into the config_pairings table.
- Introduced `run_pairing_sync_loop` for periodic synchronization of pairings.
- Enhanced `KrakenWsClient` to manage subscribed symbols for market data feeds.
- Created `build_detector_from_enabled_pairings` to initialize cycle detection based on enabled pairings.
- Updated FastAPI app to start market data feed and pairing synchronization tasks.
- Added new API routes for managing pairings, including listing, toggling, and syncing from Kraken.
- Improved dashboard templates to display pairing options and allow user interaction for backtesting.
- Refactored database queries to streamline fetching and updating of pairing data.
This commit is contained in:
2026-06-04 22:10:06 +02:00
parent 92b0b49535
commit 4c59a0e4cb
16 changed files with 733 additions and 198 deletions
+7 -8
View File
@@ -13,14 +13,13 @@ from arbitrade.storage.db import DuckDBStore
def _python_scan_compute(store: DuckDBStore) -> tuple[float, float | None, float | None]:
with store.connect() as conn:
trade_rows = conn.execute(
"""
trade_rows = conn.execute("""
SELECT started_at, finished_at, realized_pnl
FROM trades
WHERE finished_at IS NOT NULL
"""
).fetchall()
opportunity_rows = conn.execute("SELECT detected_at FROM opportunities").fetchall()
""").fetchall()
sql_d = "SELECT detected_at FROM opportunities"
orows = conn.execute(sql_d).fetchall()
realized = sum(float(row[2]) for row in trade_rows if row[2] is not None)
durations = [
@@ -30,10 +29,10 @@ def _python_scan_compute(store: DuckDBStore) -> tuple[float, float | None, float
]
avg_duration = fmean(durations) if durations else None
times = [row[0] for row in opportunity_rows if isinstance(row[0], datetime)]
times = [row[0] for row in orows if isinstance(row[0], datetime)]
if len(times) >= 2:
span_seconds = (max(times) - min(times)).total_seconds()
opm = len(times) / (span_seconds / 60.0) if span_seconds > 0.0 else float(len(times))
ss = (max(times) - min(times)).total_seconds()
opm = len(times) / (ss / 60.0) if ss > 0.0 else float(len(times))
elif len(times) == 1:
opm = 60.0
else: