Tushare介绍
Tushare pro是一个python财经数据接口包。主要实现对股票等金融数据从数据采集、清洗加工 到 数据存储的过程,能够为金融分析人员提供快速、整洁、和多样的便于分析的数据,为他们在数据获取方面极大地减轻工作量,使他们更加专注于策略和模型的研究与实现上。考虑到Python pandas包在金融量化分析中体现出的优势,Tushare返回的绝大部分的数据格式都是pandas DataFrame类型,非常便于用pandas/NumPy/Matplotlib进行数据分析和可视化。
Tushare安装
- 方式1:
pip install tushare
- 方式2:访问https://pypi.python.org/pypi/Tushare/下载安装
学习文档
说明文档:https://tushare.pro/
Tushare使用
调用Pro版本的数据
- 用户注册:
[https://tushare.pro/register?reg=379314](https://tushare.pro/register?reg=379314)
- 获取token
- 初始化接口,调取数据
```python
导入tushare模块
import tushare as ts
初始化pro接口
pro = ts.pro_api(‘your token’) pro
<a name="QY0jk"></a>
### Tushare基本使用
<a name="gomox"></a>
#### 练习1
1. 使用tushare 获取五粮液股票的历史行情数据
1. 输出该股票所有收盘比开盘上涨3%以上的日期
1. 输出该股票所有开盘比前日收盘跌幅超过2%的日期
1. 假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票。到今天为止,我的收益如何?
```python
import tushare as ts
import pandas as pd
import numpy as np
pro = ts.pro_api("your token")
"""
使用tushare获取五粮液股票的历史行情数据
"""
wly_stock = pro.daily(ts_code="000858.SZ", start_date="20000101")
"""
将数据保存为csv文件
"""
wly_stock.to_csv("wly000858.csv", index=False)
"""
读取五粮液文件数据,指定trade_date为时间序列索引.
- parse_dates 设置索引为时间序列索引,传入的类型为list
"""
wly_df = pd.read_csv("wly000858.csv", index_col="trade_date", parse_dates=["trade_date"])
wly_df.info()
wly_df.head()
"""
输出所有收盘价比开盘上涨3%以上的日期
公式: (close - open)/ open > 0.03
"""
wly_df[(wly_df["close"] - wly_df["open"])/wly_df["open"] > 0.03].index
"""
一个简单的策略
假设从2010年1月开始,每月从第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止的收益如何?
需求分析
- 每月第一个交易日买入: 1、支出 2、支出的是每月第一个交易日该股票的开盘价*1手(1手 = 100股)
- 每年最后一个交易日卖出: 1、收入 2、收入的是每年最后一个交易日该股票的开盘价*12手
"""
# 截取2010年~2019年的数据
wly_df2 = wly_df["2019":"2010"]
# 每月第一个交易日的数据
wly_monthly_f = wly_df2.resample("MS").first() # first()取每个月汇总第一个交易日的数据
# 每年最后一个交易日的数据
wly_yearly_l = wly_df2.resample("A").last()
# wly_yearly_l
"""
计算收益
"""
# 初始化每个月需要购买股票所话的成本
cost_money = 0
# 初始化,已持有的股票
hold = 0
# 获取2010~2019年每一年所有的成本以及收入
for year in range(2010, 2019):
cost_money += wly_monthly_f[str(year)]["open"].sum() * 100 # 累加每年买股票所花的成本
hold += len(wly_monthly_f[str(year)]) * 100
sell_money = wly_yearly_l[str(year)]["open"].values[0]*hold # 年末卖出的价格*所卖出的价格
cost_money -= sell_money # 每年总成本 - 每年总收入
hold = 0 # 由于已经卖出了,所以持有股数清0
print(f"save_money:{-cost_money}, hold:{hold}")
双均线分析
对于每一个交易日,都可以计算出前N天的移动平均值,然后把这些移动平均值连起来,成为一条线,就叫做N日移动平均线。移动平均线常用:5天,10天,30天,60天,120天和240天的指标
- 5天和10天的是短线操作的参照指标,称做日均线指标;
- 30天和60天的是中期均线指标,称做季均线指标;
- 120天和240天的是长期均线指标,称做年均线指标。
黄金交叉
死亡交叉
短期均线下穿长期均线,卖出信号
双均线分析练习
- 使用tushare包获取某股票的历史行情数据
- 使用tushare包计算该股票历史数据的5日均线和30日均线
- 使用matplotlib包可视化历史数据的收盘价和两条均线
- 分析输出所有金叉日期和死叉日期
- 假如我从2010年1月1日开始,初始资金为10W,金叉尽量买入,死叉全部卖出,则到今天为止。我的炒股收益率如何?
import tushare as ts
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
# 初始化pro接口
pro = ts.pro_api("28c5c9f8976917756a3d42b04a765e83782c282a70da38b0ea71615f")
# 获取云南白药2010年至今的数据
by_stock = pro.daily(ts_code="000538.SZ", start_date="20100101")
# 将数据保存到本地
by_stock.to_csv("000538.csv", index=False)
# 读取云南白药的数据
by_df = pd.read_csv("000538.csv", index_col="trade_date", parse_dates=["trade_date"])[["open","high","low","close"]]
# by_df.head()
by_df.sort_index(inplace=True) # 时间升序
"""
使用tushare包计算该股票历史数据的5日均线和30日均线
"""
# 添加MA5和MA30两列并赋值NAN
by_df["MA5"] = np.nan
by_df["MA30"] = np.nan
# by_df.head()
"""
方法1
MA5是短期均线,规律是0~4, 1~5, 2~6
公式: 定义一个变量i, i的取值范围为4~len(by_df), 取值范围从4开始是因为符合i-4~i+1的规律.
例如i=4时, i-4=0 i+1=5,由于是左闭右开的,因此就会生成从0~4的5个值,以此类推,这样就符合MA5的规律
"""
# 计算MA5
for i in range (4, len(by_df)):
# 获取到MA5列i行的值赋值为收盘价的5日均价
by_df.loc[by_df.index[i], "MA5"] = by_df["close"][i-4:i+1].mean()
for i in range (29, len(by_df)):
# 获取到MA5列i行的值赋值为收盘价的5日均价
by_df.loc[by_df.index[i], "MA30"] = by_df["close"][i-29:i+1].mean()
"""
方法二: 用rolling实现
"""
by_df["close"].rolling(5).mean()
# by_df["close"].rolling(30).mean()
"""
输出图表
"""
by_df[["close","MA5","MA30"]].plot()
plt.show()
"""
分析输出所有金叉日期和死叉日期
"""
by_data = by_df.dropna() # 过滤掉NAN的数据
# by_data.info()
# by_data.head()
"""
方法一:
- 金叉:短期均线上穿长期均线 ==> 前一天MA5<=MA30 并且后一天MA5>=30
- 死叉:短期均线下穿长期均线 ==> 前一天MA5>=MA30 并且后一天MA5<=30
"""
gloden_cross = []
death_cross = []
for i in range(1, len(by_data)):
# 金叉
if by_data["MA5"][i] >= by_data["MA30"][i] and by_data["MA5"][i-1] <= by_data["MA30"][i-1]:
# 将金叉的时间构建成列表
# print(by_data.index[i])
gloden_cross.append(by_data.index[i])
if by_data["MA5"][i] <= by_data["MA30"][i] and by_data["MA5"][i-1] >= by_data["MA30"][i-1]:
# 将金叉的时间构建成列表
death_cross.append(by_data.index[i])
# print(gloden_cross)
"""
方法2
以金叉为例
- 短期均线比长期均线波动大
- 短期均线上穿长期均线为金叉
- 金叉和死叉交替出现
如果现在是死叉,从死叉过度到金叉
- 比较MA5<MA30就会出现TRUE, 然后可能一直TTTT,然后到了某一天MA5>=MA30时,就会是False,因此出现的情况可能就是TTTFFF,所以当出现TF时,这个点就是金叉
由于除了要比较MA5<MA30,还需要比较MA5>MA30的情况,因此如果是MA5>MA30时,就会可能会出现FFFFTTTT的情况,也因此:
像这种情况:
MA5<MA30:TTTTFFFF
MA5>MA30: FFFFTTTT (往前挪一位,错位比较)
“MA5<MA30”和“MA5>MA30”在两个都出现F时,这个点就是金叉;反之,如果都为T时,就是死叉
"""
se1 = by_data["MA5"] < by_data["MA30"]
se2 = by_data["MA5"] >= by_data["MA30"]
"""
由于需要两个都出现F时,才是金叉
因此这里的比较符不能使用&, 要使用|
"""
gloden_cross2 = by_data[~(se1 | se2.shift(1))].index
# gloden_cross2
"""
两个都为T时,就是死叉
"""
death_cross2 = by_data[se1 & se2.shift(1)].index
death_cross2
"""
假如我从2010年1月1日开始,初始资金为10W,金叉尽量买入,死叉全部卖出,则到今天为止。我的炒股收益率如何?
"""
sr1 = pd.Series(1, index=gloden_cross2) # 1代表金叉
sr2 = pd.Series(0, index=death_cross2) # 0代表死叉
sr = sr1.append(sr2).sort_index() # sr1 拼接sr2
money = 100000 # 初始化起始资金
hold = 0 # 初始化持有股
for i in range(0, len(sr)):
"""
获取价格
- 获取open价格
- 再通过取出sr的时间索引获取对应时间的价格
"""
# print(by_data["open"][sr.index[i]]) # 每一次交叉点的价格
p = by_data["open"][sr.index[i]]
if sr.iloc[i] == 1:
# 金叉,买入
buy = money //(100*p) # 计算买入多少股
hold += buy*100 # 计算总共持有多少股
money -= buy*100*p # 因为买入了,所以起始资金会减少
if i == len(sr)-1:
money += buy*100*p # 如果最后一个点是金叉,买入所花的这笔钱,也算作你的收入
else:
# 死叉,卖出
money += hold*p # 卖出,资金增加
hold = 0 # 因为是全部卖出,所以持有股清0
gains = money - 100000 # 最终盈利金额
# gains