TradingGym · PARAMETERS · 源码语义

TradingGym 参数详解:README 说的和你实际会遇到的

TradingGym 的参数文档只有几行英文,真正决定实验是否成立的细节都在源码里:fee 同时出现在两处、含义不同;step() 返回的 reward 是窗口求和而不是单步收益;还有三个参数 README 完全没提。这页把 README 说法与源码行为逐条摆在一起。

  • fee 不是费率:源码里是绝对量,一处按笔扣、一处按每个持仓 tick 扣
  • reward 有三个口径:step 返回值、env.info['reward']env.info['reward_fluctuant']
  • 实测对照:同策略同数据,fee 从 0 改到 0.1,5 天账本收益由 -9.300 变 -49.400

TradingGym 观测窗口怎么推进

观测窗口obs_data_len 根 tick 的特征矩阵
前进 step_len每次 step() 窗口右移
撮合价窗口之后第一根 tick 的成交价
reward窗口内 reward 数组之和
依据 trading_env/envs/backtest_v1.pystep() 实现与本机实测绘制的窗口推进示意(非官方流程图)。关键点:撮合价取的是观测窗口之后的第一根 tick,而返回的 reward 是窗口内 reward 之和。

TradingGym · 逐条对照

TradingGym 的 README 说法和源码实际行为差在哪?十个参数逐条对

对照依据是仓库 master HEAD(08bb534)的实际代码与本机实测。凡是 README 没写的,都在「源码实际行为」列里点了出来。

参数逐条对照(左两列是 README 原文意思,中右列是源码与实测)
参数README 说法源码实际行为本机实测适用场景注意点
obs_data_lenobservation data length观测窗口的 tick 根数;观测 = 该窗口的特征矩阵取 64 时观测形状为 (64, 8)(不含附加列)做微观结构研究用短窗窗口越长,持仓信息在观测里越滞后
step_lenwhen call step rolling windows will + step_len每次 step() 窗口右移的根数;相邻 step 的窗口不重叠64/32 组合下每次 step 前进 32 根 tick调决策频率返回值却是整窗求和,见第 3 节
feewhen each deal will pay the fee两处出现、含义不同:平仓算式里按笔扣一次;reward_fluctuant 列里按每个持仓 tick 扣一次5 天 401 笔平仓 × 0.1 = 40.1 点差额观察成本敏感度它是绝对量,不是百分比费率
max_positionthe max market position for you trading share双向持仓上限;达到上限时同向动作被改写为「不动」取 1 时 5 天随机策略 802–830 笔交易控制单标的风险敞口上限同时是「开仓/加仓」的判定分界
deal_col_namethe column name for cucalate reward used盈亏计算所用价格列;必须存在于 DataFrame样例用 Price统一撮合口径选买价还是最新价,会改变回测结论
feature_nameslist contain the feature columns to use in trading status观测的特征列,逐列断言存在;顺序即观测列顺序传 8 列时观测为 (64, 16)(8 特征 + 8 附加)构造状态空间列名大小写敏感
serial_number(列,非参数)serial num of deal at each day recalculating切分交易日的唯一依据(找 ==0 的行)样例 113,059 行 → 8 个交易日所有环境夜盘品种的「交易日」跨午夜,不能按日历日期切
fluc_div(README 未提)v0 里把浮动盈亏缩放成 reward/fluc_div(默认 100.0)控制 v0 奖励量级v1 保留该参数但 step() 不再用它缩放
gameover_limit(README 未提)v0 系:浮亏超过阈值提前结束 episode(默认 5);v1 的 step 里没有这个判定backtest_v1 全程未触发提前终止限制最大回撤想做止损式提前终止,v1 得自己加
return_transaction(README 未提)v1 专有:True 时观测拼接 8 列持仓/成本/盈亏,False 时只给特征列默认 True → 观测 16 列让 Agent 看到持仓状态关掉后 Agent 会「看不见自己仓位」
这张表里最值得记的一条:三个 README 完全没提的参数(fluc_divgameover_limitreturn_transaction)都会显著改变实验,其中 gameover_limit 在 v1 环境里根本不生效——照 v0 教程写的「亏损超限自动结束」在 v1 上是不会发生的。

TradingGym · 参数深挖

TradingGym fee 到底是什么单位?源码里它出现两次,含义并不一样

网上常见的写法是 fee=0.1 并解释成「0.1% 手续费」。这个解释在源码面前站不住:它既不是百分比,也不是统一的「每笔一次」。

出处一:平仓算式(按笔扣一次)

# backtest_v1.py 的空头平仓分支(多头对称)
self.chg_reward[:] = ((self.chg_price - self.chg_price_mean) * (-1) - self.fee) * self.chg_makereal

这里 fee 从已实现盈亏里减一次,单位就是你自己价格列的单位。价格量级 277 点时,fee=0.1 约等于单笔 3.6 个基点。

出处二:持仓期间(每个 tick 扣一次)

# backtest_v1.py:265 每个 step 覆盖的窗口
self.chg_reward_fluctuant[:] = (self.chg_price - self.chg_price_mean) * self.chg_posi \
                               - np.abs(self.chg_posi) * self.fee

同一个 fee 在浮动盈亏列里按每个持仓 tick 扣。持仓 1 万根 tick 时,这一项会远大于价格波动本身——这是「收益被成本吃光」的最常见原因。

fee 影响的实测对照(backtest_v1、obs=64/step=32、max_position=1、样例数据前 5 个交易日)
实验fee交易笔数账本收益与 fee=0 的差怎么读
随机策略 seed 00802-9.300基线
随机策略 seed 00.1802-49.400-40.100恰好等于 0.1 × 401 笔平仓,反证「平仓按笔扣一次」
随机策略 seed 10830+3.800同一策略换种子由亏转盈
随机策略 seed 10.1830-37.700-41.500成本约 0.1 × 415 笔平仓
随机策略 seed 20.1812-38.900三个种子在 fee=0.1 下全部为负
双均线(20 tick 均线交叉)0132+1.300交易频率低,成本影响小
双均线(20 tick 均线交叉)0.1132-5.300-6.60066 笔平仓 × 0.1 = 6.6,与差额一致
结论:fee=0.1 的正确读法是「每笔平仓从盈亏里减 0.1 个价格单位,同时在浮动盈亏列里每个持仓 tick 再减 0.1」。不要写成 0.1%,也不要直接和 A 股佣金费率换算。以官方源码为准。

TradingGym · 窗口机制

TradingGym obs_data_len 与 step_len 如何决定你的实验

这两个参数不只控制「看多久」,还决定了撮合价落在哪里、以及 step() 返回的 reward 覆盖多大区间。

窗口参数对实验的影响(按 backtest_v1.step() 的实际顺序推导)
环节取值来源行为适用场景注意点
本次决策用到的观测前一步的观测窗口形状 (obs_data_len, 特征数+8)Agent 决策观测里已含当前持仓(return_transaction=True
窗口右移step_lenstep_st += step_len 再取新窗口调决策频率step_len 越大,单位时间内决策越少
撮合价新窗口之后的第一根 tickenter_price = self.chg_price[0]保证「先看到、后成交」的顺序它与观测窗口之间相隔了 step_len 根 tick
返回的 reward窗口内 reward 数组求和return ... self.obs_reward.sum()给 RL 用的即时反馈相邻 step 的窗口叠加会让累加值偏大
episode 终点当日 tick 用尽done=True,同时生成账本逐日回测每日行数少于 obs_data_len+step_len 时会立刻结束
参数与数据规模的关系两者共同决定步数单日步数 ≈ (当日 tick 数 − obs_data_len) / step_len估算训练/回测时长样例最长日 25,617 根、最短日 8,550 根,步数差 3 倍

短窗(如 64/32)

决策频率高、能更快反应,但噪声也被放大。本站实测 5 天就有 800 多笔交易,成本项变成主导因素。

长窗(如 256/128)

观测更平稳、交易更少,但窗口内持仓信息滞后更多;单日步数会明显下降,样本效率变差。

与日线数据组合

日线下 1 根 = 1 天,obs_data_len=20 就是「看过去 20 个交易日」。此时 serial_number 常设为 0,整段区间会被当成一个超长交易日。

TradingGym · 持仓规则

TradingGym 的 max_position 和三个动作是什么?1 不是「买 1 股」

v1 环境的 action_space 是整数 3,动作语义写在 action_describe 里:{0: 'do nothing', 1: 'long', 2: 'short'}。也就是说动作 1 表示「做多方向」,2 表示「做空方向」,具体是开仓还是加仓由当前持仓决定。

动作与持仓的组合行为(依据 v1 源码分支)
当前持仓动作环境行为适用场景注意点
01(long)开多 1 单位,记录开仓价趋势入场开仓价写入 price_mean,后续盈亏以它为基准
大于 0 且小于上限1(long)同向加仓 1 单位,entry_cover=2(increase)金字塔加仓加仓会改变持仓均价
大等于上限1(long)同向动作被改写为「不动」风险上限保护达到上限后 Agent 的加仓信号全部失效,容易误判为「策略不响应」
大于 02(short)减少多头 1 单位;到 0 时平仓,entry_cover=-1(cover)止盈止损平仓瞬间才结算已实现盈亏并扣 fee
02(short)开空 1 单位做空/对冲空头盈亏符号与多头相反,账本里看 position 正负
小于 01(long)减少空头;到 0 时平仓空头回补平仓同样扣一次 fee
任意0持仓不变,但仍按持仓量结算浮动盈亏持有观察不动不等于不亏:持仓成本项照算
max_position 设成 1 与设成 5 是两种实验:前者做「单份持仓的方向决策」,后者的胜负由加仓节奏主导。本站所有对照实验都固定在 1,才能让随机策略与 Buy&Hold 可比。

TradingGym · 未文档化参数

TradingGym README 没写的三个参数,会直接影响实验结论是什么?

这三个参数在 README 里没有说明,但对实验的影响不比文档化的参数小。下面给出它们的源码位置与行为。

未文档化参数速查(源码位置逐条给出)
参数默认值源码位置行为什么时候要动它注意点
fluc_div100.0training_v0.py 构造参数v0 把浮动盈亏缩放到 reward/fluc_divv0 奖励量级过大导致训练不稳定时v1 的 step() 不再用它缩放,改参数在 v1 上无效果
gameover_limit5training_v0.py:276backtest_v0.py:270浮亏超过阈值时提前结束 episode想模拟「爆仓/止损后停止交易」v1 的 step 里没有该判定,在 backtest_v1 上设了也不生效
return_transactionTruebacktest_v1.py:17 及 reset/stepTrue 时观测拼接 8 列持仓/成本/盈亏要区分「Agent 看得见仓位」与「看不见仓位」关掉后观测只剩特征列,Agent 需要自己记忆仓位
deal_col_name 的大小写'price'(小写默认)__init__.py:9默认值是小写 price,而官方样例列名是 Price直接按默认值建环境会断言失败必须显式传 deal_col_name='Price' 或统一改列名
feature_names 的默认值['price','volume']__init__.py:9默认只取两列不传时会因列名不存在而断言失败默认值是占位符性质,实际使用必须显式传入
观测里的附加列顺序固定 8 列backtest_v1.py:118-128position、position_variation、entry_cover、price、price_mean、reward_fluctuant、reward_makereal、reward你在做特征工程时要按位置索引附加列不可配置、不可改名,只能整体开关

TradingGym · 选型建议

TradingGym 参数怎么选:按目标而不是按「最佳实践」

网上流传的「高频用 50–100、日内 200–500、趋势 1000 以上」并没有源码或实验依据。下面这张表给的是一组可复现的起点,并写明为什么。所有数字都要在你自己的数据上重跑验证。

参数选型起点(本站实测组合在最后一列)
目标obs_data_lenstep_lenfee 起点理由注意点
先确认环境能跑(冒烟测试)64320窗口小、步数多,最快暴露数据与索引问题本站实测即用此组合,8,550 根的一日也能跑出上百步
观察成本敏感度64320 → 0.1固定其他变量,只改 fee,差额可直接归因实测 5 天 401 笔平仓对应的差额是 40.1 点
低频规则策略(如均线)64320 与 0.1 各跑一次与随机策略共用口径,便于横向比较实测 132 笔交易时,fee 0.1 使收益由 +1.300 变 -5.300
降低交易频率128 或 25664 或 128按实际成本设定窗口变长、决策变少,成本项影响下降单日步数会明显减少,样本效率变差
日线/多日窗口2050「看过去 20 个交易日、每 5 日决策」需把 serial_number 设为 0,整段区间成为一个 episode
奖励塑形研究64320先零成本,确认奖励改动方向正确再叠加成本改 reward 后必须重建净值,不能直接比较 step 返回值

TradingGym · FAQ

TradingGym 参数常见问题是什么?

TradingGym 的 fee 参数怎么设置?是 0.1% 吗?

不是。源码里 fee 是绝对量:平仓时从已实现盈亏里减一次,同时在 reward_fluctuant 列里按每个持仓 tick 再减一次(backtest_v1.py:170/178:265)。本站实测:5 天 401 笔平仓、fee=0.1 时账本比 fee=0 少 40.1 点,正好等于 0.1 × 401。要换算成费率,请拿你价格列的量级自己算,别直接抄教程里的「0.1%」。以官方源码为准。

obs_data_len 设多大合适?有「最佳实践」吗?

没有官方最佳值。README 只说明它是观测长度。网上「高频 50–100 / 日内 200–500 / 趋势 1000+」的说法没有源码或实验依据。建议从 64/32 起步做冒烟测试,再按你的决策频率调整;任何取值都要在你自己的数据上重跑,并同时报告交易笔数与成本影响——本站实测显示窗口变小会让交易笔数上升到数百笔,成本项随之主导结果。

max_position 是什么?设成 5 会怎样?

它是双向持仓的绝对上限。达到上限时,同方向的加仓动作会被环境改写成「不动」(不是报错),所以看起来像「策略突然不响应」。设为 5 意味着允许加仓到 5 份,回测结果会由加仓节奏主导;本站所有对照实验固定为 1,目的是让随机策略与 Buy&Hold 在同等敞口下可比。

为什么我在 backtest_v1 上设了 gameover_limit 却没生效?

因为该参数只在 v0 系的两个环境里参与 step() 判定(training_v0.py:276backtest_v0.py:270),而 backtest_v1step() 里没有这段逻辑。想在 v1 上实现「亏损超限终止」,只能自己在外层循环里判断 env.info['position'] 与盈亏,然后主动 break。以官方实现为准。

return_transaction 关掉会有什么区别?

关掉后观测只包含 feature_names 指定的特征列(不含持仓/成本/盈亏 8 列)。对 Agent 来说,它「看不见自己的仓位」,必须自己维护状态;对研究者来说,这更接近纯行情观测的传统设定。默认是 True(观测 16 列),这也是本站实测所用的配置。

参数改了之后,之前跑出来的收益还能比较吗?

不能。改动 obs_data_len/step_len 会改变决策频率与步数;改动 fee 会改变成本项;改动 max_position 会改变敞口规模;改动 return_transaction 会改变观测。任何一项变化都意味着换了一个实验,必须重跑包括基准策略在内的全部对照,并在报告里写明参数。

下一步该怎么做?核对回测账本与基准

参数拧好之后,最后一关是「结果到底怎么算」:三处 reward 口径数值不同,净值必须独立重建。这页把公式、实测数字与四种基准一次给全。