147 lines
7.1 KiB
Makefile
147 lines
7.1 KiB
Makefile
# tradingSystem (PMS) 常用操作一句话入口
|
|
# ============================================================================
|
|
# 为什么要这个文件: 日常命令都是「docker compose run --rm --no-deps pms-web python
|
|
# scripts/xxx.py」这种一行八十字符的东西, 手打容易漏 --no-deps (于是顺带把 beat/worker
|
|
# 也拉起来)、漏 --rm (于是攒一堆退出的容器)。把口径固定在这里, 少一类手误。
|
|
#
|
|
# make help 看有哪些目标
|
|
# make deploy 拉代码 → 重建镜像 → 重建容器 → 建表 (= scripts/deploy.sh)
|
|
# make test 跑全部单测 (不连库, 秒级)
|
|
#
|
|
# **改了 Python 代码必须 build + force-recreate**, 因为源码是打进镜像的 ——
|
|
# `docker compose restart` 跑的还是旧镜像里的旧代码, 而且一点报错都没有 (deploy.sh
|
|
# 头部有详细说明)。`make up` 用的就是这条路径, 别用 `docker compose restart` 代替。
|
|
# ============================================================================
|
|
.DEFAULT_GOAL := help
|
|
SHELL := /bin/bash
|
|
|
|
# 各 profile 的组合。只想跑页面: `make up PROFILES=`
|
|
PROFILES ?= --profile sched --profile ws
|
|
DC := docker compose $(PROFILES)
|
|
# 一次性命令一律 --no-deps: 不然跑个单测都会把 beat/worker 拉起来
|
|
RUN := docker compose run --rm --no-deps pms-web
|
|
|
|
.PHONY: help deploy deploy-local build up down ps logs test initdb check health \
|
|
probe changes industry ws-status rebuild rebuild-accept \
|
|
t-plan t-pre t-cmd t-plans t-mat t-dry t-tick t-ins t-book t-gate \
|
|
reset-ledger shell
|
|
|
|
help: ## 列出所有目标
|
|
@grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
|
|
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}'
|
|
|
|
# ---------------------------------------------------------------- 部署
|
|
deploy: ## 一句话部署: git pull → build → up --force-recreate → 建表
|
|
@./scripts/deploy.sh
|
|
|
|
deploy-local: ## 同 deploy 但跳过 git pull (本地已改好)
|
|
@./scripts/deploy.sh --no-pull
|
|
|
|
build: ## 只重建镜像
|
|
$(DC) build
|
|
|
|
up: ## 起服务 (force-recreate —— 让新镜像真正生效)
|
|
$(DC) up -d --force-recreate
|
|
@$(DC) ps
|
|
|
|
down: ## 停掉全部服务 (不删卷)
|
|
$(DC) down
|
|
|
|
ps: ## 看服务状态
|
|
@$(DC) ps
|
|
|
|
logs: ## 跟日志 (make logs S=pms-ws 只看一个服务)
|
|
$(DC) logs -f $(S)
|
|
|
|
# ---------------------------------------------------------------- 自检
|
|
test: ## 全部单测 (零外部依赖, 不连库; 应输出 ALL SUITES PASS)
|
|
$(RUN) python scripts/run_tests.py
|
|
|
|
initdb: ## 建表/补表 (幂等; 加 DRY=1 只演练打印)
|
|
$(RUN) python scripts/init_db.py $(if $(DRY),,--yes)
|
|
|
|
check: ## 实机连通性与表结构自检 (需真实 .env)
|
|
$(RUN) python scripts/check_db.py
|
|
|
|
health: ## 页面健康检查 (配置装载 + 库连通自证)
|
|
@curl -s http://127.0.0.1:38100/health | python3 -m json.tool
|
|
|
|
# ---------------------------------------------------------------- 上游 / 行业 / 通道
|
|
probe: ## 上游计划实机探活 (只读; 加 SNAP=1 顺带落一份名册快照)
|
|
$(RUN) python scripts/probe_plan_api.py $(if $(SNAP),--snapshot,)
|
|
|
|
changes: ## 榜单变化: 谁新进谁掉榜、持仓票有没有被上游摘了
|
|
@curl -s 'http://127.0.0.1:38100/api/upstream/plan-changes?limit=30' \
|
|
| python3 -m json.tool
|
|
|
|
industry: ## 行业源实探 (ready=false 就是硬拦截失效, 别当它绿着)
|
|
@curl -s http://127.0.0.1:38100/api/industry | python3 -m json.tool
|
|
|
|
ws-status: ## ws 通道状态 (连接态 / seq 水位 / 出口队列)
|
|
$(RUN) python scripts/ws_smoke.py status
|
|
|
|
# ---------------------------------------------------------------- 账本重建 (待办 #4)
|
|
rebuild: ## 账本重建预检 (只读)。加 GO=1 才真的建账, FORCE=1 连预检不过也建
|
|
$(RUN) python scripts/rebuild_ledger.py $(if $(GO),--yes,) $(if $(FORCE),--force,)
|
|
|
|
rebuild-accept: ## 只看判收: 安全垫分布 / 批次账 / 行业集中度
|
|
$(RUN) python scripts/rebuild_ledger.py --accept
|
|
|
|
# ---------------------------------------------------------------- 联测 A 段 (shadow 下逐跳)
|
|
# 一步一停, 每步都能看清楚 —— 别开 beat, 那会让几个调度位同时动, 出了岔子分不清是谁干的。
|
|
# 全程 PMS_DISPATCH_MODE=shadow: 指令照常生成、照常过规则闸、照常记账, **只是不写下游**。
|
|
# 顺序就是生产里那几个调度位的顺序, 只是改成手动触发。
|
|
#
|
|
# **A3 之前必须先下一条「任务命令」。** 参数命令 (SET_SCALE / SET_PORTFOLIO_CAP /
|
|
# SET_STOCK_CAP / SET_MAX_NAMES …) 只是设约束, **本来就不产生方案** —— 页面上它们显示
|
|
# 「0 条方案」是对的, 不是坏了。要走通链路得下 B/C 组的任务命令:
|
|
# INCREASE_EXPOSURE 升仓 pct% (全局: 垫厚票补到目标 + 候选池新票建仓)
|
|
# OPEN_TARGET 建仓某股至 x% (个股: 分批 50/25/25, 含一手合并)
|
|
#
|
|
# **这里的「择时」是 PMS 内置的实现 B, 不经决策系统。** 设计里择时有两个实现:
|
|
# 实现 A = 委托决策系统盘中择时 —— 待办 #9, 等 bionic 侧接口, **还没接**
|
|
# 实现 B = PMS 自己算 (分日配额 / 分笔 / VWAP / 回踩 / 不追高 / 14:45 兜底) —— 已实现
|
|
# 所以跑 A 段不需要动决策系统的任何逻辑, 它这一段本来就不参与。
|
|
A ?= http://127.0.0.1:38100
|
|
J := python3 -m json.tool
|
|
|
|
t-plan: ## A1 拉候选池 (= 08:40 调度位)
|
|
@curl -s -X POST '$(A)/api/ops/plan-refresh' | $(J)
|
|
|
|
t-pre: ## A2 盘前准备: T+1 可卖重置 / 参考位 / 刹车结算 (= 08:50 调度位)
|
|
@curl -s -X POST '$(A)/api/ops/premarket' | $(J)
|
|
|
|
t-cmd: ## A3 命令轮询: 新命令 → 方案生成 (先下任务命令! 参数命令不产生方案)
|
|
@curl -s -X POST '$(A)/api/ops/plan-pending' | $(J)
|
|
|
|
t-plans: ## A4 看方案 (方案是"买什么、多少股、分几批", 还没成指令)
|
|
@curl -s '$(A)/api/plans?limit=50' | $(J)
|
|
|
|
t-mat: ## A5 方案 → 指令 (先记账后动作: 指令先落表)
|
|
@curl -s -X POST '$(A)/api/ops/materialize' | $(J)
|
|
|
|
t-dry: ## A6 择时试算 (实现B, 不经决策系统; dry_run 只算不发)
|
|
@curl -s -X POST '$(A)/api/ops/exec-tick?dry_run=true' | $(J)
|
|
|
|
t-tick: ## A7 真出手 (shadow 下 = 置 DISPATCHED 但不写下游, 你照着在 QMT 手工下)
|
|
@curl -s -X POST '$(A)/api/ops/exec-tick' | $(J)
|
|
|
|
t-ins: ## A8 看指令与子单状态
|
|
@curl -s '$(A)/api/instructions?limit=50' | $(J)
|
|
|
|
t-book: ## A9 看账本 (持仓 / 批次 / 安全垫 / 行业)
|
|
@curl -s '$(A)/api/positions' | $(J)
|
|
|
|
t-gate: ## 看评审账本: 规则闸/研判闸拒了什么、为什么 (联测时最该盯的一张表)
|
|
@curl -s '$(A)/api/ledger?limit=50' | $(J)
|
|
|
|
# ---------------------------------------------------------------- 危险操作 (要确认)
|
|
reset-ledger: ## 清空账本重来 (影子期专用; 必须 CONFIRM=1)
|
|
@if [ "$(CONFIRM)" != "1" ]; then \
|
|
echo "这会清空 PMS 账本。确认请加 CONFIRM=1, 例如:"; \
|
|
echo " make reset-ledger CONFIRM=1 ARGS='--purge-channel --reset-ws'"; exit 1; fi
|
|
$(RUN) python scripts/reset_ledger.py --yes $(ARGS)
|
|
|
|
shell: ## 进容器 (排查用)
|
|
docker compose run --rm --no-deps pms-web bash
|