本周学习主要内容包括Python爬虫、文本相关操作、金融量化交易、Pandas时间序列(基础)
量化交易的步骤和数据分析联系:
衡量交易策略的性能好坏有很多指标,最重要的是最大回撤和夏普比率,二者主要关注的都是风险,而不是收益
一般业内规矩,一个交易账户如果:
本金最低5万美元(或50万人民币),
实盘交易3年(最低1年),
5%最大回撤,20%以上年化收益率(最少15%)
无论去什么地方,找什么机构(个人)要资金、合作、代客理财,都没有任何问题了。
实际指标达不到上述指标,也不意味着不能找钱,就是说服力差些
例如:本金只有三五万人民币,实盘只有几个月甚至只有回测记录,回撤大但收益大等等情况,具体情况具体看待
注意:国际上特别注重最大回撤,别的还可以商量,如果最大回撤太大了,基本账户就废了只能重写开始再来一个
年化收益:(平均收益率,累计收益图,时间段一般都是年)
年化收益率公式:
年化收益率 = ((策略最终价值 - 本金) / 本金) / 你交易的天数 * 正规交易天数 × 100%
或:
年化收益率 = (策略最终价值 / 本金 - 1) / 你交易的天数 * 正规交易天数 × 100%
注:正规交易天数一般为250天,365天除去周末和节假日等的大概天数,具体根据自己情况而定
最大回撤:(单位时间最大亏损)在特定时间段(通常是每年)内帐户净值曲线中最大的峰谷下降特征,通常以百分比形式引用
最大回撤公式:
最大回撤率 = (策略单位时间历史最高价值 - 策略单位时间最低价值) / 策略单位时间历史最高价值 * 100%
或:
最大回撤率 = max(1 - 策略当日价值 / 策略单位时间历史最高价值),注:每天的结果取最大值
夏普比率(Sharpe Ratio):收益风险比,是超额收益的均值和超额收益标准差的比
夏普比率公式:
(策略年化收益率 - 回测起始交易日的无风险利率) / 策略收益波动率
注:
策略收益波动率:用来测量资产的风险性,计算方式为:策略每日收益的年化标准差
无风险利率(超额收益):指的是无风险投资的回报率(本金的成本,默认3%),具体指的是某国固定利率国债收益率曲线上 10年期国债的年化到期收益率(或其他锚定对比的指标如标准普尔指数)。
中国 2.783:https://cn.investing.com/rates-bonds/china-10-year-bond-yield
美国 0.707:https://cn.investing.com/rates-bonds/u.s.-10-year-bond-yield
世界:https://cn.investing.com/rates-bonds/government-bond-spreads
无风险利率(超额收益)表示的意思有:
* 你资金的成本,某些情况下如果你的钱是自己的(不是借的没有利息)也不在乎机会成本,可以不减
* 你的年化收益率减去基本投资回报,剩下的才是你策略的超额回报(就像你用资金赚的钱得减去银行存钱的利息剩下才是你真赚的),必须减
夏普比率解释:
许多统计量被用来度量 调整风险收益,通常都是设法度量获得收益的成本(风险角度)。最典型的是 夏普比率
- 你的投资每承受1单位风险,会产生多少单位超额回报
- 例如夏普值为2的策略指每承担1个单位的风险,将会获得2个单位的高于无风险利率的收益率
让策略的夏普率增高的方法:收益要高,收益的波动要低
注意:
用调整交易时间频率的方法也可以算出高夏普率,但实际上是错误的,不要这么做
如计算 策略每日收益的年化标准差 时,作为时间频度的除数变大(如由250天/次变为高频的一百万次),夏普比率就会变大。所以高频策略的高夏普率是错算的。
不同时间频度的夏普比率不能直接比较,一般只看年化夏普率(以天为时间频度,一般250天),
如比较月收益和年收益的夏普比率,月度标准差需要乘以根号12(因为标准差随着时间的平方根等比例增长),而且这种算法只在特定情况下才有效,避免使用
私募基金市场上:如果夏普率小于1,这基金产品基本卖不出去
如果夏普率大于2,很多人会选择自己干
(很多对冲基金的要求,回测年化夏普率要高于2,甚至要求大于3(极少))
因此,绝大多数还行的发行产品夏普率都是1-2之间
从非结构化(非格式化)文本数据中抽取事先未知的、可理解的、最终可用的知识的过程,同时运用这些知识更好地组织信息
- 现实世界中,可获取的信息绝大多数是以非结构化0维文本形式存储的,如新闻、论文、书籍、电子邮件和Web网页
- 这些数据都存在不同程度的非结构化问题,维度有低有高
- 结构化程度低的例如一篇纯文本文章,结构化程度高的例如一个精心设计的WEB网页,内含格式化的标题、标签、摘要、作者等等
中文文本挖掘信息的精确度、正确率是世界性难题,为保证信息最大限度的精确可用,实际工作中应以人工设置信息格式为主,文本挖掘技术手段为辅:
- 挖掘再牛,不如用户手动打标签
- 分析再牛,不如用户手动评分
使用Python完成:
爬虫是实用程序自动化发送请求/获取响应的程序,主要用来抓取网页数据
img = 'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'
requests.get(img) #返回http状态码
r = requests.get(img).content #返回抓取数据 - 二进制
r #注释输出,自己解除注释
#二进制数据保存为图片(二进制)文件
with open('baidu/baidu.png','wb') as f:
f.write(r)
抓取网页源代码
url = 'https://www.baidu.com/'
r = requests.get(url)
r.content #中文乱码
temp = r.content.decode('UTF-8',errors='ignore') #二进制解码,解决中文乱码;默认转UTF-8,忽略错误
#文本数据保存为网页(文本)文件,注意编码
with open('baidu/pachong/baidu.html','w',encoding='UTF-8') as f:
f.write(temp)
发送带header的请求
#带header请求
headers = {
#去浏览器检查窗口复制
'User-Agen':'User-Agent:Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
'Cookie':''
}
url = 'https://www.baidu.com/'
#rh = requests.get(url).content.decode() #不带header
rh = requests.get(url,headers=headers).content.decode(errors='ignore') #带header,解除可能的反爬虫措施
rh
#保存新文件
with open('baidu/pachong/baidunews.html','w',encoding='UTF-8') as f:
f.write(rh)
XPath语法:选取节点
百度
HTML三种节点:
nodename 选取此节点的所有子节点,如:div选取div元素对象,及子对象
@ 选取属性值
text() 选取元素内容,文本值
选取方式:
/ 从根节点选取
// 从匹配当前选择的结点选择文档中的节点,不考虑他们的位置
. 选取当前节点
… 选取当前节点的父节点
解析网页内所有图片并抓取
一般情况下,数据抓取并解析后,需要字符串清洗处理后才能转为干净的列表模式
例如使用Python字符串和列表处理函数:
- 字符串:替换replace(),分割split()(Pandas也有类似函数,向量化的)
- 列表:合并join(),移除remove(),追加append()
等等,清理数据
列表页抓取所有内页url,再次遍历抓取的URL,抓取所有URL内页的内容
JSON系列列操作函数
json.loads():str转成dict
json.dumps():dict转成str
json.load():从文本文件中断区str的JSON数据,常用!!
json.dump():Python数据类型直接保存为str的JSON文本文件,常用!!
json.dumps()把列表或字典转成字符串
# Python数据保存为JSON文档
with open("baidu/pachong/a.json", "w", encoding='utf-8') as f:
f.write(json.dumps(c)) # 列表手动转字符串后保存文本
# JSON文档读取为Python数据
# 此方法不推荐(JSON文档有特殊字符可能会解析出错)
with open("baidu/pachong/a.json", "r", encoding='utf-8') as f:
# j = f.readline() # 字符串
j = json.loads(f.readline()) # 读入字符串手动转为Python数据
# Python数据保存为JSON文档
with open("baidu/pachong/a2.json", "w", encoding='utf-8') as f:
json.dump(c, f) # 直接将列表保存为文本(自动转化)
# JSON文档读取为Python数据
with open("baidu/pachong/a2.json", "r", encoding='utf-8') as f:
j = json.load(f) # 读入字符串自动转为Python数据
分词,就是将0维的非格式化文本转为格式化、向量化的数据
中文分词(Chinese Word Segmentation)是将一个汉字序列切分为一个一个单独的词
英文文档中,单词之间是以空格作为自然分界符的,而中文词没有一个形式上的分界符,虽然英文也存在同样的短语划分问题,不过在词上,中文分词相比英文复杂困难得多
‘0维的非格式化文本转为格式化’
分词:
[‘0维’,‘的’,‘非格式化’,‘文本’,‘转为’,‘格式化’]
中文分词库 - jieba
为了增加分词的准确率:
修改自定义词典或停用词文本文件时,不要使用记事本修改(保存时会村委UTF-8带BOM格式,导致程序载入出问题)
当句子中的某个词没有被识别分出时,可以指定自己自定义的词典,以便包含jieba词库子没有的词
词典文件的内容可以根据项目不断增加,查看初步分词,将分词不正确的词加入自定义词典然后重新再分,直到正确率达标
虽然jieba有新词识别能力,但自行添加新词可以保证更高的正确率
jieba.load_userdict(file_name) #file_name 为文件类对象或自定义词典的路径
词典格式:
次品省略时使用自动计算也能保证分出该词的词频
课程内附的通用停用词词典,涵盖大部分无用字词,可以根据项目需求不断添加累计补充
停用词jieba没有自带,需要手动实现
#方法1:手工构造停用词列表
#stopword =['哎','的','是','你','吗','!',',','?']
#方法2:载入停用词文件
#with open('data/stopword.txt','r',encoding='UTF-8') as f:
# print(f.read())
# s = f.read()
#stopword = s.split('\n')
#stopword
#方法3提升,若停用词表的特殊词载入时被自动转义,可以判断并恢复
stopword = []
with open('data/stopword.txt','r',encoding='UTF-8') as f:
for line in f.readlines():
l = line.strip()
if l =='\\n':
l == '\n'
if l == '\\u3000':
l == '\u3000'
stopword.append(l)
#去停用词,第一步,求差集
x = np.array(b)
y = np.array(stopword)
y
np.in1d(x,y)
z = x[~np.in1d(x,y)]
#非运算,在x内且不在y内的词
#第二步:去掉一个字以下的词
#k = []
#for i in z:
# print(len(i))
# if len(i) > 1:
# k.append(i)
#k
k = [i for i in z if len(i)>1]
抽取文档关键词用于在一篇文章中获取其核心内容(描述了什么?)又叫生成摘要、打标签、关键词提取等
#1. 自定义词典
jieba.load_userdict('data/custom.txt') #应用自定义词典
#2. 分词
cut = jieba.lcut(txt)
#3. 去停用词
#载入停用词表
stopword = []
with open('data/stopword.txt','r',encoding='UTF-8') as f:
for line in f.readlines():
l = line.strip()
if l =='\\n':
l == '\n'
if l == '\\u3000':
l == '\u3000'
stopword.append(l)
stopword
################
#去停用词,第一步,求差集
x = np.array(cut) #降分好的词列表转为数组
y = np.array(stopword) #将停用词转为数组
z = x[~np.in1d(x,y)] #x的元素是否包含与y
#第二步,去掉一个字的词
k = [i for i in z if len(i)>1]
#4. 计算词频并排序
result = pd.Series(k).value_counts()[:20]
#5. 保存结果
result.to_csv('data/keyword_fig.csv',header=0) #encoding='gbk'解决乱码
统计词频作为文档关键字的准确性不高
注:TF-IDF和Text-Rank算法运行都不需要手动去停用词,可以用内置函数自动去停用词
TF-IDF权重:
词频和重要词的综合分数(权重)
重要词:信息量大的词
一个词信息量大小的衡量
在本文章出现的次数多,在通用文档库出现的次数少,就是重要词
如:你我他,你好再见 这些词信息量很小
行业专有名词:如Python/MySQL,信息量很大
安装WordCloud库
如果系统未安装C++编译库,WordCloud库需要下载whl再使用pip安装
http://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud
pip install e:/wordcloud-1.5.0-cp36-cp36m-win_amd64.whl
# 载入文本数据
with open('data/大话西游.txt', 'r', encoding='utf-8') as f:
# print(f.read())
txt = f.read()
txt2 = ' '.join(jieba.cut(txt))
#print(txt2)
# 停用词
# 方式2:读入停用词文件为列表
with open('data/stopword.txt', 'r', encoding='utf-8') as f:
# print(f.read())
s = f.read()
stopword = s.split('\n')
# stopword
# 词云绘制时去停用词
wordcloud = WordCloud(font_path='data/font/arial unicode ms.ttf').generate(txt2)
wordcloud
plt.figure(figsize=(18, 10))
plt.imshow(wordcloud)
wordcloud = WordCloud(
font_path="data/font/maozedong.ttf", # 字体,不设置则汉字乱码
background_color='white',# 设置背景颜色
max_words=80, # 设置最大现显示词数
max_font_size=80, # font_size可选
stopwords=stopword, # 去停用词
).generate(txt2)
wordcloud
plt.figure(figsize=(18, 10), dpi=72)
plt.imshow(wordcloud) # 绘制数据内的图片,双线性插值绘图 interpolation='bilinear'
plt.axis("off") # 去掉坐标轴
plt.savefig('images/test3.png', dpi=300, bbox_inches='tight') # 保存为:带有最小白边且分辨率为300DPI的PNG图片
#读取背景图
alice_mask = np.array(Image.open("images/tgcf.jpg"))
# alice_mask
wordcloud = WordCloud(
background_color='white',# 设置背景颜色
max_words=100, # 设置最大现显示词数
font_path="data/font/maozedong.ttf", # 字体,不设置则汉字乱码
stopwords = stopword, # 去停用词
mask=alice_mask, # 设置背景图片
).generate(txt2)
wordcloud
plt.figure(figsize=(18, 10), dpi=300)
plt.imshow(wordcloud) # 绘制数据内的图片,双线性插值绘图 interpolation='bilinear'
plt.axis("off") # 去掉坐标轴
plt.savefig('images/test4.png', dpi=300, bbox_inches='tight')
SnowNLP(Simplified Chinese Text Processing),是一个python语言编写的类库,可以方便的处理中文文本内容,其开发受到了TextBlob的启发
下面主要使用词向量分析方法
词向量
word2vec主要通过计算词向量之间的余弦相似度来分析词之间的距离关系远近(cosA=AC/AB)
时间序列(time series)是一种重要的结构化数据形式,应用于多个领域,包括金融学、经济学、生态学、神经科学、物理学等……
时间序列:在多个时间点观察或测量到的任何数据都可以形成一段时间序列
对Pandas来说,时间序列数据就是以时间类型作为索引的Series或DataFrame数据结构
很多时间序列都是固定频率的,即数据点是根据某种规律定期出现的(比如每x秒、每x分钟、每周、每月、每年出现一次)
时间序列也可以不定期,没有固定的时间单位或单位之间的偏移量
时间序列数据的意义取决于具体的应用场景,主要有:
Pandas提供了许多内置的时间序列处理工具和数据算法。因此可以高效处理非常大的时间序列,轻松地进行切片/切块、聚合、对定期/不定期的时间序列进行重采样等
有些工具特别适合金融和经济应用
Python标准库包括日期(date)和时间(time)数据的数据类型
datetime.datetime(也可以简写为datetime)是用得最多的数据类型:
datetime模块是date和time模块的合集
datetime模块有五个类:
datetime.timedelta对象代表两个时间之间的时间差,两个datetime对象相减就可以返回一个timedelta对象
针对时间存储,timedelta内部只能存储days,seconds,microseconds(天,秒,微秒),其他参数的值会自动按如下规则进行转换:
Python中时间日期格式化符号:
年:
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
月:%m 月份(01-12)
日:%d 月内中的一天(0-31)
小时:
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
分钟:%M 分钟数(00=59)
秒:%S 秒(00-59)
%c 本地相应的日期表示和时间表示,如:Sat Feb 11 11:32:59 2017
%x 本地相应的日期表示,如:02/11/17
%X 本地相应的时间表示,如:11:32:59
%j 一年内的第x天(001-366)
%p 本地A.M.或P.M.的等价符。AM:(0:00-12:00);PM:(12:00-24:00)
%Z 当前时区的名称,默认为空
%% %号本身
星期:
%a 本地简化星期名称
%A 本地完整星期名称
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%U 一年中的星期数(00-53)星期天为星期的开始
月:
%b 本地简化的月份名称
%B 本地完整的月份名称