From 7d49aff6c724ed39e3bfae2651f932635b957162 Mon Sep 17 00:00:00 2001 From: fish Date: Sun, 3 May 2026 16:44:59 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4=20Bark=20=E6=8E=A8=E9=80=81?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E6=A8=A1=E5=9D=97=E5=8F=8A=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- CLAUDE.md | 10 ++++------ README.md | 8 +++----- tushare/requirements.txt | 1 - tushare/src/api.py | 10 +--------- tushare/src/main.py | 10 +--------- tushare/src/notifier.py | 28 ---------------------------- 6 files changed, 9 insertions(+), 58 deletions(-) delete mode 100644 tushare/src/notifier.py diff --git a/CLAUDE.md b/CLAUDE.md index c79a124..cf42aca 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## 项目概述 -基于 Docker + Python(tushare) + PostgreSQL 的中国期货行情分析系统,实现日线数据采集、三层加权打分模型与 Bark 推送通知。运行方式支持两种模式:① 宿主机 cron/launchd 定时调用 `docker-compose run` 执行 CLI;② 通过 FastAPI 服务以 HTTP API 触发。详细业务说明见 `README.md`。 +基于 Docker + Python(tushare) + PostgreSQL 的中国期货行情分析系统,实现日线数据采集与三层加权打分模型。运行方式支持两种模式:① 宿主机 cron/launchd 定时调用 `docker-compose run` 执行 CLI;② 通过 FastAPI 服务以 HTTP API 触发。详细业务说明见 `README.md`。 ## 常用命令 @@ -38,13 +38,13 @@ docker-compose exec postgres psql -U trade -d futures -c \ "SELECT ts_code, trade_date, composite, signal FROM scores ORDER BY trade_date DESC LIMIT 5;" ``` -`tushare/.env` 必须存在且含 `TUSHARE_TOKEN=xxx`(已 gitignored)。可选 `BARK_KEY` 覆盖 `notifier.py` 默认 key。 +`tushare/.env` 必须存在且含 `TUSHARE_TOKEN=xxx`(已 gitignored)。 ## 关键架构 -**单进程串行流水线**:`src.main.main()` 先按命令行参数(显式 `ts_code` 优先,否则 `contracts.active_contract(symbol)` 按当月主力自动选)定下合约,再调 `run()` 顺序执行 `fetcher → storage(candles) → scorer → storage(scores) → notifier`。无后台任务、无队列,每次 CLI 调用处理一个合约一日。 +**单进程串行流水线**:`src.main.main()` 先按命令行参数(显式 `ts_code` 优先,否则 `contracts.active_contract(symbol)` 按当月主力自动选)定下合约,再调 `run()` 顺序执行 `fetcher → storage(candles) → scorer → storage(scores)`。无后台任务、无队列,每次 CLI 调用处理一个合约一日。 -**FastAPI 服务**(`src.api`):容器默认以 `uvicorn src.api:app` 启动,暴露 `/api/v1/run`(触发流水线)、`/api/v1/scores`、`/api/v1/scores/{id}`、`/api/v1/contracts`、`/api/v1/candles` 等端点。启动时自动 `storage.init_db()` 建表。API 与 CLI 共用同一套 `fetcher/storage/scorer/notifier` 逻辑。 +**FastAPI 服务**(`src.api`):容器默认以 `uvicorn src.api:app` 启动,暴露 `/api/v1/run`(触发流水线)、`/api/v1/scores`、`/api/v1/scores/{id}`、`/api/v1/contracts`、`/api/v1/candles` 等端点。启动时自动 `storage.init_db()` 建表。API 与 CLI 共用同一套 `fetcher/storage/scorer` 逻辑。 **主力轮换规则**(`contracts.py`):每个品种在 `ROLLOVER_RULES` 中维护 `month -> (主力月, 年份偏移)` 表。FG 当前规则:1-3/12 月→05、4-7 月→09、8-11 月→01,其中 8-11 月与 12 月跨年(`year_offset=1`)。新增品种(如 RB、I)只需在该 dict 里加一条,无需改 main 流程。 @@ -54,8 +54,6 @@ docker-compose exec postgres psql -U trade -d futures -c \ **Docker 边界**:`tushare/src/` 与 `web/backend/`、`web/frontend/` 均在 Dockerfile 的 `COPY` 阶段拷进镜像,**没有源码挂载**——改完 Python/Go/Vue 代码不重建镜像就跑等于跑旧代码。这是重要陷阱。 -**Bark 推送**:`notifier.push_bark` 用 `requests.get` 走路径形式(`/{key}/{title}/{body}`),所有片段以 `quote(safe='')` URL 编码,失败仅 `print [WARN]` 不抛错。容器内首发请求有时 DNS 慢导致 15s timeout,内置 1 次重试;主机直连通常 <1s。 - ## 配置/密钥规则 `.gitignore` 排除范围广(见文件):`data/`、`*.db*`、`.env*`、CTP 流文件(`*.con`/`*.dat`/`ResultInfo.xml` 等)、`.claude/`、所有日志。新增任何账户、token、行情流文件务必先确认匹配 ignore 规则。 diff --git a/README.md b/README.md index ccbd6f7..344a88b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 期货行情分析系统 — 使用说明 -基于 Docker + Python(tushare) + PostgreSQL 的中国期货行情分析系统。当前阶段已实现数据采集、三层加权打分模型、Bark 推送通知与 Web 报表浏览端。运行方式支持两种模式:① 宿主机定时器触发 `docker-compose run` 执行 CLI;② 通过 FastAPI HTTP API 服务触发。 +基于 Docker + Python(tushare) + PostgreSQL 的中国期货行情分析系统。当前阶段已实现数据采集、三层加权打分模型与 Web 报表浏览端。运行方式支持两种模式:① 宿主机定时器触发 `docker-compose run` 执行 CLI;② 通过 FastAPI HTTP API 服务触发。 ## 环境准备 @@ -40,7 +40,6 @@ docker-compose run --rm tushare python -m src.main 2. 写入 PostgreSQL `futures` 数据库 3. 运行三层打分模型 4. 保存打分结果并输出到 stdout -5. 通过 Bark 推送评分摘要 ### 4. 通过 API 触发流水线 @@ -167,14 +166,13 @@ trade/ │ ├── Dockerfile │ ├── requirements.txt │ ├── .env # TUSHARE_TOKEN(本地,不入库) -│ └── src/ # 数据采集 + 打分 + Bark 推送 + FastAPI +│ └── src/ # 数据采集 + 打分 + FastAPI │ ├── api.py # FastAPI 服务入口 │ ├── models.py │ ├── fetcher.py │ ├── scorer.py │ ├── storage.py # PostgreSQL 读写 │ ├── contracts.py -│ ├── notifier.py │ └── main.py # CLI 入口 └── web/ # Web 浏览端 ├── .dockerignore @@ -227,7 +225,7 @@ A: 郑商所用 `.ZCE` 后缀(如 `FG2609.ZCE`),上期所用 `.SHF`,大 **Q: 如何定时自动跑?** -A: 通过宿主机 cron / launchd 等定时器调用 `docker-compose run --rm tushare ...`。打分结束会通过 Bark 推送结果(见 `tushare/src/notifier.py`)。也可直接调用 API: `curl -X POST http://localhost:8000/api/v1/run ...`。 +A: 通过宿主机 cron / launchd 等定时器调用 `docker-compose run --rm tushare ...`。也可直接调用 API: `curl -X POST http://localhost:8000/api/v1/run ...`。 ## Web 报表(浏览端) diff --git a/tushare/requirements.txt b/tushare/requirements.txt index 00ff912..2ba4caf 100644 --- a/tushare/requirements.txt +++ b/tushare/requirements.txt @@ -1,6 +1,5 @@ tushare>=1.4.0 pandas>=2.2.0 -requests>=2.31.0 fastapi>=0.115.0 uvicorn[standard]>=0.34.0 psycopg[binary]>=3.2.0 diff --git a/tushare/src/api.py b/tushare/src/api.py index 935a55e..6c2316b 100644 --- a/tushare/src/api.py +++ b/tushare/src/api.py @@ -5,7 +5,7 @@ from datetime import date from fastapi import FastAPI, HTTPException, Query from pydantic import BaseModel -from . import contracts, fetcher, notifier, scorer, storage +from . import contracts, fetcher, scorer, storage app = FastAPI(title="期货数据采集与打分服务") @@ -50,14 +50,6 @@ def run_pipeline(req: RunRequest): result = scorer.score_daily(df, req.trade_date) storage.save_score(result) - push_title = f"{result.ts_code.split('.')[0]} {result.trade_date}" - push_body = ( - f"综合 {result.composite:.1f}\n" - f"短期 {result.short_term:.1f} | 中期 {result.medium_term:.1f} | 长期 {result.long_term:.1f}\n" - f"{result.signal}" - ) - notifier.push_bark(push_title, push_body) - return RunResponse( ts_code=result.ts_code, trade_date=result.trade_date, diff --git a/tushare/src/main.py b/tushare/src/main.py index c0b0be2..8be32a3 100644 --- a/tushare/src/main.py +++ b/tushare/src/main.py @@ -1,7 +1,7 @@ import argparse import sys -from . import contracts, fetcher, notifier, scorer, storage +from . import contracts, fetcher, scorer, storage def run(ts_code: str, trade_date: Optional[str] = None) -> int: @@ -63,14 +63,6 @@ def run(ts_code: str, trade_date: Optional[str] = None) -> int: print(f"\n[OK] 数据已持久化到 PostgreSQL") - push_title = f"{result.ts_code.split('.')[0]} {result.trade_date}" - push_body = ( - f"综合 {result.composite:.1f}\n" - f"短期 {result.short_term:.1f} | 中期 {result.medium_term:.1f} | 长期 {result.long_term:.1f}\n" - f"{result.signal}" - ) - if notifier.push_bark(push_title, push_body): - print("[Bark] 推送成功") return 0 diff --git a/tushare/src/notifier.py b/tushare/src/notifier.py deleted file mode 100644 index f0f8b15..0000000 --- a/tushare/src/notifier.py +++ /dev/null @@ -1,28 +0,0 @@ -import os -from urllib.parse import quote - -import requests - -DEFAULT_BARK_KEY = "RvdtHq4py2avatt4AFJn9a" -BARK_BASE_URL = "https://api.day.app" - - -def push_bark(title: str, body: str, key: str | None = None, timeout: float = 15.0, retries: int = 1) -> bool: - bark_key = key or os.environ.get("BARK_KEY") or DEFAULT_BARK_KEY - url = f"{BARK_BASE_URL}/{bark_key}/{quote(title, safe='')}/{quote(body, safe='')}" - - last_err: Exception | None = None - for attempt in range(retries + 1): - try: - resp = requests.get(url, timeout=timeout) - except requests.RequestException as e: - last_err = e - continue - - if resp.status_code == 200: - return True - print(f"[WARN] Bark 推送返回非 200: {resp.status_code} {resp.text[:120]}") - return False - - print(f"[WARN] Bark 推送失败: {last_err}") - return False