Files
signal-platform/app/config.py
T
dennisthiessenandClaude Opus 5 7fdcac3b55
Deploy / lint (push) Successful in 9s
Deploy / test (push) Successful in 1m12s
Deploy / deploy (push) Successful in 37s
docs: carry the risk-monitor wording through docs, comments and logs
Follows 5ea0785, which renamed the user-visible labels. This finishes the pass
so code, docs and operator output use one vocabulary: README (pipeline list,
route table, FRED row), the methodology doc title, .env.example and config
comments, the snapshot model / event-study / service / test docstrings, the
scheduler section headers and morning-pipeline docstring, the TopBar status
text ("bullish regime" -> "bullish trend"), and the four "Regime monitor:" log
prefixes.

Deliberately NOT changed, because "market regime" is also a standard finance
term and most occurrences are not this job: the backtest caveat "~6 months is
roughly one market regime" in backtest_service, README, BacktestPanel and every
generated reports/*.json; "a regime shift" in TrackRecordPanel; and the
capacity-bracket findings doc. Renaming those would have made the text wrong.

Also unchanged, being persisted or externally linked rather than wording: the
regime_monitor / market_regime job ids, the regime_quadrant_enabled setting key,
the /regime route, METHODOLOGY and the snapshot fields, the service/test module
filenames, and docs/research/regime-monitor-v3.md's path (referenced from commit
messages). The doc now carries a one-line note recording the old name and why
those identifiers still use it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 22:51:49 +02:00

107 lines
4.6 KiB
Python

from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
# Database
database_url: str = "postgresql+asyncpg://stock_backend:changeme@localhost:5432/stock_data_backend"
# Auth
jwt_secret: str = "change-this-to-a-random-secret"
jwt_expiry_minutes: int = 60
# OHLCV Provider — Alpaca Markets
alpaca_api_key: str = ""
alpaca_api_secret: str = ""
# Sentiment Provider — Gemini with Search Grounding (legacy)
gemini_api_key: str = ""
gemini_model: str = "gemini-2.0-flash"
# Sentiment Provider — OpenAI
openai_api_key: str = ""
openai_model: str = "gpt-4o-mini"
openai_sentiment_batch_size: int = 5
# Sentiment Provider — DeepSeek / xAI (OpenAI-compatible; optional env fallback)
deepseek_api_key: str = ""
xai_api_key: str = ""
# Dolt bulk-data — local clone of post-no-preference/earnings (workstream A).
# dolt_binary: full path when not on PATH (dev/Windows install). dolt_data_dir
# holds the clones; in production it MUST be outside the deploy tree (deploy is
# rsync --delete) — set DOLT_DATA_DIR to a persistent path. The earnings clone
# lives at <dolt_data_dir>/<dolt_earnings_subdir>.
dolt_binary: str = "dolt"
dolt_data_dir: str = "dolt-data"
dolt_earnings_subdir: str = "earnings"
# Headroom above the ~1.7 GB earnings clone (grows with pulls); 5 GB is a safe
# production floor — override lower only in a space-constrained dev box.
dolt_min_free_disk_gb: float = 5.0
# Bound every dolt subprocess so a hung pull/sql can't pin the import's
# connection + advisory lock indefinitely.
dolt_command_timeout_seconds: float = 600.0
# SEC EDGAR (workstream A, fundamentals). Fair-access policy REQUIRES an
# identifying User-Agent with a contact email — set a real one. Stay well
# under 10 req/s (spacing below); 403 means the UA/pattern is wrong → the
# client alerts and stops rather than retry-looping.
sec_user_agent: str = "signal-platform/1.0 (contact: set-a-real-email@example.com)"
sec_request_spacing_seconds: float = 0.2
sec_max_retries: int = 4
sec_request_timeout_seconds: float = 30.0
# AI/Tech Risk Monitor — FRED (VIX level + HY credit spreads). Optional: without it
# the volatility (P5) and credit-spread (F2) signals are reported as n/a.
fred_api_key: str = ""
# Alerts — Telegram (optional env fallback; can also be set in Admin)
telegram_bot_token: str = ""
telegram_chat_id: str = ""
# Scheduled Jobs
data_collector_frequency: str = "daily"
sentiment_poll_interval_minutes: int = 30
# Sentiment search-budget controls (Gemini grounding free tier = 5000/month).
# Scope (see _get_sentiment_priority_tickers): everything that matters is always
# refreshed in full — open paper trades + the curated watchlist + top-pick
# feeders (residual-momentum leaders with a tradeable long setup) — plus a top-N composite
# discovery net. No per-run cap: the set is naturally bounded (watchlist <= 20,
# composite <= top_composite), so a full refresh stays well inside the free tier.
# Skip anything refreshed within fresh_hours (5 days: sentiment shifts slowly and
# the score window is 7 days).
sentiment_fresh_hours: int = 120
sentiment_top_composite: int = 30
rr_scan_frequency: str = "daily" # legacy label; qualifying scan is cron near-close
# alerts_frequency removed: alerts fire only via morning + near-close pipelines
# Scoring Defaults
default_watchlist_auto_size: int = 10
default_rr_threshold: float = 1.5
# Outcome evaluation: trading days before an undecided setup expires
outcome_evaluation_max_bars: int = 30
# OHLCV history depth to fetch. New tickers backfill this far; the manual
# "data_backfill" job re-fetches the full window for everyone. ~5 years so
# long-lookback factors (12-month momentum, 52-week high) and multi-regime
# backtests become computable. ~252 trading days/year.
ohlcv_history_days: int = 1825
# Backtest parallelism: replay tickers across this many worker processes on
# POSIX (forkserver), capped to cpu_count-1 so a core stays free for the web
# server. 1 disables it (sequential). No effect on Windows / spawn-only
# platforms — those fall back to a single worker thread.
backtest_workers: int = 4
# Database Pool
db_pool_size: int = 5
db_pool_timeout: int = 30
# Logging
log_level: str = "INFO"
settings = Settings()