mirror of
https://github.com/OpenByteInc/QuantDinger.git
synced 2026-09-28 15:22:56 +08:00
644 lines
25 KiB
Plaintext
644 lines
25 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=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/OpenByteInc/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/OpenByteInc/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)
|
|
# =========================
|
|
# Required: >= 10 bytes for legacy compatibility; 32+ random bytes recommended.
|
|
# The API refuses to start while empty or while using the public legacy default.
|
|
# Generate: python -c "import secrets; print(secrets.token_hex(32))"
|
|
SECRET_KEY=
|
|
# Stable key for broker credentials and MFA secrets. Keep this unchanged when
|
|
# rotating SECRET_KEY. The container generates and persists one when omitted.
|
|
CREDENTIAL_ENCRYPTION_KEY=
|
|
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
|
|
QD_PROCESS_ROLE=legacy
|
|
STRATEGY_COMMANDS_ENABLED=false
|
|
STRATEGY_COMMAND_STOP_WAIT_SEC=5
|
|
STRATEGY_COMMAND_LEASE_SEC=30
|
|
STRATEGY_COMMAND_MAX_ATTEMPTS=3
|
|
STRATEGY_COMMAND_WORKER_POLL_SEC=0.5
|
|
STRATEGY_RUNTIME_LEASE_SEC=30
|
|
STRATEGY_COMMAND_RETENTION_DAYS=30
|
|
WORKER_HEARTBEAT_RETENTION_DAYS=7
|
|
|
|
# Celery is enabled by Docker Compose. Keep it disabled for a standalone
|
|
# development process that does not run a broker and worker.
|
|
CELERY_TASKS_ENABLED=false
|
|
# Leave explicit URLs empty to use the host/password/database settings below.
|
|
CELERY_BROKER_URL=
|
|
CELERY_RESULT_BACKEND=
|
|
CELERY_REDIS_HOST=redis-jobs
|
|
CELERY_REDIS_PORT=6379
|
|
CELERY_REDIS_PASSWORD=
|
|
CELERY_BROKER_DB=0
|
|
CELERY_RESULT_DB=1
|
|
CELERY_CONCURRENCY=2
|
|
CELERY_WORKER_PREFETCH=1
|
|
CELERY_MAX_TASKS_PER_CHILD=100
|
|
CELERY_TASK_SOFT_TIME_LIMIT=3300
|
|
CELERY_TASK_TIME_LIMIT=3600
|
|
CELERY_VISIBILITY_TIMEOUT=7200
|
|
MARKET_CATALOG_SYNC_INTERVAL_SEC=86400
|
|
AI_CALIBRATION_INTERVAL_SEC=86400
|
|
# 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
|
|
# Private fill streams are the primary source of execution and actual-fee events.
|
|
# REST remains enabled as reconnect catch-up and a periodic consistency audit.
|
|
ENABLE_PRIVATE_EXECUTION_STREAMS=true
|
|
EXECUTION_STREAM_REFRESH_SEC=30
|
|
EXECUTION_STREAM_REST_AUDIT_SEC=30
|
|
# Only running live accounts receive private fill streams. Overflow accounts
|
|
# keep using REST reconciliation, so this should stay below BACKEND_PIDS_LIMIT.
|
|
EXECUTION_STREAM_MAX_ADAPTERS=64
|
|
|
|
# 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
|
|
# Aggregate tenant quota in addition to each token's rate_limit_per_min.
|
|
AGENT_TENANT_RATE_LIMIT_PER_MIN=600
|
|
# Async-job admission caps. Completed/cancelled jobs do not count.
|
|
AGENT_MAX_CONCURRENT_JOBS_PER_TENANT=4
|
|
AGENT_MAX_CONCURRENT_JOBS_PER_TOKEN=2
|
|
# A crashed request may be retried with the same key after this reservation TTL.
|
|
AGENT_IDEMPOTENCY_IN_PROGRESS_TTL_SEC=900
|
|
# Default live-trading caps copied onto newly issued Agent Tokens.
|
|
AGENT_DEFAULT_MAX_ORDER_NOTIONAL=1000
|
|
AGENT_DEFAULT_MAX_DAILY_NOTIONAL=5000
|
|
# 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, sometimes required for exchange OHLCV access)
|
|
# =========================
|
|
# 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
|
|
# Dedicated IBKR execution/commission stream session; must differ from order/UI sessions.
|
|
#IBKR_STREAM_CLIENT_ID=8
|
|
|
|
# =========================
|
|
# Captcha / OAuth (optional)
|
|
# =========================
|
|
TURNSTILE_SITE_KEY=
|
|
TURNSTILE_SECRET_KEY=
|
|
# Short-lived local auth-page clearance after a successful Turnstile challenge.
|
|
TURNSTILE_CLEARANCE_TTL_SECONDS=600
|
|
|
|
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_BACKTEST=30
|
|
BILLING_COST_AI_REVIEW=10
|
|
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: base-asset fees are recorded net; cap sell size to the full free balance by default.
|
|
SPOT_CLOSE_SAFETY_RATIO=1.0
|
|
# 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
|
|
# Shared maximum output-token budget for all LLM providers.
|
|
# Providers charge for tokens actually generated, not this full upper bound.
|
|
LLM_MAX_TOKENS=16384
|
|
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
|
|
MARKET_CATALOG_AUTO_SYNC=true
|
|
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
|
|
REDIS_PASSWORD=
|
|
REDIS_DB=0
|
|
REDIS_CACHE_NAMESPACE=quantdinger:cache:v1
|
|
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
|