从零实现一个支持深度强化学习的量化投资系统
研究过外汇自动交易,期货CTA,然后是股票的量化投资,当然本质上没有太大区别。
开源量化系统也用过几个,数据格式融合的问题,有些不方便,而且客观讲,实现一个简单的量化系统,其实非常简单。
这一次算是重构,希望它可以:
一、支持传统基于“规则”也就是技术分析为主的策略,包括投资组合、单支证券择时,多支证券轮动。
二、支持机器学习,深度强化学习等算法量化。
由于深度强化学习的环境是有openai确定规范的接口,所以,我们就按照强化学习的规则,实现一个A股基金的交易环境。
环境继承自gym.Env, env_data是从数据库加载数据并做好指标预计算备查,config就是相关的交易参数
class MarketEnv(gym.Env): def __init__(self,env_data,config): self.config = config self.env_data = env_data self.reset()
reset函数就是把环境初始化,下标零0,使用config里的benchmark做交易基准。数据我们是加载全量,calendar里去加载日期子集。这里有一个todo:可以判断universe里,日期最大的,以此为起点。
def reset(self): self.i = 0 benchmark = self.config.benchmark df = self.env_data.get_df_by_code(benchmark) self.calendar = df.index[df.index>=self.config.start] print('交易天数:{}'.format(len(self.calendar))) #初始有组合权重,未分配均为持仓占比为0,组合值为初始资金 self.last_weights = [0.0 for code in self.config.universe] self.last_portfolio = self.config.init_cash self.weights_memory = [] self.portfolio_memory = []
给传统策略一个函数的接口(强化学习不使用这个接口)。它其实就是对calendar里每一个tick进行轮询,每个tick都会使用策略去取一个动作,动作如果是None则忽略,然后调用step去执行这个action。而强化学习是自己会调这个action。
def run(self,strategy): self.strategy = strategy done = False while (not done): action = strategy.get_action(self) _, _, done, _ = self.step(action) print('回测完成!') self.analysis()
step函数会做三件事:
最后一件get_status是按强化学习的要求,返回obv,reward,done及info。如果i大于的calendar的长度,就是遍历结果。
def step(self,action=None): #收盘后执行交易 # 根据收益率更新组合情况 #self.__update_portfolio() #self.__do_action() observation, reward, done, info = self.__get_status() return observation,reward,done,info
先是根据universe里tick的收益率变化,更新组合净值。
def __update_portfolio(self): df = self.env_data.get_data(self.calendar[self.i],self.config.universe) rates = df['rate'].values #计算组合总的收益率 = 收益率加权求和 port_rate = sum(np.array(self.last_weights)*rates) new_portfolio = self.last_portfolio * (1+port_rate) new_weights = np.array(self.last_weights) * (1+rates) / (1+port_rate) #保存值 self.last_weights = new_weights self.last_portfolio = new_portfolio self.weights_memory.append(new_weights) self.portfolio_memory.append(new_portfolio)
然后执行Action,其实就是配置新的组合。这里没有计算交易手续费及滑点(todo)。
def __do_action(self,action): if not action: return self.last_weights = action
第三步,返回状态。
def __get_status(self): observation = self.env_data.get_data(self.calendar[self.i],self.config.universe) #print(observation) reward = None info = {} self.i += 1 done = False if self.i > (len(self.calendar) - 1): done = True return observation, reward, done, info
这里reward是给强化学习使用的。后续再给出。
“买入并持有”的策略这样写:
class BuyHold(object): def __init__(self,fix,rebalance='yearly'): self.fix = fix self.vars = None self.rebalance = rebalance #self.universe = universe def get_action(self,env): if env.i == 0: return self.fix if self.rebalance: if self.rebalance == 'yearly': if env.i % 252 == 0: return self.fix return None
就是第一步的时候,把权重配置为[0.2,0.8]即股债二八。
运行一下,结果长这样:
(公众号:七年实现财富自由(ailabx),用数字说基金,用基金做投资组合,践行财富自由之路)