Quantlab 4.1:基于Deap遗传算法多股票因子挖掘

原创文章第549篇,专注“AI量化投资、世界运行的规律、个人成长与财富自由"。

遗传算法本身并不复杂,但gplearn的实现,把问题复杂化了,尤其在因子挖掘这个场景。

使用deap进行因子挖掘的代码在如下位置:

图片

import copy

from deap_patch import *  # noqa
from deap import base, creator, gp
from deap import tools
from datafeed.mining.deap_alpha.add_ops import *

def convert_inverse_prim(prim, args):
    """
    Convert inverse prims according to:
    [Dd]iv(a,b) -> Mul[a, 1/b]
    [Ss]ub(a,b) -> Add[a, -b]
    We achieve this by overwriting the corresponding format method of the sub and div prim.
    """
    prim = copy.copy(prim)

    converter = {
        'Add': lambda *args_: "{}+{}".format(*args_),
        'Mul': lambda *args_: "{}*{}".format(*args_),
        'fsub': lambda *args_: "{}-{})".format(*args_),
        'fdiv': lambda *args_: "{}*Pow({}, -1))".format(*args_),
        'fmul': lambda *args_: "{}*{}".format(*args_),
        'fadd': lambda *args_: "{}+{}".format(*args_),
        'fmax': lambda *args_: "max_({},{})".format(*args_),
        'fmin': lambda *args_: "min_({},{})".format(*args_),

        'isub': lambda *args_: "{}-{}".format(*args_),
        'idiv': lambda *args_: "{}/{}".format(*args_),
        'imul': lambda *args_: "{}*{}".format(*args_),
        'iadd': lambda *args_: "{}+{}".format(*args_),
        'imax': lambda *args_: "max_({},{})".format(*args_),
        'imin': lambda *args_: "min_({},{})".format(*args_),
    }

    #print(prim.name)
    #if prim.name == "imul":
        #print('命中:',prim.name)
        #print(prim)
    prim_formatter = converter.get(prim.name, prim.format)

    return prim_formatter(*args)

def stringify_for_sympy(f):
    """Return the expression in a human readable string.
    """
    string = ""
    stack = []
    for node in f:
        stack.append((node, []))
        while len(stack[-1][1]) == stack[-1][0].arity:
            prim, args = stack.pop()
            string = convert_inverse_prim(prim, args)
            if len(stack) == 0:
                break  # If stack is empty, all nodes should have been seen
            stack[-1][1].append(string)
    print(string)
    return string

def map_exprs(evaluate, invalid_ind, gen, label, split_date):
    #print(invalid_ind)
    sources = [f'GP_{i:04d}={stringify_for_sympy(expr)}' for i, expr in enumerate(invalid_ind)]
    print(sources)


def init_pset():
    pset = gp.PrimitiveSetTyped("MAIN", [], RET_TYPE)
    pset = add_constants(pset)
    pset = add_operators(pset)
    pset = add_factors(pset)
    return pset

def init_creator():
    # 可支持多目标优化
    # TODO 必须元组,1表示找最大值,-1表示找最小值
    FITNESS_WEIGHTS = (1.0, 1.0)
    creator.create("FitnessMulti", base.Fitness, weights=FITNESS_WEIGHTS)
    creator.create("Individual", gp.PrimitiveTree, fitness=creator.FitnessMulti)
    return creator

def init_toolbox(creator):
    toolbox = base.Toolbox()
    pset = init_pset()
    toolbox.register("expr", gp.genHalfAndHalf, pset=pset, min_=2, max_=5)
    toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.expr)
    toolbox.register("population", tools.initRepeat, list, toolbox.individual)
    toolbox.register("evaluate", print)  # 不单独做评估了,在map中一并做了

    from datetime import datetime
    dt1 = datetime(2021, 1, 1)
    LABEL_y = 'RETURN_OO_1'
    from itertools import count
    toolbox.register('map', map_exprs, gen=count(), label=LABEL_y, split_date=dt1)

    return toolbox

if __name__ == '__main__':
    random.seed(9527)
    creator = init_creator()
    toolbox = init_toolbox(creator)
    pop = toolbox.population(n=100)
    fitnesses = toolbox.map(toolbox.evaluate, pop)

重点看add_ops添加咱们自己的因子表达式引擎支持的函数:

# TODO: 请在此文件中添加算子和因子
# TODO: 由于部分算子计算过慢,这里临时屏蔽了
import random


class RET_TYPE:
    # 是什么不重要
    # 只要addPrimitive中in_types, ret_type 与 PrimitiveSetTyped("MAIN", [], ret_type)中
    # 这三种type对应即可
    pass


# 改个名,因为从polars_ta中默认提取的annotation是Expr
# TODO 如果用使用其它库,这里可能要修改
Expr = RET_TYPE


def _random_int_():
    return random.choice([1, 3, 5, 10, 20, 40, 60])


def add_constants(pset):
    """添加常量"""
    # !!! 名字一定不能与其它名字重,上次与int一样,结果其它地方报错 [<class 'deap.gp.random_int'>]
    pset.addEphemeralConstant('_random_int_', _random_int_, int)
    return pset


def add_operators_base(pset):
    """基础算子"""
    # 无法给一个算子定义多种类型,只好定义多个不同名算子,之后通过helper.py中的convert_inverse_prim修正
    pset.addPrimitive(dummy, [Expr, Expr], Expr, name='fadd')
    pset.addPrimitive(dummy, [Expr, Expr], Expr, name='fsub')
    pset.addPrimitive(dummy, [Expr, Expr], Expr, name='fmul')
    pset.addPrimitive(dummy, [Expr, Expr], Expr, name='fdiv')
    pset.addPrimitive(dummy, [Expr, Expr], Expr, name='fmax')
    pset.addPrimitive(dummy, [Expr, Expr], Expr, name='fmin')

    pset.addPrimitive(dummy, [Expr, int], Expr, name='iadd')
    pset.addPrimitive(dummy, [Expr, int], Expr, name='isub')
    pset.addPrimitive(dummy, [Expr, int], Expr, name='imul')
    pset.addPrimitive(dummy, [Expr, int], Expr, name='idiv')

    return pset


def add_unary_ops(pset):
    from datafeed.expr_functions import unary_funcs
    for func in unary_funcs:
        pset.addPrimitive(dummy, [Expr], Expr, name=func)


def add_unary_rolling_ops(pset):
    from datafeed.expr_functions import unary_rolling_funcs
    for func in unary_rolling_funcs:
        pset.addPrimitive(dummy, [Expr, int], Expr, name=func)


def add_binary_ops(pset):
    from datafeed.expr_functions import binary_funcs
    for func in binary_funcs:
        pset.addPrimitive(dummy, [Expr, Expr], Expr, name=func)


def add_binary_rolling_ops(pset):
    from datafeed.expr_functions import binary_roilling_funcs
    for func in binary_roilling_funcs:
        pset.addPrimitive(dummy, [Expr, Expr, int], Expr, name=func)


def add_operators(pset):
    """添加算子"""
    pset = add_operators_base(pset)
    add_unary_ops(pset)
    add_binary_ops(pset)
    add_unary_rolling_ops(pset)
    add_binary_rolling_ops(pset)
    return pset


def add_factors(pset):
    pset.addTerminal(1, Expr, name='OPEN')
    pset.addTerminal(1, Expr, name='HIGH')
    pset.addTerminal(1, Expr, name='LOW')
    pset.addTerminal(1, Expr, name='CLOSE')
    pset.addTerminal(1, Expr, name='VOLUME')
    # pset.addTerminal(1, Expr, name='AMOUNT')

    return pset


def dummy(*args):
    # 由于生成后的表达计算已经被map和evaluate接管,所以这里并没有用到,可随便定义
    print('dummy')
    return 1

生成的因子,直接转化为咱们因子表达式可以兼容的表达式:

可以计算出因子值:

图片

明天继续对因子做ic分析,同时进行遗传算法的迭代。

代码每周五在星球更新,本周重点是deap+quantlab的因子表达式做因子挖掘。

AI量化实验室——2024量化投资的星辰大海

吾日三省吾身

听樊登讲雷殿生的《信念》。

他是世界徒步最远的人;十年风雨行,他先后走掉了19个脚趾甲,穿烂了52双鞋,行走八万一千多公里,经历19次抢劫,40多次野兽出没。他被评选为“首届中国十大徒步人物”,被誉为“当代徐霞客” 。

探险家,十年徒步走遍全中国。八万多公里,有涉及沙漠,无人区。

遇过十几次抢劫,狼群,吃过苍蝇,老鼠。。。

听完这些,首先是震撼,人之潜力无限。

然后,不自觉会开始探讨意义。

有人问珠峰攀登者,为什么要去冒险,答:因为它就在那里!

这里会回归到生命的本质与意义的问题。

生命没有意义,什么权情名利,百年之后都是过眼云烟。

生命是一场体验罢了,既然如此,体验某种程度是就是“折腾”。——但不是无意义,没有目标感的折腾,而是带着使命感、仪式感去努力做成一件事。

他受徐霞客启发和激励,花了十年时间做准备,然后花十年时间完成这一壮举。

普通人无法企及,只能仰慕。

于我们,有太多的负担,不允许我们去冒险,甚至“不允许”我们离开工作。

生活还在生存,这是一个问题。

但是人生真的具有无限潜力、惊喜。

无论生在何方,反正只来这么一趟,不要轻易就这么过去了。——无论你情不情愿,都会过去。

愿每个人都能跳出日常的琐碎,找到内心的信念,那个方向感,那个有召唤感的使命。

你若盛开,蝴蝶自来。

deap:多股票多维度遗传算法因子挖掘,可以整合chatGPT。

Quantlab4.1发布 | 新增一些策略,补充Metrics

AI量化实验室——2024量化投资的星辰大海

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
deap遗传算法中,更新后代是通过遗传算子来实现的。遗传算子是一种操作,用于模拟自然界中的遗传过程,包括选择、交叉和变异。在deap中,可以使用内置的遗传算子来更新后代。 首先,通过选择操作从当前种群中选择一些个体作为父代。选择操作通常基于个体的适应度,适应度较高的个体更有可能被选择为父代。 接下来,使用交叉操作将选定的父代个体进行交叉,生成新的个体。交叉操作通过交换个体的染色体片段来产生多样性,并将父代的优良特征传递给后代。 最后,使用变异操作对新生成的个体进行变异。变异操作是对个体的染色体进行随机改变,以引入新的基因组合。这有助于增加种群的多样性,并有可能发现更好的解决方案。 通过重复选择、交叉和变异操作,可以逐代更新后代,直到达到停止条件或达到预定的迭代次数。 总结起来,deap遗传算法通过选择、交叉和变异操作来更新后代,以逐步优化解决方案。这些操作可以根据具体的问题和需求进行调整和定制。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [deap遗传算法 tirads代码解读](https://blog.csdn.net/wtyuong/article/details/128687621)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [遗传算法实践详解(deap框架初体验)](https://blog.csdn.net/LOVEmy134611/article/details/111645521)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI量化投资实验室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值