4 个环境
training_v0、training_v1、backtest_v0、backtest_v1。两代实现并存,接口与账本形态都不一样,选错环境会让结果不可比。
TRADINGGYM · 强化学习交易环境
TradingGym 是受 OpenAI Gym 启发的强化学习交易环境工具包(tick 数据、双向持仓、自带账本)。它在 GitHub 上有 1919 star、MIT 许可,但 master HEAD 停在 2023-08-12,且 README 里的回测示例在当前 pandas 上跑不通。本站把 4 个环境逐个实测、把参数的真实语义摊开、把回测账本的口径对账,让你在花时间之前先知道会发生什么。
training_v1),3 个在 reset() 就报错max_position=1 下的账本与基准对照全部落盘可复跑1919 Star · 372 Fork · MIT · 47 次提交
查看源码 ↗
08bb534(2023-08-12)、共 47 次提交,Star/Fork 数字会随社区变化。TradingGym · 实测速览
下面每一项都是本机跑出来的,不是转述 README。环境版本、命令与产物都记在研究报告里,你可以自己复跑。
training_v0、training_v1、backtest_v0、backtest_v1。两代实现并存,接口与账本形态都不一样,选错环境会让结果不可比。
只有 training_v1 在当前 pandas 上 reset() 通过;它用的是 to_numpy(),是唯一被更新过的一支。
其余三个仍在调用 pandas 1.0 就已移除的 Series.as_matrix(),报 AttributeError。加两行兼容补丁即可继续。
README 里 simple dqn / policy gradient / actor-critic / A3C 全部标注 WIP,仓库内没有对应实现文件。算法要你自己带。
| 实测项 | 结果 | 怎么得到的 | 对你的影响 |
|---|---|---|---|
| 环境注册清单 | 4 个(v0/v1 各两支) | 调用 available_envs() | 文档里讲的「环境」其实有四个,别默认只有训练和回测各一个 |
training_v1.reset() | 通过,观测形状 (64,16) | 直接实例化并 reset | 想先摸接口,从这一支开始最快 |
| 其余三支 reset() | 失败:as_matrix 不存在 | 同上,逐支跑 | 照 README 搜到的老教程会卡在第一步 |
| README 回测示例 | 失败:没有 backtest() 方法 | 按 README 原样调用 | 回测得自己写日间循环,见「回测循环」页 |
| 官方 CI 命令 | -m trading_env/test 失败、-m trading_env.test 通过 | 两条命令各跑一次 | 照 .travis.yml 抄命令会报模块找不到 |
| PyPI 包 | trading_env 等四个名字全部 404 | 查询 PyPI JSON API | 没有 pip install 这条路,只能源码安装 |
证据:本机实测脚本与原始输出保存在研究报告 _verify\ 目录(as_is_result.txt、run_result.json、pypi_check.txt)。TradingGym 与 EasyClaw 无已证实集成。
依据 TradingGym 源码与本机实测绘制的链路示意(非官方流程图):数据 → 环境 → 自备 Agent → 账本。四段里只有中间两段是本项目提供的,算法与数据都在你这边。
TradingGym · 能力边界
这类项目的坑不在「功能不够」,而在被当成别的东西:它不是数据源,不是策略库,也不是实盘通道。下面两栏按源码事实分开写。
serial_number 的 tick/OHLC 表切成交易日,做成 step / reward 风格的环境(make(env_id=...))。obs_data_len + step_len 控制观测窗口,双向持仓(max_position)与做空都支持。env.info 里有 position、price_mean、reward、reward_fluctuant 等列。choice_action(state),不写 RL 也能做回测。gym.Env 子类:全仓库没有 import gym,接 Gymnasium / Stable-Baselines3 要自己写适配层。| 你想要的 | 现状 | 源码/实测依据 | 适用场景 | 注意点 |
|---|---|---|---|---|
| 装好就能跑 | 需先打 2 行兼容补丁 | 3/4 环境 as_matrix 报错(实测) | 想重复老教程的流程 | 补丁只解决取数,不改动项目行为 |
| 直接接 SB3 训练 | 不行,需自写适配层 | 类不是 gym.Env、空间声明与实际形状不一致 | 做 RL 实验 | 适配层要处理四元组→五元组 |
| 按天回测并取净值 | 可以,但要自己重建净值 | env.info['reward'] 与增量盈亏一致(实测 -0.5 对 -0.5) | 规则策略验证 | 不要用 reward_fluctuant 累加(同一天 +28.1) |
| 控制成本 | 可以,但 fee 语义特殊 | 平仓按笔扣一次;另一列按每个持仓 tick 扣一次 | 观察成本对策略的影响 | 它不是你熟悉的「费率」,单位由使用者定义 |
| 换品种/换市场 | 只要列齐就能用 | make() 有四个列断言 | A 股日线等自有数据 | 索引必须是 0..N 整数,否则切片会错位 |
| 商用 | MIT 许可允许 | LICENSE + GitHub API spdx_id=MIT | 二次开发 | 项目停止在 2023-08-12,需自行维护分支 |
TradingGym · 双代环境
这不是「新旧版本」,而是两套接口同时存在于同一个包:v0 系用扁平观测与单步 reward,v1 系用二维观测加窗口 reward。选错会让你的训练结果与别人不可比。
| 环境 | 取数实现 | 观测形态 | step 返回的 reward | 日间推进 | 本机实测 |
|---|---|---|---|---|---|
training_v0 | as_matrix() | 仅特征列(持仓特征被注释掉) | 单步 reward(reward_fluctuant/fluc_div) | 随机抽日,另有 backtest() 方法 | reset() 失败 |
training_v1 | to_numpy() | 特征列 + 8 列持仓/成本/盈亏 | 观测窗口内 reward 之和 | 随机抽日,无 seed 参数 | reset() 通过 |
backtest_v0 | as_matrix() | 仅特征列 | 单步 reward,含 gameover 提前终止 | 随机抽日 | reset() 失败 |
backtest_v1 | as_matrix() | 特征列 + 8 列(return_transaction=True) | 观测窗口内 reward 之和 | reset() 逐个交易日推进 | reset() 失败(打补丁后可跑) |
backtest_v1:它名字带 v1,但取数代码仍是 v0 的写法(backtest_v1.py:91),所以在当前 pandas 上一样崩。想跑回测就得打补丁——这在任何中文教程里都还没人写过。TradingGym · 快速开始
下面三步在本机实测通过(Python 3.11.9 + pandas 2.2.3)。第 0 步的两行补丁是为了让老代码在当前 pandas 上取数,不改变项目逻辑。
git clone https://github.com/Yvictor/TradingGym.git
cd TradingGym
python setup.py install
官方只提供源码安装(PyPI 上没有 trading_env 这个包,实测 404)。装完 import trading_env 就应成功。
预期输出:无报错;trading_env.available_envs() 返回 ['training_v0','training_v1','backtest_v0','backtest_v1']。
import pandas as pd, trading_env
if not hasattr(pd.Series, "as_matrix"): # 兼容补丁:pandas 1.0 起移除了 as_matrix
pd.Series.as_matrix = lambda self: self.to_numpy()
pd.DataFrame.as_matrix = lambda self: self.to_numpy()
df = pd.read_csv('trading_env/test/data/SGXTWsample.csv', index_col=0, parse_dates=['datetime'])
env = trading_env.make(env_id='training_v1', obs_data_len=256, step_len=128, df=df,
fee=0.1, max_position=5, deal_col_name='Price',
feature_names=['Price','Volume','Ask_price','Bid_price',
'Ask_deal_vol','Bid_deal_vol','Bid/Ask_deal','Updown'])
obs = env.reset()
make() 会依次断言 env_id 合法、deal_col_name 在列、serial_number 必须在列、每个特征列存在(__init__.py:13-17)。
预期输出:obs.shape == (256, 16)——8 个特征列 + 8 列持仓/成本/盈亏。
obs, reward, done, info = env.step(1) # 0=不动 1=做多 2=做空
print(reward, done, env.obs_price[:3])
print(env.obs_posi[:3]) # 观测里的持仓列
每 step() 观测窗口前进 step_len 根 tick,撮合价取窗口之后的第一根 tick(backtest_v1.py:242);窗口走完一天即 done=True。
预期输出:reward 为该观测窗口内 reward 数组之和(不是单步收益),done 在当日 tick 用尽时为 True。
training_v0、backtest_v0、backtest_v1 需要同一份补丁,否则会报 AttributeError: 'Series' object has no attribute 'as_matrix'(本站实测原文)。TradingGym · 已验证实验
实验口径统一为 backtest_v1 + obs_data_len=64 + step_len=32 + max_position=1,跑样例数据的前 5 个交易日。这样随机策略与「一直持有」才可比。
| 策略 | fee | 交易笔数 | 账本收益(env.info['reward']) | Buy&Hold 对照 | 怎么读这个数 |
|---|---|---|---|---|---|
| do nothing(不动) | 0 | 0 | 0.000 | +1.100 | 零成本基准,用来确认账本在无持仓时确实是 0 |
| always long(一直持有) | 0 | 10 | +1.000 | +1.100 | 与 Buy&Hold 差 0.1,差额来自进出场时点与撮合价位置 |
| 随机策略 seed 0 | 0 | 802 | -9.300 | +1.100 | 随机开平仓在这段数据上是亏的,说明样本本身没有「随便做都赚」 |
| 随机策略 seed 1 | 0 | 830 | +3.800 | +1.100 | 换种子由亏转盈——这正是「单次回测不可信」的直接证据 |
| 随机策略 seed 2 | 0 | 812 | +1.700 | +1.100 | 三个种子跨度 13 点,方差远大于策略差异 |
| 随机策略 seed 0(fee=0.1) | 0.1 | 802 | -49.400 | +1.100 | 同策略同数据,仅把 fee 从 0 改到 0.1,多出 -40.1(=0.1×401 笔平仓) |
脚本 _verify\run_verify.py 与原始输出 run_result.json 已落盘;换机器只要版本一致就能复现同一组数字。
同一策略在三个随机种子下从 -9.3 到 +3.8 点。只看一个种子的正收益,等于把噪声当策略。
fee 在源码里出现两次、含义不同:平仓按笔扣、另一列按每个持仓 tick 扣。用错一列,量级差几十倍。
TradingGym · SETUP AND ROUTE
TradingGym 是「环境 + 自备 Agent」的形态,用它的前提是你能接受 Python 环境与自写训练代码。如果你的真实目标只是取数、看指标或出图,那不必绕这一圈。
| 路线 | 前置条件 | 你能得到 | 适合谁 | 不适合谁 |
|---|---|---|---|---|
| 官方源码安装(不推荐直接用) | Python 环境、git;接受 3/4 环境报错 | 可读的源码与 training_v1 基础接口 | 只想读代码、做二次开发 | 想立刻跑回测的人 |
| 源码 + 2 行兼容补丁(本站实测路径) | 同上,另加两行 patch | 四个环境都能实例化,可跑逐日回测与账本 | 复现实验、做 RL 环境研究 | 期望开箱即用、免维护的人 |
| 本机技能路线(不做同类替代) | 装 EasyClaw;部分技能需 Token/API Key | 一句话取数、算区间指标、出图、规则策略回测 | 目标只是数据与指标,不做 RL 环境 | 要做 Gym 风格环境与 step/reward 实验的人 |
TradingGym · 免部署 demo
下面两张分别是 EasyClaw 处理「行情取数」与「规则策略回测」的对话示例。它们演示的是「一句话取数」与「一句话发起规则策略回测」,属于并列对比路线。
TradingGym · 选型
判断标准只有两条:你是否需要 Gym 风格的 step/reward 环境,以及你是否愿意自己写训练代码并维护一个 2023 年后没有更新的仓库。
要研究观测/动作/奖励设计本身,或要把 tick 数据做成可回放的实验环境。TradingGym 的结构简单、源码总量小(四个环境文件 + 一个包入口),改起来比大框架轻。
你已经有自己的模型或规则策略,只需要一个「能 step、能给账本」的执行壳。规则策略也能用:实现 choice_action(state) 即可,不写 RL 也能回测。
没有数据下载、没有算法实现、没有实盘通道,还要先打兼容补丁。想要「一句话取数 + 指标 + 出图」,去看对比页的技能路线更省时间。
| 你的目标 | 建议 | 理由 | 注意点 |
|---|---|---|---|
| 复现一篇 RL 交易论文的环境 | 用 TradingGym + 补丁,并从 backtest_v1 入手 | 它的 step/reward 与逐 tick 账本正好是这个用途 | 观测里已含持仓信息,论文里若假设纯行情观测需自行裁剪 |
| 验证一条规则策略(如双均线) | 用 TradingGym 的 backtest_v1,或直接用 EasyClaw 的规则回测技能 | 两条路都能出对照结果,后者不用搭环境 | 两者账本口径不同,不要跨口径比较收益 |
| 只是想看行情与指标 | 不必用 TradingGym | 它不提供数据下载能力 | 数据技能需自备 Token 或按文档安装依赖 |
| 想做实盘 | 本项目不适用 | 实时交易与 IB 接入只是 README 的将来计划 | 不要基于本项目做任何实盘改造预期 |
| 研究观测/奖励设计(如奖励塑形) | 用 TradingGym,从 training_v1 改 | 它是唯一在当前 pandas 上可直接跑的 v1 环境 | 改 reward 后要重建净值,见「奖励与基准」页 |
| 需要长期维护的生产环境 | 谨慎:把本项目当参考实现 | HEAD 停在 2023-08-12,CI 仍指向已停服的 Travis | 自行 fork 维护,并补齐测试 |
TradingGym · FAQ
免费。仓库 LICENSE 为 MIT(GitHub API 的 license.spdx_id 也是 MIT),可商用与二次开发。但注意两点:项目 master HEAD 停在 2023-08-12,仓库既有 issue 与 CI 都是停服年代的产物,商用意味着你要自己维护分支;另外数据与依赖(pandas/numpy/matplotlib/colour)各有自己的许可,以各自官方为准。
当前不能。README 写的是「未来会实现带 Interactive Brokers API 的实时交易环境」,属于计划而非现状;仓库内没有任何下单、行情连接或风控代码。本站不对接实盘做任何承诺,以官方代码为准。
不需要。全仓库没有 import gym,它只是「模仿 Gym 风格」:类里有 reset()、step()、render() 以及 action_space、observation_space 属性。反过来说,你想用 Stable-Baselines3 之类的库,必须自己写一层 gym.Env 适配——本站给了可复制的适配层写法。
有两个独立原因。一是 README 用 env_id='backtest_v1' 却调用 env.backtest(),而 backtest() 方法只存在于 training_v0.py,本机实测报 AttributeError: 'trading_env' object has no attribute 'backtest';二是 backtest_v1 仍在用已移除的 as_matrix()。正确做法见「回测循环」页,并以官方源码为准。
机制上支持——只要你的 DataFrame 满足四个断言(env_id 合法、deal_col_name 在列、有 serial_number 列、特征列齐全),并把索引整理成 0..N 的整数。但官方没有提供任何 A 股数据源或复权处理,serial_number(按交易日重置的连续编号)需要你自己生成;T+1、涨跌停、停复牌这些规则它完全不管,要自己在外层约束。以官方实现为准。
单次结果不能。本站实测同一随机策略换三个随机种子,5 天结果从 -9.3 到 +3.8 点,跨度 13 点;同时段 Buy&Hold 只有 1.1 点。要看的是「多随机种子 + 基准对照 + 净值重建」三件套,而不是一个收益率数字。全部数字可在研究报告里复跑。