Py学习  »  Python

【新财富请重点支持华泰金工】人工智能选股之Python实战——华泰人工智能系列之七

华泰金融工程 • 6 年前 • 867 次点击  


报告内容简介


授人以鱼不如授人以渔!本篇报告打破技术壁垒,进行人工智能选股算法全揭秘!Python入门-->模块导入-->数据存储-->因子处理-->模型训练-->策略构建,环环相扣,逐行代码解析,一篇报告教你彻底学会人工智能!还等什么,快来下载报告吧!(复制到浏览器打开,无密码)

http://pan.baidu.com/s/1slGQGe5


如果您喜欢这篇报告,2017新财富恳请支持【华泰金工林晓明团队】前三!

谢谢!


新财富请重点支持华泰金工



摘要

介绍Python安装方法、与机器学习相关的包以及常用命令

Python语言是目前机器学习领域使用最广泛的编程语言之一,拥有众多优秀的包和模块,并且相对简单易学。我们将简单介绍Python语言的特性,常用命令,以及和机器学习相关的包,例如NumPy,pandas,scikit-learn等,希望帮助有一定编程基础的读者迅速上手Python语言。

 

机器学习选股框架与多因子选股框架类似,具有一定优越性

机器学习中最为主流的方法监督学习,其核心思想是挖掘自变量和因变量之间的规律。我们将经典多因子模型稍加改造,以机器学习的语言描述。在训练阶段,根据历史的因子值X和收益r,训练监督学习模型r=g(X, f),得到模型自由参数的估计量f。在测试阶段:根据最新的因子值X、参数估计量f和监督学习模型g,预测下期收益r。机器学习方法相较于线性回归的优越之处在于:首先,机器学习可以挖掘数据中的非线性规律;其次,正则化的引入能够筛选出最有效的自变量;再次,参数优化的过程能够遴选出预测力最强的模型。

 

将机器学习选股代码拆分成十二个子模块进行详尽讲解

我们将机器学习选股代码拆分成十二个子模块,包括:模块导入、参数设置、数据读入、数据标记、数据预处理、模型设置、模型训练、模型预测、模型评价、策略构建、策略评价和结果保存。每个子模块我们将展示代码并且逐句进行讲解。报告中展示的代码是完备且成体系的,可以根据需要进行整合,构建一套完整的机器学习选股模型。 

 

风险提示:通过Python编写人工智能选股算法受到数据库架构、网络环境、计算机硬件条件限制,报告中代码经移植后可能不能正常运行;通过人工智能算法构建选股策略是历史经验的总结,存在失效的可能。


本文研究导读

在华泰人工智能系列的前六篇报告中,我们首先对经典的机器学习方法进行了全面梳理,随后系统地测试了广义线性模型、支持向量机、朴素贝叶斯方法、随机森林和Boosting模型,同时围绕机器学习模型构建选股策略。为了使更多的读者有机会接触到机器学习选股的实务化操作,本篇报告我们将对机器学习选股的完整代码进行详细讲解,希望对本领域的投资者产生有实用意义的参考价值。

 

本文主要包含以下几个环节:

 

1. Python语言是目前机器学习领域使用最广泛的编程语言之一,拥有众多优秀的包和模块,并且相对简单易学。本篇报告的第一部分,我们将简单介绍Python语言的特性,常用命令,以及与数据分析、机器学习相关的包和模块,例如NumPy,pandas,scikit-learn等,希望帮助有一定编程基础的读者迅速上手Python语言。

 

2. 第二部分,我们将介绍机器学习多因子模型的问题背景,将经典的多因子模型转换成机器学习的语言进行描述。同时我们也将初探机器学习多因子模型的数据格式和程序框架,为后续的代码实现部分作铺垫。

 

3. 第三部分,我们将机器学习选股代码拆分成12个子模块,包括:模块导入、参数设置、数据读入、数据标记、数据预处理、模型设置、模型训练、模型预测、模型评价、策略构建、策略评价和结果保存。每个子模块我们将展示代码并且逐句讲解。


Pyton介绍

Python语言

“Life is short, you need Python.” —— Bruce Eckel


自从1991年诞生以来,Python已经成为一种非常受欢迎的编程语言。与C/C++等编译型语言不同,Python是一门解释性语言,即Python程序不需要编译,在运行时才翻译成机器语言,每执行一次都需要翻译一次,因此在运算效率方面不如编译型语言。但是,Python不需要关注程序的编译和库的链接等问题,开发工作相比于编译型语言更加轻松;同时,解释型语言易于移植,适合跨平台的开发。

 

作为一门简单易学、适合阅读的编程语言,Python在机器学习的实践中得到了广泛的应用,其主要有以下优点:

1. 免费,开源,有大量的社区讨论交流资料。

2. 可以专注于逻辑、算法本身,而不是纠结于如何实现某个数据结构。自身的数据结构应用简单方便,可以大大提高开发效率。

3. 包(package)、库(library)和模块(module)众多,例如NumPy、SciPy、pandas、Matplotlib可以很方便地进行数据处理,scikit-learn、TensorFlow、Theano、Keras都是机器学习领域流行的包。


Anaconda及包的安装

安装Anaconda

Anaconda是一个用于科学计算的Python发行版本,支持Linux、Mac、Windows系统,提供了包管理与环境管理的功能,可以很方便地解决多版本Python并存、切换以及各种第三方包安装问题,并且已经包含了Python和相关的配套工具。Anaconda界面友好、使用方便、具有强大的包管理与环境管理功能,推荐本领域的研究者使用。Anaconda的下载安装可以通过以下两个途径:

1. 官网安装:https://www.continuum.io/downloads按照提示,下载并安装Anaconda。

2. 清华镜像源:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 在国内安装速度较快。

 

虽然Anaconda已经内嵌了很多包,但在实际运用中,我们可能会用到一些非自带的包。接下来我们学习在Windows下如何安装和更新包:首先,Windows用户在“开始”中打开Anaconda的文件夹,点击Anaconda Prompt,得到如下图的命令行窗口。



安装包

安装包的命令为conda install,具体用法为在Anaconda Prompt中输入conda install + 包的名字。下图展示了安装scikit-learn包的过程,Anaconda将自动搜取包的源。当出现对话“Proceed?”时,输入“y”,表示确认安装,等待Anaconda自动安装即可。


更新包

更新包的命令为conda update。具体用法为在Anaconda Prompt中输入conda update + 包的名称。下图展示了更新pandas包的过程。当出现对话“Proceed?”时,输入“y”,表示确认更新,等待Anaconda自动更新即可。


Python和常用包初探

获取帮助

授人以鱼不如授人以渔。当我们不清楚某个命令或者函数的用法时,使用help命令获取帮助是不错的选择,具体用法为help('函数名')。


上面的例子中,我们使用help查询print函数的用法。Python返回print的语法以及每个参数的用法。由于Python和包的迭代较快,很多纸质和网络教材编写时依据的Python版本难以保证是最新版,有的函数已被弃用或者用法发生改动,因此我们推荐有一定英语阅读能力的读者使用help命令获取最新版的帮助信息。

缩进

在介绍Python常用包和数据类型之前,我们首先介绍Python代码的缩进。Python的一大特色就是严格的代码缩进要求,与别的语言中缩进只是为了方便代码阅读与修改不同,在Python中每行代码前的缩进都有语法和逻辑上的意义。这样的强制要求增加了代码的可读性,也使得代码总体较为美观。通常我们选择4个空格或1个Tab来进行缩进, Anaconda中的Spyder IDE也会在写代码过程中自动进行缩进。如果要进行多行代码的集体缩进,可以选中目标代码按Tab进行集体向右缩进,Shift+Tab进行集体向左缩进。

 

      列表

列表(list)是Python中的有序集合类型,列表的元素可以包括任何种类的对象:数字、字符串、或者其他的列表、DataFrame等等。下面是常见的列表操作:


上述代码中,list1列表包含1个字符串'Huatai',list2列表包含1个整数601688。我们使用简单的加法,把两个列表拼接了起来,得到包含2个元素的列表list3。11-12行是列表的索引,Python序列的索引从0开始,因此list3[1] 返回的是列表中的第2个元素。在Python中,我们以#号开头为代码添加注释,如第1行所示,能够大大提高代码的可读性。

 

      NumPy 和数组

NumPy是数据科学领域最常用的Python包之一,能够储存和处理大型数组,具备强大的科学计算功能。NumPy的核心是多维数组对象,即ndarray。这种面向数组的编程方式,使得对海量数据的处理更为方便,逻辑更加清晰。


1. 调入NumPy包

在使用NumPy包之前,需要通过import命令调入NumPy包。以后每次使用NumPy包中的函数,在函数名前加上np.即可。


2. 创建ndarray数组

np.array:输入序列型的对象,通过array函数,将其转换为NumPy数组。下面的例子中我们将列表类型的data通过array函数转换为数组类型的arr1。


np.arange:构建一个等差数列。下面的例子中,我们构建了一个从0开始,包含10个元素的等差数列。


np.reshape:将数组重塑为另一个形状。下面的例子中,我们将1行10列的数组arr2通过reshape方法转换为2行5列的数组arr3。

另外,我们还可以通过np.zeros或者np.ones直接创建指定长度或形状的全0或1数组。

 

3.常用函数

np.sqrt:计算数组各元素的平方根。


np.mean:计算数组各元素的算术平均值。


np.std:计算数组各元素的标准差。

 

np.dot:实现两个矩阵的乘法。下面的例子中,arr3是一个2行5列的矩阵,arr4是5行2列的矩阵。矩阵相乘需要满足的条件是第一个矩阵的列数和第二个矩阵的行数相同。


np.multiply:实现两个数组各元素相乘,两个数据的形状必须相同。

其中random.randn是NumPy包的函数,作用是生成服从标准正态分布的随机数。参数(2,5)表示生成2行5列的随机数组。

 

np.around:对数值进行四舍五入,取近似值。参数decimal表示保留小数位数,默认保留0位小数,即四舍五入取整数。

更多关于NumPy的详细操作可以参考:http://www.numpy.org/

 

      pandas和DataFrame

pandas是Python Data Analysis Library的缩写,是基于NumPy编写的数据分析包。pandas最大的特色是提供了DataFrame这一数据结构,极大地简化了以往数据分析过程中的一些繁琐操作,受到数据科学领域工作者的欢迎。

 

1. 调入pandas包

在使用pandas包之前,需要通过import命令调入pandas包。以后每次使用pandas包中的函数,在函数名前加上pd.即可。


2. 数据的读入读出

在进行对数据的处理和分析之前,我们首先需要将数据读入内存;而在处理和分析结束后,我们往往也需要将结果写入文件之中。使用pandas可以很方便地帮助我们完成这项任务。

 

pd.read_csv('ex1.csv') :读入csv文件。其中pd指调用pandas包,单引号内为将要调用的文件名。

 

df.to_csv('ex1.csv') :读出csv文件。其中df为将要存储的DataFrame表格名,单引号内为想要存储的文件名。

 

pd.read_excel('foo.xlsx', 'Sheet1') :读入excel文件

 

df.to_excel('foo.xlsx', sheet_name='Sheet1') :读出excel文件。其中'Sheet1'是指读入或读出excel文件时使用的工作表名。其余参数用法和csv文件的读入读出类似。


3.Series

pandas的常用数据结构有Series和DataFrame。Series是一种类似于一维数组的对象,由一组数据以及一组与之相关的数据标签组成。构建Series对象的函数:pd.Series

可以看出,pd.Series得到一组一一对应的标签与数据。可以对数据进行切片、数值运算等操作。Series的操作相对简单,在此我们不深入讨论。


4.DataFrame

数据集(DataFrame)是一个表格型的数据结构,其直观的存储方式以及丰富的操作,使其成为分析海量数据时使用最多的数据结构。DataFrame通常包含一系列有序的列,每列可以是不同的值类型。DataFrame既有行索引,也有列索引。

 

pd.DataFrame:构建DataFrame。下面的例子展示了分别构建两个DataFrame即df和df2的过程。

上述代码段的第1行定义了字典(Dictionary)类型的变量data。字典是Python的常用数据类型之一,以花括号{}表示,内部包含多个条目,每个条目包含一组对应的键(key,例如第2行的'B')和值(value,例如第2行的[2,1,15,-4,27])。更多关于字典的操作可以使用help('dict')命令进行查询。

 

定义字典data之后,我们以data为基础,构建了df和df2两个DataFrame。df和df2的区别在于columns和index。columns是对其列索引的管理,可指定列的名称;index是对行索引的管理,可指定行的名称。index在赋值之后不可更改。我们可以在初始化DataFrame时,赋予其行索引值,如index=list(range(5)),默认为从0开始公差为1的等差数列,共5个数;如果需要设置为从1开始,如In[6],可使用index=list(range(1,6)),即取[1,6)中的5个正整数;当然也可以直接赋予其它值。

 

sort_index() 或 sort_values():对DataFrame按某一列进行排序。下面的例子中,我们对df按B的大小降序排列。


dropna:去除DataFrame中的缺失值。


loc和iloc:对数据进行切片,选取部分内容。loc是根据dataframe的具体标签选取列,而iloc是根据标签所在的位置,从0开始计数。其中中括号内逗号前是指选取的行序列,逗号后是指选取的列序列。


append:连接另一个DataFrame对象,产生一个新的DataFrame对象。

更多详细的pandas使用指南可以参考:http://pandas.pydata.org/pandas-docs/stable/10min.html


      scikit-learn

scikit-learn简称sklearn,是Python机器学习中使用最为广泛的包,用户界面友好,并且对常用的算法实现进行了高度优化。sklearn囊括了广义线性模型、支持向量机、朴素贝叶斯、线性和二次判别分析、决策树、随机森林、神经网络、PCA、k近邻等常见的机器学习算法,此外还提供了数据预处理、交叉验证集划分、网格搜索、分类正确率计算等众多工具。我们将在第三部分Python代码实战章节具体介绍sklearn的使用方法。sklearn的官方网站给出了更详细使用指南:http://scikit-learn.org/stable/

 

除了上述介绍的包以外,SciPy广泛应用于高级科学计算,Matplotlib是Python常用的可视化工具,可以方便地制作多种类型的图表。更多详细的使用指导可以参考官方网站:

https://docs.scipy.org/doc/scipy/reference/

http://matplotlib.org/users/index.html

多因子选股机器学习模型

问题描述

上一章节我们初步认识了Python语言的特性、安装方法和常用命令。那么,如何将Python这一利器应用于量化投资呢?纵观量化投资的各个领域,我们发现多因子选股问题最适合转换为机器学习的框架。下面我们将多因子选股以机器学习的语言加以描述。

 

经典的多因子模型表达式为:

 

经典多因子模型的实质是线性回归模型。其中可以被观测到,相当于线性回归的自变量。股票收益相当于线性回归的因变量。通过对历史上和的拟合,可以得到回归系数,即因子收益的估计量。根据和最新截面期预测股票未来收益的估计量。如果不考虑风险模型,那么只需围绕以及约束条件,进行股票选择和权重分配。比如对分行业进行排序,选择各行业排名前N的股票,按行业中性的原则配置权重,得到下一期的投资组合。

 

从以上的描述,可以发现经典多因子模型的核心在于以下两步:

1. 根据历史的自变量和因变量,拟合线性回归模型,得到回归系数。

2. 根据最新的自变量和线性回归模型,预测因变量。

 

机器学习中最为主流的方法监督学习,其核心思想与线性回归类似,同样是挖掘自变量和因变量之间的规律。我们将经典多因子模型稍加改造,以机器学习的语言描述:

1. 训练阶段:根据历史的自变量和因变量,训练监督学习模型,得到模型自由参数的估计量。

2. 测试阶段:根据最新的自变量和监督学习模型,预测因变量。

从形式上看,经典的多因子模型和机器学习方法几乎完全一致。而机器学习方法相较于线性回归的优越之处在于:首先,机器学习可以挖掘数据中的非线性规律;其次,正则化的引入能够筛选出最有效的自变量;再次,参数优化的过程能够遴选出预测力最强的模型。

数据准备

成功的机器学习实践需要依靠强大的算法,但同样也离不开高质量的数据。我们首先将散乱的原始数据通过预处理,组织成结构化的数据。我们使用的数据为csv格式,每个月度截面期对应一个csv文件。其中1.csv对应1998年4月30日截面期,232.csv对应2017年7月31日截面期。

 

每个csv文件包含该月全部股票的基本信息,下期超额收益和当期因子值三部分,如下图所示。数据包含3411行,74列。其中第1行为列名,其余3410行的每一行对应一只股票。3410为截止2017年7月31日在A股上市的所有股票的数量,包含已退市的股票。1~3列为基本信息,其中第1列为月份信息,第2列为股票代码,第3列为交易状态。如果该股票满足:(1)ST、PT股(2)处于停牌期(3)上市不满3个月三个条件中的任一个,则该股票的交易状态为0,不参与机器学习模型的训练和预测;否则交易状态为1。第4列为因变量下期超额收益,代表股票下个月相对沪深300的超额收益。第5~74列对应70个因子,例如第5列为EP因子,第6列为EPcut因子,第74列为bias因子。所有因子已完成预处理,包括中位数去极值、缺失值填充、行业市值中性化和标准化。交易状态为0的股票,其因子值全部为缺失值NaN。


程序架构

在华泰人工智能系列第三篇支持向量机模型报告中,我们使用了经典的样本内外划分方式,选取2005~2010年截面期作为样本内数据,2011年以后截面期作为样本外数据。整个机器学习程序分为12个子模块,如下图所示。


出于表述清晰的考虑,我们在本篇Python实战中将以围绕上述架构开发的程序为范例进行讲解。在实际应用过程中,模型的训练方式、样本内外的划分方法可能存在各种变化,例如我们第二篇报告广义线性模型采用滚动训练方式。读者可以很便捷地对原有代码进行子模块的添加和重组,以满足实际需要。

另外,从程序设计的角度,各个子模块之间应注重解耦合性,尽可能相互独立,写成函数或者类的方法的形式。本篇报告出于降低初学者信息负载,同时便于调试的考虑,未以函数或者类的形式给出。有一定Python经验的读者可以自行改写,降低代码的耦合度,提升代码的可扩展性和可移植性。


Python代码实战


下文我们将以支持向量机模型的完整Python代码来说明如何构建机器学习多因子选股模型。每一个子模块包含“代码实例”和“代码分析”,分析部分对代码进行逐句讲解。部分模块还包含“其余变式”,介绍其它机器学习模型的代码写法。


模块导入

模块导入通常位于整段代码的开头,将需要用到的包、库、模块等导入程序。

代码实例

代码分析

# -- import packages

#符号之后为注释,本程序用注释这种方法将程序分为各模块,以及用于提示某部分代码功能。

 

import numpy as np

import pandas as pd

import为Python中导入包的命令,NumPy包简写为np,提供众多科学计算功能;pandas包简写为pd,提供DataFrame数据类型,便于海量数据的分析。以后当我们需要调用两个包中的函数时,只需使用np + 函数名或pd + 函数名即可。

参数设置

本模块将所有可能用到的参数都在程序开头用类(class)的形式加以定义,类名为Para。预定义Para类使得在我们在调整参数时可以直接在Para类中改变值,而无需在后面的程序中逐个单独改动。


代码实例

代码分析

class Para:

class的作用为创建一个类,可以给该类下各变量赋值。Python是通过缩进的方法来表示定义类这一操作何时结束,在代码中可以看到svm_c为类定义操作中的最后一行。

 

method = 'SVM'

不同的机器学习模型对应的Python命令不尽相同。Method参数用来确定程序使用的机器学习模型,'SVM'对应支持向量机模型。也可以设置为'LR'(线性模型)或 'SGD'(随机梯度下降模型)。

 

month_in_sample = range(82, 153+1)

该参数表示样本内数据对应的月份。注意函数range(x, y)将生成一组由x(含)至y(不含)的连续整数数列。如果希望包含y,则需要写成range(x, y+1)。在我们的多因子选股框架中,82号月对应2005年1月底截面期,153号月对应2010年12月底截面期,样本内数据共包含72个月。

 

month_test = range(154, 230 + 1)

该参数表示样本外数据对应的月份。在我们的多因子选股框架中,154号月对应2011年1月底截面期,230号月对应2017年5月底截面期,样本外数据共包含76个月。

 

percent_select = [0.3, 0.3]

在训练SVM等分类器模型时,可能需要选取有代表性的数据,而非全部数据。该参数表示选取排名靠前多少比例与排名靠后多少比例的数据。本程序选用每个月超额收益排名前30%的股票作为正例,后30%的股票作为反例。

 

percent_cv = 0.1

该参数表示交叉验证集占样本内数据的比例。本程序选用样本内数据的10%作为交互验证集,剩余90%作为训练集。

 

path_data = '.\\csv_demo\\'

该参数表示数据文件所在的路径。

 

path_results = '.\\results_demo\\' 

该参数表示执行程序后生成结果文件所在的路径。

 

seed = 42

该参数表示随机数种子。Python的随机数生成方式为伪随机,随机数的值并非真正随机,而是取决于随机数种子。换言之,当随机数种子固定不变时,每次生成的随机数也将固定不变。为了保证程序运行的结果可重复,我们需要提前设定随机数种子。

 

svm_kernel = 'linear'

该参数表示支持向量机模型的核函数类型,linear表示线性核。也可以设为poly(多项式核,默认3次多项式),sigmoid(Sigmoid核)或rbf(高斯核)。

 

svm_c = 0.01

该参数表示线性支持向量机的惩罚系数C。

 

para = Para()

为Para类创建一个实例para。Para类是一个抽象的概念,para是一个具体的对象,两者的关系相当于人类和某个人。


数据标记

本模块定义一个函数:输入全部样本,选择超额收益最高和最低的部分样本,分别标记为1和0,再将未被标记的样本剔除,返回标记完成的样本。


代码实例


代码分析

def label_data(data):

def的作用为定义函数,以缩进表示函数体的开始和结束位置。定义函数后,我们可以在后续程序里直接调用该函数,使得代码简洁高效。这里我们定义一个名为label_data的函数,输入变量为包含全部股票样本的DataFrame,在函数体内的局部变量名为data。


data['return_bin'] = np.nan

向输入的DataFrame变量data的最后一列添加名为return_bin的列,初始化赋予缺失值(nan,即not a number的缩写)。return_bin列随后将记录每个样本的标签。


data = data.sort_values(by='return', ascending=False)

使用sort_values方法,按照超额收益return对DataFrame进行降序排列,并将排列后的data替代原有data。参数by决定依据哪一列为标准进行排序;参数ascending决定是否按照升序排列,设置为False则代表降序排列。注意,无论按照升序还是降序排列,nan始终排在最后,并且每行的索引始终不变。

 

n_stock_select = np.multiply(para.percent_select, data.shape[0])

调用参数类para中的percent_select值,即选取前后多少比例的样本参与训练。使用data.shape方法得到data的维数,data相当于二维矩阵,[0]表示选取第一个值即行数,代表data中的股票数量。使用numpy中的multiply函数将两者相乘,即选取前后样本比例乘以股票总数,最终得到选取前后部分样本的股票个数,并将结果赋予n_stock_select。

 

n_stock_select = np.around(n_stock_select).astype(int)

注意到n_stock_select是由小数和整数相乘获得,结果可能带有小数,然而股票个数必须为整数,因此需要进行取整操作。numpy中的函数around默认将输入变量转换成整数。取整后虽然数值为整数,但是在存储格式上仍为浮点数,因此还需要使用astype(int)强制转换成整数格式。最后将处理后的整数替代原结果。

 

data.iloc[0:n_stock_select[0], -1] = 1

使用iloc进行矩阵的切分和赋值操作。注意到[]中,逗号前为所取的行,逗号后为所取的列。n_sock_select为含有两个整数值的列表,[0]即第一个值为选取表现最好的股票数量。所以对于排序后的data,我们取0到n_stock_select[0]行,再用-1取它们的最后一列,即我们之前创建的用于记录标签的新列,赋值为1作为表现最好的股票的标签。

 

data.iloc[-n_stock_select[1]:, -1] = 0

类似的,用iloc取data中-n_stock_select[1]:所在行的样本,注意到负号代表倒着取,而:后面不加任何变量则代表取到底。之后同样取它们的最后一列(即'return_bin'列)并赋值为0,作为表现最差的股票的标签。


data = data.dropna(axis=0)

使用dropna函数剔除含有缺失值nan的样本。参数axis=0表示如果某个元素为缺失值,则删除该元素所在的整行,axis=1则删除该元素所在的整列。将剔除缺失值后的data替换原有data。


return data

通常位于函数体的结尾,返回完成标记的data。执行该函数后将得到这个新DataFrame作为输出。


数据读取

本模块的主体是一段for循环。作用为将csv表格中的数据按月份顺序逐个导入内存,剔除空值,并做标记取前后部分样本,再将所有月份的数据拼接形成一个大的DataFrame,作为最终的样本内数据集。


代码实例


代码分析

for i_month in para.month_in_sample:

和大部分编程语言一样,Python中的for用来开启循环操作。for循环的主体以缩进的形式表示。在本例中,i_month作为循环变量,循环范围为para类中的month_in_sample列表,即样本内数据集的月份编号,从82到153。


file_name = para.path_data + str(i_month) + '.csv'

使用str函数将迭代变量的数值转为字符类型,与扩展名'.csv'和para类中的path_data进行字符串拼接,得到需要读取的csv文件完整路径,赋予file_name。

 

data_curr_month = pd.read_csv(file_name, header=0)

使用pandas中的read_csv函数读取csv文件的全部内容,赋予变量data_curr_month。其中参数header=0的意义是将csv文件的第一行作为DataFrame的列名。

 

para.n_stock = data_curr_month.shape[0]

使用DataFrame的shape方法得到数据集的行数和列数,索引[0]取其第一个值行数,即股票数,将该数值赋予para类的变量n_stock。

 

data_curr_month = data_curr_month.dropna(axis=0)

同前一部分所述,使用dropna(axis=0)删除缺失值nan元素所在的行,确保data_curr_month不含缺失值。

 

data_curr_month = label_data(data_curr_month)

调用之前定义的label_data函数。取data_curr_month矩阵中排名前后各一定比例的股票,分别标记为1和0。将label_data函数处理后的新DataFrame替换原DataFrame。

 

if i_month == para.month_in_sample[0]:

       data_in_sample = data_curr_month

使用if-else语句进行判断,同样使用缩进的形式表示if-else的主体。month_in_sample[0]表示样本内集合第一个月的编号。If命令判断当前程序是否为循环中的第一次迭代,是则新建一个变量data_in_sample保存已标记的data_curr_month。


else:

data_in_sample = data_in_sample.append(data_curr_month)

若当前迭代不是循环中的第一次迭代,则将已标记的data_curr_month拼接在data_in_sample后,得到新的样本内集合。


数据预处理

本模块将样本内集合切分成训练集和交叉验证集,并通过主成分分析进行降维以及去除因子共线性。最后得到四个数组,其中X_train与y_train为训练集的特征和标签,X_cv与y_cv为交叉验证集的特征和标签。

代码实例


代码分析

X_in_sample = data_in_sample.loc[:, 'EP':'bias']

本例SVM模型的特征为70个因子,其中第一列为EP因子,最后一列为bias因子。我们使用loc函数切取样本内集合从EP列到bias列的数据作为特征X。

 

y_in_sample = data_in_sample.loc[:, 'return_bin']

取DataFrame中的return_bin列作为样本内集合的标签y。

 

from sklearn.model_selection import train_test_split

使用from导入sklearn包中的train_test_split函数,该函数将样本内集合随机切分为训练集和交叉验证集。通常的编程习惯是将模块导入语句放在整个代码的开头部分。此处为了便于读者理解,将这句命令置于执行相应功能的代码块中。

 

X_train, X_cv, y_train, y_cv = train_test_split(X_in_sample, y_in_sample, test_size=para.percent_cv, random_state=para.seed)

使用train_test_split函数进行数据切分。函数的输入为样本内集合的特征X和标签y;调用para类中的percent_cv(交叉验证集占样本内集合的比例)赋给函数下参数test_size;调用para类中的seed(随机数种子)赋给参数random_state。该函数按照我们设置的交叉验证比例随机将特征X与标签y切分为训练集和交叉验证集两部分。设置随机数种子的目的是我们希望每次随机切分的结果完全相同,从而保证实验结果可重复。如果无需回溯比对,也可以不设置种子值。

 

from sklearn import decomposition

使用from从sklearn包中导入decomposition函数,该函数提供主成份分析(PCA)功能。

 

pca = decomposition.PCA(n_components=0.95)

使用decomposition.PCA函数,将主成分分析的模型赋予模型对象pca。参数n_components可以取0到1之间的浮点数或者大于等于1的整数。当n_components为0到1之间的浮点数时,PCA模型取相应比例的主成分数量,例如0.95代表取累计方差贡献率大于等于95%的主成分。当n_components为正整数时,PCA模型取相应数目的主成分。

 

pca.fit(X_train)

使用pca.fit对训练集的特征X_train拟合主成分分析模型。

 

X_train = pca.transform(X_train)

X_cv = pca.transform(X_cv)

使用上一步训练好的pca模型,对训练集特征X_train和交叉验证集特征X_cv进行主成份分析转换。使用函数transform完成该操作,并将降维后的数组替换原数组。


其余变式


特别地,当机器学习模型为回归模型时,通常不使用分类标签作为模型的y,而是以收益率本身作为y,因此我们直接将样本内数据集的return列设为y。特征X的取法不变。



本例所使用的csv文件已事先经过多项预处理,所以不需要在程序中做额外的数据预处理操作。若需要在程序内部进行数据预处理,可以使用sklearn包中的preprocessing函数。上面的代码展示了对数据进行标准化的过程,将原数据转换为均值为0,标准差为1的新数据。


模型设置

本模块根据预设的机器学习方法和参数,调用相应包并建立模型对象model。

代码实例


代码分析

if para.method == 'SVM':

调用para类中的method。变量method表示使用何种机器学习方法。该语句判断是否为使用支持向量机模型。

 

from sklearn import svm

若判断条件通过,进入if语句内部。使用from导入sklearn包中的svm模块。

 

model = svm.SVC(kernel=para.svm_kernel, C=para.svm_c)

使用svm.SVC函数,构建SVM分类器,赋予模型对象model。参数kernel为核函数类型,此处我们调用para类中预设的核函数类型svm_kernel;参数C为惩罚系数,此处我们调用para类中预设的惩罚系数svm_c。


其余变式


如果我们希望使用线性回归模型,我们仍以if命令判断是否使用线性回归模型,随后以import导入linear_model模块,并使用linear_model.LinearRegression构建模型赋予模型对象model。注意到线性回归的参数设置和支持向量机不同,参数fit_intercept表示线性回归是否包含截距项。



同样的,如果我们需要使用SGD模型,整体框架和前两者相同,只是调用的模块为linear_model.SGDClassifier。参数loss表示损失函数类型,这里采用hinge损失;alpha为正则项前的权重;penalty为正则化方法,这里采用L2正则化;max_iter为最大迭代次数; random_state为随机数种子值,目的是使结果可重复。


模型训练

本模块根据训练集的特征和标签训练SVM模型,随后使用训练完成的模型对训练集和交叉验证集进行预测。


代码实例


代码分析

model.fit(X_train,y_train)

用训练集的特征X_train和标签y_train训练模型对象model。其中函数fit的两个参数分别为特征和标签,训练结果保存在模型对象model中。

 

y_pred_train = model.predict(X_train)

y_score_train = model.decision_function(X_train)

用训练好的模型对象model在训练集X_train上做预测,预测结果用于模型评估。其中,函数predict给出的结果是二值化的整数[0,1],表示样本对应的标签(涨或跌);函数decision_function给出的决策函数值是连续的浮点数,用于刻画样本点涨跌的“概率”,不同模型计算结果的意义不同。例如SVM的结果表示样本点到分类超平面的“距离”(可正可负,可大于1),越正表示涨的概率越大,越负表示跌的概率越大。变量y_pred_train是预测标签(二值),变量y_score_train是预测的决策函数值(连续),可理解为涨跌的概率。

 

y_pred_cv = model.predict(X_cv)

y_score_cv = model.decision_function(X_cv)

用模型对象model在交叉验证集X_cv上做预测,结果同第2,3行,预测结果常用于调参。其中,变量y_pred_cv和y_score_cv分别表示交叉验证集上的预测标签和预测的决策函数值。


其余变式


特别地,当我们需要使用线性回归模型时,回归模型不存在预测标签和决策函数的概念,而是直接以model.predict的方法给出预测值。



使用SGD模型时,模型训练的命令和SVM模型完全相同。


模型预测

本模块使用训练完成的模型在测试集上做预测。首先,创建三个空数据集y_true_test、y_pred_test和y_score_test,分别用于存储预测集上的真实收益、预测标签和预测的决策函数值。随后对测试集中的每个月进行预测,使用for循环遍历测试集的每个月。


代码实例


代码分析

y_true_test = pd.DataFrame([np.nan] * np.ones((para.n_stock,para.month_test[-1])))

y _pred_test = pd.DataFrame([np.nan] * np.ones((para.n_stock,para.month_test[-1]))

y _score_test = pd.DataFrame([np.nan] * np.ones((para.n_stock,para.month_test[-1])))

三个数据集的类型均为pandas中的DataFrame,数据集初始化为nan;行数为股票的个数para.n_stock,每一行代表一只股票的信息;列数为测试集最后一个月的月份para.month_test[-1],每一列代表一个截面(月)。


for i_month in para.month_test:

para.month_test为测试集的所有月份,类型为列表。i_month为循环变量,代表当前月份。

 

file_name = para.path_data + str(i_month) + '.csv'

data_curr_month = pd.read_csv(file_name, header = 0)

从csv文件中读取当前月份 i_month的数据,返回变量data_curr_month的类型为DataFrame。其中,函数read_csv用来读取csv文件,参数file_name 表示csv文件的存储路径,字符串类型,使用+号运算符拼接字符串时需要把 i_month 从int型强制转化为string类型;header = 0表示csv文件索引为0的行作为返回值的列名,此外header还可以取None,表示返回值没有列名。

 

data_curr_month = data_curr_month.dropna(axis=0)  #-- remove nan

删除数据集 data_curr_month中含有缺失值nan元素所在的行,返回结果仍保存在data_curr_month中。一般来说,删除缺失值后,data_curr_month的行数会变少,但是每一行的索引同原来的,于是data_curr_month.index不为连续自然数列。

 

X_curr_month = data_curr_month.loc[:,'EP':'bias']  #-- generate X

提取70个因子值,也即data_curr_month的第'EP'列到'bias'列。注意,函数loc是按列名获取切片,函数iloc是按索引获取切片。

 

X_curr_month = pca.transform(X_curr_month)  #-- pca

对因子数据集X_curr_month做主成分分析,返回结果仍保存在X_curr_month中。一般来说,主成分分析后X_curr_month的列数会变少,起到降维和去除因子共线性的作用。

 

if para.method  == 'SVM':

para.method用于选择不同的机器学习方法,SVM代表支持向量机模型。


y_pred_curr_month = model.predict(X_curr_month) 

y_score_curr_month = model.decision_function(X_curr_month)

根据当前月份的因子值X_curr_month做预测,变量y_pred_curr_month和y_score_curr_month分别表示样本点的预测标签和预测的决策函数值。

 

y_true_test.iloc[data_curr_month.index,i_month-1] = data_curr_month['return'][data_curr_month.index]

保存真实收益。将data_curr_month的第'return'列(下月的超额收益率)的所有行的值存储到y_true_test的相应位置。变量y_true_test表示所有股票的真实收益,每一行代表一只股票,每一列代表一个月份。这里变量y_true_test的列为i_month-1是因为列的索引从0开始;行为data_curr_month.index是因为只保存进行预测的股票的收益率,没有进行预测的股票收益率仍取为缺失值nan。注意到,data_curr_month在去除缺失值nan后行数会变少,因此data_curr_month.index是y_true_test.index的子集。

 

y_pred_test.iloc[data_curr_month.index,i_month-1] = y_pred_curr_month

y_score_test.iloc[data_curr_month.index,i_month-1] = y_score_curr_month

将当前月份的预测标签y_pred_curr_month和预测的决策函数值y_score_curr_month保存到相应位置。


其余变式


和模型训练模块类似,使用线性回归模型时,直接以model.predict的方法给出预测值。



使用SGD模型时,预测标签和决策函数的获取命令和SVM模型完全相同。


模型评价

模型评估部分主要计算:训练集、交叉验证集和测试集(每月)的正确率和AUC。

代码实例


代码分析

from sklearn import metrics

从sklearn包中导入metrics模块,该模块覆盖了分类任务中大部分常用的验证指标,比如正确率、ROC、AUC、混淆矩阵、分类精度、f1-score等。

 

print('training set, accuracy = %.2f'%metrics.accuracy_score(y_train, y_pred_train))

print('training set, AUC = %.2f'%metrics.roc_auc_score(y_train, y_score_train))

计算训练集上的正确率和AUC,其中,y_train为真实标签(二值),y_pred_train为预测标签(二值),y_score_train为预测的决策函数值(连续),函数accuracy_score用以计算正确率,函数roc_auc_score用以计算AUC。

 

print('cv set, accuracy = %.2f'%metrics.accuracy_score(y_cv, y_pred_cv))

print('cv set, AUC = %.2f'%metrics.roc_auc_score(y_cv, y_score_cv))

计算交叉验证集上的正确率和AUC,其中y_cv为真实标签(二值),y_pred_cv为预测标签(二值),y_score_cv为预测的决策函数值(连续)。运行上述程序片段后,将在命令行窗口显示如下的结果:



for i_month in para.month_test:

循环遍历回测区间的所有月份,计算每个月的正确率和AUC。

 

y_true_curr_month = pd.DataFrame({'return':y_true_test.iloc[:,i_month-1]}) 

y_pred_curr_month = y_pred_test.iloc[:,i_month-1] 

y_score_curr_month = y_score_test.iloc[:,i_month-1]

获取测试集中当前月份的真实收益y_true_curr_month(连续)、预测标签y_pred_curr_month(二值)和预测的决策函数值y_score_curr_month(连续),都是只有一列的DataFrame类型。

 

y_true_curr_month = y_true_curr_month.dropna(axis=0)

删除当前月份真实收益y_true_curr_month中的缺失值nan所在的行,函数dropna已经多次用到,不做赘述。

 

y_curr_month = label_data(y_true_curr_month)['return_bin']

给真实收益y_true_curr_month加标签。函数label_data(y_true_curr_month)返回一个DataFrame,两列为'return'和'return_bin',分别表示真实收益(连续)和真实标签(二值,0,1);此外,该函数对行也进行了处理,即先按照真实收益降序排列,然后取前后30%的股票,这样做的好处是尽量减少噪音影响,因为中间40%的收益很有可能在噪音的影响下变号,从而改变类别。y_curr_month是y_true_curr_month的第'return_bin'列,表示真实标签,鉴于函数label_data对行进行了筛选,因此y_curr_month.index是y_true_curr_month.index的子集。

 

y_pred_curr_month = y_pred_curr_month[y_curr_month.index] 

y_score_curr_month = y_score_curr_month[y_curr_month.index]

获取收益最好和最差的30%股票的预测标签y_pred_curr_month(二值)和预测的决策函数值y_score_curr_month(连续)。其中,y_curr_month.index是收益最好和最差的30%股票的索引,也是当前月份所有股票索引y_true_curr_month.index的子集。

 

print('test set, month %d, accuracy = %.2f'%(i_month, metrics.accuracy_score(y_curr_month, y_pred_curr_month)))

print('test set, month %d, AUC = %.2f'%(i_month, metrics.roc_auc_score(y_curr_month, y_score_curr_month)))

计算测试集中每个月的正确率和AUC,分别由函数accuracy_score和roc_auc_score给出。其中y_curr_month为真实标签(二值),y_pred_curr_month为预测标签(二值),y_score_curr_month为预测的决策函数值(连续)。运行上述程序片段后,将在命令行窗口显示如下的模型评估结果:



策略构建

本模块围绕线性SVM模型的预测结果,构建了一个简单策略:选取每个月最可能涨的100只股票,等权配置资产。随后计算该策略的收益和净值。


代码实例


代码分析

para.n_stock_select = 100

strategy = pd.DataFrame({'return':[0] * para.month_test[-1],'value':[1] * para.month_test[-1]})  

设置选股个数为100,初始化策略的收益和净值。变量strategy 是DataFrame类型,有两列'return'和'value',分别表示策略的每月收益和每月净值。'return'列的初始值均为0,'value'列的初始值均为1。

 

for i_month in para.month_test:

遍历回测区间的所有月份,计算每个月的策略收益和净值。

 

y_true_curr_month = y_true_test.iloc[:,i_month-1] 

y_score_curr_month = y_score_test.iloc[:,i_month-1] 

y_true_curr_month为当前月份的真实收益,y_score_curr_month为当前月份的预测的决策函数值,均为只包含一列的DataFrame类型。其中,函数iloc是按索引获取切片,列为i_month-1是因为列的索引从0开始。

 

y_score_curr_month = y_score_curr_month.sort_values(ascending=False)

将当前月份的预测的决策函数值y_score_curr_month降序排列。其中,函数sort_values为排列函数,参数ascending用于指定排序方式(参数True表示升序,False表示降序),参数by用于指定按哪一列排序。注意,无论按照升序还是降序排列,nan始终排在最后,并且每行的索引始终不变。

 

index_select = y_score_curr_month[0:para.n_stock_select].index

选取上涨概率最大的前100只股票。上一句命令将预测的决策函数值降序排列后,越靠前的股票上涨概率越大,并且在dropna和sort_values操作后,每只股票的索引不变,故可将索引看做股票的唯一标识,用于选股。

 

strategy.loc[i_month-1,'return'] = np.mean(y_true_curr_month[index_select])

策略的每月收益为当前选取的100只股票的收益均值。其中,np.mean是计算均值的函数,参数为数组型变量。

 

strategy['value'] = (strategy['return']+1).cumprod()

计算策略的每月净值:将当前月份之前所有月(包括当前月)的收益加1,然后累乘。其中,strategy['return']表示按列名访问这一列,函数cumprod表示累乘,参数为数组型变量。


策略评价

本模块我们将绘制上述策略的净值曲线,并计算年化超额收益,年化超额收益波动率,信息比率等指标用以评价策略。


代码实例


代码分析

import matplotlib.pyplot as plt

导入matplotlib包中的pyplot模块,并将其简记为plt。

 

plt.plot(para.month_test,strategy.loc[para.month_test,'value'],'r-') 

plt.show()

利用函数plot画图,第一个参数para.month_test为横轴,表示月份;第二个参数strategy.loc[para.month_test,'value']为纵轴,表示回测区间上每个月的净值;第三个参数'r-'为曲线的颜色和线型,这里指红色的直线。最后通过函数show将绘制的图像显示出来。运行程序时,命令行窗口将显示下图所示的净值曲线。



ann_excess_return = np.mean(strategy.loc[para.month_test,'return']) * 12

计算策略的年化超额收益:所有月份收益的均值乘以12。其中,函数np.mean表示计算一组数的均值。

 

ann_excess_vol = np.std(strategy.loc[para.month_test,'return']) * np.sqrt(12)

计算策略的年化超额收益波动率:所有月份收益的方差乘以12再开根号,等价于,所有月份收益的标准差乘以根号12。其中,函数np.std表示计算一组数的标准差,函数np.sqrt表示开根号。

 

info_ratio = ann_excess_return/ann_excess_vol

计算策略的信息比率IR:超额收益除以超额收益波动率。用于评估策略好坏,含义是承担单位主动风险所获得的超额收益,IR越大则策略越好,反之越差。


print('annual excess return = %.2f'%ann_excess_return)

print(‘annual excess volatility = %.2f'%ann_excess_vol)

print(‘information ratio = %.2f'%info_ratio)

输出策略的评估结果。其中,函数print用于打印结果;'%.2f'是格式符,用于控制输出格式,这里表示保留两位小数的浮点数,此外格式符还有'%d'(整型)、'%s'(字符串)等;单引号之后的'%'是格式化操作的标志,表示用之后的变量值依次代替输出格式中格式符的位置。运行程序后在命令行窗口将显示如下的策略评价结果:



数据保存

本模块介绍如何保存数据,将每个月的预测值以csv格式保存在某个路径下。


代码实例


代码分析

import os

导入输出模块os,用来完成数据输出的操作。os 模块提供了一些统一的操作系统接口函数,这些函数通常是平台指定的,os模块能在不同操作系统平台如nt或posix中的特定函数间自动切换,从而能实现跨平台操作。os模块包含了普遍的操作系统功能,如果你希望程序能够与平台无关的话,这个模块尤为重要。

 

if not os.path.exists(para.path_results): 

    os.makedirs(para.path_results)

建立数据的输出目录,如果没有该目录,则新建。函数os.path.exists用来判断目录是否存在,函数os.makedirs用来新建目录。如果不写这两句话,直接往一个不存在的目录下输出数据,则会报错。

 

filename = para.path_results + 'dataTestYhat.csv'

建立输出文件的文件名,即para.path_results目录下的'dataTestYhat.csv'文件。

 

y_score_test.to_csv(filename,header=0,index=False)

将测试集上预测的决策函数值y_score_test保存到输出文件filename中,其中,header=0表示列名保存在第0行,index=False表示不保存索引。最终保存的csv文件如下图所示,包含3410行和232列,每行代表1只股票,每列代表1个月末截面期。每个元素代表该月末截面期对股票下月收益的预测值(SVM模型为决策函数值)。



总结

以上我们对基于Python语言的机器学习选股代码进行了详细介绍。软件开发者的一个共识是不要重复造轮子。我们希望上述的分享能够节省读者的研究时间,帮助读者迅速上手Python机器学习框架。我们也欢迎感兴趣的读者以此为蓝本进行优化和改造,开发新的机器学习多因子选股策略。


附录

XGBoost安装方法

XGBoost是重要的Boosting集成学习模型,在最近几年获得了长足的发展。目前scikit-learn包并没有包含XGBoost,需要手动安装,过程较为繁琐。我们总结了XGBoost在Windows系统下的详细安装方法,供读者参考。


安装Git

Git是一个分布式版本控制系统,可以对项目版本进行高效的管理。GitHub是一个软件项目托管平台,使用Git可以从GitHub中下载或上传开源程序。我们将使用Git从GitHub上获取最新版的XGBoost。首先我们需要下载Git for Windows,安装Git。

下载链接:https://git-for-windows.github.io/


下载XGBoost

Git安装完成后,打开Git Bash,在命令行中依次输入:

git clone --recursive https://github.com/dmlc/xgboost

git submodule init

git submodule update

运行完成后,将在用户文件夹中(例如C:/Users/用户名/)生成一个 xgboost 文件夹。


编译

下面我们将使用MinGW编译XGBoost。首先下载mingw-w64。下载链接:

https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/5.3.0/threads-win32/seh/

点击下载x86_64-5.3.0-release-win32-seh-rt_v4-rev0.7z,解压放置于C盘根目录。

 

随后配置环境变量:将C:/mingw64/bin粘贴到path环境变量下。接下来在命令行运行mingw32-make调用该命令,如下图所示:



打开Git Bash,进入到~/xgboost(例如C:/Users/用户名/xgboost),随后输入:

cp make/mingw64.mk config.mk

mingw32-make -j4

编译结果如下:



拷贝xgboost.dll

将~/xgboost/lib目录下的xgboost.dll文件拷贝到~/xgboost/python-package/xgboost下。


安装setup.py

在命令行中进入~/xgboost/python-package,执行命令:

python setup.py install

结果如下:



查看安装结果

在命令行中进入Python,输入:

import xgboost

help(xgboost)

可以查看xgboost module的信息:



尝试在 Python 里导入 xgboost 包,如果程序没有报错则安装完成。

如果提示找不到这个包,那么将目录:

C:/Program Files/Anaconda3/Lib/site-packages/xgboost-0.6-py3.6.egg

下的xgboost文件夹拷贝到目录:

C:/Program Files/Anaconda3/Lib/site-packages

下(即将xgboost文件夹移动到xgboost-0.6-py3.6.egg文件夹外部;这里我们假设C:/Program Files/Anaconda3为Anaconda的安装路径),这是因为site-packages下的module才是Python可以直接访问的目录。


风险提示

通过Python编写人工智能选股算法受到数据库架构、网络环境、计算机硬件条件限制,报告中代码经移植后可能不能正常运行;通过人工智能算法构建选股策略是历史经验的总结,存在失效的可能。


免责申明

本公众平台不是华泰证券研究所官方订阅平台。相关观点或信息请以华泰证券官方公众平台为准。根据《证券期货投资者适当性管理办法》的相关要求,本公众号内容仅面向华泰证券客户中的专业投资者,请勿对本公众号内容进行任何形式的转发。若您并非华泰证券客户中的专业投资者,请取消关注本公众号,不再订阅、接收或使用本公众号中的内容。因本公众号难以设置访问权限,若给您造成不便,烦请谅解!本公众号旨在沟通研究信息,交流研究经验,华泰证券不因任何订阅本公众号的行为而将订阅者视为华泰证券的客户。


本公众号研究报告有关内容摘编自已经发布的研究报告的,若因对报告的摘编而产生歧义,应以报告发布当日的完整内容为准。如需了解详细内容,请具体参见华泰证券所发布的完整版报告。


本公众号内容基于作者认为可靠的、已公开的信息编制,但作者对该等信息的准确性及完整性不作任何保证,也不对证券价格的涨跌或市场走势作确定性判断。本公众号所载的意见、评估及预测仅反映发布当日的观点和判断。在不同时期,华泰证券可能会发出与本公众号所载意见、评估及预测不一致的研究报告。


在任何情况下,本公众号中的信息或所表述的意见均不构成对客户私人投资建议。订阅人不应单独依靠本订阅号中的信息而取代自身独立的判断,应自主做出投资决策并自行承担投资风险。普通投资者若使用本资料,有可能会因缺乏解读服务而对内容产生理解上的歧义,进而造成投资损失。对依据或者使用本公众号内容所造成的一切后果,华泰证券及作者均不承担任何法律责任。


本公众号版权仅为华泰证券股份有限公司所有,未经公司书面许可,任何机构或个人不得以翻版、复制、发表、引用或再次分发他人等任何形式侵犯本公众号发布的所有内容的版权。如因侵权行为给华泰证券造成任何直接或间接的损失,华泰证券保留追究一切法律责任的权利。本公司具有中国证监会核准的“证券投资咨询”业务资格,经营许可证编号为:Z23032000。


评级说明

行业评级体系

-报告发布日后的6个月内的行业涨跌幅相对同期的沪深300指数的涨跌幅为基准;

-投资建议的评级标准

增持行业股票指数超越基准

中性行业股票指数基本与基准持平

减持行业股票指数明显弱于基准

 

公司评级体系

-报告发布日后的6个月内的公司涨跌幅相对同期的沪深300指数的涨跌幅为基准;

-投资建议的评级标准

买入股价超越基准20%以上

增持股价超越基准5%-20%

中性股价相对基准波动在-5%~5%之间 

减持股价弱于基准5%-20%

卖出股价弱于基准20%以上

  

林晓明

执业证书编号:S0570516010001


新财富请重点支持华泰金工


周期定市

 

二零一六年二月,大跌之后股市仿若惊弓鸟。彼时,华泰金工据全球统一周期规律,独家坚定全球必涨;周期股引领反转,价值投资回归。一年半全球普涨验证精准判断。

 

量化方法高维视角发现周期统一性规律,并实现科学精确测度。据此而提之华泰周期三因子模型,净值曲线独占鳌头,实战验真理。

 

华泰周期研究全新视角立行业新碑、开创先河。一年一度新财富群英荟萃、百舸争先;盼君贵手能把冠军投,感恩心以精品佳作涌泉报!

 

华泰金工敬献!

二零一七年九月



今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/V7Q1nIBQr0
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/3504
 
867 次点击