原创内容第961篇,专注量化投资,AGI和智能体落地、个人成长与财富自由。

昨天的文章,咱们分享了trend_score因子在backtrader里的实现:

10年24倍!创业板+纳指+黄金+上证180,基于trend_score因子的排序轮动,附backtrader实现

今天咱们来实现完整的策略,两种方式,一种是低代码,如何通过ailabx.com官网直接配置出来。

首先打开ailabx.com网站,免费注册/登录,登录后点击“免费创建策略”。

图片

在选股里选择如下四支ETF:

图片

咱们只需要排序规则,买入和卖出留空即可:

图片

排序规则,点击添加“斜率*拟合度”即可,其余保持默认:

图片

点“运行策略”:

图片

一个年化31%的策略就做好了:

图片

有些同学想要策略代码,咱们使用backtrader来实现一下:

backtrader通用策略模板:

import backtrader as btimport numpy as np
class StrategyTemplate(bt.Strategy):    params = (        ('lookback',25),    )    def log(self, txt, dt=None):        dt = dt or self.datas[0].datetime.date(0)        print(f"{dt.isoformat()}, {txt}")
    def notify_order(self, order):
        """订单状态通知"""        if order.status in [order.Submitted, order.Accepted]:            return

        if order.status in [order.Completed]:
            if order.isbuy():                self.log(f"买入执行, 价格: {order.executed.price:.2f}, 数量: {order.executed.size}, 成本: {order.executed.value:.2f}, 佣金: {order.executed.comm:.2f}")                self.buy_price = order.executed.price                self.buy_date = self.datas[0].datetime.date(0)            elif order.issell():                profit = order.executed.value - order.created.value                self.log(f"卖出执行, 价格: {order.executed.price:.2f}, 数量: {order.executed.size}, 收益: {profit:.2f}, 佣金: {order.executed.comm:.2f}")
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:            self.log(f"订单取消/保证金不足/拒绝")
    def order_by(self, topK=1, dropN=0, desc=True):        # 步骤1:计算所有资产的当前指标值        ranking = []        for d in self.datas:            # 跳过数据不足的资产            if len(d) < self.p.lookback:                continue
            # 获取当前指标值            if 'sorter' not in self.inds[d].keys():                print('order_by==>sorter指标不存在,请检查')                return            ind_value = self.inds[d]['sorter'][0]
            # 跳过无效值            if np.isnan(ind_value):                continue
            ranking.append((d, ind_value))
        # 按指标值降序排序(从大到小)        ranking.sort(key=lambda x: x[1], reverse=desc)        selected = [asset for asset, _ in ranking[dropN:topK]]        return selected
    def weight_equally(self,selected):
        weights = {}        for data in selected:            weights[data] = 0.98/len(selected)        return weights
    def rebalance(self,weights):
        """根据新权重调整仓位"""        total_value = self.broker.getvalue()        #print(weights)        to_buy = {}

        for i, data in enumerate(self.datas):            if data in weights.keys():                # 计算目标市值                target_value = total_value * weights[data]            else:                target_value = 0
            # 计算当前持仓市值            current_value = self.getposition(data).size * data.close[0]
            # 计算需要交易的数量            size_diff = (target_value - current_value) / data.close[0]
            # 执行订单            if size_diff > 0:                to_buy[data] = size_diff
            elif size_diff < 0:                self.sell(data=data, size=abs(size_diff))
        # self.buy(data=data, size=size_diff)        for data, size in to_buy.items():            self.buy(data=data, size=size)

再实现这个策略就简单了:

class TrendScoreRotation(RotationStrategyTemplate):    params = (        ('lookback',25),    )
    def __init__(self):        self.inds = defaultdict(dict)  # 存储各资产ROC指标        for data in self.datas:            self.inds[data]['sorter'] = TrendScore(data, period=self.params.lookback)

在引擎里调用:

import os
import backtrader as btimport pandas as pd
class Engine:    def __init__(self, symbols):        # 设置回测        cerebro = bt.Cerebro()        cerebro.broker.setcash(1000000.0)  # 设置初始资金        # 添加分析器        cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')        cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')        cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')        # 添加PyFolio分析器        cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')        self.cerebro = cerebro        self._add_datas(symbols,'2013-08-30','2025-08-04')
    def _add_datas(self, symbols, start_dt, end_dt):        current_dir = os.path.dirname(os.path.abspath(__file__))        print(current_dir)        for s in symbols:            csv = f'{current_dir}/data/{s}.csv'
            data = pd.read_csv(csv)            data.set_index('date', inplace=True)            data.index = pd.to_datetime(data.index)            data = bt.feeds.PandasData(                dataname=data,                fromdate=pd.to_datetime(start_dt),                todate=pd.to_datetime(end_dt),                timeframe=bt.TimeFrame.Days            )            self.cerebro.adddata(data)
    def run(self, strategy):        self.cerebro.addstrategy(strategy)        print('回测开始...')        results = self.cerebro.run()        print('回测完成!')
        # 获取策略实例        strat = results[0]        # 提取PyFolio分析结果        pyfoliozer = strat.analyzers.getbyname('pyfolio')        returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
        import ffn        perf = (1 + returns).cumprod().calc_stats()        print(perf.display())

        # 打印分析结果        print('\n===== 策略分析 =====')        print(f"夏普比率: {strat.analyzers.sharpe.get_analysis()['sharperatio']:.3f}")        print(f"最大回撤: {strat.analyzers.drawdown.get_analysis()['max']['drawdown']:.2f}%")        print(f"年化收益率: {strat.analyzers.returns.get_analysis()['rnorm100']:.2f}%")        print(f"期末值: {self.cerebro.broker.getvalue()}")
        perf.plot()        import matplotlib.pyplot as plt        plt.show()
if __name__ == '__main__':    symbols = {'513100': '纳指100',               # '513500':'标普500',               #'510300': '沪深300',                '159915':'创业板',               '518880': '黄金',               '510180':'上证180',               # '512890':'红利低波',               # '159985':'豆粕',               # '511880':'银华日利-货币ETF',               # '511260':'十年国债',               #'511220': '城投债'               }    e = Engine(symbols=symbols)    from notebooks.rotation_strategy import TrendScoreRotation    e.run(TrendScoreRotation)

图片

图片

代码、策略和数据已经提交:

图片

大家只需要运行engine.py就可以看到结果:

图片

代码和数据下载:AI量化实验室——2025量化投资的星辰大海

AI量化实验室 星球,已经运行三年多,1700+会员。

aitrader代码,因子表达式引擎、遗传算法(Deap)因子挖掘引等,支持vnpy,qlib,backtrader和bt引擎,内置多个年化30%+的策略,每周五迭代一次,代码和数据在星球全部开源。

年化收益548%,回撤才6%,夏普比5.72,这个策略一直很稳定,附python代码

年化30.24%,最大回撤19%,综合动量多因子评分策略再升级(python代码+数据)

创业板+纳指+黄金的轮动,13年70倍 | 年入千万超级个体,才是普通人创业的趋势。

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐