因子挖掘
传统券商研报里,多使用gplearn。
gplearn有一些天然的缺陷: 为了兼容类似sklearn的接口,失去了一些数活性,比如需要传入数据X, y,需要传入预定义的函数,不支持常数项,不支持多支股票挖掘等。
而deap可以完美解决这一切。
https://deap.readthedocs.io/en/master/
下面这段代码,按照咱们给定的函数集——只需要给出“函数名”即可,不需要真正实现这些函数,这样生成了表达式,直接用咱们的因子表达式引擎来计算即可,也deap无关。
import random
from deap_patch import * # noqa
from deap import base, creator, gp
from deap import tools
from add_ops import add_operators, add_factors, add_constants, RET_TYPE
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) return toolbox random.seed(9527) creator = init_creator() toolbox = init_toolbox(creator) pop = toolbox.population(n=100) print(pop)
生成初代因子1000个:
我们预定义的函数集如下:
# 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') # !!! max(x,1)这类表达式是合法的,但生成数量太多价值就低了,所以屏蔽 # pset.addPrimitive(dummy, [Expr, int], Expr, name='imax') # pset.addPrimitive(dummy, [Expr, int], Expr, name='imin') pset.addPrimitive(dummy, [Expr], Expr, name='log') pset.addPrimitive(dummy, [Expr], Expr, name='sign') pset.addPrimitive(dummy, [Expr], Expr, name='abs_') return pset def add_operators(pset): """添加算子""" pset = add_operators_base(pset) pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_delay') pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_delta') # pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_arg_max') # pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_arg_min') pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_max') pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_min') pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_sum') pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_mean') # TODO 等待修复 # pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_decay_linear') # pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_product') pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_std_dev') pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_rank') # pset.addPrimitive(dummy, [Expr, Expr, int], Expr, name='ts_corr') # pset.addPrimitive(dummy, [Expr, Expr, int], Expr, name='ts_covariance') # TODO 其它的`primitive`,可以从`gp/primitives.py`按需复制过来 pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_scale') pset.addPrimitive(dummy, [Expr, int], Expr, name='ts_zscore') # TODO 时序IC时,不要添加`cs_`类算子 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
deap仅负责对这些因子进行,复制,交叉,变异等操作,然后按照设定的fitness进行筛选即可,比如IC值。
这个变异过程,部分可以交给GPT来做,而不是deap来随机进化。这个后续咱们都会覆盖到。
吾日三省吾身
周末不带电脑回家,把自己空出来。
不写代码也不写文章,但思考不会停,这也很重要。
想清楚一件事情,AI量化投资如何做?之前想做无数种,尝试了很多种。
量化私募是为数不多的,可以做“一人企业”,个人英雄主义有效,可以做一辈子的事业。 没有圣杯,但可以持续进化。
可积累有复利。
不需要大规模协作。
直接面对市场,没有客户(自营的话),没有交付。
可攻可守。不需要大规模前期投入,
不需要厂房设备。(
策略上云)
规模受限于策略容量,其次就是资金规模。(私募从业(投研岗优先)的同学可加我,近期启动专项研讨)
昨天写在星球里的
这些点,我相信大家都认同,而且很多人也是有此期望,才开始了解量化,希望学习的。
之前我一度犹豫过,甚至还“劝退”身边的朋友,离开这个领域。
当时的核心逻辑是: 投资没有圣杯,没有一劳永逸的解决方案,做投资是可以赚钱,但与你打一份工没有太大的差别。若如此,就不符合“被动收入”的初心。
想来,被动收入这个概念有“误导”性。
这个世界有纯粹的被动收入嘛,有。比如大类资产配置的理财收入,比如房租等等。
其余更常见的,如很多自媒体聊的,写个专栏,出本书等等。
就拿出书来说,李笑来的例子是在教书的时候,写了两本书,一本是单词书,另一本是写作书。——长销且畅销的话,一份时间多次销售。很美好对不对。
但你仔细一想,不太对。
且不说,现在内容这很多,要写一本畅销书多不容易,长销就更难了。普通的畅销书,就算年销1万本——算很厉害了。每本版税3块的话,3万块钱/年。——这个真的能让你自由嘛。
李笑来真正自由是加密货币,然后形成自己的个人IP。
这个世界上有人擅长讲道理,也很深刻。但未必是他获得成功的路径。
或者说,没有人的成功是可以复制的。
成功的人,讲了一些普适的道理。——这些道理是对的,但这些只是成功的非必要且非充份条件。
不聊被动收入,聊长期复利。
你要做的事情,应该是有长期复利的。简单说,就是有积累。
比如阅读,锻炼身体,投资能力。
从这个角度出发,量化就是很值得学习和值得长期去帮的事情。主观交易可能积累得少,但量化是有可能的。
另外,是如何做的逻辑。
没有圣杯,那量化应该做什么?概念优势。
其实一个人的成功也是如此,没有什么路径一定带你走向成功,但成长就是在积累概率优势。你多做正概率的事情,哪天运气来了,你就成功了。如此而已。
学习和研究就是积累这个优质,然后等机会。
所以,我们应该构建一套交易体系。
确保资金安全的前提下,能发挥概率优势,市场与我们契合时,会赚得多,市场没有按照预期发展时,少亏或不亏(有限的,可承受的)。
有这样的交易体系,投资就是科学,不是赌博。
所以,后续星球的核心是建立: 对标前沿量化私募来构建交易体系。
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/103369
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!