Risk controls, alerts, API token, more exchanges, presets
CI/CD / backend (pull_request) Successful in 6m18s
CI/CD / frontend (pull_request) Successful in 4m55s
CI/CD / build (pull_request) Skipped
CI/CD / deploy (pull_request) Skipped
CI/CD / cleanup (pull_request) Skipped

- RiskManager halts + flattens on max daily loss / drawdown, caps position
  size and trades per day; adds a manual kill switch (POST /api/bot/kill).
- Telegram and webhook notifications on trades, errors and halts.
- Optional API bearer token on /api, injected server-side by the frontend
  nginx so the browser never sees it.
- Kraken and Coinbase market data (public); Coinbase live broker. Live on an
  unsupported exchange now errors instead of silently falling back to paper.
- Strategy presets backed by the StrategyConfig table (CRUD API + UI).
- Idempotent additive-column migration so existing SQLite databases upgrade in
  place (fixes the new strategy_configs.name column).
This commit is contained in:
matitos committed 2026-09-18 19:26:29 +00:00
1 parent 9c3bee87ac
commit 03dfa369e5
35 files changed
+1409 -45

No files matched your search

+55
View File
@@ -0,0 +1,55 @@
from __future__ import annotations
import pytest
from app.config import Settings
from app.market.coinbase import CoinbaseMarketData, to_product_id
from app.market.kraken import KrakenMarketData
def test_symbol_mapping() -> None:
assert to_product_id("BTC/USDT") == "BTC-USDT"
assert to_product_id("eth/usd") == "ETH-USD"
def test_kraken_interval_mapping() -> None:
assert KrakenMarketData._interval("1h") == 60
assert KrakenMarketData._interval("1d") == 1440
with pytest.raises(ValueError):
KrakenMarketData._interval("2m")
def test_coinbase_granularity_mapping() -> None:
assert CoinbaseMarketData._granularity("1m") == 60
assert CoinbaseMarketData._granularity("1d") == 86400
with pytest.raises(ValueError):
CoinbaseMarketData._granularity("3m")
def test_build_market_data_supports_exchanges() -> None:
from app.market import build_market_data
assert type(build_market_data(Settings(exchange="binance"))).__name__ == "BinanceMarketData"
assert type(build_market_data(Settings(exchange="kraken"))).__name__ == "KrakenMarketData"
assert type(build_market_data(Settings(exchange="coinbase"))).__name__ == "CoinbaseMarketData"
def test_build_market_data_rejects_unknown() -> None:
from app.market import build_market_data
with pytest.raises(ValueError, match="unsupported exchange"):
build_market_data(Settings(exchange="ftx"))
def test_build_broker_paper_default() -> None:
from app.broker import build_broker
from app.broker.paper import PaperBroker
assert isinstance(build_broker(Settings(mode="paper", exchange="kraken")), PaperBroker)
def test_build_broker_live_unsupported_exchange() -> None:
from app.broker import build_broker
with pytest.raises(ValueError, match="not supported"):
build_broker(Settings(mode="live", exchange="kraken"))