diff --git a/.env.docker.example b/.env.docker.example new file mode 100644 index 00000000..f6a9d834 --- /dev/null +++ b/.env.docker.example @@ -0,0 +1,35 @@ +# Docker deployment example. +# Copy this file to .env before running docker compose: +# cp .env.docker.example .env + +# Flask +DEBUG=True +SECRET_KEY=change-this-secret + +# SQLite ORM default inside the container. +# docker-compose.yml persists this file under ./instance on the host. +SQLITE_DATABASE_PATH=/app/instance/stock_cursor.sqlite3 + +# Redis / Celery inside the Docker Compose network. +# Use the service name "redis" instead of localhost from containers. +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_DB=0 +CELERY_BROKER_URL=redis://redis:6379/0 +CELERY_RESULT_BACKEND=redis://redis:6379/0 +# Data source. +# docker-compose.yml mounts the host ./data directory to /app/data. +# Put the downloaded Parquet data package contents in ./data on the host. +DATA_SOURCE=parquet +DATA_DIR=/app/data +TUSHARE_TOKEN=your_tushare_token + +# Runtime mode. +# Docker Compose starts a worker service, so data jobs should use Celery. +DATA_JOB_EXECUTION_MODE=celery + +# OpenAI / LLM optional +LLM_PROVIDER=openai +LLM_API_KEY= +LLM_BASE_URL=https://api.deepseek.com +LLM_MODEL=deepseek-v4-flash diff --git a/Dockerfile b/Dockerfile index 93077bd3..3240b6d2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,8 +10,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config \ && rm -rf /var/lib/apt/lists/* -COPY requirements.txt requirements_minimal.txt ./ -RUN pip install --no-cache-dir -r requirements_minimal.txt +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt COPY . . diff --git a/app/celery_app.py b/app/celery_app.py index 863d7596..c2e14e56 100644 --- a/app/celery_app.py +++ b/app/celery_app.py @@ -38,12 +38,13 @@ def _decorator(func): def make_celery(config_name: str = "default"): cfg = config[config_name] - broker = f"redis://{cfg.REDIS_HOST}:{cfg.REDIS_PORT}/{cfg.REDIS_DB}" + broker = cfg.CELERY_BROKER_URL + backend = cfg.CELERY_RESULT_BACKEND if Celery is None: return _LocalCelery() - celery = Celery("quant_data_jobs", broker=broker, backend=broker) + celery = Celery("quant_data_jobs", broker=broker, backend=backend) celery.conf.update( task_serializer="json", accept_content=["json"], diff --git a/docker-compose.yml b/docker-compose.yml index cd194264..f21d3650 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,25 +1,35 @@ version: "3.9" +x-app-common: &app-common + build: . + env_file: + - .env + volumes: + - ./data:/app/data + - ./instance:/app/instance + - ./logs:/app/logs + depends_on: + - redis + restart: unless-stopped + services: web: - build: . + <<: *app-common command: python run.py ports: - "5000:5000" - env_file: - - .env - depends_on: - - redis worker: - build: . + <<: *app-common command: celery -A app.celery_app.celery worker -l info -P solo - env_file: - - .env - depends_on: - - redis redis: image: redis:7-alpine ports: - "6379:6379" + volumes: + - redis_data:/data + restart: unless-stopped + +volumes: + redis_data: diff --git a/requirements.txt b/requirements.txt index f6b9bd18..37d823c9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -72,3 +72,4 @@ cvxpy>=1.4.0 #金融数据获取 baostock>=0.8.9 tushare>=1.3.0 +pytdx>=1.72