把Engine扩展成支持投资组合的强化学习环境

关于投资,使用风险平价+动态现平衡肯定是可行的。

我们还需要加入更多的主动管理,比如有些指数,明显没有动量,或者一些择时指数是负向的,那我们直接把对应的指数权重置为0,甚至反过来,当一些指数的动量很强时,加大它的权重。

若是加上了择时,那风险平价是否还是必要的?

风险平价动态调仓的基础逻辑是:波动率有一定的平稳性,波动率大的时候,市场下行的概率大,所以波动率加大的应该降低仓位。但若是加上了动量、行业景气度这些逻辑,风险平价的最优计算似乎也失去了原本的意义?

还不如统一到一个“多因子”模型里去“学习”。

有时候,简单的反而是最好的。

有一个兄弟,真的做到极简:就是指数基金+动量轮动——骑最快的马。当然很多人觉得很好笑,现在想想还有一定的道理。动量策略本身就是一直有效的。另外直观好理解,纯右侧交易,持有感受也好。

若要把更多因子整合在一起,规则型的策略trick太多了,怎么看都像凑出来的,使用传统机器学习或者深度学习把多因子整合到一起倒是可行,最大的问题是,监督学习是需要标签的。这个标签把一个“多轮贯序决策”问题,变成一个个分类问题,根本就有一定的问题。看来看去,最前前途的,当属强化学习的范式,当然并不容易。

一个美好的愿景,应该是这样一个框架:

图片

多因子,新增的数据、指标进来都可以纳入模型;有用更好,没用至少不会影响原有结果。

可以自适应市场环境,就是需要自我进化,而不是静态的。

可以按需要优化,比如夏普比,最大回撤等。

看起来强化学习是方向。

在原有的engine的基础上,我继承并拓展它成为强化学习环境:

from abc import ABC

import gym
import numpy as np
from gym import spaces
from engine.engine_runner import Engine


class FinanceEnv(Engine, gym.Env, ABC):
    def __init__(self, symbols, names, fields, features):
        Engine.__init__(self, symbols, names, fields)
        gym.Env.__init__(self)

        # 正则化,和=1,长度就是组合里的证券数量
        self.df_features = self.df_features[features]
        self.action_space = spaces.Box(low=0, high=1, shape=(len(symbols),))
        self.observation_space = spaces.Box(
            low=-np.inf,
            high=np.inf,
            shape=(len(symbols), len(self.df_features.columns)), dtype=np.float64
        )

        print(self.action_space, self.observation_space)

    def reset(self):
        self.index = 0
        self.curr_date = self.dates[self.index]
        df = self.df_features.loc[self.curr_date]
        print(df.values.shape)
        return df.values

    def step(self, actions):
        done = False
        if self.index >= len(self.dates) - 1:
            done = True
            return self.state, self.reward, done, {}

        self._update_bar()
        weights = self.softmax_normalization(actions)
        wts = {s: w for s, w in zip(self.symbols, weights)}
        self.acc.adjust_weights(wts)

        df = self.df_features.loc[self.dates[self.index], :]
        self.state = df.values
        self.reward = self.acc.cache_portfolio_mv[0]

        self._move_cursor()
        return self.state, self.reward, done, {}

    def softmax_normalization(self, actions):
        numerator = np.exp(actions)
        denominator = np.sum(np.exp(actions))
        softmax_output = numerator / denominator
        return softmax_output


if __name__ == '__main__':
    from stable_baselines3.common.env_checker import check_env
    from stable_baselines3 import A2C
    from engine.datafeed.dataloader import Dataloader

    symbols = ['399006.SZ', '000300.SH']


    names = []
    fields = []
    features = []
    # fields += ['$close/Ref($close,20) -1']
    fields += ['Slope($close,20)']
    names += ['mom']
    features += ['mom']

    env = FinanceEnv(symbols, names, fields, features)
    check_env(env)
    model = A2C("MlpPolicy", env)
    model.learn(total_timesteps=100000)

之前的文章是从零实现的,这次是整合进了engine里。

 

发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/104187
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!

(0)
股市刺客的头像股市刺客
上一篇 2024 年 7 月 29 日
下一篇 2024 年 7 月 29 日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注