- 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).
56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
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"))
|