mirror of
https://github.com/OpenByteInc/QuantDinger.git
synced 2026-09-28 15:22:56 +08:00
508 lines
19 KiB
Plaintext
508 lines
19 KiB
Plaintext
# 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=brokermr810@gmail.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
|
||
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
|
||
# 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
|
||
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)
|
||
# =========================
|
||
# Tune these if you see `psycopg2.pool.PoolError: connection pool exhausted`
|
||
# or if you run many trading bots / portfolios concurrently.
|
||
# Make sure PG `max_connections` (docker-compose: PG_MAX_CONNECTIONS) is
|
||
# comfortably larger than DB_POOL_MAX.
|
||
DB_POOL_MIN=5
|
||
DB_POOL_MAX=50
|
||
DB_POOL_ACQUIRE_TIMEOUT=10
|
||
DB_POOL_HEALTH_CHECK=true
|
||
|
||
# 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
|
||
|
||
OPENROUTER_API_KEY=
|
||
OPENROUTER_MODEL=openai/gpt-4o
|
||
# Optional: dedicated model for AI code generation (fallback to provider default if empty)
|
||
AI_CODE_GEN_MODEL=
|
||
|
||
OPENAI_API_KEY=
|
||
OPENAI_MODEL=gpt-4o
|
||
|
||
GOOGLE_API_KEY=
|
||
GOOGLE_MODEL=gemini-1.5-flash
|
||
|
||
DEEPSEEK_API_KEY=
|
||
DEEPSEEK_MODEL=deepseek-chat
|
||
|
||
GROK_API_KEY=
|
||
GROK_MODEL=grok-beta
|
||
|
||
# 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; admins keep full control of
|
||
# paper_only and the T (Trading) scope.
|
||
# saas / hosted — multi-tenant hosted instance (e.g. ai.quantdinger.com):
|
||
# `paper_only` is force-pinned to true and any attempt to
|
||
# issue a T-scope agent token returns 403. Use this on every
|
||
# deployment that serves more than one operator's data, so a
|
||
# misconfigured token can never route real-money orders.
|
||
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 — required for Binance/Coinbase OHLCV in many CN networks)
|
||
# =========================
|
||
# 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 / MT5)
|
||
# =========================
|
||
# Interactive Brokers and MetaTrader 5 need TWS/IB Gateway or the MT5 terminal 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
|
||
|
||
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
|
||
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
|
||
# 单进程内「实盘/信号策略」并发线程上限(每个运行中策略约占用 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=
|
||
FINNHUB_TIMEOUT=10
|
||
FINNHUB_RATE_LIMIT=60
|
||
# 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
|
||
SEARCH_PROVIDER=google
|
||
SEARCH_MAX_RESULTS=10
|
||
SEARCH_GOOGLE_API_KEY=
|
||
SEARCH_GOOGLE_CX=
|
||
SEARCH_BING_API_KEY=
|
||
TAVILY_API_KEYS=
|
||
SERPAPI_KEYS=
|
||
|
||
# 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-4o,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
|