150 lines
7.2 KiB
Python
150 lines
7.2 KiB
Python
from freqtrade.freqai.prediction_models.ReinforcementLearner import ReinforcementLearner
|
||
from freqtrade.freqai.RL.Base5ActionRLEnv import Actions, Base5ActionRLEnv, Positions
|
||
import numpy as np
|
||
|
||
|
||
class MyCoolRLModel(ReinforcementLearner):
|
||
"""
|
||
用户创建的RL预测模型。
|
||
|
||
保存此文件到 `freqtrade/user_data/freqaimodels`
|
||
|
||
然后使用以下命令运行:
|
||
freqtrade trade --freqaimodel MyCoolRLModel --config config.json --strategy FreqaiPrimer
|
||
|
||
在这里,用户可以覆盖 `IFreqaiModel` 继承树中的任何函数。
|
||
对于RL来说,最重要的是在这里覆盖 `MyRLEnv`,以定义自定义的
|
||
`calculate_reward()` 函数,或覆盖环境的任何其他部分。
|
||
|
||
此类还允许用户覆盖 IFreqaiModel 树中的任何其他部分。
|
||
例如,用户可以覆盖 `def fit()` 或 `def train()` 或 `def predict()`
|
||
以对这些过程进行精细控制。
|
||
|
||
另一个常见的覆盖可能是 `def data_cleaning_predict()`,用户可以
|
||
在这里对数据处理管道进行精细控制。
|
||
"""
|
||
|
||
class MyRLEnv(Base5ActionRLEnv):
|
||
"""
|
||
用户自定义环境。此类继承自 BaseEnvironment 和 gym.Env。
|
||
用户可以覆盖这些父类中的任何函数。下面是一个
|
||
用户自定义 `calculate_reward()` 函数的示例。
|
||
|
||
警告!
|
||
此函数是功能展示,旨在展示尽可能多的
|
||
环境控制功能。它还设计用于在小型计算机上快速运行。
|
||
这是一个基准,*不* 用于生产环境。
|
||
"""
|
||
|
||
def calculate_reward(self, action: int) -> float:
|
||
"""
|
||
奖励函数的示例。这是用户可能希望
|
||
注入自己创意的一个函数。
|
||
|
||
警告!
|
||
此函数是功能展示,旨在展示尽可能多的
|
||
环境控制功能。它还设计用于在小型计算机上快速运行。
|
||
这是一个基准,*不* 用于生产环境。
|
||
|
||
:param action: int = 智能体为当前K线做出的动作。
|
||
:return:
|
||
float = 给智能体当前步骤的奖励(用于优化
|
||
神经网络中的权重)
|
||
"""
|
||
# 首先,如果动作无效,则惩罚
|
||
if not self._is_valid(action):
|
||
self.tensorboard_log("invalid", category="actions")
|
||
return -2.0
|
||
|
||
# 获取核心状态数据
|
||
pnl = self.get_unrealized_profit() # 当前浮动盈亏 (百分比,如 0.01 代表 1%)
|
||
|
||
# 获取持仓时间 (K线数量)
|
||
trade_duration = self._current_tick - self._last_trade_tick
|
||
|
||
# 读取配置中的最大持仓时间,默认 100 根 K 线
|
||
max_trade_duration = self.rl_config.get("max_trade_duration_candles", 100)
|
||
|
||
# 奖励累加器
|
||
reward = 0.0
|
||
|
||
# =========================================================
|
||
# 场景 A: 决定入场 (Long Enter / Short Enter)
|
||
# =========================================================
|
||
if action in (Actions.Long_enter.value, Actions.Short_enter.value):
|
||
if self._position == Positions.Neutral:
|
||
# 【核心修改 1】入场不给奖励,反而给微小的惩罚。
|
||
# 逻辑:开仓即产生手续费和滑点风险。
|
||
# 这迫使模型只有在预期收益远大于这个惩罚时才敢开仓。
|
||
return -0.05
|
||
|
||
# =========================================================
|
||
# 场景 B: 观望 (Neutral)
|
||
# =========================================================
|
||
if action == Actions.Neutral.value and self._position == Positions.Neutral:
|
||
# 【核心修改 2】空仓观望给 0 分,或者极小的惩罚。
|
||
# 之前的代码给 -1 分会导致模型为了避免扣分而强行开单(Overtrading)。
|
||
# 对于 PEPE 这种币,大部分时间是垃圾时间,观望是正确的。
|
||
return 0.0
|
||
|
||
# =========================================================
|
||
# 场景 C: 持仓中 (Holding) - 每一根 K 线都会触发
|
||
# =========================================================
|
||
if self._position in (Positions.Short, Positions.Long):
|
||
# 如果当前动作是继续持有 (Neutral)
|
||
if action == Actions.Neutral.value:
|
||
|
||
# 1. 时间衰减惩罚:拿得越久,资金占用成本越高
|
||
time_penalty = -0.01 * (trade_duration / max_trade_duration)
|
||
reward += time_penalty
|
||
|
||
# 2. 浮动盈亏反馈 (关键!)
|
||
if pnl > 0:
|
||
# 浮盈:给予微弱的正反馈,鼓励拿住趋势
|
||
# 使用 log 函数让奖励增长平缓,避免模型过于贪婪而不止盈
|
||
reward += np.log(1 + pnl) * 0.5
|
||
else:
|
||
# 浮亏:给予沉重的打击!
|
||
# 逻辑:浮亏不仅是钱的损失,更是机会成本。
|
||
# pnl 是负数,这里会让 reward 变得很小。
|
||
# 例如 pnl -0.02, 惩罚会显著大于浮盈 0.02 的奖励
|
||
reward -= (abs(pnl) * 2.0)
|
||
|
||
# 3. 止损惩罚加速
|
||
# 如果浮亏超过 3%,给予额外的巨额惩罚,逼迫模型学会止损
|
||
if pnl < -0.03:
|
||
reward -= 1.0
|
||
|
||
# =========================================================
|
||
# 场景 D: 离场结算 (Exit)
|
||
# =========================================================
|
||
if (action == Actions.Long_exit.value and self._position == Positions.Long) or \
|
||
(action == Actions.Short_exit.value and self._position == Positions.Short):
|
||
|
||
# 基础因子
|
||
factor = 10.0
|
||
|
||
# 【核心修改 3】非线性结算奖励
|
||
if pnl > 0:
|
||
# 盈利:奖励 = PnL * 因子
|
||
# 如果这笔交易是大赚 (比如 > 2%),因子翻倍
|
||
if pnl > 0.02:
|
||
factor *= 2.0
|
||
|
||
# 最终奖励
|
||
total_reward = pnl * factor
|
||
|
||
# 额外奖励:如果这笔交易很快就赚了钱(高效率)
|
||
if trade_duration < (max_trade_duration * 0.2):
|
||
total_reward *= 1.5
|
||
|
||
return float(total_reward)
|
||
|
||
else:
|
||
# 亏损:惩罚 = PnL * 因子
|
||
# 亏损时的惩罚系数通常要比盈利系数大,模拟"损失厌恶"
|
||
# 这会让模型非常忌惮亏损离场
|
||
loss_factor = 15.0
|
||
return float(pnl * loss_factor)
|
||
|
||
return float(reward) |