阅读高频论文并开发
EarnHFT是发表在AAAI 2024的一篇论文的实现项目,标题为(高频交易的高效分层强化学习)。论文链接:https://arxiv.org/pdf/2309.12891.pdf官方GitHub:https://github.com/qinmoelei/EarnHFT分层强化学习框架将高频交易分解为高层(策略选择)和低层(执行)两个时间尺度高层在分钟级别,低层在秒级别解决了高频环境下状态空间爆
EarnHFT 项目迁移计划:BTC → SHFE.ru2605(橡胶期货)
项目概述
将 EarnHFT 分层强化学习高频交易系统从加密货币 BTCUSDT 迁移到上期所橡胶期货 ru2605 合约。
数据范围:2026-01-05 至 2026-01-28(约24天数据)
开发环境:conda activate py396,Python 3.9.6
一、橡胶期货RU2605合约规格
| 参数 | 值 | 说明 |
|---|---|---|
| 交易单位 | 10吨/手 | 1手=10吨 |
| 最小变动价位 | 5元/吨 | 1个点位=50元/手 |
| 数据频率 | 500ms快照 | 无需resample,直接使用 |
| 交易时间 | 见下方 | 有夜盘 |
| 开仓手续费 | 3.5元/手 | 固定费用 |
| 平仓手续费 | 0元/手 | 平今免费 |
橡胶期货交易时间(含夜盘)
| 时段 | 时间 | 说明 |
|---|---|---|
| 夜盘 | 21:00 - 23:00 | 前一日夜盘 |
| 日盘上午 | 09:00 - 10:15 | |
| 日盘中场休息 | 10:15 - 10:30 | |
| 日盘上午 | 10:30 - 11:30 | |
| 午休 | 11:30 - 13:30 | |
| 日盘下午 | 13:30 - 15:00 |
每日交易时长:5.75小时 = 20700秒 = 41400个500ms快照
- 夜盘21:00-23:00:2小时
- 日盘上午09:00-11:30:2小时15分钟(含15分钟休息)
- 日盘下午13:30-15:00:1.5小时
二、核心配置变更
| 参数 | BTCUSDT 原值 | SHFE.ru2605 新值 | 说明 |
|---|---|---|---|
dataset_name |
“BTCUSDT” | “ru_mm” | 数据集名称 |
max_holding_number |
0.01 | 5.0 | 最大持仓量(手) |
transcation_cost |
0.00(比例) | 3.5(固定开仓) | 开仓3.5元/手,平仓0元 |
action_dim |
5 | 5 | 动作维度(0%, 25%, 50%, 75%, 100%) |
reward_scale |
30 (低层) / 10 (高层) | 待调优 | 奖励缩放因子 |
gamma |
1.0 | 0.9 | 折扣因子 |
data_frequency |
1秒 | 500ms | 数据快照频率 |
chunk_length |
14400 | 41400 | 数据块大小(每日500ms快照数,5.75小时) |
数据处理说明
| 项目 | BTCUSDT | SHFE.ru2605 |
|---|---|---|
| 原始数据 | 1秒快照 | 500ms快照 |
| Resample | 需要处理 | 无需resample |
| 订单簿数据 | 1秒级别 | 直接使用500ms |
| 分钟OHLC | 从1秒合成 | 从500ms合成 |
三、目录结构规划
D:\quant\earn_hft\
├── ru2605_tick.csv # 原始tick数据(2026-01-05 ~ 2026-01-28)
│
├── ru_mm/ # 新增:ru_mm项目目录
│ ├── data_preprocess/ # 数据预处理模块
│ │ └── preprocess/
│ │ ├── concat_clean_ru.py # 新增:ru数据清洗
│ │ ├── create_feature.py # 复用:特征工程(从原项目复制)
│ │ └── merge_new.py # 复用:数据合并(从原项目复制)
│ │
│ ├── EarnHFT_Algorithm/ # 算法模块(从原项目复制/修改)
│ │ ├── env/
│ │ │ ├── low_level_env.py # 修改:固定手续费、gamma=0.9
│ │ │ └── high_level_env.py # 修改:更新model_path配置
│ │ │
│ │ ├── model/
│ │ │ └── net.py # 复用:网络定义
│ │ │
│ │ ├── tool/
│ │ │ └── demonstration.py # 修改:固定手续费
│ │ │
│ │ ├── RL/
│ │ │ ├── agent/
│ │ │ │ ├── low_level/
│ │ │ │ │ └── ddqn_pes_risk_aware.py # 复用:低层训练
│ │ │ │ └── high_level/
│ │ │ │ ├── dqn_position.py # 修改:添加ru_mm配置
│ │ │ │ ├── test_dqn_position.py # 复用
│ │ │ │ └── test_single_agent.py # 复用
│ │ │ └── util/
│ │ │ ├── replay_buffer_DQN.py # 复用
│ │ │ ├── episode_selector.py # 复用
│ │ │ └── graph.py # 复用
│ │ │
│ │ ├── data/
│ │ │ ├── split_data.py # 复用:数据分割
│ │ │ └── feature/
│ │ │ ├── second_feature.npy # 需生成:秒级特征列表
│ │ │ └── minitue_feature.npy # 需生成:分钟级特征列表
│ │ │
│ │ ├── analysis/
│ │ │ ├── pick_agent/
│ │ │ │ ├── pick_agent.py # 复用
│ │ │ │ └── pick_agent_position.py # 复用
│ │ │ └── calculate_metric/
│ │ │ └── calculate_metric.py # 复用
│ │ │
│ │ ├── script/ # 训练脚本
│ │ │ └── ru_mm/ # 新增:ru_mm训练脚本目录
│ │ │ ├── low_level/
│ │ │ │ ├── train.bat # 低层训练(Windows批处理,4个beta顺序)
│ │ │ │ └── valid_multi.bat # 验证与选择
│ │ │ └── high_level/
│ │ │ ├── train.bat # 高层训练
│ │ │ └── test.bat # 测试
│ │ │
│ │ └── requirements.txt # Python依赖
│ │
│ ├── data/ # 数据目录
│ │ └── ru_mm/ # 新增:ru_mm数据目录
│ │ ├── train/ # 训练数据块(df_0.feather...)
│ │ ├── train.feather # 完整训练集
│ │ ├── valid.feather # 验证集
│ │ └── test.feather # 测试集
│ │
│ ├── log/ # 日志目录
│ │ └── train/
│ │ └── ru_mm/
│ │ ├── low_level/ # 低层训练日志
│ │ └── high_level/ # 高层训练日志
│ │
│ └── result_risk/ # 模型保存目录
│ └── ru_mm/
│ ├── potential_model/ # 低层模型池
│ │ ├── initial_action_0/ # 初始持仓0%
│ │ │ ├── model_0.pth # beta=100
│ │ │ ├── model_1.pth # beta=30
│ │ │ ├── model_2.pth # beta=-10
│ │ │ ├── model_3.pth # beta=-90
│ │ │ └── model_4.pth # 选择出的最佳模型
│ │ ├── initial_action_1/ # 初始持仓25%
│ │ ├── initial_action_2/ # 初始持仓50%
│ │ ├── initial_action_3/ # 初始持仓75%
│ │ └── initial_action_4/ # 初始持仓100%
│ └── high_level/ # 高层模型
│ └── seed_12345/
│ └── trained_model.pkl
│
└── detail.md # 原项目文档(参考)
四、实施步骤
阶段1:项目初始化
1.1 创建目录结构
cd D:\quant\earn_hft
# 激活conda环境
conda activate py396
# 创建ru_mm项目目录结构
mkdir ru_mm
cd ru_mm
# 创建子目录
mkdir data_preprocess\preprocess
mkdir data\ru_mm
mkdir data\ru_mm\train
mkdir log\train\ru_mm\low_level
mkdir log\train\ru_mm\high_level
mkdir result_risk\ru_mm
# 复制原有代码文件到ru_mm目录
xcopy ..\EarnHFT_Algorithm EarnHFT_Algorithm\ /E /I
1.2 安装依赖
cd ru_mm\EarnHFT_Algorithm
pip install -r requirements.txt
# 主要依赖:torch, gym, pandas, numpy, pyarrow(feather), tensorboard
阶段2:数据预处理
2.1 数据格式转换脚本
新建文件:ru_mm/data_preprocess/preprocess/concat_clean_ru.py
功能:
- 读取
../ru2605_tick.csv(2026-01-05 ~ 2026-01-28) - 字段映射转换:
SHFE.ru2605.last_price → close(用于生成OHLC) SHFE.ru2605.highest → high SHFE.ru2605.lowest → low SHFE.ru2605.bid_price1-5 → bid1_price-5_price SHFE.ru2605.bid_volume1-5 → bid1_size-5_size SHFE.ru2605.ask_price1-5 → ask1_price-5_price SHFE.ru2605.ask_volume1-5 → ask1_size-5_size datetime → timestamp - 过滤交易时间段(夜盘21:00-23:00 + 日盘)
- 直接使用500ms快照数据,无需resample
- 生成 trade_500ms.feather(500ms级别订单簿数据)
- 生成 trade_minitue.feather(从500ms合成分钟级OHLC)
输出路径:ru_mm/data_preprocess/preprocess/processed_data/ru_mm/2026-01-05-2026-01-28/
执行命令:
cd ru_mm\data_preprocess\preprocess
python concat_clean_ru.py
关键代码要点:
# 500ms数据直接使用,无需resample
# df已经是500ms快照数据,直接过滤交易时间即可
df = df[df['timestamp'].dt.time.between(...)] # 过滤交易时段
# 分钟级OHLC从500ms数据合成
minute_ohlc = df.resample('1T').agg({
'close': 'first', #开盘
'high': 'max', #最高
'low': 'min', #最低
'close': 'last', #收盘
'volume': 'sum'
})
2.2 特征工程
文件:ru_mm/data_preprocess/preprocess/create_feature.py(从原项目复制)
执行命令:
cd ru_mm\data_preprocess\preprocess
python create_feature.py \
--data_path processed_data/ru_mm/2026-01-05-2026-01-28 \
--save_path create_features \
--beat_fee 1e-4
输出:生成带技术指标的特征文件(订单簿特征 + Alpha158类因子)
2.3 数据合并
文件:ru_mm/data_preprocess/preprocess/merge_new.py(从原项目复制)
执行命令:
python merge_new.py \
--data_path create_features/ru_mm/2026-01-05-2026-01-28/beatrate_1e-4 \
--save_path merge
输出:ru_mm/data_preprocess/preprocess/merge/ru_mm/2026-01-05-2026-01-28/df.feather
2.4 数据分割
文件:ru_mm/EarnHFT_Algorithm/data/split_data.py(从原项目复制,修改chunk_length)
修改内容:
# 第18-19行,更新默认参数
parser.add_argument("--chunk_length", type=int, default=41400) # 原:14400,改为500ms快照数
parser.add_argument("--future_sight", type=int, default=7200) # 1小时 = 7200个500ms
执行命令:
cd ..\..\EarnHFT_Algorithm
python data\split_data.py \
--data_path ..\data_preprocess\preprocess\merge\ru_mm\2026-01-05-2026-01-28 \
--chunk_length 41400 \
--future_sight 7200
输出:60%训练集 / 20%验证集 / 20%测试集
数据量估算:
- 24天 × 41400个500ms快照/天 ≈ 993,600个快照
- 训练集:60% ≈ 596,160个快照 ≈ 14.4天 ≈ 14个chunk
- 验证集:20% ≈ 198,720个快照 ≈ 4.8天 ≈ 5个chunk
- 测试集:20% ≈ 198,720个快照 ≈ 4.8天 ≈ 5个chunk
2.5 生成特征列表
需要运行IC分析或手动创建特征列表文件:
# 创建秒级特征列表(从原始特征中筛选)
# 保存到:EarnHFT_Algorithm/data/feature/second_feature.npy
# 创建分钟级特征列表
# 保存到:EarnHFT_Algorithm/data/feature/minitue_feature.npy
阶段3:代码修改
3.1 低层环境修改(固定手续费)
文件:ru_mm/EarnHFT_Algorithm/env/low_level_env.py
修改内容:
# 第19-22行,更新默认参数
transcation_cost = 3.5 # 原:0.00(固定开仓费用3.5元/手)
max_holding_number = 5.0 # 原:0.01
关键修改:sell_value 和 buy_value 方法需要改为固定手续费
# 第63-86行,修改sell_value方法
def sell_value(self, price_information, position):
# ...(原有计算逻辑)
# 平仓手续费为0
self.comission_fee_history.append(0) # 平仓不收费
return value, actual_changed_position
# 第88-110行,修改buy_value方法
def buy_value(self, price_information, position):
# ...(原有计算逻辑)
# 开仓手续费为3.5元/手 × 手数
self.comission_fee_history.append(3.5 * (actual_changed_position / self.max_holding_number * 5))
return value * (1 + 0), actual_changed_position # 不使用比例费用
3.2 高层环境配置
文件:ru_mm/EarnHFT_Algorithm/env/high_level_env.py
修改内容:
- 第29-32行,更新默认参数:
transcation_cost = 3.5 # 固定开仓费用
max_holding_number = 5.0 # 最大持仓量
- 第41-77行,修改
model_path_list_dict配置:
model_path_list_dict = {
0: ["result_risk/ru_mm/potential_model/initial_action_0/model_0.pth", ...],
1: ["result_risk/ru_mm/potential_model/initial_action_1/model_0.pth", ...],
2: ["result_risk/ru_mm/potential_model/initial_action_2/model_0.pth", ...],
3: ["result_risk/ru_mm/potential_model/initial_action_3/model_0.pth", ...],
4: ["result_risk/ru_mm/potential_model/initial_action_4/model_0.pth", ...],
}
3.3 动态规划Q表计算(固定手续费)
文件:ru_mm/EarnHFT_Algorithm/tool/demonstration.py
修改内容:
make_q_table_reward函数中的commission_fee参数改为固定费用逻辑- 开仓时使用3.5元/手,平仓时使用0元
3.4 高层训练脚本
文件:ru_mm/EarnHFT_Algorithm/RL/agent/high_level/dqn_position.py
修改内容:
- 第207行附近,添加
ru_mm到 dataset_name 断言:
assert args.dataset_name in ["BTCUSDT", "ETHUSDT", "GALAUSDT", "BTCTUSD", "ru_mm"]
- 第360行附近,添加 ru_mm 的
model_path_list_dict配置:
elif args.dataset_name == "ru_mm":
model_path_list_dict = {
0: ["result_risk/ru_mm/potential_model/initial_action_0/model_0.pth", ...],
1: ["result_risk/ru_mm/potential_model/initial_action_1/model_0.pth", ...],
2: ["result_risk/ru_mm/potential_model/initial_action_2/model_0.pth", ...],
3: ["result_risk/ru_mm/potential_model/initial_action_3/model_0.pth", ...],
4: ["result_risk/ru_mm/potential_model/initial_action_4/model_0.pth", ...],
}
3.5 gamma参数更新
在 low_level_env.py 和 ddqn_pes_risk_aware.py 中更新 gamma 默认值为 0.9:
# low_level_env.py Training_Env类
def __init__(self, ..., gamma=0.9, ...): # 原:gamma=1
# ddqn_pes_risk_aware.py
parser.add_argument("--gamma", type=float, default=0.9, help="the learning rate")
阶段4:训练脚本创建
4.1 低层训练脚本
新建文件:ru_mm/EarnHFT_Algorithm/script/ru_mm/low_level/train.bat
@echo off
REM 激活conda环境
call conda activate py396
REM 单GPU顺序训练4个不同beta值的低层代理
REM Beta 100: 高度偏好好行情
echo Training low_level agent with beta=100...
python RL/agent/low_level/ddqn_pes_risk_aware.py ^
--beta 100 --train_data_path ../../data/ru_mm/train --dataset_name ru_mm ^
--max_holding_number 5.0 --transcation_cost 3.5 ^
--reward_scale 30 --num_sample 200 --gamma 0.9 ^
--buffer_size 100000 --batch_size 256 ^
>../../log/train/ru_mm/low_level/beta_100.log 2>&1
REM Beta 30: 温和偏好好行情
echo Training low_level agent with beta=30...
python RL/agent/low_level/ddqn_pes_risk_aware.py ^
--beta 30 --train_data_path ../../data/ru_mm/train --dataset_name ru_mm ^
--max_holding_number 5.0 --transcation_cost 3.5 ^
--reward_scale 30 --num_sample 200 --gamma 0.9 ^
--buffer_size 100000 --batch_size 256 ^
>../../log/train/ru_mm/low_level/beta_30.log 2>&1
REM Beta -10: 略微风险厌恶
echo Training low_level agent with beta=-10...
python RL/agent/low_level/ddqn_pes_risk_aware.py ^
--beta -10 --train_data_path ../../data/ru_mm/train --dataset_name ru_mm ^
--max_holding_number 5.0 --transcation_cost 3.5 ^
--reward_scale 30 --num_sample 200 --gamma 0.9 ^
--buffer_size 100000 --batch_size 256 ^
>../../log/train/ru_mm/low_level/beta_-10.log 2>&1
REM Beta -90: 高度风险厌恶
echo Training low_level agent with beta=-90...
python RL/agent/low_level/ddqn_pes_risk_aware.py ^
--beta -90 --train_data_path ../../data/ru_mm/train --dataset_name ru_mm ^
--max_holding_number 5.0 --transcation_cost 3.5 ^
--reward_scale 30 --num_sample 200 --gamma 0.9 ^
--buffer_size 100000 --batch_size 256 ^
>../../log/train/ru_mm/low_level/beta_-90.log 2>&1
echo All low_level training completed!
pause
4.2 验证与代理选择脚本
新建文件:ru_mm/EarnHFT_Algorithm/script/ru_mm/low_level/valid_multi.bat
@echo off
call conda activate py396
REM 验证所有训练好的低层模型并选择最佳模型
REM 需要先创建 pick_agent 脚本或手动运行
echo Validating and selecting best models for each initial action...
REM TODO: 实现验证逻辑
echo Validation completed!
pause
4.3 高层训练脚本
新建文件:ru_mm/EarnHFT_Algorithm/script/ru_mm/high_level/train.bat
@echo off
call conda activate py396
echo Training high_level agent...
python RL/agent/high_level/dqn_position.py ^
--train_data_path ../../data/ru_mm/train.feather --dataset_name ru_mm ^
--max_holding_number 5.0 --transcation_cost 3.5 ^
--reward_scale 10 --num_sample 100 --gamma 0.9 ^
--buffer_size 100000 --batch_size 256 ^
>../../log/train/ru_mm/high_level/log.log 2>&1
echo High_level training completed!
pause
4.4 测试脚本
新建文件:ru_mm/EarnHFT_Algorithm/script/ru_mm/high_level/test.bat
@echo off
call conda activate py396
echo Testing complete system...
python RL/agent/high_level/test_dqn_position.py ^
--test_data_path ../../data/ru_mm/test.feather --dataset_name ru_mm ^
--max_holding_number 5.0 --transcation_cost 3.5 ^
--model_path ../../result_risk/ru_mm/high_level/seed_12345/trained_model.pkl
pause
阶段5:执行流程
# ========== 步骤1:项目初始化 ==========
cd D:\quant\earn_hft
conda activate py396
mkdir ru_mm
cd ru_mm
# 复制代码框架
xcopy ..\EarnHFT_Algorithm EarnHFT_Algorithm\ /E /I
mkdir data\ru_mm\train
mkdir log\train\ru_mm\low_level
mkdir log\train\ru_mm\high_level
mkdir result_risk\ru_mm
# ========== 步骤2:数据预处理 ==========
cd data_preprocess
mkdir preprocess
cd preprocess
# 运行数据清洗脚本
python concat_clean_ru.py
# 运行特征工程
python create_feature.py --data_path processed_data/ru_mm/2026-01-05-2026-01-28
# 运行数据合并
python merge_new.py --data_path create_features/ru_mm/2026-01-05-2026-01-28/beatrate_1e-4
# ========== 步骤3:数据分割 ==========
cd ..\..\EarnHFT_Algorithm
python data\split_data.py --data_path ..\data_preprocess\preprocess\merge\ru_mm\2026-01-05-2026-01-28
# ========== 步骤4:低层代理训练 ==========
cd script\ru_mm\low_level
train.bat
# ========== 步骤5:验证与选择 ==========
# 手动检查训练结果,选择最佳模型
# 复制模型到 result_risk/ru_mm/potential_model/initial_action_X/
# ========== 步骤6:高层代理训练 ==========
cd ..\high_level
train.bat
# ========== 步骤7:系统测试 ==========
test.bat
五、固定手续费实现细节
5.1 手续费规则
| 操作 | 费用 | 计算 |
|---|---|---|
| 开仓 | 3.5元/手 | 3.5 × 手数 |
| 平仓 | 0元/手 | 0 |
5.2 代码实现要点
原项目使用比例手续费,需要修改为固定手续费:
原代码(比例):
# 开仓
value = value * (1 + commission_fee) # commission_fee = 0.00
# 平仓
value = value * (1 - commission_fee)
新代码(固定):
# 开仓:添加固定费用
fixed_cost = 3.5 * num_contracts
self.comission_fee_history.append(fixed_cost)
return value + fixed_cost, actual_changed_position
# 平仓:无费用
self.comission_fee_history.append(0)
return value, actual_changed_position
六、数据时间处理
6.1 夜盘跨日处理
橡胶期货夜盘(21:00-23:00)在日历上属于"前一日",但交易逻辑上属于"当日":
- 建议按交易日划分:夜盘+日盘为同一个交易日
- 时间戳统一使用
datetime类型,方便后续处理
6.2 非交易时段处理
需要过滤的时间段:
- 00:00 - 09:00(休息)
- 10:15 - 10:30(中场休息)
- 11:30 - 13:30(午休)
- 15:00 - 21:00(休市)
七、需要修改/创建的文件清单
| 文件路径 | 操作 | 说明 |
|---|---|---|
ru_mm/data_preprocess/preprocess/concat_clean_ru.py |
新建 | ru数据清洗与格式转换 |
ru_mm/data_preprocess/preprocess/create_feature.py |
复制 | 特征工程 |
ru_mm/data_preprocess/preprocess/merge_new.py |
复制 | 数据合并 |
ru_mm/EarnHFT_Algorithm/env/low_level_env.py |
修改 | 固定手续费、gamma=0.9、max_holding=5.0 |
ru_mm/EarnHFT_Algorithm/env/high_level_env.py |
修改 | 更新model_path配置 |
ru_mm/EarnHFT_Algorithm/tool/demonstration.py |
修改 | 固定手续费逻辑 |
ru_mm/EarnHFT_Algorithm/RL/agent/high_level/dqn_position.py |
修改 | 添加ru_mm配置 |
ru_mm/EarnHFT_Algorithm/data/split_data.py |
修改 | chunk_length=17100 |
ru_mm/EarnHFT_Algorithm/script/ru_mm/low_level/train.bat |
新建 | 低层训练脚本 |
ru_mm/EarnHFT_Algorithm/script/ru_mm/high_level/train.bat |
新建 | 高层训练脚本 |
ru_mm/EarnHFT_Algorithm/script/ru_mm/high_level/test.bat |
新建 | 测试脚本 |
ru_mm/EarnHFT_Algorithm/data/feature/second_feature.npy |
生成 | 秒级特征列表 |
ru_mm/EarnHFT_Algorithm/data/feature/minitue_feature.npy |
生成 | 分钟级特征列表 |
八、验证检查点
8.1 数据检查
- ru2605_tick.csv 读取正常,数据时间范围正确
- 字段映射正确(bid/ask price/volume)
- 交易时间段过滤正确(含夜盘)
- 降采样后数据无缺失
8.2 特征检查
- 特征工程无报错
- second_feature.npy 和 minitue_feature.npy 已生成
- 特征数量合理(建议50-200个)
8.3 环境检查
- low_level_env 可正常实例化
- 固定手续费计算正确
- gamma=0.9 正确设置
- high_level_env 可正常加载低层模型
8.4 训练检查
- 4个beta的训练均正常启动
- TensorBoard日志正常记录
- 模型保存路径正确
8.5 结果检查
- 低层模型收敛(loss下降)
- 高层模型训练完成
- 回测收益率合理
- 手续费计算正确
九、预期工作量
| 阶段 | 工作内容 | 预计时间 |
|---|---|---|
| 项目初始化 | 创建目录、复制代码、安装依赖 | 30分钟 |
| 数据预处理 | 开发concat_clean_ru.py、特征工程 | 2-3小时 |
| 代码修改 | 修改手续费逻辑、gamma配置 | 1-2小时 |
| 训练脚本 | 创建bat脚本 | 30分钟 |
| 训练执行 | 低层+高层训练 | 数小时 |
| 调试优化 | 根据结果调参 | 根据实际情况 |
| 总计 | 约半天到1天 |
十、风险与注意事项
- 数据量限制:24天数据可能不够充分,建议监控训练效果,必要时补充更多历史数据
- 手续费影响:固定手续费可能使高频策略成本较高,建议降低交易频率
- 夜盘跨日:需正确处理夜盘与日盘的日期归属
- 过拟合风险:数据量有限,需注意模型泛化能力
- reward_scale调优:橡胶价格波动与BTC不同,可能需要调整奖励缩放
EarnHFT 项目详解:分层强化学习高频交易系统
一、项目概述
EarnHFT 是发表在 AAAI 2024 的一篇论文的实现项目,标题为 “Efficient Hierarchical Reinforcement Learning for High Frequency Trading”(高频交易的高效分层强化学习)。
论文链接:https://arxiv.org/pdf/2309.12891.pdf
官方GitHub:https://github.com/qinmoelei/EarnHFT
核心创新点
本项目提出了**分层强化学习(HRL)**框架来解决高频交易问题:
- 高层代理(High-level Agent):在分钟级别运行,负责选择合适的低级代理
- 低层代理(Low-level Agent):在秒级别运行,负责具体的仓位管理决策
这种分层设计解决了高频交易中的两个核心挑战:
- 高维状态空间:每秒的市场状态变化剧烈
- 长期信用分配:交易决策的收益需要较长时间才能体现
二、整体架构图
┌─────────────────────────────────────────────────────────────────┐
│ 高级环境 (Minute Level) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ High-Level DQN Agent │ │
│ │ - 输入:分钟级特征 + 当前持仓 │ │
│ │ - 输出:选择哪个低层代理 (5个选择) │ │
│ │ - 奖励:1分钟内所有低层代理的累积收益 │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│
选择低层代理池中的某个代理
│
┌─────────────────────────────────────────────────────────────────┐
│ 低级环境 (Second Level) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Low-Level DDQN Agent (多个,不同beta偏好) │ │
│ │ - 输入:秒级特征 + 上一动作 + 可用动作掩码 │ │
│ │ - 输出:5维动作 (持仓比例 0%, 25%, 50%, 75%, 100%) │ │
│ │ - 奖励:即时收益 + 未来价值 (Q-Table引导) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
三、论文核心逻辑详解
3.1 问题建模
将高频交易建模为马尔可夫决策过程(MDP):
- 状态空间 S:市场状态特征(订单簿 + 技术指标)
- 动作空间 A:持仓比例调整(0%, 25%, 50%, 75%, 100%)
- 奖励函数 R:基于持仓价值变化
- 转移函数 P:市场动态
3.2 分层强化学习的必要性
为什么需要分层?
-
时间尺度分离:
- 低层:秒级决策,需要快速响应市场变化
- 高层:分钟级决策,关注市场趋势
-
信用分配缓解:
- 低层代理的奖励由动态规划Q-Table预计算引导
- 高层代理关注长期的代理选择决策
-
策略多样性:
- 训练多个具有不同风险偏好的低层代理
- 高层学习在不同市场环境下选择合适的代理
3.3 动态规划Q-Table初始化(核心创新)
论文使用动态规划预计算Q值作为RL训练的引导:
数学公式:
Q[t][prev_action][curr_action] = 即时奖励 + γ × max(Q[t+1][curr_action][:])
核心思想:
- 从最后一个时间步开始倒推
- 每个Q值表示:在t时刻,给定前一动作prev_action,选择当前动作curr_action的期望累积收益
- 这相当于"作弊"地告诉智能体最优策略应该是什么样的
作用:
- 加速收敛:智能体从"好的起点"开始学习
- 解决信用分配:即时奖励可能很小,但长期来看是最优的决策
- 提供演示信号:通过KL散度让智能体模仿最优策略
论文逻辑:数据从 Tardis 下载,包含5档订单簿快照和交易记录
代码实现 (data_preprocess/):
# 数据预处理流程
1. download_code/download.sh - 从Tardis下载原始数据
2. preprocess/concat_clean.sh - 数据清洗和降采样
3. preprocess/create_feature.sh - 创建特征
4. preprocess/merge_new.sh - 合并特征
5. ic_analysis/calculate_ic.sh - 计算IC选择优质特征
数据流程详解:
- 订单簿快照 (book_snapshot_5):包含5档买卖挂单详情
- 交易记录 (trades):实时成交记录
经过预处理后生成:
orderbook.feather:秒级订单簿数据trade_second.feather:秒级OHLC数据trade_minitue.feather:分钟级OHLC数据
2. 低层环境(Second-level Trading)
论文逻辑:低层代理在每秒级别做决策,学习在特定市场环境下如何调整仓位
代码实现 (EarnHFT_Algorithm/env/low_level_env.py):
class Testing_env(gym.Env):
def __init__(self, df, tech_indicator_list, transcation_cost,
back_time_length, max_holding_number, action_dim):
self.action_dim = action_dim # 5个离散动作
self.action_space = spaces.Discrete(action_dim) # 0-4
self.max_holding_number = max_holding_number # 最大持仓
self.observation_space = spaces.Box(
low=-np.inf, high=+np.inf,
shape=(back_time_length * len(self.tech_indicator_list),))
关键函数:
def sell_value(self, price_information, position):
"""计算卖出价值 - 考虑订单簿深度"""
value = 0
for i in range(1, 6):
if position < price_information["bid{}_size".format(i)]:
break
value += price_information["bid{}_price".format(i)] * \
price_information["bid{}_size".format(i)]
return value * (1 - self.comission_fee)
def buy_value(self, price_information, position):
"""计算买入成本 - 考虑订单簿深度"""
value = 0
for i in range(1, 6):
if position < price_information["ask{}_size".format(i)]:
break
value += price_information["ask{}_price".format(i)] * \
price_information["ask{}_size".format(i)]
return value * (1 + self.comission_fee)
3. 动态规划 Q-Table 初始化(论文创新点)
论文逻辑:使用动态规划预计算Q值作为RL训练的引导,加速收敛
代码实现 (EarnHFT_Algorithm/tool/demonstration.py):
def make_q_table_reward(df, num_action, max_holding, reward_scale,
gamma, commission_fee, max_punish):
"""
使用动态规划预计算 Q-Table
Q[t][prev_action][curr_action] = 即时奖励 + γ × max(Q[t+1][curr_action][:])
"""
q_table = np.zeros((len(df), num_action, num_action))
# 从后往前倒推计算Q值
for t in range(2, len(df) + 1):
current_price = df.iloc[-t]
future_price = df.iloc[-t + 1]
for previous_action in range(num_action):
for current_action in range(num_action):
# 买入情况
if current_action > previous_action:
position_change = (current_action - previous_action) / scale_factor * max_holding
reward = future_value - (current_value + buy_money)
# 卖出/持仓情况
else:
position_change = (previous_action - current_action) / scale_factor * max_holding
reward = future_value + sell_money - current_value
# Q值 = 即时奖励 × 奖励缩放 + γ × 下一时刻最大Q值
q_table[len(df)-t][previous_action][current_action] = \
reward * reward_scale + gamma * np.max(q_table[len(df)-t+1][current_action][:])
return q_table
4.4 低层代理训练(DDQN + PES + KL散度)
代码实现 (EarnHFT_Algorithm/RL/agent/low_level/ddqn_pes_risk_aware.py):
核心特性:
- DDQN(双DQN):使用当前网络选动作,目标网络算Q值
- PES(优先级经验回放):根据收益分布选择训练样本
- KL散度约束:模仿动态规划Q-Table的最优策略
class DQN(object):
def __init__(self, args):
# PES优先级转换函数
self.beta = args.beta
self.type = args.type # "even", "sigmoid", "boltzmann"
if self.type == "even":
self.priority_transformation = get_transformation_even_risk
elif self.type == "sigmoid":
self.priority_transformation = get_transformation_even_based_sigmoid_risk
elif self.type == "boltzmann":
self.priority_transformation = get_transformation_even_based_boltzmann_risk
# 网络结构
self.eval_net = Qnet(self.n_state, self.action_dim, self.hidden_nodes).to(self.device)
self.target_net = copy.deepcopy(self.eval_net)
def update(self, states, info, actions, rewards, next_states, info_, dones):
"""DDQN更新 + KL散度约束"""
b = states.shape[0]
# 1. DDQN:计算当前网络选动作的Q值
q_eval = self.eval_net(
states.reshape(b, -1),
info["previous_action"].float().unsqueeze(1),
info["avaliable_action"],
).gather(1, actions)
# 2. 目标网络计算Q值(detach不计算梯度)
q_next = self.target_net(
next_states.reshape(b, -1),
info_["previous_action"].float().unsqueeze(1),
info_["avaliable_action"],
).detach()
# 3. Q目标 = 即时奖励 + γ × 下一状态最大Q值
q_target = rewards + torch.max(q_next, 1)[0].view(self.batch_size, 1) * (1 - dones)
# 4. TD误差
td_error = self.loss_func(q_eval, q_target)
# 5. KL散度:让智能体模仿动态规划的最优策略
demonstration = info["q_value"] # 预计算的Q-Table值
predict_action_distrbution = self.eval_net(...)
KL_div = F.kl_div(
(predict_action_distrbution.softmax(dim=-1) + 1e-8).log(),
(demonstration.softmax(dim=-1) + 1e-8),
reduction="batchmean",
)
# 6. 总损失 = TD误差 + KL散度 × ada系数
loss = td_error + KL_div * self.ada
# 7. 反向传播 + 梯度裁剪
self.optimizer.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(self.eval_net.parameters(), self.grad_clip)
self.optimizer.step()
# 8. 软更新目标网络
for param, target_param in zip(self.eval_net.parameters(), self.target_net.parameters()):
target_param.data.copy_(self.tau * param.data + (1-self.tau) * target_param.data)
训练流程:
def train(self):
# 1. 初始化PES采样器
for i in range(df_number):
df = pd.read_feather(...)
# 计算每个chunk的收益率
return_rate_list.append(df.iloc[self.chunk_num]["bid1_price"] / df.iloc[0]["ask1_price"] - 1)
initial_priority_list = self.priority_transformation(return_rate_list, beta=self.beta)
self.start_selector = start_selector(range(df_number), initial_priority_list)
# 2. 双经验回放缓冲区
replay_buffer_perfect = Multi_step_ReplayBuffer_multi_info(...) # 使用最优策略采样
replay_buffer_normal = Multi_step_ReplayBuffer_multi_info(...) # 正常探索采样
for sample in range(self.num_sample):
# 使用PES选择训练样本
df_index = self.start_selector.sample()[0]
self.train_df = pd.read_feather(...)
# 3. 第一阶段:使用预计算的Q-Table(最优策略)训练
train_env = Training_Env(...)
s, info = train_env.reset()
while True:
a = self.act_perfect(info) # 直接使用Q-Table的最大值作为动作
s_, r, done, info_ = train_env.step(a)
replay_buffer_perfect.add(s, info, a, r, s_, info_, done)
if done:
break
# 4. 第二阶段:使用探索策略训练
train_env = Training_Env(...)
s, info = train_env.reset()
while True:
a = self.act(s, info, self.epsilon) # ε-贪婪探索
s_, r, done, info_ = train_env.step(a)
replay_buffer_normal.add(s, info, a, r, s_, info_, done)
# 5. 训练更新
if step_counter > batch_size and step_counter % target_freq == 1:
for _ in range(self.update_times):
states, infos, actions, rewards, ... = replay_buffer_normal.sample()
self.update(states, infos, actions, rewards, ...)
if done:
break
5. 低层代理池构建(Comprehensive Evaluation)
代码实现 (EarnHFT_Algorithm/analysis/pick_agent/pick_agent.py):
def get_best_model(label_name, root_path):
"""评估所有低层代理,按收益排序选择"""
result_dict = {}
for coffient in coffient_list:
for epoch in epoch_list:
target_path = os.path.join(epoch_path, "valid_multi", label_name)
return_rate = final_balance / required_money
result_dict["{}_{}".format(coffient, epoch)] = {
"average_return_rate": np.mean(return_rate_list),
}
return find_max_average_return_rate(result_dict)
if __name__ == "__main__":
save_path = "result_risk/BTCUSDT/potential_model"
for i in range(5):
index_model = get_best_model(label_name="label_{}".format(i))
model_path_list.append(best_model_path)
6. 高层环境(Minute-level Agent Selection)
代码实现 (EarnHFT_Algorithm/env/high_level_env.py):
class high_level_testing_env(Testing_env):
def __init__(self, df, model_path_list_dict):
self.low_level_agent_list_dict = {}
for key in model_path_list_dict:
self.low_level_agent_list_dict[key] = []
for model_path in model_path_list_dict[key]:
model = Qnet(...).to("cpu")
model.load_state_dict(torch.load(model_path))
self.low_level_agent_list_dict[key].append(model)
self.action_space = spaces.Discrete(5)
def step(self, macro_action):
current_position_level = int(self.position / step)
self.chosen_model = self.low_level_agent_list_dict[current_position_level][macro_action]
reward_mintue = 0
while self.data.iloc[-1].timestamp.second != 59:
macro_action = self.pose_macro_action(self.state, self.info)
self.state, reward, done, self.info = super().step(macro_action)
reward_mintue += reward
return self.state, reward_mintue, done, self.info
7. 高层代理训练
代码实现 (EarnHFT_Algorithm/RL/agent/high_level/dqn.py):
class DQN(object):
def update(self, info, actions, rewards, info_, dones):
q_eval = self.eval_net(torch.squeeze(info["high_level_state"])).gather(1, actions)
q_next = self.target_net(torch.squeeze(info_["high_level_state"])).detach()
q_target = rewards + torch.max(q_next, 1)[0] * (1-dones) * self.gamma
td_error = self.loss_func(q_eval, q_target)
self.optimizer.zero_grad()
td_error.backward()
torch.nn.utils.clip_grad_norm_(self.eval_net.parameters(), self.grad_clip)
self.optimizer.step()
for param, target_param in zip(self.eval_net.parameters(), self.target_net.parameters()):
target_param.data.copy_(self.tau * param.data + (1-self.tau) * target_param.data)
4.8 经验回放缓冲区
代码实现 (EarnHFT_Algorithm/RL/util/replay_buffer_DQN.py):
class Multi_step_ReplayBuffer_multi_info:
"""多步经验回放缓冲区"""
def __init__(self, buffer_size, batch_size, device, seed, gamma, n_step):
self.buffer_size = buffer_size
self.gamma = gamma # 折扣因子
self.n_step = n_step # n步回报
self.n_step_buffer = deque(maxlen=n_step)
def add(self, state, info, action, reward, next_state, next_info, done):
"""添加经验到缓冲区"""
self.n_step_buffer.append((state, info, action, reward, next_state, next_info, done))
if len(self.n_step_buffer) == self.n_step:
transition = self.calc_multistep_return(self.n_step_buffer)
self.memory.append(transition)
def calc_multistep_return(self, n_step_buffer):
"""计算n步回报"""
Return = 0
for i in range(self.n_step):
Return += self.gamma ** i * n_step_buffer[i][3] # 累加折扣奖励
return (
n_step_buffer[0][0], # 初始状态
n_step_buffer[0][1], # 初始info
n_step_buffer[0][2], # 动作
Return, # n步回报
n_step_buffer[-1][4], # 最后一个状态
n_step_buffer[-1][5], # 最后一个info
n_step_buffer[-1][6], # 最后一个done
)
def sample(self):
"""随机采样一批经验"""
experiences = random.sample(self.memory, k=self.batch_size)
# 转换为tensor并移动到指定设备
...
return (states, infos, actions, rewards, next_states, next_infos, dones)
五、完整训练流程
┌─────────────────────────────────────────────────────────────────┐
│ 步骤1: 数据预处理 │
├─────────────────────────────────────────────────────────────────┤
│ 1.1 下载订单簿快照 + 交易数据 (Tardis API) │
│ 1.2 数据清洗:秒级/分钟级聚合 │
│ 1.3 特征工程:创建技术指标特征 │
│ 1.4 IC分析:筛选优质特征 │
│ - second_feature.npy: 低层代理特征 (秒级) │
│ - minitue_feature.npy: 高层代理特征 (分钟级) │
│ 1.5 数据分割:60%训练 / 20%验证 / 20%测试 │
│ 1.6 训练集分块:每块14400秒,避免内存溢出 │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步骤2: 低层代理训练 │
├─────────────────────────────────────────────────────────────────┤
│ 2.1 预计算Q-Table (动态规划) │
│ 2.2 使用不同beta参数训练多个DDQN代理: │
│ - beta = 100: 高度偏好好行情 │
│ - beta = 30: 温和偏好好行情 │
│ - beta = -10: 略微风险厌恶 │
│ - beta = -90: 高度风险厌恶 │
│ 2.3 训练过程: │
│ - 第一阶段:使用Q-Table引导(模仿最优策略) │
│ - 第二阶段:ε-贪婪探索 + 经验回放 │
│ - KL散度约束:保持与Q-Table一致 │
│ 2.4 输出:result_risk/{dataset}/beta_XX/.../trained_model.pkl │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步骤3: 低层代理综合评估 │
├─────────────────────────────────────────────────────────────────┤
│ 3.1 在验证集上评估所有低层代理 │
│ 3.2 按市场状态分类评估 (label_0 ~ label_4): │
│ - 基于斜率/分位数划分5种市场环境 │
│ 3.3 计算指标: │
│ - 原始收益率:final_balance / required_money │
│ - 归一化收益率:收益率 / 交易次数 │
│ 3.4 选择每个状态下的最佳代理 │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步骤4: 构建代理池 │
├─────────────────────────────────────────────────────────────────┤
│ 4.1 将选中的低层代理保存到代理池 │
│ 4.2 代理池结构: │
│ potential_model/ │
│ ├── initial_action_0/ │
│ │ ├── model_0.pth │
│ │ └── ... │
│ ├── initial_action_1/ │
│ └── ... │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步骤5: 高层代理训练 │
├─────────────────────────────────────────────────────────────────┤
│ 5.1 加载低层代理池 │
│ 5.2 高层环境:每分钟调用一次低层代理 │
│ 5.3 高层DQN学习:选择能带来长期收益的低层代理 │
│ 5.4 输出:result_risk/{dataset}/high_level/.../trained_model.pkl│
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 步骤6: 测试与评估 │
├─────────────────────────────────────────────────────────────────┤
│ 6.1 在测试集上运行完整系统 │
│ 6.2 生成回测报告和收益曲线图 │
│ 6.3 计算指标:收益率、夏普比率、最大回撤等 │
└─────────────────────────────────────────────────────────────────┘
六、关键超参数说明
| 参数 | 说明 | 默认值 | 作用 |
|---|---|---|---|
action_dim |
动作维度 | 5 | 0%, 25%, 50%, 75%, 100% 持仓 |
max_holding_number |
最大持仓 | 0.01 (BTC) | 决定仓位管理的粒度 |
back_time_length |
历史状态长度 | 1 | 使用多少历史时间步 |
beta |
PES偏好参数 | -90, -10, 30, 100 | 控制对不同收益分布的偏好 |
gamma |
折扣因子 | 1.0 | 远期奖励的重要性 |
epsilon_init |
初始探索率 | 0.9 | 初始随机探索概率 |
epsilon_min |
最小探索率 | 0.3 | 保持一定的探索能力 |
batch_size |
批次大小 | 512 | 每次更新的样本数 |
lr_init |
初始学习率 | 1e-2 | 模型收敛速度 |
reward_scale |
奖励缩放 | 30 | 稳定训练过程 |
tau |
软更新系数 | 0.005 | 目标网络更新速度 |
ada |
KL系数 | 256→128 | KL散度约束强度 |
七、论文贡献点总结
7.1 核心创新
-
分层强化学习框架
- 将高频交易分解为高层(策略选择)和低层(执行)两个时间尺度
- 高层在分钟级别,低层在秒级别
- 解决了高频环境下状态空间爆炸和信用分配问题
-
动态规划Q-Table预训练
- 使用后向递推计算理论最优Q值
- 作为RL训练的引导信号,加速收敛
- 通过KL散度让智能体模仿最优策略
-
代理池机制
- 训练多个具有不同风险偏好的低层代理
- 在验证集上评估并选择最佳代理
- 高层代理学习"何时使用哪个代理"
-
流动性约束的动作空间
- 基于订单簿深度动态限制可执行动作
- 避免模拟执行与真实市场脱节
- 更贴近实际交易约束
7.2 实践意义
- 解决了RL在高频领域的两个核心挑战:状态爆炸和信用分配
- 模块化设计:可灵活替换低层代理或调整高层策略
- 可解释性:通过代理池选择,可以分析高层决策的偏好
七、运行指南
环境配置
conda create -n earnhft python=3.7
conda activate earnhft
pip install -r EarnHFT_Algorithm/requirements.txt
训练流程
# 1. 数据预处理
cd data_preprocess
bash preprocess/concat_clean.sh
bash preprocess/create_feature.sh
bash preprocess/merge_new.sh
bash ic_analysis/calculate_ic.sh
# 2. 低层代理训练
cd ../EarnHFT_Algorithm
bash script/BTCUSDT/low_level/train.sh
# 3. 低层代理评估
bash script/BTCUSDT/low_level/valid_multi.sh
# 4. 策略选择
python analysis/pick_agent/pick_agent.py
# 5. 高层代理训练
bash script/BTCUSDT/high_level/train.sh
# 6. 测试
bash script/BTCUSDT/high_level/test.sh
八、文件结构
earn_hft/
├── 2309.12891v1.pdf # 原始论文
├── README.md # 项目说明
├── detail.md # 本文档
│
├── data_preprocess/ # 数据预处理
│ ├── download_code/ # 数据下载
│ │ ├── download.py
│ │ └── download.sh
│ ├── preprocess/ # 数据清洗和聚合
│ │ ├── concat_clean.py
│ │ ├── create_feature.py
│ │ └── merge_new.py
│ ├── ic_analysis/ # 特征选择
│ │ ├── calculate_ic.py
│ │ └── feature/ # 筛选后的特征
│ │ ├── second_feature.npy
│ │ └── minitue_feature.npy
│ └── pic/ # 数据结构图
│
└── EarnHFT_Algorithm/ # 核心算法
├── env/ # 强化学习环境
│ ├── low_level_env.py # 低层环境(秒级)
│ ├── high_level_env.py # 高层环境(分钟级)
│ └── test_env.py # 测试环境
│
├── model/ # 神经网络模型
│ └── net.py # Qnet, Actor, Critic等
│
├── RL/ # 强化学习算法
│ ├── agent/
│ │ ├── base/ # 基础算法实现
│ │ │ ├── dqn_train.py
│ │ │ ├── dqn_test.py
│ │ │ └── ...
│ │ ├── high_level/ # 高层代理
│ │ │ ├── dqn.py
│ │ │ └── dqn_position.py
│ │ └── low_level/ # 低层代理
│ │ └── ddqn_pes_risk_aware.py
│ └── util/ # 工具函数
│ ├── replay_buffer_DQN.py # 经验回放
│ ├── graph.py # 可视化
│ └── episode_selector.py # PES采样
│
├── tool/ # 工具函数
│ ├── demonstration.py # 动态规划Q-Table
│ ├── label_util.py # 市场状态标注
│ └── market_dynamics_modeling_analysis.py
│
├── analysis/ # 分析工具
│ ├── pick_agent/ # 策略选择
│ │ └── pick_agent.py
│ └── calculate_metric/ # 指标计算
│
├── comprehensive_evaluation/ # 综合评估
│ ├── analyzer.py
│ └── slice_model.py
│
├── data/ # 数据处理
│ ├── split_data.py
│ └── split.sh
│
├── script/ # 训练脚本
│ ├── BTCUSDT/
│ │ ├── low_level/
│ │ │ ├── train.sh
│ │ │ └── valid_multi.sh
│ │ └── high_level/
│ │ ├── train.sh
│ │ ├── pick.sh
│ │ └── test.sh
│ ├── ETHUSDT/
│ └── GALAUSDT/
│
└── requirements.txt # Python依赖
九、参考资源
- 论文原文:https://arxiv.org/pdf/2309.12891.pdf
- 官方GitHub:https://github.com/qinmoelei/EarnHFT
- Tardis API:https://tardis.dev/ (加密货币数据源)
- 相关论文:
- EIIE: “Deep reinforcement learning for automated stock trading”
- Alpha158: 微软Qlib的特征工程方法
- 代码参考:
- https://github.com/Lizhi-sjtu/DRL-code-pytorch/tree/main/3.Rainbow_DQN
更多推荐

所有评论(0)