组织介绍

MLPT-RC 项目架构设计与核心逻辑

文档路径:docs/plans/README.md 最后更新:2026-07-07(v4) 仓库:https://gitee.com/mlpt-dev/mlpt-rc


1. 项目总体架构

MLPT-RC 是一个面向新疆电力现货市场的滚动撮合与电价预测系统,采用前后端分离架构:

┌─────────────────────────────────────────────────────────────────┐
│                         前端 (Vue 3)                             │
│  web/ → Vben Admin + Ant Design Vue + Vite + Pinia + TypeScript │
│  生产构建产物 → backend/static_web/                               │
└─────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│                    后端 (Django + Ninja)                         │
│  backend/application/  │  backend/spot/     │  backend/slove/   │
│  backend/sider/        │  backend/xhxtapi/  │  backend/gwapi/   │
│  backend/trading/      │  backend/system/   │  backend/common/  │
│  backend/feishu/       │  backend/database/                     │
└─────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│              数据层:MySQL / SQLite / 文件(Excel/模型)          │
│  电价预测模型 │ PMOS Excel │ xhxtapi 代理 │ 金风科技功率预测      │
│                        飞书机器人                                 │
└─────────────────────────────────────────────────────────────────┘

2. 后端模块职责

模块 路径 主要职责
application backend/application/ Django 壳:settings.pyurls.py、Django-Ninja 入口 main.py、Celery celery.py、WSGI/ASGI
common backend/common/ 公共基础设施:JWT 认证 fu_auth.py、通用 CRUD fu_crud.py、软删/审计基类 fu_model.py、分页、API 日志、代码生成模板
config backend/config/ 多环境配置(dev/uat/prd/win),提供数据库、用户数据目录等配置
database backend/database/ 数据库模型/API 封装
fixtures backend/fixtures/ Django 初始演示数据
gwapi backend/gwapi/ 金风科技功率预测接口(通过 xhxt.chng.com.cn 拉取):power_forecast_client.pyforecast_d2d4.pyauth.py
hooks backend/hooks/ 钩子脚本目录
logs backend/logs/ 运行时日志
sider backend/sider/ PMOS 数据抓取与监控、Flask 大屏
submit backend/submit/ PMOS 自动批量申报:通过 CDP 连接 Chrome,自动填写 PMOS 网页表单并提交滚动撮合交易申报
slove backend/slove/ AI 电价预测核心:训练、预测、滚动验证、物理后处理、模型注册
spot backend/spot/ 现货/滚动撮合/中长期业务核心:模型、API、服务、策略信号、Python 规则引擎、偏差回收、策略回测
system backend/system/ RBAC 基础平台:用户、登录、菜单、角色、部门、字典、文件、代码生成、日志、Celery 任务
trading backend/trading/ 通用滚动套利核心:rolling_arb_core/(信号、状态机、Walk-Forward 回测)、spot_adapter.py(SpotSignalProvider)、spot_config.py
workflow backend/workflow/ 工作流引擎
xhxtapi backend/xhxtapi/ 现货系统数据代理:server.py(FastAPI,端口 12345)、client.pydaily_clearing_calculator.py(日清分计算)
feishu backend/feishu/ 飞书机器人集成:长连接消息处理、PMOS 在线表格推送、群公告管理

3. Slove:AI 电价预测模块

3.1 职责

slove 负责新疆日前现货电价预测,输出 D+1~D+4 共 384 点(15 分钟粒度),包含训练、生产预测、滚动验证、物理后处理、真实电价回填。

3.2 核心入口文件

文件 作用
backend/slove/train_xinjiang.py 模型训练入口:加载历史数据,训练特征工程 + 4 个 horizon 的 MinimalL3 模型 + 物理后处理 + 稀缺校正
backend/slove/predict_xinjiang.py 生产预测入口:加载 outputs/models/current 下模型,逐 horizon 自回归预测,输出 CSV
backend/slove/wfv_xinjiang.py Walk-Forward Validation:对每个 anchor 日期重新训练并预测 D+1~D+4,输出 MAE 到 outputs/wfv_xinjiang.csv
backend/slove/actual_price_backfill.py xhxtapi 拉取真实日前出清电价,回填 spot.PriceForecastRecord.actual_price
backend/slove/update_from_api.py 从 API 拉取市场供需、负荷预测数据,生成 training_data/新疆合并数据.json(已从 xlsx 改为 JSON 单文件全量)
backend/slove/model_registry.py 模型目录管理,按周归档/滚动模型

3.3 核心算法子模块(backend/slove/src/

文件 作用
snapshot_builder.py 从 Excel 合并数据构建预测 snapshot
stateful_fe.py 有状态特征工程,按月份/星期/小时的历史同期中位数填充
minimal_l3.py horizon L3 预测模型(当前主力,仅新疆使用),内含 _apply_recency_weight 近期样本加权
physics_postprocess.py 物理一致性后处理:零价闸门、尖峰闸门、价格上下限
morning_scarcity_calibrator.py 凌晨/晚高峰稀缺时段偏置校正
walk_forward.py 通用 WFV 协议与可视化
api_data_fetcher.py 现货系统数据拉取器

3.4 模型存储结构

backend/slove/outputs/models/
└── current/           # 当前生产模型(7 个 .pkl + metadata.json),每天10:00自动训练更新
    ├── xinjiang_fe.pkl
    ├── xinjiang_h1_l3.pkl    # horizon 1 模型
    ├── xinjiang_h2_l3.pkl    # horizon 2 模型
    ├── xinjiang_h3_l3.pkl    # horizon 3 模型
    ├── xinjiang_h4_l3.pkl    # horizon 4 模型
    ├── xinjiang_morning_calib.pkl
    ├── xinjiang_physics.pkl
    └── metadata.json         # 训练元数据(样本范围、训练时间等)

3.5 与 spot 的交互

slove 预测流程:

训练/预测任务 ──→ slove/train_xinjiang.py / predict_xinjiang.py


            输出 D+1~D+4 384 点电价


      写入 spot.PriceForecastRecord


       spot.api 提供给前端 dashboard / 滚动撮合页面


       actual_price_backfill.py 反向回填真实电价

4. Spot:滚动撮合与交易模块

4.1 数据模型

模型 说明
SpotStation 场站:名称、编码(外部API机组ID)、容量、省份、城市、机制比例、station_type(wind/solar)、branch_company(分公司)、trader(交易员)、unit_ids(JSON机组ID列表)、generation_mapping(预测电量映射)
RehearsalScenario 中长期模拟方案
RehearsalContract / RehearsalContractHourly 中长期合同及 24 点明细
SpotRollingContract 滚动撮合合同
SpotTradeOperation 交易操作流水
SpotRollingResult 滚动撮合结果(预测/实际收益)
SpotRollingStrategyResult 滚动撮合策略信号结果(24 小时)
SpotRollingStrategyTrade 策略执行/模拟交易记录
RollingStrategyRule Python 策略规则
PriceForecastRecord 电价预测记录(slove/官方/真实电价)
MonthlySpotPrice [新增] 月度中长期预测价格录入(24时点,支持日覆盖覆盖月度默认值)
DeviationRecoveryResult [新增] 偏差回收测算结果(含 24 时点明细)
SpotRollingStrategyBacktest [新增] 策略回测记录
RevenueDaily 日收益汇总
SettlementPrice 结算价格

4.2 核心服务

RehearsalCalculationServicebackend/spot/services.py

中长期合同日分解、24 点汇总、加权均价、可用容量约束计算。

SpotRollingTradeServicebackend/spot/services.py

方法 作用
create_contract_simulate() 生成模拟合同,申报编码格式 `YYYYMMDDHH{s
execute_trade() 执行 BUY/SELL,更新合同当前电量/电价/调整量
calculate_revenue_forecast() 收益预测
calculate_revenue_bounds() 收益边界
sync_from_external_api() 从外部 API 同步真实合同

RollingMarketViewServicebackend/spot/services.py

构建 24 点市场视图,聚合:

  • 滚动合同当前持仓
  • 中长期真实数据
  • PMOS 买/卖一价/量
  • slove / 官方电价预测
  • 预测发电量
  • 火电趋势特征

RollingStrategyServicebackend/spot/strategy_service.py

统一策略信号生成入口,协调市场视图构建、信号注入、Python 规则链式执行、收益计算。

DeviationRecoveryServicebackend/spot/deviation_recovery_service.py[新增]

偏差回收机制测算,计算 24 时点持仓率、触发判定、回收金额:

  • 持仓率 = Q中长期 / Q实际上网
  • 合理区间:[max(0, 0.8 - 机制比例), 1.2 - 机制比例]
  • 持仓不足/过多 + 价格方向一致 → 触发回收
  • 支持 full_month(全月外推)和 d_minus_1(D-1口径)两种计算模式

BacktestServicebackend/spot/backtest_service.py[新增]

策略历史回测服务,支持标准/高级信号模式回测,计算总收益、年化收益、夏普比率、最大回撤、胜率等指标。

SimpleBacktestServicebackend/spot/simple_backtest_service.py[新增]

简单模式回测与参数择优,遍历多组参数组合寻找最优策略配置。

4.3 辅助服务

文件 职责
signal_provider.py 封装 trading.spot_adapter.SpotSignalProvider,将高级信号转换为 dict 注入到市场上下文中
risk_assessment.py 风险评估服务,输出 LOW/MEDIUM/HIGH 等级
prediction_accuracy.py 电价预测准确率计算(MAE/RMSE/方向准确率)
prediction_confidence.py 预测置信区间服务
pmos_realtime.py PMOS 实时价格服务
powerplant_mapping.py 场站-发电厂预测电量映射

4.4 滚动交易数据流

外部数据
  ├── xhxtapi:中长期合同数据
  ├── PMOS Excel:实时报价排名
  ├── slove:日前电价预测
  └── gwapi:金风科技场站功率预测/实测电量(经 xhxt 接口)


  RollingMarketViewService.build_market_view()


  RollingStrategyService.generate_signals()


  PythonRuleService.execute() 逐小时执行规则


  生成 SpotRollingStrategyResult(24 点信号)


  前端可执行交易 → SpotTradeOperation → 更新 SpotRollingContract

5. Python 规则引擎

注:项目已彻底移除 Lua 执行栈,全部策略规则通过 Python 脚本执行。

5.1 核心文件

文件 职责
backend/spot/python_engine.py Python 脚本沙箱执行引擎:execute_python_script() 通过子进程 -m spot.python_worker 执行脚本,各请求线程独立 worker,带超时与错误处理
backend/spot/python_worker.py 独立 worker 子进程(__main__ 入口),从 stdin 逐行读取 JSON 脚本并执行,输出结果 JSON
backend/spot/python_rule_service.py 规则匹配、链式执行、默认规则管理(PythonRuleService 类)
backend/spot/python_defaults.py 默认脚本字符串:DEFAULT_STANDARD_PYTHON_SCRIPTDEFAULT_ADVANCED_PYTHON_SCRIPT、规则模板
backend/spot/python_strategy.py 策略接口封装:PythonStrategyExecutor 继承 PythonRuleService,添加策略级方法;统一导出 get_default_scriptsget_rule_templates
backend/spot/strategy_service.py 统一策略信号生成服务 RollingStrategyService
backend/spot/signal_provider.py 封装 trading.spot_adapter.SpotSignalProvider,将高级信号转换为 dict 注入到市场上下文中

5.2 规则模型 RollingStrategyRule

字段 含义
name 规则名称
signal_mode all / standard / advanced
rule_type full(完整策略) / post_override(后置覆盖)
priority 优先级,数字小的先执行(升序),相同 priority 按创建时间倒序
enabled 是否启用
station_ids 生效场站列表,空表示全局
target_date_start / target_date_end 生效日期范围
hour_start / hour_end / hours 生效时段
python_script Python 策略脚本
params 规则参数 JSON

5.3 信号生成流程

RollingStrategyService.generate_signals(
    target_date, station_id, signal_mode
)


RollingMarketViewService.build_market_view()


if signal_mode == 'advanced':
    SignalProviderService.generate()  # 注入 rolling_arb_core 信号


逐小时构造 market 上下文


PythonRuleService.execute(station_id, target_date, hour, signal_mode, market)


匹配规则 → 按 priority 排序 → 链式执行


规则脚本 decide_action(...) 返回 {action, target_qty, trade_price, reason}


_compute_action_revenue() 计算收益


批量写入 SpotRollingStrategyResult

5.4 规则链执行细节

PythonRuleService.execute() 逻辑:

  1. 调用 match_rules() 按场站、日期、时段、signal_mode 筛选启用规则;
  2. 若未匹配到规则,自动使用默认规则(standardadvanced);
  3. priority 升序执行(数字小的先执行);
  4. 第一条规则的 default_action 为空,后续规则使用上一条结果;
  5. 任意规则执行失败不会中断,返回 HOLD 并记录错误原因;
  6. 返回最终结果、最后匹配规则、所有生效规则名。

脚本约定:

def decide_action(market, config, hour, target_date, station_id, station_code, default_action):
    # ...
    return {
        'action': 'BUY' | 'SELL' | 'HOLD',
        'target_qty': float,
        'trade_price': float,
        'reason': str,
        'predicted_ref_price': float,      # 可选
        'reference_price_source': str,     # 可选
    }

6. 偏差回收机制 [新增]

6.1 核心概念

偏差回收机制基于新疆电力市场中长期持仓率考核规则,当场站持仓率越界且价格方向一致时,触发偏差收益回收。

6.2 关键公式

持仓率 = Q中长期 / Q实际上网

合理区间:
  下限 = max(0, 0.8 - 机制比例 m)
  上限 = 1.2 - 机制比例 m

持仓不足(under):持仓率 < 下限
持仓过多(over) :持仓率 > 上限

6.3 触发判定

  1. Q实际上网 ≤ 0 → 不触发
  2. 持仓率在合理区间内 → 不触发
  3. 持仓率越界 + 价格方向一致 → 触发

价格方向一致性判定:

  • Q中长期=0(无合同):仅看全网,持仓不足需 P中长期(全网) < P日前(全网)
  • 有合同:需自己+全网方向都一致
    • 持仓不足:P中长期(自己) < P日前(自己) 且 P中长期(全网) < P日前(全网)
    • 持仓过多:P中长期(自己) > P日前(自己) 且 P中长期(全网) > P日前(全网)

6.4 回收金额计算

持仓不足(under):
  R = (P日前(全网) − P中长期(全网)) × ((0.8−m)×Q实际上网 − Q中长期) × K

持仓过多(over):
  R = (P中长期(全网) − P日前(全网)) × (Q中长期 − (1.2−m)×Q实际上网) × K

回收系数 K = 1
全月回收总额 = Σ24时点 R

6.5 数据来源

字段 来源
Q中长期 xhxtapi 中长期合同数据(contractEle)+ 本库滚动撮合合同调整量,区间 [月初, D-1]
Q实际上网 gwapi 全月预测发电量(full_month 口径含 D+3 外推,d_minus_1 口径仅用实测)
P日前(全网) xhxtapi 市场供需汇总 totalAvgClearingPriceRt,[月初, D-1] 日均
P中长期(全网) MonthlySpotPrice 手动录入表(支持日覆盖覆盖月度默认值)
P日前(自己) xhxtapi 日清分明细,省内日前电量加权电价
P中长期(自己) 复用高级信号 contract_price(合同电量加权)

7. 数据接入层

7.1 PMOS 抓取(backend/sider/

文件 作用
scrape_pmos.py Playwright CDP 连接 Chrome(localhost:9222),从 PMOS 网站提取表格到 pmos_table_data.xlsx
scrape_pmos_monitor.py 每 60 秒监控所有日期标签页,提取最新价、买1/卖1 价量,追加到 pmos_data.xlsx
api.py Django Ninja API:/api/sider/* 提供 sheet 列表、报价、排名、K线、统计、预警
dashboard/app.py Flask 大屏服务(端口 5000),可选启动

7.2 xhxtapi(现货系统)

文件 作用
backend/xhxtapi/server.py FastAPI 服务(端口 12345),接收自然语言指令,代理查询现货系统各类市场数据
backend/xhxtapi/client.py Python 客户端,封装登录、会话刷新、各类查询
backend/xhxtapi/apis.json 接口配置(dsId、timeDeltaEnum、默认参数)
backend/xhxtapi/daily_clearing_calculator.py 日清分结算计算引擎,拉取日清分明细 + 日前统一电价,计算各市场结算结果。与 spot/api.py nlq_daily_clearing 共用同一套逻辑

API 端点

端点 方法 作用
/query POST 通用数据查询,自然语言 → 现货系统数据
/clearing POST 日清分结算查询,支持按场站/交易员/分公司维度过滤
/health GET 健康检查
/refresh POST 手动刷新登录态

/clearing 日清分结算

接收自然语言指令,自动解析场站/交易员/分公司维度,支持多种日期格式:

  • 维度匹配:从 SpotStation 表动态解析场站名、交易员、分公司
  • 日期支持YYYY-MM-DDYYYY-MM月、今天/昨天/最近N天
  • 市场类型:总体结算(含考核)、日前市场、实时市场、省内中长期、省间中长期、省间日前、省间日内
  • 可选参数:合计(汇总)、剔除考核(去除考核回收项)
  • 场站匹配:双向模糊匹配,支持简称如"新特1期"→"乌鲁木齐新特发电有限责任公司(新特盐湖西风电一场一期)",数字/中文互转

示例指令:

查询贾赛交易员2026-06月日清分结算数据
查询新特1期场站昨天日清分总体结算
查询清能分公司最近3天中长期市场合计

7.3 gwapi(金风科技功率预测)

文件 作用
backend/gwapi/power_forecast_client.py 登录 xhxt.chng.com.cn,按 powerplant_id 获取近期准确率排名第一的短期预测电量(金风科技),支持多场站合并、24 点聚合
backend/gwapi/forecast_d2d4.py D+2~D+4 金风预测电量示例

注:预测发电量已改为使用 observation(实测电量)接口 get_observed_energy_for_powerplants,而非 forecast 接口。

7.4 飞书机器人(backend/feishu/

文件 作用
feishu_handler.py 飞书消息处理:解析群聊事件、提取查询指令、调用 xhxtapi、回复结果。支持上下文统计(平均值/最大值/最小值/总和/中位数)
feishu_config.py 飞书配置:凭证、Token 缓存、消息回复、在线表格 CRUD、群公告更新
pmos_notify.py PMOS 市场监测定时推送:每 5 分钟读取 pmos_data.xlsx,创建飞书在线表格并发送链接到群
start_all.py 统一启动器:同时管理 xhxtapi、feishu bot、PMOS 推送的启停
feishu_bot.py 飞书长连接模式(WebSocket),接收并分发事件
bot_server.py 飞书事件回调 HTTP 服务器(事件接收、URL 验证)

消息处理流程

飞书群 @MLPT_AI 消息


feishu_bot.py 接收事件


feishu_handler.py.handle_message()

    ├── 日清分查询 → POST http://127.0.0.1:12345/clearing
    │       │
    │       ├── > 10 条 → 导出飞书在线表格(_send_clearing_sheet)
    │       └── ≤ 10 条 → 文本回复

    ├── 统计查询 → 从上下文缓存计算 平均值/最大值/最小值/总和/中位数

    └── 其他查询 → POST http://127.0.0.1:12345/query

            ├── 在线表格模式 → 创建飞书表格 + 图表
            ├── 图表模式 → 发送折线图
            ├── CSV 模式 → 发送文件
            └── 默认 → 文本回复

PMOS 推送

pmos_notify.py 每 5 分钟(00, 05, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55 各整分时刻):

  1. 读取 backend/sider/pmos_data.xlsx 各标的日 Sheet
  2. 每个标的日取各时段最后一行:最新价(PMOS 最新成交价字段,为空/"-"时视为 0)和成交价((买1价+卖1价)/2,仅用于推送展示)
  3. 创建飞书在线表格,每标的日一个 Sheet
  4. 发送表格链接到群 TARGET_CHAT_ID

7.5 Celery 任务调度

  • 配置backend/application/celery.py
    • broker:sqlalchemy+mysql://...
    • 结果后端:django-db
    • scheduler:django_celery_beat
  • 核心任务backend/spot/tasks.py
    • run_price_prediction_rebuild:每天 10:00 训练模型并预测 D+1~D+4
    • backfill_actual_prices:回填真实电价
    • run_rolling_strategy_backtest:滚动策略回测

8. PMOS 自动批量申报 (backend/submit/)

8.1 功能概述

通过 Chrome DevTools Protocol (CDP) 连接已登录的 PMOS 平台,自动化完成滚动撮合交易的批量申报。根据合同对应的单个时段(SpotRollingContract.target_hour),自动在 PMOS 网页表单 #multipleTable 中填写电量、电价、买卖方向,并提交至平台。

8.2 申报流程

1. 选择标的日期 Tab    ── select_date_tab()
   ├─ 匹配 .el-tabs__item 文本中的日期
   ├─ 点击 Tab 后等待 networkidle + 验证 is-active 状态
   └─ 验证 active tab 日期与目标日期一致

2. 选择交易单元         ── select_trading_unit()
   └─ 通过 input / __vue__ 实例设置 Element UI el-select

3. 点击"批量上报"       ── click_batch_report()
   ├─ 点击前验证当前 active tab 日期是否正确
   ├─ 检查按钮是否被禁用(11:00-15:00 限制)
   └─ 等待弹窗 networkidle + 3s 渲染

4. 填写网页表单         ── fill_web_form()
   ├─ 第一步:勾选复选框 + 填写电量/电价输入框
   └─ 第二步:设置买卖方向(td[6]/div 内的买入/卖出选项)

5. 提交申报             ── submit_declaration()
   ├─ dry_run=True → 跳过提交
   └─ dry_run=False → 定位提交按钮(当前已禁用点击,需手动启用)

8.3 PMOS 网页表单结构

表格 ID:#multipleTable

列 (td 索引) 说明
td[1] (index=0) 复选框(需勾选)
td[2] (index=1) 时段文字,格式 段1(00:00-00:00)
td[6] (index=5) 买卖方向(第一个=买入,第二个=卖出)
td[7] (index=6) 挂牌电量输入框
td[8] (index=7) 挂牌电价输入框

时段匹配:段Nhour = N - 1data_by_hour[str(N-1)],每个合同只提交其 target_hour 对应的单个时段。

8.4 CDP 并发锁机制

sider 监控脚本(每 60 秒切换所有日期 Tab)和 submit 提交脚本共用同一个 Chrome CDP,通过文件锁 .cdp_submit.lock 协调:

  • submit 提交run_full_flow 开始时创建锁文件,finally 中删除
  • sider 监控:每轮循环开始检查锁文件,存在则跳过本轮

8.5 API 接口

端点 方法 作用
/api/submit/pmos/{uuid:contract_id}/ POST 单合同申报(传入 target_date, station_id, dry_run)
/api/submit/pmos/batch/ POST 批量申报(遍历指定日期所有 approved 合同)
/api/submit/pmos/status/{uuid:contract_id}/ GET 查询合同 PMOS 提交状态
/api/submit/pmos/cdp-status/ GET 检查 Chrome CDP 连接状态

8.6 配置项

# settings.py
PMOS_CDP_ENDPOINT = 'http://localhost:9222'
PMOS_TARGET_URL_PATTERN = 'pmos.xj.sgcc.com.cn'
PMOS_FRAME_URL_PATTERN = 'pxf-trade-auction-extranet'
PMOS_TRADING_UNIT_ID = ''       # 交易单元 ID
PMOS_TRADING_UNIT_NAME = ''      # 交易单元名称
PMOS_MARKET_MEMBER_ID = ''      # 市场主体 ID
PMOS_MARKET_MEMBER_NAME = ''     # 市场主体名称
PMOS_MARKET_MEMBER_TYPE = '10'  # 市场主体类型

8.7 关键文件

文件 职责
backend/submit/pmos_submitter.py 自动化核心逻辑(PMOSSubmitter 类,CDP 连接、Tab 切换、表单填写、提交)
backend/submit/views.py REST API 视图(4 个端点,申报数据构建)
backend/submit/urls.py Ninja Router 导出
backend/submit/README.md 模块详细文档

9. 前端与部署

9.1 前端技术栈

  • 框架:Vue 3 + TypeScript + Vite
  • UI:Ant Design Vue + Vben Admin
  • 状态:Pinia
  • HTTP:Axios 封装 defHttp
  • 包管理:pnpm workspace + turbo

9.2 关键目录

目录 作用
web/src/api/spot/ spot 业务 API 封装
web/src/views/spot/rolling/ 滚动撮合页面(交易监控/日融合合同/标准策略信号/高级策略信号/策略配置/策略回测/偏差回收)
web/src/views/spot/station/ 场站管理页面(增删改查 + Excel 导入导出)
web/src/views/spot/dashboard/ 仪表盘
web/src/views/spot/utils/export.ts 表格导出 Excel 工具
web/src/views/spot/rolling/rolling-theme.css 滚动撮合模块科技蓝统一主题(设计令牌 + 工具类)
web/src/components/CodeEditor/ 代码编辑器组件(CodeMirror 6)
web/src/components/Excel/ Excel 导入导出组件(ImpExcel / ExpExcelModal
backend/static_web/ Vite 构建直接输出目录,Django 静态文件服务根目录

9.3 前端页面结构(web/src/views/spot/rolling/

文件 页面 功能
index.vue 交易监控主页 共享筛选(场站/标的日期)+ Tabs 导航
monitor/index.vue 交易监控 24 时点市场视图、PMOS 报价、持仓汇总
RollingAdjustment.vue 日融合合同 滚动撮合合同管理(新建/审批/收益预测/策略推荐)
StrategySignals.vue 标准策略信号 标准模式 24 时点信号 + 统计卡片 + 应用交易
StrategySignalsAdvanced.vue 高级策略信号 高级模式 24 时点信号(含 rolling_arb_core 7 信号)
PythonRules.vue 策略配置 Python 规则脚本管理(CodeMirror 编辑器)
StrategyBacktest.vue 策略回测 历史回测任务管理 + 收益指标 + 图表
DeviationRecovery.vue 偏差回收 偏差回收测算 + 24 时点明细 + 价格录入

9.4 前端统一主题

rolling-theme.css 提供共享设计令牌和工具类,被 rolling/ 下所有页面通过 @import 引入:

  • 设计令牌--tech-primary(#2563eb)、--tech-text-secondary--tech-radius-*--tech-shadow-*
  • 工具类.tech-stat-card(数据卡片)、.tech-form-label(表单标签)、.tech-toolbar(工具栏容器)、.tech-btn(按钮)等
  • 统一风格:所有 spot/ 页面的工具栏标签、统计卡片、表格表头、按钮均使用科技蓝风格

9.5 部署方式

  • 生产构建:Remove-Item -Recurse -Force node_modules/.vite; pnpm build --emptyOutDir
  • 静态文件:Vite outDir 已配置指向 ../backend/static_web,构建后无需手动拷贝
  • Django 在 ENV='win' 时将其加入 STATICFILES_DIRS
  • backend/application/urls.py 中的 serve_static_or_index 提供静态文件服务,并 SPA fallback 到 index.html

9.6 start_all.py 服务组合

编号 服务 端口 说明
1 Django 8000 Web/API
2 Web Dev 5173 Vite 开发服务器
3 Celery Worker - 异步任务
4 Celery Beat - 定时任务调度
5 PMOS 监控 - 每60秒抓取 PMOS 买1/卖1数据(与 submit 共享 CDP,通过 .cdp_submit.lock 文件锁互斥)
6 Flask 大屏 5000 PMOS 数据大屏(可选)
7 xhxtapi 12345 现货系统数据查询 + 日清分计算
8 飞书机器人 - 长连接消息处理
9 PMOS 推送 - 每5分钟推送在线表格到飞书群

预设组合:

  • core:1, 4, 5
  • web:1, 2, 4, 5
  • feishu:7, 8, 9
  • all:1, 2, 3, 4, 5, 7, 8, 9

注:根目录 start_all.py (交互式) 和 backend/feishu/start_all.py (命令行) 是两套启动器, 前者管理全体服务,后者专注于 xhxtapi + feishu + PMOS 推送的组合。


10. 目标电量(target_qty)计算逻辑

注:以下为标准/高级模式的策略逻辑简化概述。实际实现以 backend/spot/python_defaults.pyDEFAULT_STANDARD_PYTHON_SCRIPTDEFAULT_ADVANCED_PYTHON_SCRIPT 为准, 逻辑比下文更复杂(含组合价差、强制机制修正、月度累计机制等)。

10.1 整体流程

每个时段执行策略计算:

  1. 匹配生效的 Python 规则;
  2. priority 升序执行规则链;
  3. 规则脚本返回 decide_action(...) 结果;
  4. 最终 target_qty 用于计算新合同量、均价、收益。

10.2 机制比例(mechanism_ratio)

SpotStation.mechanism_ratio 表示机制电量占比(0~1)。

标准模式:逐日/逐时机制

standard 信号模式下,默认脚本按当前小时/日的预测发电量计算机制边界:

mechanism_floor   = max(0.0, sell_qty_gen_ratio_min - mechanism_ratio)  # 默认 sell_qty_gen_ratio_min=0.8
mechanism_ceiling = max(0.0, sell_qty_gen_ratio_max - mechanism_ratio)  # 默认 sell_qty_gen_ratio_max=1.2
position_floor    = mechanism_floor * predicted_generation
position_ceiling  = mechanism_ceiling * predicted_generation
  • 实际仓位比例 < mechanism_floor> mechanism_ceiling 时,视为纳入机制。
  • mechanism_ratio=0.3 时,下界为 0.5,上界为 0.9mechanism_ratio=0.9 时,下界为 0,上界为 0.3

高级/CAR 模式:月度累计机制规则见 docs/plans/trading.md,当前尚未开发完成。README 中仅记录已落地的标准模式。

自定义脚本

自定义脚本应读取 market['mechanism_ratio'],并按当前模式选择日/时或月度累计口径应用边界逻辑。标准模式默认脚本已实现上述机制 guard。

10.3 Standard 模式目标电量

默认脚本:DEFAULT_STANDARD_PYTHON_SCRIPT

核心信号(默认 direction_signal_source='market_spread'):

predicted_ref_price = slove_price  official_price reference_price_source 决定
contract_spread      = contract_price - predicted_ref_price
market_spread        = pmos_latest_price - predicted_ref_price
combined_spread      = contract_spread + market_spread_weight * market_spread

关键pmos_latest_price 为空/"-"/None 时视为 0,此时 market_spread = 0 - predicted_ref_price = -predicted_ref_price(负值 → 触发买入)。

方向信号由 direction_signal_source 选择(默认 market_spread):

  • direction_signal < buy_threshold(默认 -10,即市场价差低于 -10 元才触发:PMOS 最新成交价明显低于预测结算价)→ BUY,买入量 = contract_qty(买回至零仓位),交易价取 pmos_sell_price
  • direction_signal > sell_threshold(默认 15,即市场价差高于 15 元才触发:PMOS 最新成交价明显高于预测结算价)→ 比较实际仓位与偏差考核目标 predicted_generation * (0.8 - mechanism_ratio)
    • 仓位 < 目标 → SELL 补齐,交易价取 pmos_buy_price
    • 仓位 > 目标 → BUY 压降,交易价取 pmos_sell_price
  • -10 ≤ direction_signal ≤ 15HOLD(误差带死区,过滤预测不准的小波动)

强制偏差考核修正(在方向信号判断之前执行,最高优先级):

  • actual_qty < position_floor → 强制 SELL 补齐至偏差考核下界 mechanism_floor * predicted_generation
  • actual_qty > position_ceiling → 强制 BUY 压降至偏差考核上界 mechanism_ceiling * predicted_generation

10.4 Advanced 模式目标电量

默认脚本:DEFAULT_ADVANCED_PYTHON_SCRIPT

依赖 rolling_arb_core 生成的 7 个原始信号(info_gapre_surprisemomentummarket_spreadprice_volatilityforecast_deviationthermal_quantity), 在脚本内按可配置权重合成 composite(综合信号),再通过 tanh(composite * k) 映射为目标仓位比例。

核心逻辑:

  • abs(composite) < min_signal_strengthHOLD
  • composite > 0(看多)且 pmos_buy_price 可用 → SELL,卖出量 = min(qty_ratio * max_sell_qty, position_ceiling - month_contract_qty, pmos_buy_qty)
  • composite < 0(看空)且 pmos_sell_price 可用 → BUY,买入量 = min(qty_ratio * max_buy_qty, month_contract_qty - position_floor, pmos_sell_qty)
  • 月度累计机制:以月初至今的累计合约电量 month_contract_qty 为基准,约束在 [position_floor, position_ceiling]

注:引擎方向与现货交易方向相反(看多→卖出增仓,看空→买入减仓)。

10.5 后置覆盖规则(post_override)

rule_type='post_override' 读取上一条结果,只修改特定字段。例如默认覆盖模板会把 BUYtarget_qty 最低提升到 max(0, 0.8 - mechanism_ratio) * predicted_generation

10.6 可配置参数

参数 默认值 含义
reference_price_source 'slove' 参考电价来源
sell_qty_gen_ratio_min 0.8 偏差考核下界基数,实际下界 = max(0, 0.8 - mechanism_ratio)
sell_qty_gen_ratio_max 1.2 偏差考核上界基数,实际上界 = max(0, 1.2 - mechanism_ratio)
market_spread_weight 1.0 市场价差在组合价差中的权重(仅当 direction_signal_source='combined_spread' 时生效)
min_signal_strength 0.0 advanced 最小信号强度
max_position 0.5 advanced 最大目标仓位比例
tanh_k 3.0 advanced tanh 压缩系数
mechanism_scope 'daily' advanced 机制范围: daily / monthly

10.7 常见误区

误区 实际逻辑
市场价差 < 0 就买 买入量 = contract_qty(买回至零仓位),不是依据价差比例计算
市场价差 > 0 就卖 仅在实际仓位低于偏差考核目标 predicted_generation * (0.8 - mechanism_ratio) 时卖出补齐
最新成交价为空就不交易 空值/"-"视为 0,价差 = 0 - predicted_ref_price = -predicted_ref_price(负值仍触发买入)
最新成交价 = 买1卖1均价 最新成交价是 PMOS 的"最新价"字段;(买1价+卖1价)/2 是推送飞书表格里的"成交价"列,仅用于展示
卖出量 = (预测发电量 - 合同量) * 0.8 卖出量 = 偏差考核目标 predicted_generation * (0.8 - mechanism_ratio) - actual_qty,不乘比例
机制比例只影响标准模式 Advanced 模式也有月度累计机制约束 [position_floor, position_ceiling]

10.8 自定义规则示例

实现"市场价差 < 0 买入(最新成交价为空视为 0);价差 > 0 按偏差考核目标仓位调整":

DEFAULT_PARAMS = {
    'reference_price_source': 'slove',
    'sell_qty_gen_ratio_min': 0.8,
    'sell_qty_gen_ratio_max': 1.2,
    'market_spread_weight': 1.0,
}


def to_number(v, default_val=0):
    if v is None:
        return default_val
    try:
        return float(v)
    except Exception:
        return default_val


def decide_action(market, config, hour, target_date, station_id, station_code, default_action):
    params = dict(DEFAULT_PARAMS)
    params.update(config.get('rule_params', {}) or {})

    predicted_ref_price = market.get('slove_price')
    if params['reference_price_source'] == 'official':
        predicted_ref_price = market.get('official_price')
    predicted_ref_price = to_number(predicted_ref_price, None)
    if predicted_ref_price is None:
        return {'action': 'HOLD', 'target_qty': 0, 'trade_price': None,
                'reason': '预测参考电价缺失,持有不动'}

    contract_qty = to_number(market.get('contract_qty'), 0)
    actual_qty = to_number(market.get('actual_qty'), 0)
    predicted_generation = to_number(market.get('predicted_generation'), 0)
    mechanism_ratio = to_number(market.get('mechanism_ratio'), 0)
    pmos_buy_price = market.get('pmos_buy_price')
    pmos_sell_price = market.get('pmos_sell_price')
    pmos_latest_price = market.get('pmos_latest_price')

    mechanism_floor = max(0.0, params['sell_qty_gen_ratio_min'] - mechanism_ratio)
    mechanism_ceiling = max(0.0, params['sell_qty_gen_ratio_max'] - mechanism_ratio)
    position_floor = mechanism_floor * predicted_generation
    position_ceiling = mechanism_ceiling * predicted_generation

    # 偏差考核强制修正:仓位越界先修正
    if actual_qty < position_floor and pmos_buy_price is not None:
        qty = position_floor - actual_qty
        return {'action': 'SELL', 'target_qty': qty, 'trade_price': pmos_buy_price,
                'reason': '合同电量低于偏差考核下界(预测发电量%.1fMW×%.2f倍),强制卖出%.3fMW补齐' % (predicted_generation, mechanism_floor, qty)}
    if actual_qty > position_ceiling and pmos_sell_price is not None:
        qty = actual_qty - position_ceiling
        return {'action': 'BUY', 'target_qty': qty, 'trade_price': pmos_sell_price,
                'reason': '合同电量高于偏差考核上界(预测发电量%.1fMW×%.2f倍),强制买回%.3fMW压降' % (predicted_generation, mechanism_ceiling, qty)}

    # 市场价差信号:最新成交价为空/"-"时视为 0
    latest_val = to_number(pmos_latest_price, 0)
    market_spread = latest_val - predicted_ref_price

    if market_spread < 0 and pmos_sell_price is not None:
        return {'action': 'BUY', 'target_qty': contract_qty, 'trade_price': pmos_sell_price,
                'reason': '市场价差%.2f<0(最新成交价%.2f-预测参考价%.2f),买入%.2fMW' % (market_spread, latest_val, predicted_ref_price, contract_qty)}
    if market_spread > 0 and pmos_buy_price is not None:
        target = predicted_generation * (0.8 - mechanism_ratio)
        if actual_qty < target:
            qty = target - actual_qty
            return {'action': 'SELL', 'target_qty': qty, 'trade_price': pmos_buy_price,
                    'reason': '市场价差%.2f>0,仓位低于偏差考核目标%.3f,卖出%.3fMW补齐' % (market_spread, target, qty)}

    return {'action': 'HOLD', 'target_qty': 0, 'trade_price': None,
            'reason': '市场价差%.2f,持有不动' % market_spread}

_result = decide_action(market, config, hour, target_date, station_id, station_code, default_action)

11. 场站管理 [增强]

11.1 场站模型 SpotStation 字段

字段 类型 说明
name CharField(100) 场站名称
code CharField(50) 外部 API 机组 ID(唯一)
capacity DecimalField 装机容量(MW)
province / city CharField 省份 / 城市
mechanism_ratio DecimalField(0~1) 机制比例,用于计算偏差回收下限
station_type CharField 场站类型:wind(风电) / solar(光伏)
branch_company CharField 分公司(清能公司/南疆公司/东疆公司等),用于数据权限隔离
trader CharField 交易员姓名,用于数据权限隔离
unit_ids JSONField 外部 API 机组 ID 列表(支持一站多机)
generation_mapping JSONField 预测电量场站映射:[(powerplant_id, ratio), ...]
status CharField 状态:active(启用) / inactive(停用)

11.2 Excel 导入导出

  • 导出exportTableToExcel() 按表格列定义导出当前数据
  • 导入POST /api/spot/stations/import,按 code 字段匹配 upsert(已存在则更新,不存在则新建)
    • 支持字段:场站名称、外部API机组ID、装机容量、机制比例、省份、城市、类型(支持"风电"/"光伏")、分公司、交易员、状态(支持"启用"/"停用")
    • 返回 { total, created, updated, errors },逐行容错

11.3 数据权限

基于 system_user.data_scope 字段实现数据隔离:

data_scope 可见范围
all 全部场站(超管)
branch 本分公司场站(按 branch_company 过滤)
trader 本人负责场站(按 trader 过滤)

_filter_stations_by_user_scope()_get_user_allowed_station_ids() 在 API 层统一过滤。

成就
0
Star
0
Fork
成员(2)
Adam_lxd
ngqf666ya

搜索帮助