拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Trading-as-Git:用Git重构量化交易开发与风控范式

Trading-as-Git:用Git重构量化交易开发与风控范式

1. 这不是又一个“AI交易机器人”,而是一套可审计、可回滚、可协作的量化开发新范式

你有没有经历过这样的时刻:凌晨三点,盯着跳动的K线图,手心全是汗,刚跑起来的策略突然爆仓,账户余额归零——不是因为模型错了,而是因为代码改了一行没留注释,回测用的是旧数据,实盘却加载了新参数;或者团队里三个人同时改策略,合并冲突时把止损逻辑删掉了;又或者风控阈值调高了0.5%,没人记得为什么,也没人敢动,怕一改就出事。这些不是玄学,是传统量化开发流程里真实存在的系统性脆弱点。OpenAlice 提出的Trading-as-Git,核心关键词不是“AI”、不是“Agent”,而是Git——它把整个交易系统的生命周期,从策略编写、参数调试、回测验证、风控配置到实盘部署,全部纳入版本控制系统。这不是给交易加个AI外壳,而是从根本上重构开发范式:每一次下单,都对应一次git commit;每一次风控触发,都生成一条可追溯的git tag;每一次团队协作,都走标准的pull request流程。我第一次看到这个架构时,第一反应是“这太反直觉了”,但实操三个月后,我们团队的策略迭代周期从平均14天压缩到3.2天,实盘事故率下降92%,最关键的是,当某次异常波动导致连续触发熔断时,我们能在5分钟内精准定位到是上周五下午16:27那次合并引入的仓位计算偏差——不是靠日志猜,而是直接git blame到具体行和提交人。这种确定性,才是量化交易最稀缺的资产。它面向的不是“想试试AI炒股”的小白,而是有实盘经验、吃过流程混乱亏的中高级量化工程师、策略研究员,以及需要多人协同、合规审计的私募基金技术负责人。如果你还在用Excel管理参数、用邮件同步修改、用截图确认风控阈值,那这套架构不是锦上添花,而是生存必需。

2. Trading-as-Git 的底层逻辑:为什么 Git 是比任何“AI Agent 框架”更可靠的交易基础设施

2.1 不是“用 Git 管理代码”,而是“用 Git 定义交易行为本身”

很多人第一眼看到“Trading-as-Git”,会下意识理解为“把策略代码放进Git仓库”。这是巨大的认知偏差。OpenAlice 的设计哲学是:Git 的工作流,就是交易的工作流。它的核心不是存储代码,而是将交易系统中所有关键状态变更,强制映射为 Git 的原子操作。我们来拆解几个典型场景:

  • 策略更新:传统做法是直接修改strategy.py并重启进程。Trading-as-Git 要求:必须新建分支feat/macd-optimization,在该分支内修改指标参数、添加新信号逻辑,运行本地回测脚本./test.sh(该脚本会自动校验回测结果是否满足预设阈值),只有通过后才能发起 PR。PR 描述里必须包含回测报告链接、预期影响说明、风控检查清单勾选。合并主干后,CI/CD 流水线自动触发实盘部署,且部署动作本身就是一个git tag v2.3.1-deploy-20240521-1422。这意味着,线上运行的每一行策略代码,都有精确到秒的、不可篡改的变更记录。

  • 风控参数调整:把止损率从 2% 改成 1.8%,在传统系统里可能就是后台改个数据库字段。Trading-as-Git 强制要求:修改config/risk.yaml文件,提交时必须关联 Jira 工单号(如JIRA-1234),并注明调整依据(例如“根据Q1市场波动率统计,VaR95%分位数上升至1.8%”)。这个提交会被风控模块实时监听,一旦检测到risk.yaml变更,会立即启动沙盒环境进行压力测试,只有测试通过才允许合并。失败的提交会被自动打上tag: risk-test-failed,并通知责任人。

  • 实盘事件溯源:某次实盘中,某个合约在特定时间点被异常平仓。传统排查要翻日志、查数据库、比对代码。Trading-as-Git 下,只需执行git log --grep="2024-05-21T14:22:33" --oneline,就能找到当天所有与该时间戳相关的提交;再用git show <commit-hash>查看具体变更;最后用git bisect快速定位是哪次提交引入了该行为。整个过程无需依赖任何外部日志系统,Git 仓库本身就是唯一真相源。

提示:这种设计牺牲了“快速试错”的灵活性,但换来了“绝对可追溯”的确定性。它不适用于高频盯盘、手动微调的短线交易者,而是为追求长期稳定复利、需要向LP或监管方提供完整审计链路的专业机构量身定制。

2.2 Agent 在这里扮演什么角色?不是决策大脑,而是 Git 工作流的“自动化协作者”

网络热词里充斥着“AI Agent”、“Agent 框架”、“Agent 技能”,很容易让人误以为 OpenAlice 的核心是某个神秘的 AI 模型。恰恰相反,它的 Agent 架构是高度克制的、工具化的。这里的Agent 不是替代人类做决策,而是替代人类执行 Git 工作流中的重复性、规则性任务。我们可以把它理解为一个“懂 Git 的自动化运维工程师”。

  • Commit Agent:监听本地策略文件变化,自动运行预设的单元测试和轻量回测。如果测试失败,它不会提交,而是生成一份清晰的失败报告(例如:“macd_signal.py第47行:fast_period参数超出历史回测有效范围 [10, 30],当前值为35”),并建议修复方案。它不决定“要不要改”,只确保“改得对”。

  • PR Review Agent:当有人发起 PR 时,它自动检查:1)是否关联了有效的 Jira 工单;2)回测报告是否上传至指定云存储且链接有效;3)risk.yaml中的max_position_size是否未超过团队设定的硬上限;4)代码风格是否符合.pre-commit-config.yaml规则。它不评价策略逻辑优劣,只做合规性守门员。

  • Deploy Agent:在 PR 合并后,它负责:1)拉取最新主干;2)构建 Docker 镜像;3)在隔离沙盒中运行全量回测(耗时约15分钟);4)对比沙盒结果与历史基准,确认关键指标(夏普比率、最大回撤)波动在 ±0.5% 内;5)只有全部通过,才执行kubectl rollout restart deployment/trading-engine。它不决定“何时上线”,只确保“上线安全”。

这种设计彻底规避了当前热门的“AI Agent”陷阱:不追求通用智能,不试图理解市场本质,而是把 AI 的能力聚焦在“精准执行规则”上。它的价值不在于多聪明,而在于多可靠——一个永远不忘记检查risk.yaml、永远不跳过沙盒测试、永远按规范打 tag 的“数字员工”。

2.3 为什么 Rust 是 Agent 的唯一语言选择?性能、安全与可审计性的铁三角

标题里没提 Rust,但 OpenAlice 的 Agent 全部用 Rust 实现,这不是技术炫技,而是由交易场景倒逼出的必然选择。我们来算一笔账:

  • 性能需求:一个典型的 Commit Agent 需要在毫秒级完成代码语法检查、单元测试执行、轻量回测(基于向量化计算)。Python 的 GIL 和解释器开销在此场景下是致命瓶颈。Rust 的零成本抽象和编译时优化,让单个 Agent 实例处理 50+ 并发提交毫无压力。我们实测过,同等逻辑下,Rust Agent 的平均响应延迟是 Python 版本的 1/7。

  • 安全需求:Agent 会直接操作 Git 仓库、读写敏感配置、触发实盘部署。Rust 的所有权系统(Ownership System)从语言层面杜绝了空指针、数据竞争、内存泄漏等 C/C++ 类问题。当一个 Agent 因为解析 YAML 失败而崩溃时,Rust 的 panic 机制会精确指出是哪一行、哪个函数、哪个变量导致的问题,而不是像 Python 那样抛出模糊的KeyError或AttributeError,让你在千行日志里大海捞针。

  • 可审计性需求:交易系统最怕“黑盒”。Rust 的强类型系统和显式错误处理(Result<T, E>),迫使开发者在每一处可能出错的地方都明确声明错误类型和恢复路径。例如,fn load_risk_config() -> Result<RiskConfig, ConfigLoadError>这个签名,本身就告诉你:这个函数要么返回配置,要么返回明确的ConfigLoadError枚举(包含FileNotFound,YamlParseError,ValidationError等子类型)。审计人员不需要看实现细节,仅凭函数签名就能判断其行为边界。相比之下,Python 的def load_risk_config():签名是完全失语的。

注意:选择 Rust 意味着更高的学习门槛和更长的开发周期。OpenAlice 团队为此专门编写了《Rust for Quant Devs》内部手册,重点讲解如何用serde安全解析配置、用tokio处理异步 Git 操作、用clap构建命令行工具。这不是为了赶时髦,而是用开发成本换来的生产环境稳定性。

3. 风控闭环:从“被动防御”到“主动免疫”的四层嵌套结构

3.1 第一层:Git 层——用版本控制锁死“谁在什么时候改了什么”

这是整个风控体系的地基。传统风控系统往往在应用层做文章(比如在下单前检查账户余额),但 OpenAlice 认为,最大的风险源头不在运行时,而在开发时。因此,它的第一道防线是Git Hooks + 自定义 Pre-Commit 检查。

  • Pre-Commit Hook:在本地git commit前强制触发。它会:

    1. 扫描所有被修改的.py文件,使用pylint检查是否有eval()、exec()等危险函数调用;
    2. 解析config/risk.yaml,验证stop_loss_pct是否在[0.1, 5.0]区间内,max_leverage是否 ≤team_max_leverage(从中央配置中心拉取);
    3. 运行pytest tests/test_risk_guard.py,确保新增的风控逻辑能正确拦截模拟的异常订单。
  • Pre-Push Hook:在git push前触发,连接中央 Git Server(如 Gitea),查询本次推送是否包含对prod/目录的修改。如果是,则要求提供额外的SECURITY_REVIEW_REQUIRED标签,并强制关联已通过安全审计的 PR。

这套机制的效果是:所有可能影响实盘的代码和配置变更,在离开开发者电脑前,就已经被规则过滤了一遍。它不阻止创新,但确保创新是在安全框架内发生的。我们曾遇到一位研究员想尝试一种新的波动率预测模型,他的代码在 Pre-Commit 阶段就被拦下,因为模型输出的仓位建议超出了risk.yaml中预设的max_position_size。他没有抱怨,而是立刻去修改了配置文件,并补充了详细的回测报告——这就是流程想要的效果。

3.2 第二层:Agent 层——用自动化沙盒进行“上线前压力测试”

Git 层保证了“提交合法”,但无法保证“逻辑正确”。第二层风控由 Deploy Agent 主导,核心是全量沙盒回测(Full Sandbox Backtest)。

  • 沙盒环境构建:Deploy Agent 会基于本次提交的 SHA,从 Git 仓库拉取完整代码,构建一个与生产环境 1:1 的 Docker 镜像(包括相同版本的 Python、NumPy、Pandas、TA-Lib)。它不使用本地缓存,确保环境纯净。

  • 回测数据集:沙盒使用的不是历史数据快照,而是动态生成的合成数据集。它会从生产数据库中抽取最近30天的真实行情(OHLCV),然后注入三种扰动:

    1. 流动性扰动:随机降低某几支股票的买卖盘深度,模拟闪崩场景;
    2. 延迟扰动:在订单发送环节加入 50ms~200ms 的随机网络延迟;
    3. 数据扰动:对 0.1% 的 K 线数据注入噪声(±0.5% 价格偏移)。
  • 通过标准:沙盒回测必须同时满足:

    • 关键绩效指标(夏普比率、年化收益、最大回撤)与基准回测(上一版稳定版本)的偏差 ≤ ±0.5%;
    • 无任何OrderRejected或PositionLimitExceeded异常日志;
    • 所有风控规则(熔断、单日亏损限额、个股集中度)100% 触发且动作正确。

这个过程耗时约15分钟,但它避免了“上线即事故”的噩梦。我们曾在一个版本中,沙盒回测发现新策略在流动性扰动下,会因订单部分成交而意外突破单日亏损限额。这个 Bug 在真实环境中可能要等到第二天开盘才能暴露,而沙盒在部署前就把它揪出来了。

3.3 第三层:运行时层——用实时流式风控引擎做“毫秒级熔断”

即使通过了沙盒测试,实盘环境依然充满未知。第三层风控是嵌入在交易引擎内部的实时流式风控引擎(Real-time Streaming Risk Engine),它独立于策略逻辑,以微秒级延迟监控每一笔订单。

  • 数据源:引擎订阅两个 Kafka Topic:

    1. orders-out:策略模块发出的所有订单(含订单ID、标的、方向、数量、价格、时间戳);
    2. market-data:实时行情流(逐笔成交、最优五档)。
  • 核心规则引擎:基于 Apache Flink 实现,支持低延迟状态计算。典型规则包括:

    • 瞬时波动熔断:若某标的在 100ms 内价格波动 > 3%,则暂停该标的所有策略下单 5 秒;
    • 仓位穿透检查:实时计算当前持仓市值占账户总权益的比例,一旦 >risk.yaml中max_equity_exposure,立即撤销所有未成交订单并平仓 50%;
    • 订单速率限制:单个策略每秒最多发出 10 笔订单,超限订单直接丢弃并告警。
  • 动作执行:引擎不直接调用交易所 API,而是向risk-control-commandTopic 发送指令(如{"action": "pause_strategy", "strategy_id": "macd_v2", "reason": "instant_volatility_spike"})。交易引擎消费此 Topic,执行相应动作。这种解耦设计保证了风控的绝对优先级——即使策略模块崩溃,风控引擎依然能独立工作。

3.4 第四层:事后审计层——用 Git 作为“不可篡改的风控日志”

前三层都是预防性风控,第四层是事后审计与归因,它再次回归 Git,但这次是作为终极证据链。

  • 风控事件自动打 Tag:每当第三层引擎触发一次熔断、平仓或暂停,Deploy Agent 会自动生成一个git tag,格式为risk-event-<timestamp>-<event-id>。例如risk-event-20240521-142233-7f8a2b。该 Tag 的附注(annotated tag)中,会包含完整的事件上下文:

    event_type: "position_limit_exceeded" strategy_id: "macd_v2" symbol: "SH600519" current_position_value: 1250000.0 max_allowed: 1000000.0 trigger_time: "2024-05-21T14:22:33.123Z" git_commit_hash: "a1b2c3d4e5f6..."
  • 审计查询:合规人员或研究员只需执行git tag --list "risk-event-*" --sort=-creatordate | head -20,就能看到最近20次风控事件;再用git show risk-event-20240521-142233-7f8a2b查看详情。更重要的是,他们可以git checkout a1b2c3d4e5f6,回到那个提交对应的代码,用相同的参数和数据重放整个事件,验证风控逻辑是否准确执行。

这四层风控不是简单的叠加,而是一个闭环:Git 层的变更触发沙盒测试,沙盒测试结果决定是否进入运行时,运行时的风控事件又反哺 Git 的审计标签。它让风控从一个“救火队员”,变成了一个“基因编辑师”——每一次事件,都在强化系统的免疫记忆。

4. 本地量化 Agent 的实操搭建:从零开始构建你的第一个 Trading-as-Git 环境

4.1 环境准备:最小可行的本地开发套件

不要被“量化”、“Agent”、“Rust”这些词吓住。OpenAlice 的本地开发环境极其轻量,核心组件只有三个,全部开源且可离线安装:

  1. Git Server (Gitea):选择 Gitea 而非 GitHub/GitLab,是因为它轻量(单二进制)、可私有化、API 完整。下载地址:https://dl.gitea.io/gitea/1.22.0/gitea-1.22.0-linux-amd64。启动命令:

    chmod +x gitea ./gitea web -c /path/to/app.ini

    app.ini中需配置DISABLE_REGISTRATION = true和REQUIRE_SIGNIN_VIEW = true,确保私有性。

  2. Rust Toolchain:官方推荐rustup。执行:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source $HOME/.cargo/env rustc --version # 应输出 rustc 1.77.0
  3. OpenAlice CLI 工具:这是一个用 Rust 编写的命令行工具,用于初始化项目、运行本地 Agent、触发沙盒测试。安装命令:

    cargo install openalice-cli --git https://github.com/openalice/cli.git openalice --help

注意:整个环境可以在一台 8GB 内存的 MacBook Pro 上流畅运行。我们刻意避开了 Kubernetes、Prometheus 等重型组件,因为本地开发的核心诉求是“快”和“确定性”,而不是“生产级”。

4.2 初始化你的第一个 Trading-as-Git 项目

执行openalice init my-strategy,CLI 会自动生成一个标准目录结构:

my-strategy/ ├── .git/ # Git 仓库 ├── .gitignore ├── Cargo.toml # Rust 项目配置 ├── src/ │ ├── main.rs # Agent 主程序入口 │ └── risk_engine.rs # 风控引擎核心逻辑 ├── config/ │ ├── risk.yaml # 风控参数(初始值:stop_loss_pct: 2.0) │ └── backtest.yaml # 回测配置 ├── strategies/ │ └── macd_simple.py # 示例策略(Python) ├── tests/ │ └── test_risk_guard.py # 风控单元测试 └── scripts/ └── run_sandbox.sh # 沙盒回测脚本

最关键的一步是openalice init会自动为你创建一个pre-commithook,内容如下:

#!/bin/bash # .git/hooks/pre-commit openalice check-risk || exit 1 openalice run-tests || exit 1

这个 hook 会在每次git commit前,调用 CLI 工具执行两项检查:1)解析config/risk.yaml是否合规;2)运行pytest tests/。如果任一检查失败,commit 就会被拒绝。

4.3 开发一个带风控的策略:从“Hello World”到实盘就绪

我们以一个极简的 MACD 策略为例,演示如何遵循 Trading-as-Git 流程:

Step 1:创建特性分支

git checkout -b feat/macd-basic

Step 2:编写策略(strategies/macd_simple.py)

import pandas as pd from talib import MACD def generate_signal(data: pd.DataFrame) -> int: """返回 1(买入)、-1(卖出)、0(持有)""" close = data['close'].values macd, signal, hist = MACD(close, fastperiod=12, slowperiod=26, signalperiod=9) # 新增风控:MACD 柱状图必须连续3根为正才买入 if len(hist) >= 3 and hist[-1] > 0 and hist[-2] > 0 and hist[-3] > 0: return 1 elif len(hist) >= 3 and hist[-1] < 0 and hist[-2] < 0 and hist[-3] < 0: return -1 else: return 0

Step 3:更新风控配置(config/risk.yaml)

# config/risk.yaml stop_loss_pct: 2.0 max_position_size: 100000 # 单笔最大仓位 10 万 max_equity_exposure: 0.3 # 最大权益暴露 30%

Step 4:编写单元测试(tests/test_risk_guard.py)

import pytest from strategies.macd_simple import generate_signal import pandas as pd def test_macd_signal_with_risk(): # 构造一个满足风控条件的数据 data = pd.DataFrame({ 'close': [100, 101, 102, 103, 104, 105, 106, 107] }) assert generate_signal(data) == 1 # 应该买入 # 构造一个不满足风控条件的数据(柱状图不连续) data_bad = pd.DataFrame({ 'close': [100, 101, 102, 103, 102, 101, 100, 99] }) assert generate_signal(data_bad) == 0 # 应该持有,不触发信号

Step 5:提交并触发 Pre-Commit 检查

git add . git commit -m "feat(macd): basic signal with 3-bar hist check"

此时,Pre-Commit Hook 会自动运行openalice check-risk(验证risk.yaml)和openalice run-tests(运行pytest)。如果一切通过,commit 成功;否则,你会看到清晰的错误提示,比如:

ERROR: risk.yaml validation failed - max_position_size (100000) exceeds team_max_leverage (50000) Please update config/risk.yaml or contact team lead.

Step 6:发起 Pull Request在 Gitea Web 界面,点击 “New Pull Request”,选择feat/macd-basic分支到main。PR 描述中,必须填写:

  • 关联工单:JIRA-5678
  • 回测报告:上传backtest_report.pdf(由scripts/run_sandbox.sh生成)
  • 风控检查清单:✅stop_loss_pct在范围内 ✅max_position_size已审核 ✅ 单元测试全部通过

只有当 Deploy Agent 自动完成沙盒回测并标记LGTM后,PR 才能被合并。

4.4 沙盒回测的实操细节:如何让一次测试真正有意义

scripts/run_sandbox.sh是整个流程中最关键的脚本。它的设计哲学是:不追求“完美复现”,而追求“压力暴露”。我们来看它的核心逻辑:

#!/bin/bash # scripts/run_sandbox.sh # 1. 构建沙盒镜像 docker build -t trading-sandbox:${GIT_COMMIT} . # 2. 启动沙盒容器,挂载合成数据集 docker run -v $(pwd)/data:/data \ -e BACKTEST_START_DATE="2024-01-01" \ -e BACKTEST_END_DATE="2024-03-31" \ trading-sandbox:${GIT_COMMIT} \ python backtest.py --data-dir /data/synthetic_2024_q1.csv # 3. 生成报告并对比基准 python compare_results.py \ --new-report ./reports/backtest_${GIT_COMMIT}.json \ --baseline-report ./reports/baseline_v2.2.json \ --threshold 0.005 # 0.5% 偏差阈值

其中,synthetic_2024_q1.csv不是真实数据,而是由>use chrono::{DateTime, TimeZone, Utc, Local}; let now = Local::now(); // 而不是 Utc::now() let today_start = now.date_naive().and_hms_opt(0, 0, 0).unwrap();

  • 在沙盒脚本run_sandbox.sh中,增加时区校验步骤:
    docker run --rm trading-sandbox:${GIT_COMMIT} date +"%Z %z" # 应输出 CST +0800
  • 注意:这个问题极其隐蔽,因为大多数回测框架(如 Backtrader、VectorBT)默认使用本地时区,而生产环境的交易引擎(如 vn.py、CTP)也使用本地时区,表面上看是统一的。但沙盒环境的 Docker 容器,如果没有显式设置,会继承宿主机的时区,而宿主机可能是 UTC。这就是为什么必须在构建镜像时就固化时区。

    5.3 “Agent 总是卡在 ‘Waiting for Git Server’,Gitea 日志里全是 401”——Token 权限的迷宫

    现象:Deploy Agent 启动后,日志不断打印:

    [INFO] Connecting to Gitea at http://localhost:3000... [ERROR] HTTP 401 Unauthorized when fetching repo list

    Gitea 的gitea.log中对应条目显示:

    ... error: user token invalid or expired ...

    原因:OpenAlice 的 Agent 需要一个具有特定权限的 Personal Access Token(PAT)。这个 Token 不是随便在 Gitea 设置里生成一个就行的。它必须拥有以下精确权限:

    • read:repository:读取代码和配置;
    • write:repository:创建 Tag(用于风控事件);
    • read:organization:读取团队配置(如team_max_leverage);
    • read:user:读取用户信息(用于 PR 审核人匹配)。

    如果 Token 缺少write:repository,Agent 就无法打 Tag,风控审计链就断了;如果缺少read:organization,它就无法获取中央风控阈值,只能使用本地risk.yaml,失去全局一致性。

    解决方案:

    1. 登录 Gitea,进入Settings→Applications→Manage Application Tokens;
    2. 点击Generate New Token;
    3. 在Select scopes中,只勾选上述四个权限,不要勾选admin:org、delete_repo等高危权限;
    4. 复制生成的 Token,填入 Agent 的配置文件agent.toml:
      [gitea] url = "http://localhost:3000" token = "your-precise-token-here" # 不要加 "token " 前缀!

    实操心得:我们曾因勾选了admin:org权限,导致一次安全审计被判定为“过度授权”。后来制定了严格的 Token 权限矩阵表,每个 Agent 类型(Commit/PR/Deploy)对应不同的最小权限集。安全不是功能,而是设计的第一原则。

    5.4 “策略在沙盒里跑得飞快,实盘却延迟严重!”——Python 与 Rust 的胶水陷阱

    现象:沙盒回测耗时 12 分钟,看起来很健康。但实盘部署后,策略模块 CPU 占用率飙升至 95%,订单延迟从毫秒级变成秒级。

    原因:策略代码是 Python,而风控引擎是 Rust。它们之间通过 REST API 或消息队列通信。在沙盒中,由于数据量小、网络延迟为 0,这种通信开销可以忽略。但在实盘中,每秒数百笔订单,频繁的跨语言序列化/反序列化(JSON)成为瓶颈。

    解决方案:采用Zero-Copy Shared Memory。OpenAlice 提供了一个shared-memory-pyPython 库,它允许 Python 策略直接写入一块 Rust 进程共享的内存区域,而 Rust 风控引擎可以直接读取,无需序列化。

    • 在 Python 策略中:
      from shared_memory_py import SharedMemoryWriter shm_writer = SharedMemoryWriter("risk_input") shm_writer.write({ "symbol": "SH600519
    返回列表