spb/crypto-trade-bot
Public
Python 54.7%
TypeScript 42.5%
SQL 1.9%
1"""Runtime configuration (environment-injected; never log secrets)."""23from __future__ import annotations45from functools import lru_cache6from typing import Annotated, Literal78from pydantic import Field, field_validator9from pydantic_settings import BaseSettings, NoDecode, SettingsConfigDict1011TradingMode = Literal["offline", "paper", "live"]121314class Settings(BaseSettings):15 model_config = SettingsConfigDict(env_prefix="KTRADE_", env_file=".env", extra="ignore")1617 env: str = "dev"18 app_base_url: str = "http://127.0.0.1:8471"19 api_host: str = "127.0.0.1"20 api_port: int = 847021 log_level: str = "INFO"22 log_json: bool = True2324 database_url: str = "postgresql+asyncpg://ktrade:ktrade@127.0.0.1:5432/ktrade"25 redis_url: str = "redis://127.0.0.1:6379/3"2627 # Session / auth28 secret_key: str = Field(default="dev-insecure-change-me", description="Signs session cookies")29 owner_password_hash: str = Field(default="", description="bcrypt hash of the owner password")30 session_ttl_seconds: int = 12 * 360031 cookie_secure: bool = False3233 # Kraken — three least-privilege key pairs. Data/account keys must NOT have trade permission;34 # the trade key is only read when live mode is armed. Withdrawal permission is never used.35 kraken_rest_url: str = "https://api.kraken.com"36 kraken_ws_url: str = "wss://ws.kraken.com/v2"37 kraken_ws_auth_url: str = "wss://ws-auth.kraken.com/v2"38 kraken_api_key: str = ""39 kraken_api_secret: str = ""40 kraken_trade_api_key: str = ""41 kraken_trade_api_secret: str = ""42 kraken_tier: Literal["starter", "intermediate", "pro"] = "starter"4344 # Universe & ingestion45 universe: Annotated[list[str], NoDecode] = Field(default_factory=lambda: ["BTC/USD", "ETH/USD", "SOL/USD", "XRP/USD", "ADA/USD", "LINK/USD", "DOT/USD", "LTC/USD"])46 candle_intervals: Annotated[list[int], NoDecode] = Field(default_factory=lambda: [1, 5, 60, 1440])47 backfill_poll_seconds: int = 6048 book_depth: int = 2549 stale_data_seconds: int = 1205051 # Trading mode gates52 trading_mode: TradingMode = "offline"53 live_trading_enabled: bool = False # feature flag; UI activation also required (Phase 5)5455 # Observability56 metrics_enabled: bool = True5758 @field_validator("universe", "candle_intervals", mode="before")59 @classmethod60 def _split_csv(cls, v): # noqa: ANN00161 if isinstance(v, str):62 parts = [p.strip() for p in v.split(",") if p.strip()]63 return [int(p) if p.isdigit() else p for p in parts]64 return v6566 @property67 def sync_database_url(self) -> str:68 return self.database_url.replace("+asyncpg", "")6970 def has_data_key(self) -> bool:71 return bool(self.kraken_api_key and self.kraken_api_secret)7273 def has_trade_key(self) -> bool:74 return bool(self.kraken_trade_api_key and self.kraken_trade_api_secret)757677@lru_cache78def get_settings() -> Settings:79 return Settings()80