网易首页 > 网易号 > 正文 申请入驻

基于强化学习的量化交易框架 TensorTrade

0
分享至

打开交易图表,堆上十个技术指标,然后对着屏幕发呆不知道下一步怎么操作——这场景对交易员来说太熟悉了。如果把历史数据丢给计算机,告诉它“去试错”。赚了有奖励,亏了有惩罚。让它在不断的尝试和失败中学习,最终迭代出一个不说完美、但至少能逻辑自洽的交易策略。

这就是TensorTrade的核心逻辑。

TensorTrade 是一个专注于利用强化学习 (Reinforcement Learning, RL)构建和训练交易算法的开源 Python 框架。

数据获取与特征工程

这里用 yfinance 抓取数据,配合 pandas_ta 计算技术指标。对数收益率 (Log Returns)、RSI 和 MACD 是几个比较基础的特征输入。

pip install yfinance pandas_ta
import yfinance as yf
import pandas_ta as ta
import pandas as pd
# Pick your ticker
TICKER = "TTRD" # TODO: change this to something real, e.g. "AAPL", "BTC-USD"
TRAIN_START_DATE = "2021-02-09"
TRAIN_END_DATE = "2021-09-30"
EVAL_START_DATE = "2021-10-01"
EVAL_END_DATE = "2021-11-12"
def build_dataset(ticker, start, end, filename):
# 1. Download hourly OHLCV data
df = yf.Ticker(ticker).history(
start=start,
end=end,
interval="60m"
)
# 2. Clean up
df = df.drop(["Dividends", "Stock Splits"], axis=1)
df["Volume"] = df["Volume"].astype(int)
# 3. Add some basic features
df.ta.log_return(append=True, length=16)
df.ta.rsi(append=True, length=14)
df.ta.macd(append=True, fast=12, slow=26)
# 4. Move Datetime from index to column
df = df.reset_index()
# 5. Save
df.to_csv(filename, index=False)
print(f"Saved {filename} with {len(df)} rows")
build_dataset(TICKER, TRAIN_START_DATE, TRAIN_END_DATE, "training.csv")
build_dataset(TICKER, EVAL_START_DATE, EVAL_END_DATE, "evaluation.csv")

脚本跑完,目录下会生成 training.csv 和 evaluation.csv。包含了 OHLCV 基础数据和几个预处理好的指标。这些就是训练 RL 模型的数据。

构建 TensorTrade 交互环境

强化学习没法直接使用CSV 文件。所以需要一个标准的交互环境 (Environment):能够输出当前状态 (State),接收智能体的动作 (Action),并反馈奖励 (Reward)。

TensorTrade 把这个过程模块化了:

  • Instrument:定义交易标的(如 USD, TTRD)。
  • Wallet:管理资产余额。
  • Portfolio:钱包组合。
  • Stream / DataFeed:处理特征数据流。
  • reward_scheme / action_scheme:定义怎么操作,以及操作的好坏怎么评分。

pip install tensortrade

下面是一个环境工厂函数 (Environment Factory) 的实现,设计得比较轻量,这样可以方便后续接入 Ray:

import os
import pandas as pd
from tensortrade.feed.core import DataFeed, Stream
from tensortrade.oms.instruments import Instrument
from tensortrade.oms.exchanges import Exchange, ExchangeOptions
from tensortrade.oms.services.execution.simulated import execute_order
from tensortrade.oms.wallets import Wallet, Portfolio
import tensortrade.env.default as default
def create_env(config):
"""
Build a TensorTrade environment from a CSV.
config needs:
- csv_filename
- window_size
- reward_window_size
- max_allowed_loss
"""
# 1. Read the dataset
dataset = (
pd.read_csv(config["csv_filename"], parse_dates=["Datetime"])
.fillna(method="backfill")
.fillna(method="ffill")
)
# 2. Price stream (we'll trade on Close)
commission = 0.0035 # 0.35%, tweak this to your broker
price = Stream.source(
list(dataset["Close"]), dtype="float"
).rename("USD-TTRD")
options = ExchangeOptions(commission=commission)
exchange = Exchange("TTSE", service=execute_order, options=options)(price)
# 3. Instruments and wallets
USD = Instrument("USD", 2, "US Dollar")
TTRD = Instrument("TTRD", 2, "TensorTrade Corp") # just a label
cash_wallet = Wallet(exchange, 1000 * USD) # start with $1000
asset_wallet = Wallet(exchange, 0 * TTRD) # start with zero TTRD
portfolio = Portfolio(USD, [cash_wallet, asset_wallet])
# 4. Renderer feed (optional, useful for plotting later)
renderer_feed = DataFeed([
Stream.source(list(dataset["Datetime"])).rename("date"),
Stream.source(list(dataset["Open"]), dtype="float").rename("open"),
Stream.source(list(dataset["High"]), dtype="float").rename("high"),
Stream.source(list(dataset["Low"]), dtype="float").rename("low"),
Stream.source(list(dataset["Close"]), dtype="float").rename("close"),
Stream.source(list(dataset["Volume"]), dtype="float").rename("volume"),
])
renderer_feed.compile()
# 5. Feature feed for the RL agent
features = []
# Skip Datetime (first column) and stream everything else
for col in dataset.columns[1:]:
s = Stream.source(list(dataset[col]), dtype="float").rename(col)
features.append(s)
feed = DataFeed(features)
feed.compile()
# 6. Reward and action scheme
reward_scheme = default.rewards.SimpleProfit(
window_size=config["reward_window_size"]
)
action_scheme = default.actions.BSH(
cash=cash_wallet,
asset=asset_wallet
)
# 7. Put everything together in an environment
env = default.create(
portfolio=portfolio,
action_scheme=action_scheme,
reward_scheme=reward_scheme,
feed=feed,
renderer=[],
renderer_feed=renderer_feed,
window_size=config["window_size"],
max_allowed_loss=config["max_allowed_loss"]
)
return env

这样“游戏”规则就已经定好了:观察最近 N 根 K 线和指标(State),决定买卖持(Action),目标是让一段时间内的利润最大化(Reward)。

基于 Ray RLlib 与 PPO 算法的模型训练

底层环境搭好,接下来让Ray RLlib介入处理 RL 的核心逻辑。

选用PPO (Proximal Policy Optimization)算法,这在连续控制和离散动作空间都有不错的表现。为了找到更优解,顺手做一个简单的超参数网格搜索:网络架构、学习率、Minibatch 大小,都跑一遍试试。

pip install "ray[rllib]"

训练脚本如下:

import os
import ray
from ray import tune
from ray.tune.registry import register_env
from your_module import create_env # wherever you defined create_env
# Some hyperparameter grids to try
FC_SIZE = tune.grid_search([
[256, 256],
[1024],
[128, 64, 32],
])
LEARNING_RATE = tune.grid_search([
0.001,
0.0005,
0.00001,
])
MINIBATCH_SIZE = tune.grid_search([
5,
10,
20,
])
cwd = os.getcwd()
# Register our custom environment with RLlib
register_env("MyTrainingEnv", lambda cfg: create_env(cfg))
env_config_training = {
"window_size": 14,
"reward_window_size": 7,
"max_allowed_loss": 0.10, # cut episodes early if loss > 10%
"csv_filename": os.path.join(cwd, "training.csv"),
}
env_config_evaluation = {
"max_allowed_loss": 1.00,
"csv_filename": os.path.join(cwd, "evaluation.csv"),
}
ray.init(ignore_reinit_error=True)
analysis = tune.run(
run_or_experiment="PPO",
name="MyExperiment1",
metric="episode_reward_mean",
mode="max",
stop={
"training_iteration": 5, # small for demo, increase in real runs
},
config={
"env": "MyTrainingEnv",
"env_config": env_config_training,
"log_level": "WARNING",
"framework": "torch", # or "tf"
"ignore_worker_failures": True,
"num_workers": 1,
"num_envs_per_worker": 1,
"num_gpus": 0,
"clip_rewards": True,
"lr": LEARNING_RATE,
"gamma": 0.50, # discount factor
"observation_filter": "MeanStdFilter",
"model": {
"fcnet_hiddens": FC_SIZE,
},
"sgd_minibatch_size": MINIBATCH_SIZE,
"evaluation_interval": 1,
"evaluation_config": {
"env_config": env_config_evaluation,
"explore": False, # no exploration during evaluation
},
},
num_samples=1,
keep_checkpoints_num=10,
checkpoint_freq=1,
)

这段代码本质上是在运行一场“交易机器人锦标赛”。Ray 会根据定义的参数组合并行训练多个 PPO 智能体,追踪它们的平均回合奖励,并保存下表现最好的 Checkpoint 供后续调用。

自定义奖励机制 (PBR)

默认的 SimpleProfit 奖励逻辑很简单,但实战中往往过于粗糙。我们有时需要根据具体的交易逻辑来重塑奖励函数。比如说基于持仓的奖励方案PBR (Position-Based Reward):

  • 维护当前持仓状态(多头或空头)。
  • 监控价格变动。
  • 奖励计算= 价格变动 × 持仓方向。

价格涨了你做多,给正反馈;价格跌了你做空,也给正反馈。反之则是惩罚。

from tensortrade.env.default.rewards import RewardScheme
from tensortrade.feed.core import DataFeed, Stream
class PBR(RewardScheme):
"""
Position-Based Reward (PBR)
Rewards the agent based on price changes and its current position.
"""
registered_name = "pbr"
def __init__(self, price: Stream):
super().__init__()
self.position = -1 # start flat/short
# Price differences
r = Stream.sensor(price, lambda p: p.value, dtype="float").diff()
# Position stream
position = Stream.sensor(self, lambda rs: rs.position, dtype="float")
# Reward = price_change * position
reward = (r * position).fillna(0).rename("reward")
self.feed = DataFeed([reward])
self.feed.compile()
def on_action(self, action: int):
# Simple mapping: action 0 = long, everything else = short
self.position = 1 if action == 0 else -1
def get_reward(self, portfolio):
return self.feed.next()["reward"]
def reset(self):
self.position = -1
self.feed.reset()

接入也很简单,在 create_env 函数里替换掉原来的 reward_scheme 即可:

reward_scheme = PBR(price)

这样改的好处是反馈更密集。智能体不需要等到最后平仓才知道赚没赚,每一个 step 都能收到关于“是否站对了队”的信号。

后续优化方向与建议

这套流程跑通只是个开始,想要真正可用,还有很多工作要做 比如:

  • 数据置换:代码里的 TTRD 只是个占位符,换成真实的标的(股票、Crypto、指数)。
  • 特征工程:RSI 和 MACD 只是抛砖引玉,试试 ATR、布林带,或者引入更长时间周期的特征。
  • 参数调优:gamma(折扣因子)、window_size(观测窗口)对策略风格影响巨大,值得花时间去扫参。
  • 基准测试:这一步最关键。把你训练出来的 RL 策略和 Buy & Hold(买入持有)比一比,甚至和随机策略比一比。如果跑不过随机策略,那就得从头检查了。

最后别忘了,我们只是研究,所以不要直接实盘。模型在训练集上大杀四方是常态,能通过样本外测试和模拟盘 (Paper Trading) 的考验才是真本事。

https://avoid.overfit.cn/post/8c9e08414e514c73ab3aefd694294f79

作者CodeBun

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
1962年玛丽莲梦露穿480万美元礼服为总统唱歌,3个月后却死在床上

1962年玛丽莲梦露穿480万美元礼服为总统唱歌,3个月后却死在床上

宅家伍菇凉
2026-01-03 09:00:03
日军为啥要在帽子上挂两块布?专家:此举可帮日军减少10万伤亡

日军为啥要在帽子上挂两块布?专家:此举可帮日军减少10万伤亡

鉴古知微
2026-10-14 03:09:52
利马会晤曼联高层后用AI道歉并遭罚款!曝其因一人首发暴怒,要求免费转会

利马会晤曼联高层后用AI道歉并遭罚款!曝其因一人首发暴怒,要求免费转会

罗米的曼联博客
2026-10-16 09:11:51
斯蒂芬·库里表示,勒布朗·詹姆斯加盟勇士队的传闻并非空穴来风

斯蒂芬·库里表示,勒布朗·詹姆斯加盟勇士队的传闻并非空穴来风

好火子
2026-10-15 22:31:38
难以置信!网传44岁程序员求职无果酿成悲剧,网友:在AI冲击下,未来程序员会成为最烂的职业

难以置信!网传44岁程序员求职无果酿成悲剧,网友:在AI冲击下,未来程序员会成为最烂的职业

火山詩话
2026-10-14 08:27:27
深夜!天津东丽发生紧急事件!

深夜!天津东丽发生紧急事件!

天津族
2026-10-16 07:34:36
演员童瑶发文告别

演员童瑶发文告别

背包旅行
2026-10-16 11:55:16
恐被架空?乌克兰议会放话:解除泽连斯基兵权,不然西方就断供

恐被架空?乌克兰议会放话:解除泽连斯基兵权,不然西方就断供

白日追梦人
2026-10-15 15:17:12
6场2球后突遭噩耗!曼联锋霸伤情加重或手术,卡里克再遇执教危机

6场2球后突遭噩耗!曼联锋霸伤情加重或手术,卡里克再遇执教危机

体坛鉴春秋
2026-10-16 10:42:34
太“记仇”了?徐杰胡明轩手牵手欢迎弗格,复制辽粤大战经典

太“记仇”了?徐杰胡明轩手牵手欢迎弗格,复制辽粤大战经典

绯雨儿
2026-10-16 11:56:07
超市蔬菜不停喷水,根本不是为了保鲜!藏在日常买菜里的隐形大坑

超市蔬菜不停喷水,根本不是为了保鲜!藏在日常买菜里的隐形大坑

青苹果sht
2026-10-13 04:47:21
厦门一男子看上了别人的妻子,竟然直接开价100万

厦门一男子看上了别人的妻子,竟然直接开价100万

匹夫来搞笑
2026-10-16 08:52:31
间谍通常都是怎么暴露的?网友:俄罗斯间谍拍毕业照,发网上

间谍通常都是怎么暴露的?网友:俄罗斯间谍拍毕业照,发网上

另子维爱读史
2026-10-14 20:52:11
禁用“日本鬼子”一词,究竟动了谁的蛋糕,为啥有这么大的争议?

禁用“日本鬼子”一词,究竟动了谁的蛋糕,为啥有这么大的争议?

世界有奇事
2026-10-12 16:01:15
烂番茄100%,《欢迎来龙餐馆》北美口碑爆了

烂番茄100%,《欢迎来龙餐馆》北美口碑爆了

犀牛娱乐
2026-10-15 08:48:46
吴卓羲称与张曦雯心灵相通,大赞女方每个角度都漂亮!豪言:给我们一些空间

吴卓羲称与张曦雯心灵相通,大赞女方每个角度都漂亮!豪言:给我们一些空间

我爱追港剧
2026-10-16 11:38:50
想留Win10太难了!电脑凌晨1点自动更新Win 11:用户称根本没点同意

想留Win10太难了!电脑凌晨1点自动更新Win 11:用户称根本没点同意

快科技
2026-10-15 17:41:08
福州一工人被指长相酷似陈小春,网友猜测其是陈小春失散多年的弟弟,当事人发帖澄清:并不是他弟弟,只是长得像

福州一工人被指长相酷似陈小春,网友猜测其是陈小春失散多年的弟弟,当事人发帖澄清:并不是他弟弟,只是长得像

极目新闻
2026-10-15 17:30:56
成都市原市长王凤朝被提起公诉,曾为谋求职务晋升搞“政绩工程”

成都市原市长王凤朝被提起公诉,曾为谋求职务晋升搞“政绩工程”

界面新闻
2026-10-15 10:18:36
这就是赤裸裸的现实!工商银行已经到了最危险的时候?

这就是赤裸裸的现实!工商银行已经到了最危险的时候?

财经保探长
2026-08-23 21:43:55
2026-10-16 12:32:49
deephub incentive-icons
deephub
CV NLP和数据挖掘知识
2028文章数 1465关注度
往期回顾 全部

科技要闻

杨天若院士:AI是中国弯道超车的机会

头条要闻

莎拉弹劾案突然转向 菲总统和副总统的"战争"加速了

头条要闻

莎拉弹劾案突然转向 菲总统和副总统的"战争"加速了

体育要闻

工资一分不要,曼联名将想把母队带回西甲

娱乐要闻

徐艺洋官宣生子,完全看不出生过宝宝

财经要闻

特斯拉“飞”起来了!意向金33.2万元

汽车要闻

年轻人专属的大五座 小鹏MONA L05预售16.98万起

态度原创

艺术
手机
数码
公开课
军事航空

艺术要闻

徐明 风景油画选

手机要闻

苹果首款折叠屏iPhone Duo今晚8点天猫开抢!15999元起 最高24期免息

数码要闻

高频打印、需要自动双面,打印质量好首选惠普连供670系列

公开课

李玫瑾:为什么性格比能力更重要?

军事要闻

知情人士:乌克兰"爱国者"拦截弹库存耗尽

无障碍浏览 进入关怀版