0%

AI名词解释

激活函数

image-20240324192957319

训练方式

  • 监督学习(Supervised Learning):监督学习是一种机器学习方法,其中算法通过学习从输入数据到输出数据的映射关系,从而对给定的输入数据进行预测或分类。在监督学习中,训练数据集包含了输入和对应的输出标签,模型通过学习这些数据对输入进行预测。常见的监督学习任务包括分类和回归。
  • 无监督学习(Unsupervised Learning):无监督学习是一种机器学习方法,其中算法从未标记的数据中学习数据的结构和模式,而无需提供标签或目标输出。在无监督学习中,算法试图发现数据中的隐藏结构或组织,以便对数据进行更深入的理解。常见的无监督学习任务包括聚类、降维和关联规则挖掘。
  • 强化学习(Reinforcement Learning):强化学习是一种机器学习方法,其中智能体通过与环境进行交互,学习如何采取行动以达到最大化累积奖励的目标。在强化学习中,智能体在与环境交互的过程中不断尝试并学习哪些行动能够获得更多的奖励,从而逐步改进其策略。与监督学习和无监督学习不同,强化学习的反馈通常是延迟的,并且通常是稀疏的。强化学习常用于解决需要决策制定的问题,如游戏、机器人控制和金融交易。

损失函数

image-20240324193143565

梯度下降(让损失函数变小的算法)

*反向传播:解释梯度如何在隐藏层中传递的,反向传播法用来调整网络中的权重

image-20240324194951018

提高神经网络收敛性的技术

  • L1L2正则化

image-20240324195914419

  • Elastic Net

image-20240324200229670

  • Dropout
image-20240324200359441
  • Batch Normalization

image-20240324200623429

多因子框架

1.数据处理

数据处理大致可以分为四步:极值处理、缺失值处理、标准化处理、中性化处理。

极值处理

大部分数据都集中在一个“大范围”之内,少量的数据偏离了大众,分布在这个“大范围”之外的两个极端,这些数据就被称做极端值。极值处理就是对这些极端值数据进行处理,通常分为两种方法:剔除和拉回。剔除就是直接删掉位于“大范围”之外的极端值;拉回则是把这些极端值拉回“大范围”之内,具体来说,就是替换极端值为“大范围”的边界值。

那这个“大范围”该怎么确定呢,目前比较常见的有三种方法:百分位法、均值标准差法、中位数法。三种方法不同在于确定“大范围”的方式,之后的极值处理方式是一样的:剔除或拉回。

  • 百分位法:用所有因子值的百分位区间来划分极值的范围,这个范围是可以自己确定的,一般情况下,百分位区间范围设为2.5%-97.5%、5%-95%等。

  • 均值标准差法:基于正态分布假设,用均值正负3倍标准差来划分极值的范围。但样本均值和样本标准差本身易受极值大小的影响,并非稳健统计量。而且很多因子的分布存在厚尾现象,并不满足正态分布假设。

  • 中位数法:用不受极值大小影响的样本中位数和绝对中位值MAD来划分极值的范围。其中,绝对中位值MAD为所有样本值与样本中位数绝对差值的中位数。中位数法可以说是对均值标准差法的改进,相比于均值,中位数相对来说是一个较为稳健的统计量。

image-20240325154545403

缺失值处理

缺失值即为缺失的数据,与极值处理类似,也分为两种方法:剔除和填充(赋值)

填充通常可以分为均值填充和中位数填充,其中又分为行业均值/中位数填充、样本均值/中位数填充。样本均值/中位数填充很好理解,而行业均值/中位数填充就是用一个行业内所有股票对应因子值的均值/中位数,来填充这个行业内股票因子值的缺失值。

除此之外,还有一些其它的填充方法,比如向前填充、向后填充、插值填充等等,就是利用缺失值前后的值来进行填充。

标准化处理

标准化处理即为消除数据的量纲,或者说是统一数据的量纲,使得不同量纲的数据具有可比性,也就是说,在统一的量纲之下对数据进行比较和分析。如“总市值”这个因子的值是很大的,而“过去一个月收益率”的因子值又是很小的数,两个因子的量纲不同,导致直接等权相加时,“过去一个月收益率”的因子值可以忽略不计。所以对因子值进行标准化处理消除量纲的影响,就显得十分重要。

  • Z-score标准化:使用样本数据的均值(mean)和标准差(std)进行标准化,对原数据x进行(x-mean)/std变换。Z-Score标准化实际上是一种中心化,将原数据变换为均值为0、方差为1的分布。

  • Min-Max标准化:使用样本数据的最小值(min)和最大值(max)进行标准化,对原数据x进行(x-min)/(max-min)变换。Max-Min标准化实际上是一种归一化,将原数据变换为[0,1]区间内的分布。

这两种方法的本质其实都是线性变换,并不会改变数据原始的排列顺序,但也是存在一定区别的。Min-Max标准化输出的数据范围严格限制在[0,1]区间,而Z-score标准化则无范围限制;Min-Max标准化对数据的缩放比例仅与最大值、最小值有关,而Z-score标准化中的均值和标准差与所有数据值相关,会随着任意数据值的变化而变化。

中性化处理

在多因子模型中,我们使用因子来筛选股票。但是不同行业的股票会呈现出不同的特征,同样的,不同市值规模的股票也会有其特点,不同风格的股票也是如此。

这些因素可能会对选股造成很大的影响:比如银行行业的股票特性通常是市盈率偏低、市值偏高;而科技行业的股票通常是市盈率偏高,市值偏小。如果用市盈率因子,或者一些与市值相关性较高的因子来选股,选股的结果就会十分集中,形成一定的偏向。

风格也是类似的。所以就需要进行市值中性化、行业中性化、风格中性化来消除这些影响,从而获得较为分散的选股结果。

  • 常用的就是市值中性化、行业中性化,而风格中性化多用于其它方面(组合优化等),涉及到风格因子等更为复杂

2.单因子检测

单因子检验可以用来判断因子有效性(包括显著性、稳定性),因子方向(以及因子方向的稳定性),还可以判断因子的单调性。

目前常用的单因子检验主要有三种:ICIR、t值、分层回测。其中,ICIR常用于多因子打分模型;t值常用于多因子回归模型; 但是这两种方法都只能判断因子的有效性。分层回测法则可以判断因子的单调性,常与前两种方法结合起来使用。

*

相关系数和回归系数都是用来衡量变量之间关系的指标,但它们有不同的用途和含义。

  1. 相关系数: 相关系数衡量的是两个变量之间的线性关系强度和方向。它的取值范围在-1到1之间,当相关系数为1时表示完全正相关,为-1时表示完全负相关,为0时表示无相关性。相关系数只描述两个变量之间的关系,不涉及因果关系。
  2. 回归系数: 回归系数是用来衡量自变量对因变量的影响程度的指标。在线性回归模型中,回归系数表示因变量每单位变化时自变量变化的幅度。回归系数可以帮助我们理解自变量对因变量的影响方向和大小。在回归分析中,我们可以根据回归系数来预测因变量的取值。

因此,相关系数用于衡量变量之间的关联程度,而回归系数用于描述自变量对因变量的影响。在实际应用中,相关系数和回归系数通常会一起使用,以全面了解变量之间的关系。

ICIR

IC代表因子对于收益的预测能力。计算方法为:因子值与下期收益率的截面相关系数。日频换仓的话便是指:选股日因子值与下期收益率的相关系数。IR代表因子稳定获取收益的能力。具体的计算方法为:IC均值/IC标准差。

IC的计算方式有两种:normal IC和rank IC

  • normalIC rankIC 主要是求rankIC

其中,normal IC计算的是皮尔森相关系数(Pearson correlation),就是我们最常见的一种线性相关系数,为两个变量的协方差/标准差乘积,Python中的corr()函数便可以直接求解。但是,皮尔森相关系数存在较多假设前提:连续数据,正态分布,线性关系等等。

要计算IC的话,两个变量分别是因子值、下期收益率,但这两个变量通常情况下无法满足这些假设前提。所以大家一般会使用另一种适用范围更广的相关系数,即为斯皮尔曼秩相关系数(The Spearman’s rank coefficient of correlation)。

其实就是比皮尔森相关系数多了一步:排序。斯皮尔曼秩相关系数计算的是两个变量排序值的相关系数,皮尔森相关系数计算的是两个变量原始值的相关系数。所以我们将其称为rank IC,“秩”即为rank。

  • IR

有了所有选股日的IC值,那便可以计算IC均值了,IC均值常用于判断因子的显著性。一般IC均值的绝对值>0.03(标准高一些一般会是0.05),则认为该因子较为显著。(也有说法称有效性)

接着,计算IC均值/IC标准差就可以得到IR值,其中IC标准差反映了IC值的波动性(又称稳定性)。而IR同时考虑了因子的显著性和稳定性,常用于判断因子的有效性。一般IR值的绝对值>0.3(标准高一些一般会是0.5),则认为该因子较为有效。

  • 数值

其中,IC均值、IR的正负号反映了因子的方向,正号则说明因子为正向,与下期收益率呈正相关;负号则说明因子为负向,与下期收益率呈反相关。但是由于IC均值、IR是通过多期IC值计算得来的,所以我们并不能通过它们的正负号来武断地判断因子的正负方向。

t值

用因子值与下期收益率进行线性回归,因子值为自变量x,下期收益率为因变量y,然后对回归系数(即自变量x的系数)进行t检验,得到回归系数的显著性水平,即为t值。

  • 数值

一般来说,t值的绝对值>1.96(有的会是>2),则说明其对应的回归系数(因子收益率)较为显著。当然,同ICIR一样,通过回归系数和t值也是可以判断因子方向的。

分层

分层回测,顾名思义,就是分层+回测。分层就是对股票分层,回测就是计算每层股票组合的收益率。

首先需要获取股票池对应的因子值,通过因子值对股票进行排序(一般为升序排序,即因子值较小的排在前面)。然后根据这个排序将股票池等分为5层(通常为5层,也可以自定义层数,多的会有10层)。如果是升序排序,那么第1层股票的因子值最小,第5层股票的因子值最大。与此同时,注意这个“等分”是等分股票个数,即每层的股票个数相等,通常是通过分位数实现的。

3.因子合成

那么通过单因子检验挑选出有效因子之后,就需要进行“因子合成”,合成一个综合因子,通过这个综合因子值对股票进行打分。

话不多说,直接来看看“因子合成”的方法。有以下方法:

1.等权加权 2.历史IC加权 3.历史ICIR加权

4.历史IC半衰加权 5.历史ICIR半衰加权 6.最大化ICIR加权

7.最大化IC加权 8.主成分分析(PCA)

4.因子正交化

因子正交化通常与因子合成是一起进行的,还将介绍两种较为常用的“因子正交化”方法:

1.施密特正交化 2.对称正交化

深度学习工程

AI相关

import torch
import numpy as np
Tensor
# 1. 初始化张量
# 直接用列表数据建立
torch.tensor(data)
# numpy数组转tensor:用numpy数组建立是浅拷贝,如改变np_array,x_np随之改变
x_np = torch.from_numpy(np_array)
# tensor转numpy数组
t = torch.ones(3) n = t.numpy()
# 用另一个Tensor建立
torch.ones_like(x_data)
torch.rand_like(x_data, dtype=torch.float)
# 使用随机变量或常量建立
torch.rand(shape)
torch.ones(shape)
torch.zeros(shape)
# 在GPU上创建张量
tensor.to(‘cuda’)
# 2. 张量的属性
# 形状
tensor.shape
# 数据类型
tensor.dtype
# 存储设备
tensor.device
# 3. 张量操作
# 索引和切片
tensor = torch.ones(4, 4)
print('First row: ',tensor[0])
print("First column: ",tensor [:, 0])
print('Last column: ',tensor[: ,-1])
# 拼接 stack会多一个dimension
torch.cat([tensor,tensor1,tensor2],dim=1)
torch.stack([tensor,tensor1,tensor2],dim=1)
# 算数
# 矩阵乘法
tensor @ tensor1
tensor.matmul(tensor1)
# 元素点乘
tensor * tensor1
tensor.mul(tensor1)
# 聚合
# 聚合张量的所有值为一个值:tensor.sum()
agg = tensor.sum()
# 把张量转变为python常数值:agg.item()
agg_item = agg.item()
数据集与数据导入

pytorch提供两个数据库:torch.utils.data.Datasettorch.utils.data.DataLoader
Dataset 存储样本及其相应的标签,
DataLoader 围绕 Dataset 包装一个可迭代对象,以便轻松访问样本。

用自己的文件创建自定义数据集

自定义 Dataset 类必须实现三个函数:init__、__len 和 __getitem__。以下示例图像存储在目录img_dir中,它们的标签单独存储在CSV文件annotations_file中。

遗传算法gplearn

步骤

  • image-20240402222104246

  • image-20240402222143935

  • image-20240403002246407
  • image-20240402222306745

库表设计

数据库:cryptoDB
行情表:kline_1m 分区一:日 分区二:[标的名哈希,10]
# ======================================
_date date
_symbol varchar(30)
_timestamp timestamp
_open float8
_high float8
_low float8
_close float8
_vol float8
# ======================================

数据库:factorDB
日频因子表:fator_1d 分区一:年 分区二:[标的名哈希,10]
因子列表:[市值 marketcap]
# ======================================
_year int
_factor varchar(30)
_timestamp timestamp
_symbol varchar(30)
_val float8
# ======================================

数据库:factorDB
5分钟频因子表:fator_5m 分区一:日 分区二:[标的名哈希,10]
因子列表:[全局多空比 global_lsr,大户多空比 top_lsr,大户多空持仓比 top_lsr_position,持仓量 open_interest 资费 fundingrate]
# ======================================
_date date
_factor varchar(30)
_timestamp timestamp
_symbol varchar(30)
_val float8
# ======================================


数据库:optionDB
表:option_data 分区一:日 分区二:[标的名哈希,25]
# ======================================
_date date
_symbol varchar(30)
_timestamp timestamp
_type varchar(10)
_strike_price float8
_expiration timestamp
_open_interest float8
_last_price float8
_bid_price float8
_bid_amount float8
_bid_iv float8
_ask_price float8
_ask_amount float8
_ask_iv float8
_mark_price float8
_mark_iv float8
_underlying_index varchar(30)
_underlying_price float8
_delta float8
_gamma float8
_vega float8
_theta float8
_rho float8
# ======================================
exchange,symbol,timestamp,local_timestamp,type,strike_price,expiration,open_interest,last_price,bid_price,bid_amount,bid_iv,ask_price,ask_amount,ask_iv,mark_price,mark_iv,underlying_index,underlying_price,delta,gamma,vega,theta,rho
deribit,BTC-27SEP24-160000-P,1704067200027000,1704067200029840,put,160000,1727424000000000,0,2.45,,,,,,,2.4467,75.18,BTC-27SEP24,46593.7,-0.94333,0,45.67483,-6.35109,-1169.77956

接口设计

查询kline

_conn_pool = connector.init_conn_pool()
_list = connector.execute_sql(_conn_pool, """select * from kline_1m where _symbol='BTC/USDT:USDT'""")
df = pd.DataFrame(_list, columns=['_date', '_symbol', '_timestamp', '_open', '_high', '_low', '_close', '_vol'])

查询5分钟因子

_conn_pool = connector.init_conn_pool("factordb")
_list = connector.execute_sql(_conn_pool, """select * from factor_5m where _symbol='BTC/USDT:USDT' order by _timestamp""")
df = pd.DataFrame(_list, columns=['_date', '_factor', '_timestamp', '_symbol', '_val',])

PS命令行

连接阿里云数据库:
ssh Administrator@47.74.5.152

拷贝文件至本地:
scp -r Administrator@47.74.5.152:C:/Users/Administrator\Desktop\crypto_database\U PERP D:\BackUps\kLines
scp -r Administrator@47.74.5.152:"/C:/Users/Administrator/Desktop/crypto_database/U PERP/" "D:/BackUps/kLines/"
登录:
psql -h <主机名> -p <端口号> -U <用户名> -d <数据库名>
psql -h localhost -p 5432 -U postgres -d cryptoDB

一般性
\bind [PARAM]... set query parameters
\copyright 显示PostgreSQL的使用和发行许可条款
\crosstabview [COLUMNS] execute query and display result in crosstab
\errverbose 以最冗长的形式显示最近的错误消息
\g [(OPTIONS)] [FILE] execute query (and send result to file or |pipe);
\g with no arguments is equivalent to a semicolon
\gdesc 描述查询结果,而不执行它
\gexec 执行策略,然后执行其结果中的每个值
\gset [PREFIX] execute query and store result in psql variables
\gx [(OPTIONS)] [FILE] 就像\g,但强制扩展输出模式
\q 退出 psql
\watch [[i=]SEC] [c=N] execute query every SEC seconds, up to N times

帮助
\? [commands] 显示反斜线命令的帮助
\? options 显示 psql 命令行选项的帮助
\? variables 显示特殊变量的帮助
\h [NAME] SQL命令语法上的说明,用*显示全部命令的语法说明

查询缓存区
\e [FILE] [LINE] 使用外部编辑器编辑查询缓存区(或文件)
\ef [FUNCNAME [LINE]] 使用外部编辑器编辑函数定义
\ev [VIEWNAME [LINE]] 用外部编辑器编辑视图定义
\p 显示查询缓存区的内容
\r 重置(清除)查询缓存区
\w 文件 将查询缓存区的内容写入文件

输入/输出
\copy ... 执行 SQL COPY,将数据流发送到客户端主机
\echo [-n] [STRING] 将字符串写到标准输出(-n表示没有换行符)
\i 文件 从文件中执行命令
\ir FILE 与 \i类似, 但是相对于当前脚本的位置
\o [文件] 将全部查询结果写入文件或 |管道
\qecho [-n] [STRING] 将字符串写入\o输出流(-n表示无换行)
\warn [-n] [STRING] 将字符串写入标准错误(-n 表示无换行)

条件
\if EXPR 开始条件块
\elif EXPR 当前条件块内的备选方案
\else 当前条件块内的最终备选方案
\endif 条件块的结尾

资讯性
(选项: S = 显示系统对象, + = 其余的详细信息)
\d[S+] 列出表,视图和序列
\d[S+] 名称 描述表,视图,序列,或索引
\da[S] [模式] 列出聚合函数
\dA[+] [模式] 列出访问方法
\dAc[+] [AMPTRN [TYPEPTRN]] 列出运算符
\dAf[+] [AMPTRN [TYPEPTRN]] 列出运算符集合
\dAo[+] [AMPTRN [OPFPTRN]] 列出运算符集合
\dAp[+] [AMPTRN [OPFPTRN]] 列出运算符集合所支持的功能
\db[+] [模式] 列出表空间
\dc[S+] [模式] 列表转换
\dconfig[+] [PATTERN] list configuration parameters
\dC[+] [模式] 列出类型强制转换
\dd[S] [模式] 显示没有在别处显示的对象描述
\dD[S+] [模式] 列出共同值域
\ddp [模式] 列出默认权限
\dE[S+] [模式] 列出引用表
\des[+] [模式] 列出外部服务器
\det[+] [模式] 列出引用表
\deu[+] [模式] 列出用户映射
\dew[+] [模式] 列出外部数据封装器
\df[anptw][S+] [FUNCPTRN [TYPEPTRN ...]]
列出 [only agg/normal/procedure/trigger/window] 函数
\dF[+] [模式] 列出文本搜索配置
\dFd[+] [模式] 列出文本搜索字典
\dFp[+] [模式] 列出文本搜索解析器
\dFt[+] [模式] 列出文本搜索模版
\dg[S+] [模式] 列出角色
\di[S+] [模式] 列出索引
\dl[+] list large objects, same as \lo_list
\dL[S+] [模式] 列出所有过程语言
\dm[S+] [模式] 列出所有物化视图
\dn[S+] [模式] 列出所有模式
\do[S+] [OPPTRN [TYPEPTRN [TYPEPTRN]]]
列出运算符
\dO[S+] [模式] 列出所有校对规则
\dp[S] [PATTERN] list table, view, and sequence access privileges
\dP[itn+] [PATTERN] 列出[仅表/索引]分区关系[n=nested]
\drds [ROLEPTRN [DBPTRN]] list per-database role settings
\drg[S] [PATTERN] list role grants
\dRp[+] [模式] 列出复制发布
\dRs[+] [模式] 列出复制订阅
\ds[S+] [模式] 列出序列
\dt[S+] [模式] 列出表
\dT[S+] [模式] 列出数据类型
\du[S+] [模式] 列出角色
\dv[S+] [模式] 列出视图
\dx[+] [模式] 列出扩展
\dX [PATTERN] 列出扩展统计信息
\dy[+] [PATTERN] 列出所有事件触发器
\l[+] [模式] 列出所有数据库
\sf[+] FUNCNAME 显示一个函数的定义
\sv[+] VIEWNAME 显示一个视图的定义
\z[S] [PATTERN] same as \dp

大对象
\lo_export LOBOID FILE write large object to file
\lo_import FILE [COMMENT]
read large object from file
\lo_list[+] list large objects
\lo_unlink LOBOID delete a large object

格式化
\a 在非对齐模式和对齐模式之间切换
\C [字符串] 设置表的标题,或如果没有的标题就取消
\f [字符串] 显示或设定非对齐模式查询输出的字段分隔符
\H 切换HTML输出模式 (目前是 关闭)
\pset [NAME [VALUE]] 设置表输出选项
(border|columns|csv_fieldsep|expanded|fieldsep|
fieldsep_zero|footer|format|linestyle|null|
numericlocale|pager|pager_min_lines|recordsep|
recordsep_zero|tableattr|title|tuples_only|
unicode_border_linestyle|unicode_column_linestyle|
unicode_header_linestyle
\t [开|关] 只显示记录 (目前是关闭)
\T [字符串] 设置HTML <表格>标签属性, 或者如果没有的话取消设置
\x [on|off|auto] 切换扩展输出模式(目前是 关闭)

连接
\c[onnect] {[DBNAME|- USER|- HOST|- PORT|-] | conninfo}
连接到新数据库(当前是"postgres"
\conninfo 显示当前连接的相关信息
\encoding [编码名称] 显示或设定客户端编码
\password [USERNAME] 安全地为用户更改口令

操作系统
\cd [目录] 更改目前的工作目录
\getenv PSQLVAR ENVVAR fetch environment variable
\setenv NAME [VALUE] 设置或清空环境变量
\timing [开|关] 切换命令计时开关 (目前是关闭)
\! [命令] 在 shell中执行命令或启动一个交互式shell

变量
\prompt [文本] 名称 提示用户设定内部变量
\set [名称 [值数]] 设定内部变量,若无参数则列出全部变量
\unset 名称 清空(删除)内部变量

批量写入

import psycopg2

# 连接到 PostgreSQL 数据库
conn = psycopg2.connect(database="your_db", user="your_user", password="your_password", host="localhost", port="5432")
cur = conn.cursor()

# 定义要插入的数据
data = [('value1', 'value2'), ('value3', 'value4')]

try:
# 开始事务
cur.execute("BEGIN TRANSACTION;")

# 构建 INSERT INTO 语句并执行
query = "INSERT INTO target_table (column1, column2) VALUES %s;"
execute_values(query, data, page_size=1000)

# 提交事务
cur.execute("COMMIT;")
except Exception as e:
print("Error occurred during batch insertion: ", str(e))
# 如果发生错误则回滚事务
cur.execute("ROLLBACK;")
finally:
# 关闭数据库连接
cur.close()
conn.close()

(建库表备份)

  • cryptodb kline_1m
CREATE TABLE kline_1m (
_date DATE NOT NULL,
_symbol VARCHAR(30) NOT NULL,
_timestamp timestamp NOT NULL,
_open float8,
_high float8,
_low float8,
_close float8,
_vol float8
) PARTITION BY RANGE (_date);


DO $$
DECLARE
start_date DATE := '2019-01-01';
end_date DATE := '2026-01-01';
cur_date DATE := start_date; -- 将 current_date 改为 cur_date
BEGIN
WHILE cur_date < end_date LOOP
-- 创建每日的分区
EXECUTE format('CREATE TABLE kline_1m_%s PARTITION OF kline_1m FOR VALUES FROM (%L) TO (%L) PARTITION BY HASH (_symbol);',
to_char(cur_date, 'YYYYMMDD'),
cur_date,
cur_date + 1);

-- 为每日的分区创建哈希子分区
FOR i IN 0..9 LOOP
EXECUTE format('CREATE TABLE kline_1m_%s_symbol_%s PARTITION OF kline_1m_%s FOR VALUES WITH (MODULUS 10, REMAINDER %s);',
to_char(cur_date, 'YYYYMMDD'), i,
to_char(cur_date, 'YYYYMMDD'), i);
END LOOP;

cur_date := cur_date + 1; -- 同样将 current_date 改为 cur_date
END LOOP;
END $$;


SELECT relname, pg_get_expr(relpartbound, oid)
FROM pg_class
WHERE relpartbound is not null;
  • factordb factor_5m
CREATE TABLE factor_5m (
_date DATE NOT NULL,
_factor VARCHAR(30) NOT NULL,
_timestamp timestamp NOT NULL,
_symbol VARCHAR(30) NOT NULL,
_val float8,
) PARTITION BY RANGE (_date);


DO $$
DECLARE
start_date DATE := '2023-01-01';
end_date DATE := '2026-01-01';
cur_date DATE := start_date;
BEGIN
WHILE cur_date < end_date LOOP
EXECUTE format('CREATE TABLE factor_5m_%s PARTITION OF factor_5m FOR VALUES FROM (%L) TO (%L) PARTITION BY HASH (_symbol);',
to_char(cur_date, 'YYYYMMDD'),
cur_date,
cur_date + 1);

-- 为每日的分区创建哈希子分区
FOR i IN 0..9 LOOP
EXECUTE format('CREATE TABLE factor_5m_%s_symbol_%s PARTITION OF factor_5m_%s FOR VALUES WITH (MODULUS 10, REMAINDER %s);',
to_char(cur_date, 'YYYYMMDD'), i,
to_char(cur_date, 'YYYYMMDD'), i);
END LOOP;

cur_date := cur_date + 1; -- 同样将 current_date 改为 cur_date
END LOOP;
END $$;
  • factordb factor_1d
CREATE TABLE factor_1d (
_year int2 NOT NULL,
_factor VARCHAR(30) NOT NULL,
_timestamp timestamp NOT NULL,
_symbol VARCHAR(30) NOT NULL,
_val float8,
) PARTITION BY RANGE (_year);

DO $$
DECLARE
start_year INT := 2019;
end_year INT := 2026;
cur_year INT := start_year;
BEGIN
WHILE cur_year <= end_year LOOP
EXECUTE format('CREATE TABLE factor_1d_%s PARTITION OF factor_1d FOR VALUES FROM (%L) TO (%L) PARTITION BY HASH (_symbol);',
cur_year, -- 直接使用年份
cur_year,
cur_year + 1);

-- 为每年的分区创建哈希子分区
FOR i IN 0..9 LOOP
EXECUTE format('CREATE TABLE factor_1d_%s_symbol_%s PARTITION OF factor_1d_%s FOR VALUES WITH (MODULUS 10, REMAINDER %s);',
cur_year, i, -- 直接使用年份
cur_year, i);
END LOOP;

cur_year := cur_year + 1; -- 将年份加1
END LOOP;
END $$;
  • optiondb option_data
CREATE TABLE option_data (
_date date NOT NULL,
_symbol VARCHAR(30) NOT NULL,
_timestamp timestamp,
_type VARCHAR(10),
_strike_price float8,
_expiration timestamp,
_open_interest float8,
_last_price float8,
_bid_price float8,
_bid_amount float8,
_bid_iv float8,
_ask_price float8,
_ask_amount float8,
_ask_iv float8,
_mark_price float8,
_mark_iv float8,
_underlying_index VARCHAR(30),
_underlying_price float8,
_delta float8,
_gamma float8,
_vega float8,
_theta float8,
_rho float8,
) PARTITION BY RANGE (_date);


DO $$
DECLARE
start_date DATE := '2023-01-01';
end_date DATE := '2026-01-01';
cur_date DATE := start_date;
BEGIN
WHILE cur_date < end_date LOOP
EXECUTE format('CREATE TABLE option_data_%s PARTITION OF option_data FOR VALUES FROM (%L) TO (%L) PARTITION BY HASH (_symbol);',
to_char(cur_date, 'YYYYMMDD'),
cur_date,
cur_date + 1);

-- 为每日的分区创建哈希子分区
FOR i IN 0..24 LOOP
EXECUTE format('CREATE TABLE option_data_%s_symbol_%s PARTITION OF option_data_%s FOR VALUES WITH (MODULUS 25, REMAINDER %s);',
to_char(cur_date, 'YYYYMMDD'), i,
to_char(cur_date, 'YYYYMMDD'), i);
END LOOP;

cur_date := cur_date + 1; -- 同样将 current_date 改为 cur_date
END LOOP;
END $$;
  • factordb factor_1m
CREATE TABLE factor_1m (
_date DATE NOT NULL,
_factor VARCHAR(30) NOT NULL,
_timestamp timestamp NOT NULL,
_symbol VARCHAR(30) NOT NULL,
_val float8,
) PARTITION BY RANGE (_date);

DO $$
DECLARE
start_date DATE := '2023-01-01';
end_date DATE := '2026-01-01';
cur_date DATE := start_date;
BEGIN
WHILE cur_date < end_date LOOP
EXECUTE format('CREATE TABLE factor_1m_%s PARTITION OF factor_1m FOR VALUES FROM (%L) TO (%L) PARTITION BY HASH (_symbol);',
to_char(cur_date, 'YYYYMMDD'),
cur_date,
cur_date + 1);

FOR i IN 0..9 LOOP
EXECUTE format('CREATE TABLE factor_1m_%s_symbol_%s PARTITION OF factor_1m_%s FOR VALUES WITH (MODULUS 10, REMAINDER %s);',
to_char(cur_date, 'YYYYMMDD'), i,
to_char(cur_date, 'YYYYMMDD'), i);
END LOOP;

cur_date := cur_date + 1;
END LOOP;
END $$;
import numpy as np
import pandas as pd
from gplearn import fitness
# 数据集
from gplearn.genetic import SymbolicRegressor

train_data = pd.read_csv('../data/IC_train.csv', index_col=0, parse_dates=[0])
test_data = pd.read_csv('../data/IC_test.csv', index_col=0, parse_dates=[0])
feature_names = list(train_data.columns)
train_data.loc[:, 'y'] = np.log(train_data['Close'].shift(-4) / train_data['Close'])
train_data.dropna(inplace=True)

from examples.backtest import BackTester

class SymbolicTestor(BackTester): # 回测的设定
def init(self):
self.params = {'factor': pd.Series}

@BackTester.process_strategy
def run_(self, *args, **kwargs) -> dict[str: int]:
factor = np.array(self.params['factor'])
long_cond = factor > 0
short_cond = factor < 0
self.backtest_env['signal'] = np.where(long_cond, 1, np.where(short_cond, -1, np.nan))
self.construct_position_(keep_raw=True, max_holding_period=1200, take_profit=None, stop_loss=None)

# 回测环境(适应度函数)
comm = [0 / 10000, 0 / 10000] # 买卖费率
bt = SymbolicTestor(train_data, transact_base='PreClose', commissions=(comm[0], comm[1])) # 加载数据,根据Close成交,comm是买-卖

def score_func_basic(y, y_pred, sample_weight): # 因子评价指标
try:
_ = bt.run_(factor=y_pred)
factor_ret = _['annualized_mean']/_['max_drawdown'] if _['max_drawdown'] != 0 else 0 # 可以把max_drawdown换成annualized_std
except:
factor_ret = 0
return factor_ret

def my_gplearn(function_set, my_fitness, pop_num=100, gen_num=3, tour_num=10, random_state = 42, feature_names=None):
# pop_num, gen_num, tour_num的几个可选值:500, 5, 50; 1000, 3, 20; 1000, 15, 100
metric = fitness.make_fitness(function=my_fitness, # function(y, y_pred, sample_weight) that returns a floating point number.
greater_is_better=True, # 上述y是输入的目标y向量,y_pred是genetic program中的预测值,sample_weight是样本权重向量
wrap=False) # 不保存,运行的更快 # gplearn.fitness.make_fitness(function, greater_is_better, wrap=True)
return SymbolicRegressor(population_size=pop_num, # 每一代公式群体中的公式数量 500,100
generations=gen_num, # 公式进化的世代数量 10,3
metric=metric, # 适应度指标,这里是前述定义的通过 大于0做多,小于0做空的 累积净值/最大回撤 的评判函数
tournament_size=tour_num, # 在每一代公式中选中tournament的规模,对适应度最高的公式进行变异或繁殖 50
function_set=function_set,
const_range=(-1.0, 1.0), # 公式中包含的常数范围
parsimony_coefficient='auto',
# 对较大树的惩罚,默认0.001,auto则用c = Cov(l,f)/Var( l), where Cov(l,f) is the covariance between program size l and program fitness f in the population, and Var(l) is the variance of program sizes.
stopping_criteria=100.0, # 是对metric的限制(此处为收益/回撤)
init_depth=(2, 3), # 公式树的初始化深度,树深度最小2层,最大6层
init_method='half and half', # 树的形状,grow生分枝整的不对称,full长出浓密
p_crossover=0.8, # 交叉变异概率 0.8
p_subtree_mutation=0.05, # 子树变异概率
p_hoist_mutation=0.05, # hoist变异概率 0.15
p_point_mutation=0.05, # 点变异概率
p_point_replace=0.05, # 点变异中每个节点进行变异进化的概率
max_samples=1.0, # The fraction of samples to draw from X to evaluate each program on.
feature_names=feature_names, warm_start=False, low_memory=False,
n_jobs=1,
verbose=1,
random_state=random_state)

# 函数集
function_set=['add', 'sub', 'mul', 'div', 'sqrt', 'log', # 用于构建和进化公式使用的函数集
'abs', 'neg', 'inv', 'sin', 'cos', 'tan', 'max', 'min',
# 'if', 'gtpn', 'andpn', 'orpn', 'ltpn', 'gtp', 'andp', 'orp', 'ltp', 'gtn', 'andn', 'orn', 'ltn', 'delayy', 'delta', 'signedpower', 'decayl', 'stdd', 'rankk'
] # 最后一行是自己的函数,目前不用自己函数效果更好

my_cmodel_gp = my_gplearn(function_set, score_func_basic, random_state=0,
feature_names=feature_names) # 可以通过换random_state来生成不同因子
my_cmodel_gp.fit(train_data.loc[:, :'rank_num'].values, train_data.loc[:, 'y'].values)
print(my_cmodel_gp)

# 策略结果
factor = my_cmodel_gp.predict(test_data.values)
bt_test = SymbolicTestor(test_data, transact_base='PreClose', commissions=(comm[0], comm[1])) # 加载数据,根据Close成交,comm是买-卖
bt_test.run_(factor=factor)
md = bt_test.summary()
print(md.out_stats)
print(bt.fees_factor)
md.plot_(comm=comm, show_bool=True)

函数

  • 获取所有分区表
SELECT 
pg_class.relname AS partition_table_name
FROM
pg_inherits
JOIN
pg_class ON pg_inherits.inhrelid = pg_class.oid
WHERE
pg_inherits.inhparent = 'option_data'::regclass;
  • 新建表空间
create tablespace pg_2 owner postgres location 'G:\DevTools\PostgreSQL\16\data';
  • 批量更换表空间
DO $$
DECLARE
start_date DATE := '2021-01-01';
end_date DATE := '2023-01-01';
cur_date DATE := start_date;
BEGIN
WHILE cur_date < end_date LOOP

FOR i IN 0..24 LOOP
EXECUTE format('ALTER TABLE option_data_%s_symbol_%s SET TABLESPACE database_2;',
to_char(cur_date, 'YYYYMMDD'), i);
END LOOP;

cur_date := cur_date + 1;
END LOOP;
END $$;
  • 添加索引
navicat -> 字段 -> 索引 -> 添加索引 ->  名:idx_timestamp  字段:_timestamp  索引方法:B-Tree