原创文章第119篇,专注“个人成长与财富自由、世界运作的逻辑, AI量化投资”。

继续强化学习应用于金融投资。

我们的AI量化平台,针对传统规则量化策略,进行了“积木式”的拆分,这种拆分的好处,就是最大化复用代码逻辑,这样开发策略又快且不容易出错。

针对强化学习环境,我们也打算这么做。看到有些平台,股票一个环境,加密货币一个环境,期货又是另一个环境,甚至把数据源处理都耦合到环境中,这是不对的。维护起来特别麻烦且容易出错。

01 强化学习环境的构成

一个完整的金融强化学习环境,包括数据(通常是OHLC以及特征数据)、交易动作(做多,平仓或者权重),回测系统(回测系统能够对交易动作做出反馈),激励指标(收益率、夏普比等)。

当下很多开源包在实现这个环境,存在一些问题。它们大篇幅做数据特征处理,实现了简单的量化回测,激励指标比较单一。这些环境扩展性不好,更谈不上接入实盘。

前文我们对传统量化与机器学习量化实现了统一的框架,数据管理及自动化标注,接入到backtrader的回测系统中。

同样,我们也希望可以最大化复用之前的成果,把强化学习环境也整合到一起,我们就不必关心数据处理,回测系统等环节的处理。

然而,backtrader本身为是传统量化而生,它的run直接就遍历了整个时间序列,而强化学习是由环境来调用回测引擎,一步一步往前走。

对于backtrader要进行一些改造。

一、重写_run_next

Backtrader在执行run的时间,在_runnext函数里整个顺序进行遍历。我们重写这个函数,只做第一步初始化的运算。

def _runnext(self, runstrats):'''Actual implementation of run in full next mode. All objects have its``next`` method invoke on each data arrival'''self.runstrats_container = runstratsself._init_run()def _init_run(self):datas = sorted(self.datas,key=lambda x: (x._timeframe, x._compression))datas1 = datas[1:]data0 = datas[0]d0ret = Truersonly = [i for i, x in enumerate(datas)if x.resampling and not x.replaying]onlyresample = len(datas) == len(rsonly)noresample = not rsonlyclonecount = sum(d._clone for d in datas)ldatas = len(datas)ldatas_noclones = ldatas - clonecountdt0 = date2num(datetime.datetime.max) - 2  # default at maxself.bt_state_container = {"datas": datas,"datas1": datas1,"data0": data0,"d0ret": d0ret,"rsonly": rsonly,"onlyresample": onlyresample,"noresample": noresample,"ldatas_noclones": ldatas_noclones,"dt0": dt0,}

二、提供一个step单步执行函数

这个函数的代码大多可以从cerebro里查到,这里就是展开描述。

def _step(self, runstrats, datas, datas1, data0, d0ret, rsonly,onlyresample, noresample, ldatas_noclones, dt0):# if any has live data in the buffer, no data will wait anythingnewqcheck = not any(d.haslivedata() for d in datas)if not newqcheck:# If no data has reached the live status or all, wait for# the next incoming datalivecount = sum(d._laststatus == d.LIVE for d in datas)newqcheck = not livecount or livecount == ldatas_nocloneslastret = False# Notify anything from the store even before moving datas# because datas may not move due to an error reported by the storeself._storenotify()if self._event_stop:  # stop if requestedreturn Trueself._datanotify()if self._event_stop:  # stop if requestedreturn True# record starting time and tell feeds to discount the elapsed time# from the qcheck valuedrets = []qstart = datetime.datetime.utcnow()for d in datas:qlapse = datetime.datetime.utcnow() - qstartd.do_qcheck(newqcheck, qlapse.total_seconds())drets.append(d.next(ticks=False))d0ret = any((dret for dret in drets))if not d0ret and any((dret is None for dret in drets)):d0ret = Noneif d0ret:dts = []for i, ret in enumerate(drets):dts.append(datas[i].datetime[0] if ret else None)# Get index to minimum datetimeif onlyresample or noresample:dt0 = min((d for d in dts if d is not None))else:dt0 = min((d for i, d in enumerate(dts)if d is not None and i not in rsonly))dmaster = datas[dts.index(dt0)]  # and timemasterself._dtmaster = dmaster.num2date(dt0)self._udtmaster = num2date(dt0)# slen = len(runstrats[0])# Try to get something for those that didn't returnfor i, ret in enumerate(drets):if ret:  # dts already contains a valid datetime for this icontinue# try to get a data by checking with a masterd = datas[i]d._check(forcedata=dmaster)  # check to force outputif d.next(datamaster=dmaster, ticks=False):  # retrydts[i] = d.datetime[0]  # good -> store# self._plotfillers2[i].append(slen)  # mark as fillelse:# self._plotfillers[i].append(slen)  # mark as emptypass# make sure only those at dmaster level end up deliveringfor i, dti in enumerate(dts):if dti is not None:di = datas[i]rpi = False and di.replaying  # to check behaviorif dti > dt0:if not rpi:  # must see all ticks ...di.rewind()  # cannot deliver yet# self._plotfillers[i].append(slen)elif not di.replaying:# Replay forces tick fill, else force heredi._tick_fill(force=True)# self._plotfillers2[i].append(slen)  # mark as fillelif d0ret is None:# meant for things like live feeds which may not produce a bar# at the moment but need the loop to run for notifications and# getting resample and others to produce timely barsfor data in datas:data._check()else:lastret = data0._last()for data in datas1:lastret += data._last(datamaster=data0)if not lastret:# Only go extra round if something was changed by "lasts"return True  # return somethin signaling the end# Datas may have generated a new notification after nextself._datanotify()if self._event_stop:  # stop if requestedreturn Trueif d0ret or lastret:  # if any bar, check timers before brokerself._check_timers(runstrats, dt0, cheat=True)if self.p.cheat_on_open:for strat in runstrats:strat._next_open()if self._event_stop:  # stop if requestedreturn Trueself._brokernotify()if self._event_stop:  # stop if requestedreturn Trueif d0ret or lastret:  # bars produced by data or filtersself._check_timers(runstrats, dt0, cheat=False)for strat in runstrats:strat._next()if self._event_stop:  # stop if requestedreturn Trueself._next_writers(runstrats)self.bt_state_container = {"datas": datas,"datas1": datas1,"data0": data0,"d0ret": d0ret,"rsonly": rsonly,"onlyresample": onlyresample,"noresample": noresample,"ldatas_noclones": ldatas_noclones,"dt0": dt0,}return False

如此,我们的backtrader就可以实现单步循环,为我们的环境提供回测能力了。

一些思考:

疫情还在持续,不知要多久,不知以何种方式结束。

目前大家看到的,可预见到的,肯定不是大家所期待的。

我们很多时候决定不了什么,只能耐心等待,保护好自己,积蓄能力。

三年后,也许这些都是故事 ,也许一个超级疫苗就研发出来,从此人间皆安。

我们要做的事情是,如果再有类似的“黑天鹅”事件发生,我们是否不那么被动,有更多的选择的权利?!

小时候,受到不公正的待遇,私下默默努力。但现代毕竟不是武侠里的快意恩愁。我们能做的事情是升级自己的环境,有能力远离那些不喜欢的人,不喜欢的事。尽管不好的事情哪里都有,但越往上走,会越发文明,越发自由。

努力的意义是自由,财务自由就是你能离得开职场,进而不受地点的约束,而同样可以过上有品质的生活,你就是自由的。

创业九死一生,若成会带来大自由,不成则更加不自由。读书,写作也许是很好的一条路。读书,写作是在疫情封控这样的情境下都可以做的事情。

代码细节,请前往星球微信群交流。

强化学习框架stable-baseline3以及pandas datareader

ETF轮动+RSRS择时,加上卡曼滤波:年化48.41%,夏普比1.89

把backtrader改造成金融强化学习回测引擎相关推荐

  1. 打造一个投资组合管理的金融强化学习环境

    原创文章第120篇,专注"个人成长与财富自由.世界运作的逻辑, AI量化投资". 今天继续金融强化学习环境. 网上的金融学习环境不少,但都太过于"业余",或者离 ...

  2. 《强化学习周刊》第29期:Atari 深度强化学习的研究综述、金融强化学习的最新进展...

    No.29 智源社区 强化学习组 强 化 学  习 研究 观点 资源 活动 关于周刊 强化学习作为人工智能领域研究热点之一,其研究进展与成果也引发了众多关注.为帮助研究与工程人员了解该领域的相关进展和 ...

  3. backtrader股票技术指标自定义与量化回测

    01 引言 股票市场自交易以来,人们就开始孜孜不倦地探索各种各样的投资理论,其中技术分析是重要的理论之一.实际上,技术分析是100多年前创建的股票投资理论,是投资者对股票量价变化长期观察归纳总结的若干 ...

  4. 如何用backtrader对股票组合进行量化回测?

    01 引言 backtrader是功能非常强大的量化回测框架之一,得到欧洲很多银行.基金等金融机构的青睐,并应用于实盘交易中.公众号Python金融量化针对backtrader的入门和应用已连续发布了 ...

  5. 使用Backtrader对股票历史数据进行指标回测

    本次使用tushare接口,股票为600018,时间是20200101--20211231. 使用的指标是:收盘价大于简单移动平均价. 佣金为0.001. 英文代码的英文原文:Quickstart G ...

  6. 回测引擎代码分析流程图

    转载:https://www.vnpy.com/forum/topic/26-hui-ce-yin-qing-dai-ma-fen-xi-liu-cheng-tu

  7. 基于强化学习的期权量化交易回测系统5

    我们现在已经可以在主循环中获取行情数据,并且传给了Agent类.接下来Agent类会调用策略类,由于决定采取的行动.在策略类做决策时,需要参考用户仓位Position信息,还有就是权利金.保证金.手续 ...

  8. 金融工程python报告期权_利用Backtrader进行期权回测之一:获取期权数据

    最近在学习一些期权方面的知识,希望有一个期权的回测环境,方便自己做一些测试.初步做了一些功课之后,打算从通达信软件获得期权数据,并使用backtrader进行回测.编程语言使用python. 下载期权 ...

  9. 【手把手教你】用backtrader量化回测海龟交易策略

    01 引言 海龟交易策略是比较经典的趋势交易系统之一,涵盖了从入场交易(品种选择).仓位管理(基于ATR加减仓).离场(触发条件)的整个过程.机械套用海龟交易法则在A股上进行交易可能效果不佳,但其交易 ...

最新文章

  1. python中csv文件操作_python中操作csv文件
  2. 《简明电路分析》——1.6节简单电路分析实例
  3. php自动处理,thinkphp中的三种自动处理
  4. Oracle数据库的性能调整
  5. python subprocess popen 无法打开_使用subprocess.Popen()在python脚本中设置PYTHONPATH失败...
  6. Jquery对象和DOM对象---Jquery API (1)
  7. luoguP1463:反素数ant(打表心得☆)
  8. 酒桌上的规矩,社会的潜规则
  9. Lucene Boost 精度表
  10. linux拿虚拟机充当路由,Linux通过虚拟机模拟路由器实现主机跨路由通信
  11. ubuntu设置虚拟显示器且远程连接
  12. 三步骤详解张正友标定法
  13. excel打开很慢_从海量Excel文件中快速高效地提取数据
  14. 计算机白板培训报道,学习电子白板心得体会
  15. 建筑工地人脸识别门禁通道闸机如何安装 1
  16. 计算机基础之冯诺依曼体系结构
  17. 点击跳出商务通对话框
  18. java security_java.security.NoSuchAlgorithmException
  19. 那些创新是如何产生的?
  20. java mht 转html_【JAVA】mht文件转html

热门文章

  1. 替换=(等于号)正则表达式
  2. 前后端分离 Spring Security 对登出.logout()的处理
  3. 第11章组件装饰和视觉效果-DecoratedBox装饰盒子-背景图效果
  4. jQuery DOM元素的遍历
  5. yolov7运行自己的VOC格式数据集
  6. ES索引创建、新增与修改字段
  7. 电脑耳机没声音怎么设置?(win7/win10电脑耳机没声音的解决方法)
  8. 隐私泄露中的人性剖析
  9. [bzoj5473] 仙人掌
  10. pfamscan 的使用_使用 HMMER 进行 PFAM 注释