LGBRanker排序算法重构,29个行业轮动滚动回测长期年化11.1%(代码与数据下载)

聚焦目标,做有意义的事情。

之于当下而言,可能有两件事:一是AI量化可以产出交付实盘的有效策略;二是如何有效切入AIGC

今天先来看看因子分析

代码在这个位置:alphalens相对复杂,其实我们一般也仅看ic和ric两个数值,我们就自己实现了。

图片

from typing import Tupleimport pandas as pddef calc_ic(pred: pd.Series, label: pd.Series, date_col="date", dropna=False) -> Tuple[pd.Series, pd.Series]:    df = pd.DataFrame({"pred": pred, "label": label})    ic = df.groupby(date_col).apply(lambda df: df["pred"].corr(df["label"]))    ric = df.groupby(date_col).apply(lambda df: df["pred"].corr(df["label"], method="spearman"))    if dropna:        return ic.dropna(), ric.dropna()    else:        return ic, ricif __name__ == '__main__':    from engine.datafeed.dataloader import CSVDataloader    from engine.config import etfs_indexes    from engine.config import DATA_INDEX    loader = CSVDataloader(DATA_INDEX.resolve(), etfs_indexes.values(), start_date="20120101")    df = loader.load(fields=['ta("MACD",close)','shift(close,-5)/close-1'], names=['factor','label'])    print(df)    ic, ir = calc_ic(pred=df['label'], label=df['factor'],dropna=True)    print(ic.mean(), ir.mean())    ic.plot()    import matplotlib.pyplot as plt    plt.show()

5天的RSI值为未来5天收益的因子分析:ic/ric均值为0.04,是有相关性的。

图片

图片

目前看,即便0.04,0.05的因子,对于未来5天收益率的分类准确性,样本外仍然是10%左右。如果是仅预测未来是上涨还是下跌的2分类,样本外可以达到60%多。

因此,我们仍然把希望寄托在排序上。

投资无外乎选股、择时。而择时本身也是一种广义的选股。

选择本身就是一种排序,择其优者而选之

大家最熟悉的分类算法,在AI量化也算一种排序。就是通过分类算法,预测未来股票上涨概率。然后按概率值排序——这里对应的就是pointwise。这里有一个明显的问题在于,我们对每一支股票的截面数据进行预测,但没有关心股票与股票之间的相对关系,而我们知道,预测收益概率是非常难的事情,而判断它们之间的相对优劣则更为容易。

重构GBMRanker

图片

import numpy as np
from sklearn.model_selection import train_test_split
import lightgbm as lgb

from engine.datafeed.dataset import DataSet
import joblib, os

from engine.models.model_base import ModelBase


class LGBRanker(ModelBase):
    def __init__(self, name, load_model, feature_cols=None):
        super(LGBRanker, self).__init__(name, load_model)
        self.feature_cols = feature_cols
        self.label_col = 'label'

    def _prepare_groups(self, df):
        df['day'] = df.index
        group = df.groupby('day')['day'].count()
        print(group.values)
        return group.values

    def predict(self, data):
        data = data.copy(deep=True)
        if self.feature_cols:
            data = data[self.feature_cols]

        pred = self.ranker.predict(data)
        return pred

    def train(self, df, split_date):
        if split_date:
            df_train = df[df.index < split_date]
            df_val = df[df.index >= split_date]

        query_train = self._prepare_groups(df_train.copy(deep=True))
        query_val = self._prepare_groups(df_val.copy(deep=True))

        ranker = lgb.LGBMRanker()

        ranker.fit(df_train[self.feature_cols], df_train[self.label_col], group=query_train,
                   eval_set=[(df_val[self.feature_cols], df_val[self.label_col])], eval_group=[query_val],
                   eval_at=[1, 2, 5, 10, 20], early_stopping_rounds=50)

        self.ranker = ranker

        print(ranker.n_features_)
        print(ranker.feature_importances_)
        print(ranker.feature_name_)

        score, names = zip(*sorted(zip(ranker.feature_importances_, ranker.feature_name_), reverse=True))
        print(score)
        print(names)


if __name__ == '__main__':
    from engine.config import etfs_indexes
    from engine.datafeed.dataloader import CSVDataloader
    from engine.config import DATA_INDEX
    from engine.datafeed.alpha import AlphaLit

    loader = CSVDataloader(path=DATA_INDEX.resolve(), symbols=etfs_indexes.values())
    ds = DataSet("行业指数数据集", loader=loader, handler=AlphaLit(), cache=False)
    print(ds.data)

    df = ds.data
    df.dropna(inplace=True)
    print(df)

    LGBRanker('', feature_cols=ds.get_feature_names(), load_model=False).train(df, '2022-01-01')
    # lightgbm.plot_importance(ranker, figsize=(12, 8))

图片

实证告诉我们一个结论:

因子不是越多越好,哪怕GBDT可以筛选因子,但因子之间是会冲突,不恰当的加入多余的因子,会降低训练的性能!这里就需要验证因子之间的相关性,正效性。——所以,不要试图一股恼把一堆因子加到模型里,让模型自己去筛选。——如果真这样,那就太简单了。

模型回测——滚动回测

图片

from engine.config import etfs_indexes
from engine.datafeed.dataset import DataSet
from engine.env import Env

from engine.config import etfs_indexes
from engine.datafeed.dataloader import CSVDataloader
from engine.config import DATA_INDEX
from engine.datafeed.alpha import AlphaLit

loader = CSVDataloader(path=DATA_INDEX.resolve(), symbols=etfs_indexes.values())
ds = DataSet("行业指数数据集", loader=loader, handler=AlphaLit(), cache=False)
print(ds.data)

from engine.algo.algos import *
from engine.algo.algo_weights import *
from engine.algo.algo_model import ModelWFA
from engine.models.lgb_ranker import LGBRanker
from engine.env import Env

model = LGBRanker(name='滚动回测——排序',load_model=False, feature_cols=ds.get_feature_names())
# model.train(ds.data, '2022-01-01')

env = Env(ds.data)
env.set_algos([
    RunWeekly(),
    ModelWFA(model=model),
    SelectTopK(K=2, order_by='pred_score', b_ascending=False),
    WeightEqually()
])

env.backtest_loop()
env.show_results()

图片

之于这第二件事,有效切入AIGC当下很多自媒体,甚至很多技术人员,都是看热闹阶段,或者在周边用chatGPT的api或者作图的api,所谓的prompt,生成一些文章或者一些图片。真正有效参与到这个生产力提升的环节,普通人或者创业公司,要从头训练大模型即不现实也不需要。把大模型看成传统“预训练”模型就好,传统我们也不会去从零开始训练bert或者GPT,而是在预训练的基础上进行微调,对于通用大模型,逻辑类似。

而且我们切入的方向一定是垂直方向,专有知识解决领域问题。我想到最好落地的仍然是金融,与AI量化类似,FinGPT应该也会很有意思。之有做FinRL的团队开源了FinGPT,至少这个构想是特别好的。后续会持续关注下。

 

发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/104088
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!

(0)
股市刺客的头像股市刺客
上一篇 2024 年 7 月 29 日
下一篇 2024 年 7 月 29 日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注