[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/litter998/QuantDinger--/feture2/backend_api_python/env.example [Back]  [Original]

# QuantDinger local configuration (copy to `.env` and edit)
# `run.py` will load `backend_api_python/.env` automatically if present.
#
# This file is organized as:
# 1) first-time deployment settings at the top
# 2) advanced / rarely changed settings at the bottom
# For Docker image source / ports, use the project-root `.env`.

# =========================
# Brand / identity (drives logo, footer, version label, legal modals)
# =========================
# Frontend reads these via /api/settings/brand-config  leave any field empty
# to fall back to the bundled QuantDinger defaults. Change here (or via the
# Settings page) to rebrand a deployment without rebuilding the frontend.
BRAND_APP_NAME=QuantDinger
BRAND_COPYRIGHT= 2025-2026 QuantDinger. All rights reserved.

# Logo / favicon URLs (HTTPS recommended; leave empty to use bundled assets)
BRAND_LOGO_LIGHT_URL=
BRAND_LOGO_DARK_URL=
BRAND_LOGO_COLLAPSED_URL=
BRAND_FAVICON_URL=

# Contact & support links surfaced in the sidebar footer.
BRAND_CONTACT_EMAIL=support@quantdinger.com
BRAND_CONTACT_SUPPORT_URL=https://t.me/quantdinger
BRAND_CONTACT_LIVE_CHAT_URL=https://t.me/quantdinger
BRAND_CONTACT_FEATURE_REQUEST_URL=https://github.com/brokermr810/QuantDinger/issues

# Social accounts shown as icons in the sidebar footer. Leave any single
# entry empty to hide that icon.
BRAND_SOCIAL_GITHUB=https://github.com/brokermr810/QuantDinger
BRAND_SOCIAL_X=https://x.com/quantdinger_en
BRAND_SOCIAL_DISCORD=https://discord.com/invite/tyx5B6TChr
BRAND_SOCIAL_TELEGRAM=https://t.me/quantdinger
BRAND_SOCIAL_YOUTUBE=https://youtube.com/@quantdinger

# Legal: external URL takes priority; if both URL and inline text are empty,
# the frontend falls back to the built-in i18n copy.
BRAND_LEGAL_USER_AGREEMENT_URL=
BRAND_LEGAL_USER_AGREEMENT_TEXT=
BRAND_LEGAL_PRIVACY_POLICY_URL=
BRAND_LEGAL_PRIVACY_POLICY_TEXT=

# =========================
# Auth (required)
# =========================
# >= 32 bytes for HS256 (JWT). Generate: python -c "import secrets; print(secrets.token_hex(32))"
# Also derives Fernet key for encrypting qd_exchange_credentials.encrypted_config (do not rotate casually).
SECRET_KEY=quantdinger-secret-key-change-me
ADMIN_USER=quantdinger
# Leaving ADMIN_PASSWORD as 123456 will trigger a first-login change-password reminder.
# Set any non-default value before startup to skip that reminder and initialize safely.
ADMIN_PASSWORD=123456
ADMIN_EMAIL=

# =========================
# Core app
# =========================
DATABASE_URL=postgresql://quantdinger:quantdinger123@postgres:5432/quantdinger
# FRONTEND_URL: the canonical user-facing URL of the web app.
# - Used for: CORS allow-list, default post-login OAuth redirect target.
# - Comma-separated multi-origin IS supported (the first entry is the
#   default OAuth redirect; every entry is added to the CORS / OAuth
#   allow-list). Prefer the simpler `OAUTH_ALLOWED_REDIRECTS` below for
#   the second / third front-end origin so that this stays a single URL.
# - You do NOT need to add Capacitor / Cordova / Ionic mobile-app origins
#   here (https://localhost, capacitor://localhost, ionic://localhost,
#   http://localhost). The backend whitelists those automatically because
#   they are fixed synthetic origins controlled by the OS, not user input.
# - If your mobile app uses a separate API subdomain like
#   https://api.quantdinger.com, make sure your nginx server_block for that
#   host is reverse-proxying /api/* to the backend port (5000).
# Examples:
#   FRONTEND_URL=https://ai.quantdinger.com
#   FRONTEND_URL=https://ai.quantdinger.com,https://m.quantdinger.com
FRONTEND_URL=http://localhost:8888,http://localhost:8889
# Extra front-end origins allowed as OAuth post-login redirect targets.
# Comma-separated, scheme + host (+ optional port). Used when multiple clients
# (e.g. PC web + mobile web) share the same backend. FRONTEND_URL is always
# allowed implicitly; list every additional front-end here.
# Example: OAUTH_ALLOWED_REDIRECTS=https://m.quantdinger.com,https://app.quantdinger.com,com.quantdinger.mobile://login
OAUTH_ALLOWED_REDIRECTS=
# OAuth CSRF state TTL (minutes); stored in Postgres for multi-worker. Default 20, clamped [5,120].
OAUTH_STATE_TTL_MINUTES=20
ENABLE_REGISTRATION=true

# =========================
# Mobile app (in-app version check)
# =========================
# Semver-like string shown to clients; leave empty to avoid "new version" prompts.
MOBILE_APP_LATEST_VERSION=
# APK / install page URL for one-tap update on Android (HTTPS recommended).
MOBILE_APP_DOWNLOAD_URL=https://www.quantdinger.com/download/app.apk

# =========================
# Database bootstrap behaviour
# =========================
# On every backend startup we auto-apply `migrations/init.sql` so a fresh
# install (especially bare-metal / Windows local PG) gets the full schema
# without anyone remembering to `psql -f` first. The file uses
# `CREATE TABLE IF NOT EXISTS` everywhere so re-running is a no-op.
# Set to `true` if you manage schema externally (Flyway, Liquibase, etc.)
# and don't want the backend touching DDL on boot. Permission probing on
# critical tables still runs either way.
SKIP_AUTO_MIGRATE=false

# =========================
# Database connection pool (psycopg2 ThreadedConnectionPool)
# =========================
# DB_POOL_MAX defaults to auto. Most self-hosted deployments should leave it
# as auto; the backend probes PostgreSQL max_connections and picks a safe
# per-process pool size. Advanced operators may set an integer override.
DB_POOL_MIN=5
DB_POOL_MAX=auto
DB_POOL_ACQUIRE_TIMEOUT=10
DB_POOL_HEALTH_CHECK=true
DB_POOL_AUTO_CAP=true
DB_POOL_AUTO_DEFAULT_MAX=50
DB_POOL_RESERVE_FOR_OTHER_CLIENTS=20
DB_APPLICATION_NAME=quantdinger_api

# Route-level parallel fetch executors.  Each worker may hold one DB
# connection, so keep MARKET_EXECUTOR_WORKERS + PORTFOLIO_EXECUTOR_WORKERS
# well below DB_POOL_MAX.
MARKET_EXECUTOR_WORKERS=6
PORTFOLIO_EXECUTOR_WORKERS=3

# Gunicorn worker/thread model
GUNICORN_WORKERS=1
GUNICORN_THREADS=8

# =========================
# AI / LLM (choose one provider)
# =========================
LLM_PROVIDER=openrouter
# LLM calls are direct by default. Use this only when your model provider
# must be reached through a proxy. This is intentionally separate from PROXY_URL.
LLM_PROXY_URL=
# Advanced: inherit HTTP_PROXY / HTTPS_PROXY / ALL_PROXY for LLM calls.
# Keep false unless the backend can actually reach that proxy endpoint.
LLM_USE_SYSTEM_PROXY=false

OPENROUTER_API_KEY=
OPENROUTER_MODEL=openai/gpt-5.4
# Optional: dedicated model for AI code generation (fallback to provider default if empty)
AI_CODE_GEN_MODEL=

OPENAI_API_KEY=
OPENAI_MODEL=gpt-5.4

GOOGLE_API_KEY=
GOOGLE_MODEL=gemini-1.5-flash

DEEPSEEK_API_KEY=
DEEPSEEK_MODEL=deepseek-chat

GROK_API_KEY=
GROK_MODEL=grok-beta

# AtlasCloud (set LLM_PROVIDER=atlascloud)
# Official OpenAI-compatible LLM base URL must include /v1.
ATLASCLOUD_API_KEY=
ATLASCLOUD_MODEL=openai/gpt-5.4
ATLASCLOUD_BASE_URL=https://api.atlascloud.ai/v1

# OpenAI-compatible third-party API (set LLM_PROVIDER=custom)
# Local Ollama example (backend must reach this host; Docker Desktop: http://host.docker.internal:11434/v1):
#   CUSTOM_API_URL=http://127.0.0.1:11434/v1
#   CUSTOM_MODEL=llama3.2
# Ollama usually needs no key  leave CUSTOM_API_KEY empty.
CUSTOM_API_URL=
CUSTOM_API_KEY=
CUSTOM_MODEL=

# MiniMax (set LLM_PROVIDER=minimax)
MINIMAX_API_KEY=
MINIMAX_MODEL=MiniMax-M2.7
MINIMAX_BASE_URL=https://api.minimax.io/v1

# =========================
# Common background jobs
# =========================
ENABLE_PENDING_ORDER_WORKER=true
ENABLE_PORTFOLIO_MONITOR=true
DISABLE_RESTORE_RUNNING_STRATEGIES=false

# Position sync (pending_order_worker): polls exchange positions for live strategies.
# Many strategies often share one API key  cache + longer interval avoids Binance IP bans.
POSITION_SYNC_ENABLED=true
POSITION_SYNC_INTERVAL_SEC=30
# Reuse one get_positions() result per credential for this many seconds (0 = auto: max(30, INTERVAL)).
POSITION_SYNC_CACHE_TTL_SEC=0
# After HTTP 418 / rate-limit, pause sync for this credential (seconds).
EXCHANGE_SYNC_BACKOFF_SEC=900

# =========================
# Agent Gateway (/api/agent/v1)  see docs/agent/AI_INTEGRATION_DESIGN.md
# =========================
# Thread pool size for async agent jobs (backtests, experiment pipelines).
AGENT_JOBS_MAX_WORKERS=4
# Hard kill switch for live trading from agent tokens. Even when a token is
# issued with paper_only=false, live order routing remains disabled until this
# flag is true AND a live executor implementation is wired in. Until then,
# `T`-class agent calls always record paper orders in qd_agent_paper_orders.
AGENT_LIVE_TRADING_ENABLED=false
# Deployment topology hint for the Agent Gateway.
#   (unset)         single-tenant / self-hosted; users manage tokens in Profile.
#   saas / hosted   multi-tenant hosted instance (e.g. ai.quantdinger.com):
#                    users self-issue tokens (incl. T scope) from Profile  My Agent Token.
#                    paper_only defaults to true; live T requires ack_live_trading_risk
#                    at issuance plus AGENT_LIVE_TRADING_ENABLED on the server.
QUANTDINGER_DEPLOYMENT_MODE=

# =========================
# Email / SMTP (optional)
# =========================
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASSWORD=
SMTP_FROM=
SMTP_USE_TLS=true
SMTP_USE_SSL=false

# =========================
# Proxy (optional, often required for Binance/Coinbase OHLCV in some networks)
# =========================
# PROXY_URL is for market data, exchange and broker API traffic. LLM providers do
# not use it by default; configure LLM_PROXY_URL above if an LLM provider needs a proxy.
# CCXT reads PROXY_URL for api.binance.com / exchange REST calls. System VPN does
# NOT apply inside Docker; set this when logs show "binance GET ... exchangeInfo" failures.
# Clash: enable "Allow LAN", use HTTP port (often 7890). Docker Desktop on Windows/macOS:
# PROXY_URL=http://host.docker.internal:7890
# PROXY_URL=socks5h://127.0.0.1:10808              # backend run directly on host
# PROXY_URL=socks5h://host.docker.internal:10808     # Docker + Clash SOCKS
PROXY_URL=

# Outbound HTTPS to exchanges when using PROXY_URL (especially SOCKS). If you see
# SSLCertVerificationError / "unable to get local issuer certificate":
# - Prefer: install OS ca-certificates in the image, or point to a PEM bundle:
#   LIVE_TRADING_CA_BUNDLE=/path/to/ca-bundle.pem
#   (REQUESTS_CA_BUNDLE / SSL_CERT_FILE are also honored.)
# - Last resort only: LIVE_TRADING_SSL_VERIFY=false  # disables TLS verify; insecure
#LIVE_TRADING_CA_BUNDLE=
#LIVE_TRADING_SSL_VERIFY=

# =========================
# Local desktop brokers (IBKR)
# =========================
# Interactive Brokers needs TWS/IB Gateway on a
# machine reachable from this API (typically your own PC or a VPS with those apps).
# On a public multi-tenant cloud deployment, set to false so users see a clear message
# instead of broken flows. Crypto exchange API keys are unaffected.
ALLOW_LOCAL_DESKTOP_BROKERS=true

# IBKR: clientId for live orders (strategy worker). Must differ from POST /api/ibkr/connect
# default (1) or TWS will disconnect one of the sessions within seconds.
#IBKR_ORDER_CLIENT_ID=7

# =========================
# Captcha / OAuth (optional)
# =========================
TURNSTILE_SITE_KEY=
TURNSTILE_SECRET_KEY=

GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REDIRECT_URI=http://localhost:5000/api/auth/oauth/google/callback

GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_REDIRECT_URI=http://localhost:5000/api/auth/oauth/github/callback

# =========================
# Billing / payments
# =========================
BILLING_ENABLED=false

# 
BILLING_COST_AI_ANALYSIS=10
BILLING_COST_AI_CODE_GEN=30
BILLING_COST_AI_TUNING=50

CREDITS_REGISTER_BONUS=100
CREDITS_REFERRAL_BONUS=50

# Membership plans
MEMBERSHIP_MONTHLY_PRICE_USD=19.9
MEMBERSHIP_YEARLY_PRICE_USD=199
MEMBERSHIP_LIFETIME_PRICE_USD=499
MEMBERSHIP_MONTHLY_CREDITS=500
MEMBERSHIP_YEARLY_CREDITS=8000
MEMBERSHIP_LIFETIME_MONTHLY_CREDITS=800

# =========================
# USDT payment (v3.0.6+: single fixed address per chain + amount-suffix matching)
# =========================
# How it works (replaces the old xpub HD-derived per-order address model):
#   - One fixed receiving address per chain (your own main wallet).
#   - Every order is identified on-chain by a unique amount suffix in the
#     low decimals, e.g. base $19.9 -> 19.991234 USDT, where .001234 is the
#     unique order tag. Funds land directly in your wallet, no consolidation.
#   - Chains without an address configured are auto-hidden in the UI.
#
# Global switch.
USDT_PAY_ENABLED=false

# Comma-separated list of enabled chains. Any code not in this list is rejected
# at order creation even if its address is configured. Valid codes:
# TRC20 / BEP20 / ERC20 / SOL
USDT_PAY_ENABLED_CHAINS=TRC20,BEP20,ERC20,SOL

# --- Receiving addresses (one per chain). Leave blank to hide that chain ---
# TRON  (base58, starts with T...)
USDT_TRC20_ADDRESS=
# BSC   (EVM 0x..., the same Ethereum-style address)
USDT_BEP20_ADDRESS=
# Ethereum  (EVM 0x...)
USDT_ERC20_ADDRESS=
# Solana  (wallet address; the SPL USDT mint ATA is computed on-chain by the wallet)
USDT_SOL_ADDRESS=

# --- USDT contract / mint per chain (override only if you know what you're doing) ---
USDT_TRC20_CONTRACT=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t
USDT_BEP20_CONTRACT=0x55d398326f99059fF775485246999027B3197955
USDT_ERC20_CONTRACT=0xdAC17F958D2ee523a2206206994597C13D831ec7
USDT_SOL_MINT=Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB

# --- Block explorers / RPC endpoints used to reconcile incoming transfers ---
TRONGRID_BASE_URL=https://api.trongrid.io
TRONGRID_API_KEY=

# BSC (BEP20) USDT reconciliation runs on public BSC JSON-RPC by default
#  Etherscan's V2 free plan no longer covers BSC and the legacy v1 host
# is deprecated. The watcher calls eth_getLogs against the USDT contract,
# filtered by Transfer(from, to, value) events, which every public BSC
# node supports natively at no cost. Comma-separated list; leave blank
# to use the curated defaults baked into the code.
BSC_RPC_URLS=https://bsc-dataseed1.binance.org,https://bsc.publicnode.com,https://rpc.ankr.com/bsc

# ERC20 (Ethereum) USDT reconciliation uses Etherscan V2 first because
# its free plan still covers Ethereum mainnet, falling back to public
# Ethereum RPC if the explorer call fails. Set ETHERSCAN_API_KEY to a
# key from https://etherscan.io/myapikey (free tier is enough for ETH).
ETHERSCAN_API_KEY=
ETHERSCAN_V2_BASE_URL=https://api.etherscan.io/v2/api
ETH_RPC_URLS=https://ethereum-rpc.publicnode.com,https://rpc.ankr.com/eth

# Override per-chain reconciliation strategy. Set BEP20_PREFER_EXPLORER=true
# only if you upgrade to an Etherscan API paid plan that covers BSC; leave
# it false (default) for RPC-only reconciliation. Same idea for ERC20.
# BEP20_PREFER_EXPLORER=false
# ERC20_PREFER_EXPLORER=true

# Legacy v1 explorer overrides  only set these if you intentionally pin
# to a deprecated v1 host (api.bscscan.com / api.etherscan.io). Leave them
# commented out for new deployments; the v2 unified API + RPC fallback
# above is preferred.
# ETHERSCAN_BASE_URL=
# BSCSCAN_BASE_URL=
# BSCSCAN_API_KEY=

SOLANA_RPC_URL=https://api.mainnet-beta.solana.com

# --- Amount suffix policy ---
# Number of decimals used for the suffix portion. 6 means 0.000001 USDT
# granularity, giving a collision space of ~10^5 per (chain, base_price)
# inside the active window. The unique index on (chain, amount_usdt) where
# status IN ('pending','paid') guarantees no two live orders collide.
USDT_AMOUNT_SUFFIX_DECIMALS=6

# --- Confirm / expiry / worker tuning ---
USDT_PAY_CONFIRM_SECONDS=30
USDT_PAY_EXPIRE_MINUTES=30
USDT_WORKER_POLL_INTERVAL=30

# =========================
# Advanced / rarely changed
# =========================

# Network / App tuning
PYTHON_API_HOST=0.0.0.0
PYTHON_API_PORT=5000
PYTHON_API_DEBUG=false
# Interactive OpenAPI browsers (/api/docs/swagger, /api/docs/redoc).
# Defaults to on when PYTHON_API_DEBUG=true; set true explicitly to enable in production.
OPENAPI_ENABLED=false
RATE_LIMIT=100
ENABLE_CACHE=false
ENABLE_REQUEST_LOG=true

# Strategy / execution tuning
PENDING_ORDER_STALE_SEC=90
ORDER_MODE=market
MAKER_WAIT_SEC=10
MAKER_OFFSET_BPS=2
# Spot sizing (also editable in Admin  Settings  Live Trading)
# Close: cap sell size to free base  ratio (fees often make DB position > sellable qty)
SPOT_CLOSE_SAFETY_RATIO=0.998
# Open: use only this fraction of allocated USDT/notional on spot buys
SPOT_OPEN_QUOTE_BUFFER=0.995
STRATEGY_TICK_INTERVAL_SEC=10
# User script runtime guardrails. Keep callback timeout below tick interval
# so one bad strategy cannot occupy a live execution thread indefinitely.
STRATEGY_SCRIPT_CALLBACK_TIMEOUT_SEC=5
STRATEGY_SCRIPT_MAX_CONSECUTIVE_TIMEOUTS=3
STRATEGY_SCRIPT_MAX_BARS_PER_CALL=1000
STRATEGY_SCRIPT_MAX_LOGS_PER_FLUSH=50
STRATEGY_SCRIPT_MAX_LOG_CHARS=500
# Live grid bots ignore per-strategy tick_interval_sec; fixed price loop (seconds).
GRID_STRATEGY_TICK_SEC=1
# Global grid fill poller (ENABLE_GRID_FILL_POLLER=true in app startup).
ENABLE_GRID_FILL_POLLER=true
GRID_FILL_POLL_SEC=3
# Per resting order min interval between exchange status queries (seconds).
GRID_FILL_MIN_ORDER_INTERVAL_SEC=5
# Max orders polled per poller loop (spread load across cycles).
GRID_FILL_MAX_ORDERS_PER_CYCLE=150
# Max exchange API calls per credential per minute (rate-limit guard).
GRID_FILL_MAX_REQ_PER_CREDENTIAL_PER_MIN=120
# Grid: auto-stop after N consecutive order failures (non-fatal errors).
GRID_ORDER_ERROR_STOP_THRESHOLD=5
# / 1  64 API
STRATEGY_MAX_THREADS=64
PRICE_CACHE_TTL_SEC=10
K_LINE_HISTORY_GET_NUMBER=500
SIGNAL_NOTIFY_TIMEOUT_SEC=6

# LLM advanced tuning
OPENROUTER_API_URL=https://openrouter.ai/api/v1/chat/completions
OPENROUTER_TEMPERATURE=0.7
OPENROUTER_MAX_TOKENS=4000
OPENROUTER_TIMEOUT=300
OPENROUTER_CONNECT_TIMEOUT=30
OPENAI_BASE_URL=https://api.openai.com/v1
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
GROK_BASE_URL=https://api.x.ai/v1
MINIMAX_BASE_URL=https://api.minimax.io/v1

# Data sources
DATA_SOURCE_TIMEOUT=30
DATA_SOURCE_RETRY=3
DATA_SOURCE_RETRY_BACKOFF=0.5
FINNHUB_API_KEY=
# Optional free-tier Finnhub helper for US stock quotes, company profile and news.
# Keep FINNHUB_FREE_ONLY=true unless your plan includes paid endpoints such as Economic Calendar/Social Sentiment.
FINNHUB_FREE_ONLY=true
FINNHUB_TIMEOUT=10
FINNHUB_RATE_LIMIT=60
# Optional official international economic calendar provider.
# Leave empty to use the no-key AkShare/WallstreetCN fallback. The legacy Trading Economics guest account is discontinued.
TRADING_ECONOMICS_CLIENT=
TRADING_ECONOMICS_KEY=
TRADING_ECONOMICS_BASE_URL=https://api.tradingeconomics.com
TRADING_ECONOMICS_TIMEOUT=10
# US macro time-series and official macro detail sources.
FRED_API_KEY=
FRED_BASE_URL=https://api.stlouisfed.org/fred
FRED_TIMEOUT=10
BLS_API_KEY=
BLS_BASE_URL=https://api.bls.gov/publicAPI/v2
BLS_TIMEOUT=10
BEA_API_KEY=
BEA_BASE_URL=https://apps.bea.gov/api/data
BEA_TIMEOUT=10
# Public crypto OHLCV/ticker (no API keys). binance supports BTC/USDT.
# In mainland CN / Docker without outbound access to api.binance.com, set PROXY_URL above.
CCXT_DEFAULT_EXCHANGE=binance
CCXT_TIMEOUT=10000
AKSHARE_TIMEOUT=30
YFINANCE_TIMEOUT=30
TIINGO_API_KEY=
TIINGO_TIMEOUT=10

# Crypto derivatives / on-chain data (optional, used by some AI prompts)
COINGLASS_API_KEY=
CRYPTOQUANT_API_KEY=

# Twelve Data (CN/HK stock K-lines  recommended for overseas servers)
# Free tier: 800 API credits/day, 8 requests/minute. https://twelvedata.com
TWELVE_DATA_API_KEY=

# Adanos Market Sentiment (optional US stock sentiment enrichment)
# If ADANOS_API_KEY is empty, /api/global-market/adanos-sentiment returns enabled=false.
ADANOS_API_KEY=
ADANOS_SENTIMENT_SOURCE=reddit
ADANOS_API_BASE_URL=https://api.adanos.org
ADANOS_API_TIMEOUT=10

# AI search / news
# Recommended order: Tavily -> SearXNG -> GDELT -> SerpAPI -> DuckDuckGo.
SEARCH_PROVIDER=tavily
SEARCH_MAX_RESULTS=10
SEARCH_GOOGLE_API_KEY=
SEARCH_GOOGLE_CX=
SEARCH_BING_API_KEY=
TAVILY_API_KEYS=
SERPAPI_KEYS=
SEARCH_SEARXNG_BASE_URL=
SEARCH_SEARXNG_ENGINES=
SEARCH_SEARXNG_CATEGORIES=general
SEARCH_SEARXNG_LANGUAGE=auto
SEARCH_SEARXNG_TIMEOUT=12
GDELT_BASE_URL=https://api.gdeltproject.org/api/v2/doc/doc
GDELT_TIMEOUT=12
GDELT_MAX_RESULTS=10
ALPHA_VANTAGE_API_KEY=
ALPHA_VANTAGE_BASE_URL=https://www.alphavantage.co/query
ALPHA_VANTAGE_TIMEOUT=12
ALPHA_VANTAGE_NEWS_LIMIT=20

# SMS / phone (optional)
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_FROM_NUMBER=

# Security / verification tuning
SECURITY_IP_MAX_ATTEMPTS=10
SECURITY_IP_WINDOW_MINUTES=5
SECURITY_IP_BLOCK_MINUTES=15
SECURITY_ACCOUNT_MAX_ATTEMPTS=5
SECURITY_ACCOUNT_WINDOW_MINUTES=60
SECURITY_ACCOUNT_BLOCK_MINUTES=30
VERIFICATION_CODE_EXPIRE_MINUTES=10
VERIFICATION_CODE_RATE_LIMIT=60
VERIFICATION_CODE_IP_HOURLY_LIMIT=10
VERIFICATION_CODE_MAX_ATTEMPTS=5
VERIFICATION_CODE_LOCK_MINUTES=30

# AI analysis tuning
ENABLE_CONFIDENCE_CALIBRATION=false
ENABLE_AI_ENSEMBLE=false
AI_ENSEMBLE_MODELS=openai/gpt-5.4,openai/gpt-4o-mini
ENABLE_REFLECTION_WORKER=false
REFLECTION_WORKER_INTERVAL_SEC=86400
REFLECTION_MIN_AGE_DAYS=7
REFLECTION_VALIDATE_LIMIT=200
AI_CALIBRATION_MARKETS=Crypto
AI_CALIBRATION_LOOKBACK_DAYS=30
AI_CALIBRATION_MIN_SAMPLES=80
AI_ANALYSIS_CONSENSUS_TIMEFRAMES=1D,4H

# Redis cache (auto-configured by docker-compose; set CACHE_ENABLED=true to use)
REDIS_HOST=redis
REDIS_PORT=6379
CACHE_ENABLED=true

# Internal
INTERNAL_API_KEY=

# Market visibility (which markets appear in the watchlist picker /
# Agent API catalog / home AI radar).
#
# Primary knob (recommended):
#   ENABLED_MARKETS  CSV whitelist. When set, ONLY these markets are
#   visible everywhere. Unknown values are ignored. Empty = whitelist
#   disabled (falls back to the legacy SHOW_* flags below).
#   Valid values: Crypto, USStock, CNStock, HKStock, Forex, Futures, MOEX
#   Examples:
#     ENABLED_MARKETS=Crypto,USStock           # crypto + US stocks only
#     ENABLED_MARKETS=Crypto                   # crypto-only deployment
#     ENABLED_MARKETS=                         # unset  legacy flags apply
# ENABLED_MARKETS=
#
# Legacy flags (kept for back-compat; ignored when ENABLED_MARKETS is set):
#   SHOW_CN_STOCK (default false)  China A-shares
#   SHOW_HK_STOCK (default true)   Hong Kong stocks
# All other known markets default to visible.
SHOW_CN_STOCK=false
# SHOW_HK_STOCK=true
# ============================================================
# ALPACA MARKETS (US stocks, ETFs, crypto)
# ============================================================
# Paper: keys start with "PK..." (paper-api.alpaca.markets)
# Live:  keys start with "AK..." (api.alpaca.markets)
# Get keys: https://app.alpaca.markets
ALPACA_API_KEY=
ALPACA_SECRET_KEY=
ALPACA_PAPER=true


Web Proxy Viewer  |  New URL  |  Original Page