按quantlab5.x的规划,我们同样纳入backtrader,但不做太多的封装。
使用notebook来呈现它的策略开发过程。
首先同样是数据预处理和加载:
backtrader与bt、pybroker不同:
它是加载一个个独立的dataframe,然后需要加一个字段——openinterest,这是期货里的概念,暂时用不到,直接置为0即可。
@staticmethod
def get_backtrader_df(symbol: str):
df = CSVDataloader.get_df([symbol])
df.set_index('date', inplace=True)
df['openinterest'] = 0
df = df[['open', 'high', 'low', 'close', 'volume', 'openinterest']]
return df
同样实现昨天的策略:
class roc_trend(bt.Strategy):
# 参数定义
params = dict(
period=20, # 动量周期
)
def __init__(self):
self.roc = bt.indicators.ROC(self.data, period=self.p.period)
# self.roc = bt.talib.ROC(self.data, period=self.p.period)
def next(self):
if not self.position: # not in the market
if self.roc[-1] > 0.08: # if fast crosses slow to the upside
self.order_target_percent(self.data, 0.99) # enter long
# self.buy() # enter long elif self.roc[-1] < 0: # in the market & cross to the downside self.close() # close long position
客观讲,backtreader更接近传统像zipline和quantopian的逻辑:
支持order_target_percent(目标比例仓位)这样的api。
我们使用quantstats做结果分析:
代码在如下位置:
对比一下:
吾日三省吾身
人们习惯低估做成一件事情的难度,尤其在开发回测系统这件事上。
要做一个demo几行代码就够了,比如一个向量化的信号回测策略。
但,要写一个完善的,稳定的系统,那需要考虑的事情,细节就相当多了。
一开始,低估难度,追求可控性,选择自己从零开始写。
刚开始当然很爽,很有成就感。
但越后面,发现稳定性,扩展性,功能。
不如选择成熟的框架,即便一开始有学习成本,甚至有些看似不合理的地方。
第二个问题,在选择框架方面,同样过于追求可控性,代码可读性。忽视了,其实,稳定性,生态,扩张性才是最重要的。真正需要改造框架的机会不多!
第三个问题,在界面上,网站上,数据自动更新,缓存上,规则配置上花了不少时间,没有直奔主题。真正的点是策略,可实盘交易的策略,交易体系。
——大道至简!福尔摩斯只关心且精通与侦破有关的知识,对于地球围绕太阳转还是反过来,他完全不关心,甚至觉得,你就算知道了,也应该尽快忘掉它!。
精力有限,专注于最重要的事情上并取得突破。
在量化投资配置,还是“与交易为生”的投资能力上摇摆。——这是基础逻辑。
“具备职业投资的能力,但不需要依赖它谋生”——以出世的心态做入世的事情。
感悟
阅读三体有一个体会,当你在一段关系中,由于某种原因暂时无法离开,如同三体人在黑暗森林威慑下,应该报持何种态度对待地球人?
1、真心诚意地满足对方。
2、时刻准备让自己离的开它。
一段感情如是,职场纷争亦然。
几个心态:
“允许一切发生”的淡定与释然。
“凡事发生必有利于我”——生命中看似让你不爽,不愉快的人和事,必定是来“提醒你”,还有进步与提升的空间,或者,在某些方面需要最出改变。
“避免与猪在泥地里摔跤”。
你要做的是,有能力离开泥地。
社会运行规律是价值交换,让自己强大。
然后笑看风云。
你会发现身边的人都会越来越美好。
基于pybroker实现的“创业板-择时策略”,策略代码在这个notebook里,
首先加载数据——这里可以加载多个symbols,
from datafeed.dataloader import CSVDataloader
df = CSVDataloader.get_df(['000300.SH', #沪深300
'000905.SH', #创业板
'159915.SZ'
])
df
得到如下数据:
自定义一个指标,这里我们没有使用pandas的函数,而是使用numba来加速。
这里需要说明的是ctx里的数据,已经是按symbol,group_by之后的结果,因此可以直接使用。
import talib import pybroker import numpy as np from numba import njit def roc_N(bar_data, lookback): @njit # Enable Numba JIT. def vec_roc(values): # Initialize the result array. n = len(values) out = np.array([np.nan for _ in range(n)]) for i in range(lookback, n): out[i] = values[i]/values[i-lookback] -1 return out # Calculate with close prices. return vec_roc(bar_data.close)
这里的指标,还有更简洁的实现方式,调用talib:
roc_20 = pybroker.indicator('roc_20', lambda data: talib.ROC(data.close, timeperiod=20)/100)
与如下这行代码是等价的:
roc_20 = pybroker.indicator('roc_20', roc_N, lookback=20)
定义好的指标,就可以开始写策略了:
def pick_time(ctx): if ctx.indicator("roc_20")[-1] > 0.08: ctx.buy_shares = ctx.calc_target_shares(1.0) if ctx.indicator("roc_20")[-1] < 0:
ctx.sell_all_shares()
roc_20 = pybroker.indicator('roc_20', roc_N, lookback=20) from pybroker import Strategy strategy = Strategy(df, '20100101','20240601') strategy.add_execution(pick_time, ['159915.SZ'],indicators=[roc_20]) result = strategy.backtest() result.orders
年化收益19.3%, 最大回撤率:-18.32%。
这里需要说明的是,简单的信号择时策略,bt框架也是胜任的,而且代码量会更少。
不过如果要涉及更复杂的操作,比如加减仓策略,止损、止赢等,那bt就不太方便了,或者多重逻辑判断,多重if-else信号,bt也比较麻烦。
因此,还是那句话,每个框架有其优缺点。
比如backtesing.py就支持多个参数网格调优,搜寻最优参数——类似backtrader的单symbol版本,但代码更简洁,它不支持多symbols。
backtrader不支持机器学习,qlib不支持传统规则量化。
vnpy和wonder trader偏重实盘,写策略就有点麻烦了。
所以,都可以关注一下,艺多不压身,当然更重要的是,策略、思路、因子。——框架只是工具罢了。
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/103216
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!