diff --git a/README.md b/README.md index 943d7a9..acd1d3c 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,57 @@ -# 国内期货 · 交易复盘系统 +# 国内期货 · 交易复盘系统 · 个人用户版 -基于 Flask 的国内期货 **CTP 下单 + 监控 + 复盘 + 统计** Web 应用。模拟盘连接 SimNow,实盘连接期货公司 CTP;支持关键位/计划提醒、交易记录同步、资金曲线、可开仓品种(仓位纪律)与企业微信推送。 +> **发行标识**:`v1.0.0-user`(分支 `release/v1.0-user`) +> 基于 Flask 的国内期货 **CTP 下单 + 监控 + 复盘 + 统计** Web 应用。模拟盘连接 SimNow,实盘连接期货公司 CTP。 + +本分支为 **个人用户版**,与完整版 `main` 功能范围不同,详见 [发行说明](docs/RELEASE-v1.0.0-user.md)。 + +## 用户版功能范围 + +| 包含 | 不含 | +|------|------| +| 下单监控(报单、持仓、CTP) | 行情 K 线页面 | +| 关键位监控 | 可开仓品种筛选大表 | +| 交易记录与复盘(**手动截图**) | 复盘自动生成 K 线图 | +| 统计分析、系统设置、备份 | — | +| **小账户四品种限制**(≤20 万或未连 CTP:玉米、豆粕、甲醇、螺纹钢) | — | ## 文档 | 文档 | 说明 | |------|------| -| **[功能说明](docs/FEATURES.md)** | 各模块功能、页面路径、数据库与后台任务 | -| **[部署文档](docs/DEPLOY.md)** | 一键部署、更新、PM2、故障排查 | -| **[备份与恢复](docs/BACKUP.md)** | 自动备份、下载、跨服务器恢复 | +| **[发行说明 v1.0.0-user](docs/RELEASE-v1.0.0-user.md)** | 版本标识、与完整版差异、交付与升级 | +| **[功能说明](docs/FEATURES.md)** | 各模块功能、页面路径 | +| **[部署文档](docs/DEPLOY.md)** | 一键部署、PM2、故障排查 | | **[SimNow 接入](docs/SIMNOW.md)** | 仿真账号注册与 CTP 前置 | -| **[期货公司实盘 CTP](docs/CTP_LIVE.md)** | 实盘接入、与 SimNow 开平仓对比 | -| **[交易与策略](docs/TRADING.md)** | 下单、持仓、可开仓品种、策略 API | -| **[手续费与导航](docs/FEES.md)** | CTP 费率同步、导航开关 | -| **[软件购买与使用协议](docs/软件购买与使用协议.md)** | 个人版授权模板(含签署栏) | +| **[交易与策略](docs/TRADING.md)** | 下单、小账户品种限制 | +| **[软件购买与使用协议](docs/软件购买与使用协议.md)** | 个人版授权模板 | ## 功能一览 | 模块 | 路径 | 说明 | |------|------|------| -| **下单监控**(默认首页) | `/positions` | CTP 连接、期货下单、当前持仓、可开仓品种 | -| **策略交易** | `/strategy` | 趋势回调 / 顺势加仓(可导航开关) | -| **开单计划** | `/plans` | 当日决策区间、触发推送(可开关) | -| **关键位监控** | `/keys` | 箱体/阻力支撑突破提醒 | -| **行情 K 线** | `/market` | 多周期 K 线(可开关) | -| **交易记录与复盘** | `/records` | 资金曲线、CTP 成交同步、复盘上传 | -| **统计分析** | `/stats` | 汇总指标 + 多维度分项统计 | -| **手续费配置** | `/fees` | CTP / 本地费率(可开关) | -| **系统设置** | `/settings` | 交易模式、CTP、计仓、微信、主题 | - -登录后默认进入 **下单监控**;刷新当前页不会跳转,仅访问根路径 `/` 或新登录时进入默认页。 +| **下单监控**(默认首页) | `/positions` | CTP 连接、期货下单、当前持仓 | +| 策略交易 | `/strategy` | 可导航开关 | +| 开单计划 | `/plans` | 可导航开关 | +| 关键位监控 | `/keys` | 箱体/阻力支撑突破提醒 | +| 交易记录与复盘 | `/records` | 资金曲线、CTP 成交同步、手动复盘 | +| 统计分析 | `/stats` | 汇总指标 + 分项统计 | +| 手续费配置 | `/fees` | 可导航开关 | +| 系统设置 | `/settings` | 交易模式、CTP、计仓、微信 | ## 快速开始 **服务器(Ubuntu)** ```bash -cd /opt/qihuo && bash deploy.sh +git clone https://gitee.com/dekun/qihuo.git /opt/qihuo +cd /opt/qihuo +git fetch --tags +git checkout v1.0.0-user +bash deploy.sh # 访问 http://:6600 ``` -**更新** - -```bash -cd /opt/qihuo -git fetch origin && git reset --hard origin/main -source venv/bin/activate && pip install -r requirements.txt -pm2 restart qihuo -``` - -详见 [部署文档](docs/DEPLOY.md)。 - **本地开发** ```bash @@ -61,27 +62,18 @@ cp .env.example .env python app.py ``` -## 品种与行情 - -- 合约代码:**同花顺格式**(`ag2606`、`SR609`、`IF2606`),中文联想匹配主力 -- 行情:默认 **新浪财经**;机构用户可配置同花顺 iFinD token - ## 环境要求 - Python 3.10+(vnpy_ctp) - PM2(生产部署) -- 网络:新浪行情、Git 仓库、SimNow/CTP 前置(见部署文档) - -## 仓库 - -https://git.bz121.com/dekun/qihuo.git +- 网络:新浪现价(内部逻辑)、SimNow/CTP 前置 ## 版权与授权 - 著作权人:**马建军** - 许可说明:[LICENSE.zh-CN.txt](LICENSE.zh-CN.txt) -- 个人购买协议模板:[docs/软件购买与使用协议.md](docs/软件购买与使用协议.md) +- 个人购买协议:[docs/软件购买与使用协议.md](docs/软件购买与使用协议.md) -本软件为 **专有软件**,仅供经授权的个人自用部署。严禁用于带单、向他人推荐期货品种或买卖建议、融资配资、转售源码或搭建共享交易室等用途。本软件不构成投资建议,期货交易风险由使用者自行承担。 +本软件为 **专有软件**,仅供经授权的个人自用部署。 联系:手机 18364911125 · 微信 dekun03 diff --git a/app.py b/app.py index f105799..8f4928b 100644 --- a/app.py +++ b/app.py @@ -44,7 +44,8 @@ from fee_specs import ( count_fee_rates_by_source, purge_non_ctp_fee_rates, ) -from nav_settings import NAV_TOGGLES, get_nav_items, nav_enabled, save_nav_items +from edition import EDITION_ID, EDITION_LABEL, USER_EDITION +from nav_settings import NAV_TOGGLES, get_nav_items, nav_enabled, nav_toggles_for_settings, save_nav_items from stats_engine import ( STATS_VIEWS, build_all_stats, @@ -266,7 +267,13 @@ def _ua_is_phone(ua: str) -> bool: @app.context_processor def inject_globals(): - return {"nav_items": get_nav_items(get_setting), "asset_v": _static_asset_v()} + return { + "nav_items": get_nav_items(get_setting), + "asset_v": _static_asset_v(), + "user_edition": USER_EDITION, + "edition_id": EDITION_ID, + "edition_label": EDITION_LABEL, + } def _trading_mode() -> str: @@ -765,16 +772,17 @@ def start_background_threads(): from trading_context import get_trading_mode threading.Thread(target=background_task, daemon=True).start() - threading.Thread( - target=lambda: kline_hub.worker_loop( - DB_PATH, - lambda sym, mc, sc: build_market_quote_payload( - sym, mc, sc, prefer_sina=True, + if not USER_EDITION: + threading.Thread( + target=lambda: kline_hub.worker_loop( + DB_PATH, + lambda sym, mc, sc: build_market_quote_payload( + sym, mc, sc, prefer_sina=True, + ), + get_mode_fn=lambda: get_trading_mode(get_setting), ), - get_mode_fn=lambda: get_trading_mode(get_setting), - ), - daemon=True, - ).start() + daemon=True, + ).start() threading.Thread(target=refresh_main_index, daemon=True).start() start_backup_worker(get_setting_fn=get_setting, set_setting_fn=set_setting) @@ -867,7 +875,7 @@ def api_symbols_mains(): @app.route("/api/symbols/recommended") @login_required def api_symbols_recommended(): - """品种下拉:仅展示当前资金下可开仓品种(与下方可开仓品种表一致)。""" + """品种下拉:当前资金下可报单品种(小账户四品种限制;完整版与下方可开仓表一致)。""" from recommend_store import recommend_payload from trading_context import ( get_fixed_lots, @@ -1506,7 +1514,7 @@ def add_review(): ) pnl_net = round((gross_pnl or 0) - fee, 2) if gross_pnl is not None else None - auto_kline = bool(d.get("auto_kline")) + auto_kline = bool(d.get("auto_kline")) and not USER_EDITION if auto_kline and not screenshot: try: generated = generate_review_kline_chart( @@ -1732,6 +1740,9 @@ def api_dashboard_live(): @login_required @require_nav("market") def market_page(): + if USER_EDITION: + flash("个人用户版不含行情 K 线") + return redirect(url_for("positions")) symbol = request.args.get("symbol", "").strip() period = request.args.get("period", "15m").strip() valid = {p["key"] for p in MARKET_PERIODS} @@ -1758,6 +1769,8 @@ def market_page(): @app.route("/api/kline") @login_required def api_kline(): + if USER_EDITION: + return jsonify({"error": "个人用户版不含行情 K 线"}), 403 symbol = request.args.get("symbol", "").strip() period = request.args.get("period", "15m").strip() if not symbol: @@ -1781,6 +1794,8 @@ def api_kline(): @app.route("/api/kline/stream") @login_required def api_kline_stream(): + if USER_EDITION: + return jsonify({"error": "个人用户版不含行情 K 线"}), 403 from queue import Empty symbol = request.args.get("symbol", "").strip() @@ -2094,7 +2109,7 @@ def settings(): flash_msg = f"CTP 配置已保存;{pwd_note or '请稍后在持仓监控页重连'}" flash(flash_msg) elif action == "nav": - items = {k: request.form.get(f"nav_{k}") == "on" for k in NAV_TOGGLES} + items = {k: request.form.get(f"nav_{k}") == "on" for k in nav_toggles_for_settings()} save_nav_items(set_setting, items) flash("导航显示已保存") elif action == "password": @@ -2143,7 +2158,7 @@ def settings(): trailing_be_tick_buffer=get_setting("trailing_be_tick_buffer", "2"), pending_order_timeout_min=get_setting("pending_order_timeout_min", "5"), nav_items=get_nav_items(get_setting), - nav_toggles=NAV_TOGGLES, + nav_toggles=nav_toggles_for_settings(), backup_dir=str(backup_dir()), backup_last_at=get_backup_last_at(get_setting), backup_running=backup_in_progress(), diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index a527551..7f928c8 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -4,6 +4,22 @@ --- +## 个人用户版 v1.0.0-user + +客户交付请使用 **tag**,勿部署 `main`: + +```bash +git clone https://gitee.com/dekun/qihuo.git /opt/qihuo +cd /opt/qihuo +git fetch --tags +git checkout v1.0.0-user +bash deploy.sh +``` + +功能范围见 [RELEASE-v1.0.0-user.md](./RELEASE-v1.0.0-user.md)。**你自己**的开发服务器继续用 `main` 即可。 + +--- + ## 部署概要 | 项目 | 默认值 | diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 4b5e46f..fba88a8 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -1,9 +1,9 @@ # 功能说明文档 -国内期货 · 交易复盘系统(Flask + SQLite + vnpy_ctp + PM2)。 +国内期货 · 交易复盘系统 · **个人用户版 v1.0.0-user**(Flask + SQLite + vnpy_ctp + PM2)。 -> **分板块详细说明(含下单逻辑、风控、微信模板)** → [INDEX.md](./INDEX.md) -> 重点:[WECHAT.md](./WECHAT.md) · [AI.md](./AI.md) · [RISK.md](./RISK.md) +> 完整版功能差异 → [RELEASE-v1.0.0-user.md](./RELEASE-v1.0.0-user.md) +> 分板块详细说明 → [INDEX.md](./INDEX.md) --- @@ -26,7 +26,6 @@ | 策略交易 | `/strategy` | 是 | | 开单计划 | `/plans` | 是 | | 关键位监控 | `/keys` | 否 | -| 行情 K 线 | `/market` | 是 | | 交易记录与复盘 | `/records` | 否 | | 统计分析 | `/stats` | 否 | | AI 分析 | `/ai` | 是 | @@ -49,7 +48,7 @@ ### 期货下单 -- 品种联想(可开仓品种表与下拉一致;小账户或 CTP 未连接时仅四品种,见 [TRADING.md](./TRADING.md)) +- 品种联想(小账户或 CTP 未连接时仅四品种,见 [TRADING.md](./TRADING.md)) - 方向、手数(固定手数 / 固定金额计仓) - 限价 / 市价(FAK)、止盈、止损 - **移动保本**(默认关闭):开启后隐藏止盈与盈亏比,仅填止损;由移动止损监控平仓,不设固定止盈 @@ -62,16 +61,12 @@ - 持仓卡片:浮盈亏、保证金、止盈止损、平仓等 - 数据经 SSE 推送,无需整页刷新 -### 可开仓品种 +### 小账户品种限制 -- 按当前权益与保证金上限筛选可开品种,养成开仓纪律、限制仓位 -- **权益 ≤20 万** 或 **CTP 未连接** 时,仅展示并可交易:玉米、豆粕、甲醇、螺纹钢(SimNow/实盘一致);未连接时最大手数按 **10 万权益** 估算 -- **夜盘时段** 仅显示有夜盘品种,并标注「夜盘」 -- **行业分类**、走势(多头/空头/震荡/转多/转空)、跳空、昨日成交量(手)、成交额 -- 支持行业筛选与多字段排序 -- 每日后台刷新缓存 +- **权益 ≤20 万** 或 **CTP 未连接** 时,品种下拉与开仓校验仅允许:玉米、豆粕、甲醇、螺纹钢 +- **夜盘时段** 品种下拉仅显示有夜盘品种 -详见 [TRADING.md](./TRADING.md)。 +个人用户版 **不含**「可开仓品种」筛选大表(走势、成交量、行业排序等)。详见 [TRADING.md](./TRADING.md)。 --- @@ -106,16 +101,6 @@ --- -## 行情 K 线 - -**路径**:`/market` · 详见 [MARKET.md](./MARKET.md) - -- 多周期 K 线(TradingView Lightweight Charts) -- 支持 CTP 连接后部分数据增强 -- 需在导航中开启 - ---- - ## 交易记录与复盘 **路径**:`/records`(`/trades` 重定向至此) · 详见 [RECORDS.md](./RECORDS.md) @@ -137,7 +122,7 @@ ### 复盘上传 / 复盘历史 -- 手动复盘表单、截图、自动 K 线图(matplotlib) +- 手动复盘表单、**截图上传**(个人用户版不含自动 K 线图) - 按本日/本周/本月/自定义日期筛选历史 --- diff --git a/docs/FEES.md b/docs/FEES.md index 197abfa..fb956cf 100644 --- a/docs/FEES.md +++ b/docs/FEES.md @@ -30,7 +30,7 @@ |-----|------| | `fees` | 手续费配置 | | `plans` | 开单计划 | -| `market` | 行情 K 线 | +| `market` | 行情 K 线(**用户版不含**) | | `strategy` | 策略交易 | 关闭后顶栏隐藏;直接访问 URL 会提示并跳转到 **下单监控**。 diff --git a/docs/INDEX.md b/docs/INDEX.md index c06fadf..ac64731 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -1,6 +1,8 @@ -# 文档索引 +# 文档索引 · 个人用户版 v1.0.0-user -国内期货 · 交易复盘系统各板块说明。每篇文档包含 **下单逻辑**、**风控规则**,并在需要时引用 [微信推送模板](./WECHAT.md)。 +国内期货 · 交易复盘系统各板块说明。 + +> **版本差异** → [RELEASE-v1.0.0-user.md](./RELEASE-v1.0.0-user.md) --- @@ -26,7 +28,6 @@ | 策略交易 | `/strategy` | [STRATEGY.md](./STRATEGY.md) | | 开单计划 | `/plans` | [PLANS.md](./PLANS.md) | | 关键位监控 | `/keys` | [KEY_MONITORS.md](./KEY_MONITORS.md) | -| 行情 K 线 | `/market` | [MARKET.md](./MARKET.md) | | 交易记录与复盘 | `/records` | [RECORDS.md](./RECORDS.md) | | 统计分析 | `/stats` | [STATS.md](./STATS.md) | | 手续费配置 | `/fees` | [FEES.md](./FEES.md) | @@ -38,7 +39,7 @@ | 文档 | 说明 | |------|------| -| [TRADING.md](./TRADING.md) | 可开仓品种、计仓、SimNow/实盘 | +| [TRADING.md](./TRADING.md) | 小账户四品种、计仓、SimNow/实盘 | | [SIMNOW.md](./SIMNOW.md) | SimNow 仿真注册与接入 | | [CTP_LIVE.md](./CTP_LIVE.md) | **期货公司实盘 CTP** 与开平仓对比 | | [DEPLOY.md](./DEPLOY.md) | 部署说明 | diff --git a/docs/MARKET.md b/docs/MARKET.md index 0e73dca..188c5bf 100644 --- a/docs/MARKET.md +++ b/docs/MARKET.md @@ -1,5 +1,7 @@ # 行情 K 线 +> **个人用户版 v1.0.0-user 不含本模块。** 本文档仅适用于完整版 `main`。用户版说明见 [RELEASE-v1.0.0-user.md](./RELEASE-v1.0.0-user.md)。 + **页面路径**:`/market` **相关文件**:`market.py`、`kline_chart.py`、`templates/market.html` diff --git a/docs/ORDER_MONITOR.md b/docs/ORDER_MONITOR.md index 52e6cdf..8f9b37c 100644 --- a/docs/ORDER_MONITOR.md +++ b/docs/ORDER_MONITOR.md @@ -1,4 +1,4 @@ -# 下单监控 +# 下单监控 · 个人用户版 **页面路径**:`/positions`(默认首页) @@ -13,7 +13,8 @@ | 顶栏 | 模拟/实盘、CTP 状态、风险状态、权益、连接按钮 | | 期货下单 | 手动开仓/平仓表单 | | 当前持仓 | pending 挂单 + active 持仓卡片 | -| 可开仓品种 | 按权益与保证金筛选的推荐表 | + +个人用户版 **不含**「可开仓品种」筛选大表。 --- @@ -38,114 +39,21 @@ 5. **成交后**: - 写入 `trade_order_monitors`(status=active 或 pending) - 注册本地 SL/TP 守护(`sl_tp_guard`) - - 微信:结构化开仓推送(有止损)或简版 - - AI:后台开仓分析(有止损时) -### 挂单(限价未立即成交) +### 小账户四品种 -- status=`pending`,显示「挂单中」。 -- **超时撤单**:`pending_order_worker` 每 10 秒 reconcile(有 pending 时);默认超时见系统设置 `pending_order_timeout_sec`。 -- 微信:`委托已提交 · … 挂单中(N 分钟未成交自动撤单)` - -### 手动平仓 - -- 市价平仓当前品种方向持仓。 -- 关闭对应 monitor,写入 `trade_logs`。 -- 若当日手动平仓次数超限 → 触发冷静期([RISK.md](./RISK.md))。 -- 微信:结构化平仓推送(成交同步后)。 - -### 止盈止损守护 - -后台 `sl_tp_guard` 线程 + tick 事件: - -| 条件 | 动作 | -|------|------| -| 价格触及 **止盈价** | 市价平仓,结果=止盈 | -| 价格触及 **止损价** | 市价平仓,结果=止损 | -| 开启 **移动保本** | 见下节 | - -触发时先推简版「平仓委托已提交」,成交写入 trade_logs 后推 **结构化平仓**。 +权益 ≤20 万或未连 CTP 时,非 `c` / `m` / `MA` / `rb` 品种开仓会被拒绝。品种下拉同样受限。 --- ## 移动保本 -**开启条件**:下单表单勾选「移动保本」,**必须填写止损**,不设固定止盈。 - -**逻辑**(`sl_tp_guard._update_trailing_stop_loss`): - -| 浮盈 R 倍数 | 止损移动至 | -|-------------|------------| -| ≥ 1R | 开仓价 ± `trailing_be_tick_buffer` 跳(保本) | -| ≥ 2R | 开仓价 ± 1R | -| ≥ nR | 开仓价 ± (n−1)R | - -**平仓结果标签**: - -- 1R 锁定后止损出场 → **保本止盈** -- 2R 及以上锁定后止损出场 → **移动止盈** - -关键位自动单若开启移动保本且设目标盈亏比(默认 3R),达 TP 仍按 **止盈** 平仓;移动止损与显式 TP **可同时生效**。 - ---- - -## 风控规则 - -本板块执行 [RISK.md](./RISK.md) 全部规则,另加: - -| 规则 | 说明 | -|------|------| -| 非交易时段 | 禁止开仓 | -| 移动保本 | 必须填止损 | -| 固定金额 | 必须填止损才能算手数 | -| 保证金 | 新开仓前校验总占用 | -| 单笔 50 手 | 超限拒绝 | - -顶栏 **风险状态** 实时反映:正常 / 冷静期 / 日冻结 / 仓位上限。 - ---- - -## 可开仓品种表 - -- 按当前权益、`max_margin_pct`、合约保证金计算可开手数。 -- 权益 ≤20 万或 CTP 未连接:仅四品种;未连接按 10 万权益估算。 -- 夜盘时段过滤无夜盘品种。 -- 每日后台刷新 `product_recommend_cache`。 - -详见 [TRADING.md](./TRADING.md)。 - ---- - -## 微信推送 - -| 事件 | 模板 | -|------|------| -| 开仓成交(有止损) | [WECHAT §1](./WECHAT.md#1-手动开仓成功) | -| 开仓成交(无止损) | [WECHAT §2](./WECHAT.md#2-简版开仓) | -| 挂单提交 | [WECHAT §3](./WECHAT.md#3-挂单提交) | -| 平仓完成 | [WECHAT §4](./WECHAT.md#4-平仓完成) | -| SL/TP 触发 | [WECHAT §5](./WECHAT.md#5-本地止盈止损触发) | -| AI 分析 | [AI.md](./AI.md)(仅页面,默认不推微信) | - ---- - -## 数据流 - -``` -用户下单 → API /api/trade/order - → CTP 报单 - → trade_order_monitors - → sl_tp_guard 监控 - → 平仓 → trade_logs → 微信 + AI -``` - -SSE:`/api/trading/stream` 推送持仓快照,无需整页刷新。 +见 [TRADING.md](./TRADING.md) 与完整版 ORDER_MONITOR 说明(逻辑相同)。 --- ## 相关文档 -- [RISK.md](./RISK.md) -- [WECHAT.md](./WECHAT.md) - [TRADING.md](./TRADING.md) -- [SETTINGS.md](./SETTINGS.md) +- [RISK.md](./RISK.md) +- [RELEASE-v1.0.0-user.md](./RELEASE-v1.0.0-user.md) diff --git a/docs/RECORDS.md b/docs/RECORDS.md index 3ce5812..17cd225 100644 --- a/docs/RECORDS.md +++ b/docs/RECORDS.md @@ -1,4 +1,4 @@ -# 交易记录与复盘 +# 交易记录与复盘 · 个人用户版 **页面路径**:`/records`(`/trades` 重定向) @@ -12,9 +12,11 @@ |------|------| | 资金曲线 | Lightweight Charts,随主题变色 | | 交易记录 | `trade_logs` 主表 | -| 复盘表单 | 手动复盘 + 截图 + 自动 K 线图 | +| 复盘表单 | 手动复盘 + **截图上传** | | 复盘历史 | 按日/周/月/自定义筛选 | +个人用户版 **不含** 复盘「自动 K 线」选项(不调用新浪 K 线生成 matplotlib 截图)。 + --- ## 下单逻辑 @@ -46,10 +48,6 @@ - **日冻结** — 当日禁止新开仓([RISK.md](./RISK.md)) - 手动平仓超限后的冷静期可因填写日记缩短为 **1 小时** -### 记录本身 - -交易记录页不改变持仓;删除/编辑仅影响本地数据库。 - --- ## 平仓后的联动 @@ -61,25 +59,16 @@ --- -## 主要字段 +## 复盘上传 -品种、类型(monitor_type)、方向、开仓/平仓价、止损/止盈、手数、保证金、盈亏、手续费、净盈亏、最新资金、结果、持仓时长。 - ---- - -## 微信推送 - -| 事件 | 模板 | -|------|------| -| 程序/同步平仓 | [WECHAT §4](./WECHAT.md#4-平仓完成) | - -开单计划结果见 [PLANS.md](./PLANS.md)(§10 简版模板)。 +- 填写开平仓时间、价格、止损止盈、行为标签等 +- **截图**:使用表单中的文件上传(`accept="image/*"`) +- 个人用户版请自行截图保存 K 线或盘面,系统不会自动生成 K 线图 --- ## 相关文档 -- [STATS.md](./STATS.md) — 统计来源 trade_logs -- [RISK.md](./RISK.md) — 复盘触发冻结 +- [FEATURES.md](./FEATURES.md) +- [RELEASE-v1.0.0-user.md](./RELEASE-v1.0.0-user.md) - [WECHAT.md](./WECHAT.md) -- [AI.md](./AI.md) diff --git a/docs/RELEASE-v1.0.0-user.md b/docs/RELEASE-v1.0.0-user.md new file mode 100644 index 0000000..305e328 --- /dev/null +++ b/docs/RELEASE-v1.0.0-user.md @@ -0,0 +1,102 @@ +# v1.0.0-user 个人用户版 · 发行说明 + +**Tag**:`v1.0.0-user` +**分支**:`release/v1.0-user` +**完整版开发线**:`main`(功能更多,勿与客户环境混用) + +--- + +## 版本定位 + +面向 **个人购买者** 的首次交付版本:聚焦 **CTP 下单纪律、关键位、记录复盘与统计**,去掉易引发误解或依赖新浪 K 线展示的功能模块。 + +本软件为 **交易纪律与记录辅助工具**,不构成投资建议。 + +--- + +## 包含功能 + +| 模块 | 路径 | +|------|------| +| 下单监控 | `/positions` | +| 关键位监控 | `/keys` | +| 交易记录与复盘 | `/records` | +| 统计分析 | `/stats` | +| 系统设置 / 备份 | `/settings` | +| 策略交易、开单计划、AI、手续费等 | 可在导航中开关(默认以交付时配置为准) | + +### 小账户品种限制(保留) + +- 权益 **≤20 万元** 或 **CTP 未连接** 时,仅可浏览、搜索、报单:**玉米、豆粕、甲醇、螺纹钢** +- 品种下拉与开仓 API 校验一致 +- **不含**「可开仓品种」筛选大表(走势、成交量、行业排序等) + +--- + +## 不含功能 + +| 功能 | 说明 | +|------|------| +| 行情 K 线 | 无 `/market` 页面;无 K 线 SSE | +| 可开仓品种表 | 无下单页下方大表;无 recommend SSE | +| 复盘自动 K 线 | 复盘请 **手动上传截图** | + +--- + +## 部署(SSH 代部署) + +```bash +git clone https://gitee.com/dekun/qihuo.git /opt/qihuo +cd /opt/qihuo +git fetch --tags +git checkout v1.0.0-user +bash deploy.sh +nano /opt/qihuo/.env # ADMIN_*、SIMNOW_* 等 +pm2 restart qihuo +``` + +验收: + +- 顶栏无「行情 K 线」 +- `/positions` 无「可开仓品种」大表 +- `/records` 无「自动 K 线」选项 +- 小账户四品种限制生效 + +详见 [DEPLOY.md](./DEPLOY.md)。 + +--- + +## 与完整版(main)的关系 + +| | 个人用户版 | 完整版 main | +|--|-----------|-------------| +| 代码线 | `release/v1.0-user` | `main` | +| 行情 K 线 | 无 | 有 | +| 可开仓品种表 | 无 | 有 | +| 复盘自动 K 线 | 无 | 有 | +| 小账户四品种 | 有 | 有 | + +- 用户版 bug 修复:在 `release/v1.0-user` 发 `v1.0.1-user` 等 patch tag +- 完整版新功能:**不会**自动进入用户版;客户升级需另议 + +--- + +## 协议与交付 + +- 协议附件填写:**版本 tag `v1.0.0-user`** +- 交付:SSH 部署 + 管理员账号 + 本文档与 [FEATURES.md](./FEATURES.md) +- 不提供 `main` 分支写权限 + +--- + +## 技术说明 + +- 发行标识:`edition.py` 中 `USER_EDITION = True` +- 现价报价(新浪 `hq.sinajs.cn`)仍用于计划、关键位等内部逻辑;**不对用户提供 K 线浏览服务** +- 关键位监控后台可能使用 K 线数据计算箱体(用户不可见) + +--- + +## 联系 + +著作权人:马建军 · 手机 18364911125 · 微信 dekun03 diff --git a/docs/SETTINGS.md b/docs/SETTINGS.md index 82c15f0..682cefc 100644 --- a/docs/SETTINGS.md +++ b/docs/SETTINGS.md @@ -58,13 +58,13 @@ `nav_settings.py` 中 `NAV_TOGGLES` 控制菜单可见性;`@require_nav` 保护路由。 -| 键 | 菜单 | -|----|------| -| strategy | 策略交易 | -| plans | 开单计划 | -| market | 行情 K 线 | -| fees | 手续费配置 | -| ai | AI 分析 | +| 键 | 菜单 | 用户版 | +|----|------|--------| +| strategy | 策略交易 | 可开关 | +| plans | 开单计划 | 可开关 | +| market | 行情 K 线 | **不含**(设置中不显示) | +| fees | 手续费配置 | 可开关 | +| ai | AI 分析 | 可开关 | 下单监控、关键位、记录、统计、设置 **不可关闭**。 diff --git a/docs/TRADING.md b/docs/TRADING.md index ae5b5cd..a694aa4 100644 --- a/docs/TRADING.md +++ b/docs/TRADING.md @@ -1,4 +1,4 @@ -# 下单监控与策略交易 +# 下单监控与策略交易 · 个人用户版 ## 默认首页 @@ -9,9 +9,8 @@ | 顶栏 | 交易模式、CTP 状态、权益/可用、连接 CTP | | 期货下单 | 限价/市价报单、止盈/止损、移动保本、以损定仓/固定手数 | | 当前持仓 | CTP 持仓卡片、挂单中、撤单、平仓 | -| 可开仓品种 | 按权益与保证金上限筛选、行业分类、走势/跳空/成交量排序 | -`/trade`、`/recommend` 均重定向到 `/positions`(可开仓品种锚点 `#recommend`)。 +个人用户版 **不含** 下单页下方的「可开仓品种」筛选大表。`/trade`、`/recommend` 重定向至 `/positions`。 ## 两种交易通道 @@ -21,7 +20,7 @@ | **实盘** | 期货公司 CTP(`.env` 中 `CTP_LIVE_*`) | 柜台权益 | 模拟盘与实盘均走 **vnpy_ctp**,无本地假撮合。 -**实盘接入与开平仓对比** → [CTP_LIVE.md](./CTP_LIVE.md) · SimNow → [SIMNOW.md](./SIMNOW.md) +**实盘接入** → [CTP_LIVE.md](./CTP_LIVE.md) · SimNow → [SIMNOW.md](./SIMNOW.md) ## 下单与持仓 @@ -30,18 +29,7 @@ - **平仓**:程序平仓写入 `trade_logs`(来源「本地」) - **持仓数据**:SSE `/api/trading/stream` 推送,约 1 秒刷新 -## 可开仓品种 - -- 用于开仓纪律与仓位限制:按保证金上限计算最大手数,仅展示当前权益下可开的品种 -- 每日后台刷新列表(`/api/recommend/stream`) -- 最大手数 = floor(权益 × 保证金上限 ÷ 1 手保证金) -- **1 手保证金**:**CTP 已连接** 时优先读取柜台合约的 `long_margin_ratio` / `short_margin_ratio` 与乘数计算(表格标注「柜台」);未连接或合约信息暂不可用时,才用本地参考保证金率估算 -- 开仓前校验、固定金额计仓、保证金占用比例检查均与上述规则一致,避免交易所上调保证金后仍按旧比例显示可开手数 -- 展示近一周日线走势、跳空、昨日成交量(手)、成交额 -- 可按 **行业** 筛选,支持多字段排序 -- **夜盘时段**:品种下拉与可开仓表仅显示有夜盘交易的品种,并带「夜盘」标记 - -### 小账户品种范围(≤20 万) +## 小账户品种范围(≤20 万) 权益 **不超过 20 万元** 时,系统限制可浏览、可搜索、可报单的品种为以下 **4 个**: @@ -54,13 +42,14 @@ 适用范围: -- 可开仓品种表 - 期货下单品种联想 / 下拉 - 开仓报单校验(含趋势策略首仓) -**SimNow 与实盘规则一致**:**CTP 未连接** 时,可开仓表 **当前权益固定按 10 万** 估算最大手数,并 **仅展示四品种**(玉米、豆粕、甲醇、螺纹钢);与系统设置中的参考资金无关。连接 CTP 后改用柜台权益;若柜台权益 ≤20 万,同样仅上述四品种。 +**SimNow 与实盘规则一致**:**CTP 未连接** 时,品种下拉 **仅展示四品种**(玉米、豆粕、甲醇、螺纹钢);与系统设置中的参考资金无关。连接 CTP 后改用柜台权益;若柜台权益 ≤20 万,同样仅上述四品种。 -页面会提示:「未连接 CTP,按 10 万权益估算最大手数,仅显示并可交易 …」。 +页面会提示小账户范围说明(在下单区底部)。 + +> 完整版另有「可开仓品种」大表(按保证金筛选、走势/成交量排序);**个人用户版不含该表**。 ## 期货下单 · 止盈止损与移动保本 @@ -78,51 +67,22 @@ | 表单项 | 行为 | |--------|------| -| 止盈 | **隐藏**,不提交止盈价 | -| 盈亏比 / 止盈金额 | **不显示** | -| 止损 | **必填**,仅保留止损输入 | +| 止盈 | 隐藏 | +| 止损 | 必填 | +| 盈亏比提示 | 隐藏 | +| 平仓逻辑 | 达 1R 后止损移至开仓价 ± 缓冲跳;2R 移 1R,依次类推 | -平仓逻辑: - -- **不再** 按固定止盈价监控 -- 程序按 **移动止损** 管理出场:浮盈达 **1R** 后止损移至开仓价 ± N 跳(保本);达 **2R** 移至 1R,依次类推(N 见系统设置「移动保本缓冲」) -- 开启移动保本 **必须填写止损价**,否则无法开仓 - -持仓卡片在开启移动保本时同样 **不展示盈亏比、盈利金额、止盈状态**,仅保留止损与移动保本进度(如已锁 N R)。 +详见 [ORDER_MONITOR.md](./ORDER_MONITOR.md#移动保本)。 ## 策略交易 -| 页面 | 路径 | -|------|------| -| 策略交易 | `/strategy` | -| 策略记录 | `/strategy/records` | +**路径**:`/strategy` · 详见 [STRATEGY.md](./STRATEGY.md) -趋势回调、顺势加仓等策略需先在下单监控完成开仓,再在策略页配置。 +- 趋势回调、顺势加仓等(需 CTP 已连接) +- 策略记录单独归档 -## 参考资金 +## 相关文档 -系统设置中的「参考资金」在 **CTP 未连接** 时用于以损定仓估算;连接后自动改用柜台权益。 - -可开仓品种与品种白名单:**未连接 CTP 时** 可开仓表按 **10 万权益** 估算最大手数,且仅四品种;连接后若柜台权益 ≤20 万,同样仅上述四品种。 - -## 首次使用 SimNow - -完整步骤见 **[SimNow 注册与接入说明](./SIMNOW.md)**。 - -简要:注册 SimNow → 填写 `.env` → 安装 vnpy_ctp → 登录系统 → **下单监控** → **连接 CTP**。 - -## 主要 API - -| 接口 | 说明 | -|------|------| -| `POST /api/ctp/connect` | 连接 SimNow 或实盘 CTP | -| `GET /api/ctp/status` | 连接状态 | -| `POST /api/trade/order` | 报单(需已连接 CTP) | -| `POST /api/trading/order/cancel` | 撤单(交易时段) | -| `POST /api/trading/close` | 平仓 | -| `GET /api/trading/stream` | 持仓 SSE | -| `GET /api/recommend/list` | 可开仓品种 JSON | -| `GET /api/recommend/stream` | 可开仓品种 SSE | -| `POST /api/strategy/trend/execute` | 执行趋势策略 | - -详见 [DEPLOY.md](./DEPLOY.md) 中 CTP 故障排查。 +- [ORDER_MONITOR.md](./ORDER_MONITOR.md) +- [RISK.md](./RISK.md) +- [RELEASE-v1.0.0-user.md](./RELEASE-v1.0.0-user.md) diff --git a/edition.py b/edition.py new file mode 100644 index 0000000..09406c8 --- /dev/null +++ b/edition.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025-2026 马建军. All rights reserved. +# 专有软件 — 未经授权禁止复制、传播、转售。 +# 详见 LICENSE.zh-CN.txt 与 docs/软件购买与使用协议.md + +"""发行版标识:release/v1.0-user 分支为个人用户版(v1.0.0-user)。""" + +USER_EDITION = True +EDITION_ID = "v1.0.0-user" +EDITION_LABEL = "个人用户版" diff --git a/install_trading.py b/install_trading.py index b8b08f9..e163072 100644 --- a/install_trading.py +++ b/install_trading.py @@ -15,6 +15,8 @@ from typing import Any, Callable, Optional from flask import flash, jsonify, redirect, render_template, request, url_for, Response, stream_with_context +from edition import USER_EDITION + from contract_specs import calc_position_metrics, get_contract_spec from fee_specs import calc_fee_breakdown from kline_stream import sse_format @@ -1858,12 +1860,13 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se try: payload = _refresh_trading_live_snapshot(fast=fast) position_hub.broadcast("positions", payload) - conn = get_db() - try: - rec = _recommend_payload(conn) - recommend_hub.broadcast("recommend", {"ok": True, **rec}) - finally: - conn.close() + if not USER_EDITION: + conn = get_db() + try: + rec = _recommend_payload(conn) + recommend_hub.broadcast("recommend", {"ok": True, **rec}) + finally: + conn.close() except Exception as exc: logger.debug("push position snapshot: %s", exc) @@ -2070,8 +2073,8 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se max_margin_pct=get_max_margin_pct(get_setting), pending_order_timeout_min=get_pending_order_timeout_min(get_setting), ctp_auto_connect=is_ctp_auto_connect_enabled(get_setting), - recommend_rows=rec_cache.get("rows") or [], - recommend_updated_at=rec_cache.get("updated_at"), + recommend_rows=[] if USER_EDITION else (rec_cache.get("rows") or []), + recommend_updated_at=None if USER_EDITION else rec_cache.get("updated_at"), night_session=is_night_trading_session(), small_account_scope=should_apply_small_account_scope( capital, ctp_connected=ctp_connected, @@ -2090,6 +2093,8 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se @app.route("/recommend") @login_required def recommend_page(): + if USER_EDITION: + return redirect(url_for("positions")) return redirect(url_for("positions") + "#recommend") @app.route("/api/trading/live") @@ -2992,6 +2997,8 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se @app.route("/api/recommend/stream") @login_required def api_recommend_stream(): + if USER_EDITION: + return jsonify({"ok": False, "error": "个人用户版不含可开仓品种表"}), 403 from queue import Empty def generate(): @@ -3026,6 +3033,8 @@ def install_trading(app, *, login_required, require_nav, get_db, get_setting, se @login_required def api_recommend_refresh(): """手动触发一次后台刷新(仍写入数据库)。""" + if USER_EDITION: + return jsonify({"ok": False, "error": "个人用户版不含可开仓品种表"}), 403 conn = get_db() try: init_strategy_tables(conn) diff --git a/nav_settings.py b/nav_settings.py index fcd337c..b61541b 100644 --- a/nav_settings.py +++ b/nav_settings.py @@ -9,6 +9,8 @@ from __future__ import annotations import json from typing import Callable +from edition import USER_EDITION + # 可在系统设置中开关的导航项 NAV_TOGGLES: dict[str, str] = { "dashboard": "数据看板", @@ -20,7 +22,18 @@ NAV_TOGGLES: dict[str, str] = { "ai": "AI 分析", } +_USER_EDITION_NAV_HIDDEN = frozenset({"market"}) + DEFAULT_NAV: dict[str, bool] = {k: True for k in NAV_TOGGLES} +if USER_EDITION: + DEFAULT_NAV["market"] = False + + +def nav_toggles_for_settings() -> dict[str, str]: + """系统设置页展示的导航开关(用户版隐藏行情 K 线)。""" + if not USER_EDITION: + return dict(NAV_TOGGLES) + return {k: v for k, v in NAV_TOGGLES.items() if k not in _USER_EDITION_NAV_HIDDEN} def get_nav_items(get_setting: Callable[[str, str], str]) -> dict[str, bool]: @@ -36,18 +49,24 @@ def get_nav_items(get_setting: Callable[[str, str], str]) -> dict[str, bool]: out[k] = bool(data[k]) except json.JSONDecodeError: pass + if USER_EDITION: + out["market"] = False return out def save_nav_items(set_setting: Callable[[str, str], None], items: dict[str, bool]) -> None: merged = dict(DEFAULT_NAV) - for k in NAV_TOGGLES: + for k in nav_toggles_for_settings(): if k in items: merged[k] = bool(items[k]) + if USER_EDITION: + merged["market"] = False set_setting("nav_items", json.dumps(merged, ensure_ascii=False)) def nav_enabled(get_setting: Callable[[str, str], str], key: str) -> bool: + if USER_EDITION and key == "market": + return False if key not in NAV_TOGGLES: return True return get_nav_items(get_setting).get(key, True) diff --git a/static/css/base.css b/static/css/base.css index 118707f..8c343e2 100644 --- a/static/css/base.css +++ b/static/css/base.css @@ -121,6 +121,7 @@ min-height:100vh; .page-wrap{max-width:1800px;margin:0 auto;min-height:100vh} .site-header{text-align:center;padding:1.5rem 1rem 1.25rem;border-bottom:1px solid var(--border-header);position:relative} .site-title{font-size:1.75rem;font-weight:700;color:var(--text-title);margin-bottom:1.65rem;line-height:1.3} +.site-edition-tag{display:inline-block;margin-left:.45rem;padding:.12rem .45rem;font-size:.62rem;font-weight:600;vertical-align:middle;border-radius:4px;background:var(--accent-dim, rgba(56,189,248,.15));color:var(--accent,#38bdf8);letter-spacing:.02em} .header-tools{position:absolute;top:1rem;left:1.5rem;display:flex;gap:.5rem;align-items:center;z-index:20} .theme-switch{ display:inline-flex;align-items:center; diff --git a/static/js/trade.js b/static/js/trade.js index 45004d8..7822864 100644 --- a/static/js/trade.js +++ b/static/js/trade.js @@ -46,6 +46,7 @@ var REC_INDUSTRY_CACHE = 'qihuo_rec_industry_v1'; var REC_COLSPAN = 18; var marketNavEnabled = false; + var userEdition = false; var productCategories = []; var POS_CACHE_KEY = 'qihuo_trading_live_v5'; @@ -58,6 +59,7 @@ if (sizingMode === 'risk') sizingMode = 'amount'; ctpAutoConnectEnabled = cfg.ctp_auto_connect !== false; marketNavEnabled = !!cfg.market_nav_enabled; + userEdition = !!cfg.user_edition; productCategories = cfg.product_categories || []; window.TRADE_FIXED_LOTS = cfg.fixed_lots; window.TRADE_FIXED_AMOUNT = cfg.fixed_amount; @@ -1939,15 +1941,24 @@ connectPositionStream(); bindSlTpModal(); initCtpOnLoad(); - connectRecommendStream(); - initRecommendSortControls(); - if (window.__RECOMMEND_ROWS__ && window.__RECOMMEND_ROWS__.length) { - recRowsRaw = window.__RECOMMEND_ROWS__.slice(); - renderRecommendTable(); + if (!userEdition) { + connectRecommendStream(); + initRecommendSortControls(); + if (window.__RECOMMEND_ROWS__ && window.__RECOMMEND_ROWS__.length) { + recRowsRaw = window.__RECOMMEND_ROWS__.slice(); + renderRecommendTable(); + } } fetch('/api/recommend/list') .then(function (r) { return r.json(); }) - .then(function (data) { if (data.ok) renderRecommendations(data); }) + .then(function (data) { + if (!data.ok) return; + if (userEdition) { + updateRecommendMaxMaps(data); + return; + } + renderRecommendations(data); + }) .catch(function () {}); updateSessionUi(); updateRRDisplay(); diff --git a/templates/base.html b/templates/base.html index fa75a69..25f1287 100644 --- a/templates/base.html +++ b/templates/base.html @@ -66,7 +66,7 @@

期货监控 - 国内期货 · 交易复盘系统Position Management · Disciplined Execution + 国内期货 · 交易复盘系统{% if user_edition %}{{ edition_id }}{% endif %}Position Management · Disciplined Execution

diff --git a/templates/records.html b/templates/records.html index 384fa76..d1bbea2 100644 --- a/templates/records.html +++ b/templates/records.html @@ -350,6 +350,7 @@
+ {% if not user_edition %}
@@ -357,6 +358,9 @@
+ {% else %} +

个人用户版请使用截图上传复盘;不含自动 K 线图。

+ {% endif %}

勾选行为标签即为情绪单

{% for tag in behavior_tags %} diff --git a/templates/trade.html b/templates/trade.html index f746d2d..00e098d 100644 --- a/templates/trade.html +++ b/templates/trade.html @@ -76,9 +76,10 @@
  • 移动保本:须填止损、不设固定止盈;达 1R 止损移至开仓±缓冲跳,2R 移 1R,依次类推
  • 手动平仓写入交易记录;当日手动平仓次数超限 → 进入冷静期
  • -

    可开仓品种表

    +

    小账户品种限制

      -
    • 按权益与保证金上限筛选;权益 ≤20 万或 CTP 未连接时仅四品种(玉米、豆粕、甲醇、螺纹钢)
    • +
    • 权益 ≤20 万或 CTP 未连接时,仅可交易玉米、豆粕、甲醇、螺纹钢
    • +
    • 品种下拉与开仓校验与上述规则一致;保证金占用不超过系统设置上限
    @@ -142,6 +143,9 @@
    + {% if not user_edition %}

    可开仓品种

    @@ -268,6 +273,7 @@
    + {% endif %}