01 为何要造轮子
星球群里,今天大家在讨论一个问题:这么多量化框架和平台,为何还要自己造一个轮子,应该把精力放在选股、择时、因子、策略等等才对呀?
这个讨论很有意思。其实我也不断告诉我自己,不能陷入工程师思维,为造轮子而造轮子。仔细回想起来,从pyalgotrade,backtrader, pybroker,还有AI量化的qlib我都深度用过,写过策略,而且呢,还细细读过它们的代码。另外平台型的产品如聚宽,bigquant等都尝试过策略。
第三方平台好处是数据全,不用自己找数据,缺点就是慢。对于我们要不断尝试策略,优化因子的过程,这个速度是非常重要的。且不说如果你真要实盘的策略,放在第三方平台是肯定不放心的; 还有一点就是你若想到了平台未实现的功能,那要扩展起来就几乎不可能了。
再说开源框架,有几个成熟的框架着实不错,各有各的优点。
但是仍然无法完全满足我的诉求,因此,我决定取它们所有人的精华,自己整合一个。毕竟AI量化是一辈子的事业,所以“磨刀不误砍柴功”。
希望我们的框架做到几个点:
1、一定要快,可以缓存数据、因子、模型,回测结果等,并行计算,向量化加速等。
2、支持传统量化。——这一点qlib就不满足。
3、兼容机器学习量化,支持WFA前向滚动式训练回测。——只有qlib满足,pyBroker有一点,但它是一个symbol一个model,不符合诉求。支持调参,因子扩展等。
4、环境可以扩展支持强化学习。——目前也只有qlib支持。或者像tensortrade,finRL-meta这样的专用框架。
5、支持“积木式”快速策略开发。
所以,有点像 pybroker+qlib+bt(支持积木式)。
02 数据加载
传统回测平台,基础数据与指标是分开的,比如backtrader和pybroker。但这在机器学习里就非常麻烦了,机器学习随便就搞上百个因子,这要用indicator,那就太麻烦了,这里我们会参考qlib的dataset加载数据,自动计算因子,以及自动标注数据—— 为里我们实现了自己的因子表达式计算引擎。
一堆因子自动计算与数据标注自动完成,传统量化框架需要一个个添加indicator,这对于机器学习而言,太麻烦,不好维护。
03 架构设计
Portfolio有点类似我之前的Account的定位,但叫Portfolio更加合适,说白了包括了cash和投资组合。做多:buy/sell, 做空:short/cover。好在我们不是做通过框架,当前市场我们不需要做空,先可以不支持。止损单先期都可以不支持。
ExecContext是执行上下文,有Portfolio的实例引用,有curr_bar=传统量化需要用当天的curr_ba_df, curr_df=当天及之前所有的bar,这个风险平价计算权重时需要用,或者滚动机器学习时需要用。
ExecContext产生交易信号,所有都产生完成后,统计执行订单。这里写策略就不必关心下单顺序,比如“先卖后买”。
之前我的简化模型,不太心收盘价,只关心收益率,这样做非常简单。但就没有办法计算某一个trade,成本是多少,持仓多久,交易胜率之类的,因此,这里把pybroker里的逻辑学习过来,也不复杂。
# 当日收盘合,要根据se_bar更新一次及市值,再进行交易——次日开盘交易(这里有滑点)。 def update_bar(self, date: np.datetime64, se_bar: pd.Series): # 当前的cash部分 total_equity = self.cash total_market_value = total_equity total_margin = 0.0 for s, pos in self.long_positions.items(): close = None # 这里不同市场,比如海外市场,可能不存在的,不存在变化率就是0.0, 即不变 if s in se_bar.index: close = se_bar[s] if close: pos.equity = pos.shares * close pos.market_value = pos.equity pos.close = close pos.pnl = _calculate_pnl(close, pos.entries, "long") total_equity += pos.equity total_market_value += pos.equity self.equity = total_equity self.market_value = total_market_value self.margin = total_margin bar = PortfolioBar( date=date, cash=self.cash, equity=self.equity, market_value=self.market_value, margin=self.margin, pnl=self.market_value - self._initial_market_value, # fees=self.fees, ) self.bars.append(bar)
交易环境上下文,不像pyBroker分成多个context,直接一个context,传入当前可获得的所有数据:
像线上回测平台那个order_target_percent这种好用的函数,是一定要实现的:
import numpy as np from quant.portfolio import Portfolio import numpy as np import pandas as pd class ExecContext: def __init__(self, date: np.datetime64, portfolio: Portfolio, bar_df: pd.Series, hist_df: pd.DataFrame ): self.date = date self.portfolio = portfolio self.bar_df = bar_df self.hist_df = hist_df def _get_symbol_price(self, symbol): price = self.bar_df.loc[symbol]['close'] return price def _calc_target_shares(self, symbol, target_percent) -> float: cash = self.portfolio.cash price = self._get_symbol_price(symbol) shares = int(cash / price) return shares def order_target_percent(self, symbol, target_percent): target_shares = self._calc_target_shares(symbol, target_percent) if symbol in self.portfolio.long_positions.keys(): shares = self.portfolio.long_positions[symbol].shares if target_shares > shares: self.portfolio.buy(self.date, symbol, target_shares-shares , self._get_symbol_price(symbol)) else: self.portfolio.sell(self.date, symbol, shares - target_shares , self._get_symbol_price(symbol)) else: self.portfolio.buy(self.date, symbol, target_shares, self._get_symbol_price(symbol))
周末基本把框架刷了一下,写一个量化框架其实并不难,主要是为了研究因子与策略要顺手。
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/104118
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!