Risk controls, alerts, API token, more exchanges, presets
- 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:
1 parent
9c3bee87ac
commit
03dfa369e5
35 files changed
+1409
-45
No files matched your search
@@ -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"))
|
||||
Reference in new issue
Block a user