需求:股票分析
- 使用tushare包获取某股票的历史行情数据。
- 输出该股票所有收盘比开盘上涨3%以上的日期。
- 输出该股票所有开盘比前日收盘跌幅超过2%的日期。
-
假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?
-
tushare财经数据接口包
- pip install tushare
In [1]:
import tushare as ts
import pandas as pd
from pandas import DataFrame,Series
import numpy as np
In [2]:
#获取某只股票的历史行情数据
#code:字符串形式的股票代码
df = ts.get_k_data(code='600519',start='2000-01-01')
df
本接口即将停止更新,请尽快使用Pro版接口:https://tushare.pro/document/2
Out[2]:
date | open | close | high | low | volume | code | |
---|---|---|---|---|---|---|---|
0 | 2001-08-27 | -91.359 | -91.174 | -90.778 | -91.654 | 406318.00 | 600519 |
1 | 2001-08-28 | -91.274 | -90.941 | -90.916 | -91.341 | 129647.79 | 600519 |
2 | 2001-08-29 | -90.920 | -91.027 | -90.916 | -91.076 | 53252.75 | 600519 |
3 | 2001-08-30 | -91.044 | -90.899 | -90.826 | -91.094 | 48013.06 | 600519 |
4 | 2001-08-31 | -90.890 | -90.915 | -90.806 | -90.952 | 23231.48 | 600519 |
... | ... | ... | ... | ... | ... | ... | ... |
4906 | 2022-03-09 | 1764.100 | 1779.180 | 1805.000 | 1721.110 | 56434.00 | 600519 |
4907 | 2022-03-10 | 1808.000 | 1794.430 | 1821.000 | 1791.000 | 36462.00 | 600519 |
4908 | 2022-03-11 | 1766.000 | 1769.010 | 1777.000 | 1718.080 | 47727.00 | 600519 |
4909 | 2022-03-14 | 1730.000 | 1700.000 | 1750.000 | 1700.000 | 49007.00 | 600519 |
4910 | 2022-03-15 | 1650.000 | 1603.000 | 1685.000 | 1603.000 | 89056.00 | 600519 |
4911 rows × 7 columns
In [3]:
#将互联网上获取的股票数据存储到本地
df.to_csv('./maotai.csv')#调用to_xxx方法将df中的数据写入到本地进行存储
In [4]:
#将本地存储的数据读入到df
df = pd.read_csv('./maotai.csv')
df.head()
Out[4]:
Unnamed: 0 | date | open | close | high | low | volume | code | |
---|---|---|---|---|---|---|---|---|
0 | 0 | 2001-08-27 | -91.359 | -91.174 | -90.778 | -91.654 | 406318.00 | 600519 |
1 | 1 | 2001-08-28 | -91.274 | -90.941 | -90.916 | -91.341 | 129647.79 | 600519 |
2 | 2 | 2001-08-29 | -90.920 | -91.027 | -90.916 | -91.076 | 53252.75 | 600519 |
3 | 3 | 2001-08-30 | -91.044 | -90.899 | -90.826 | -91.094 | 48013.06 | 600519 |
4 | 4 | 2001-08-31 | -90.890 | -90.915 | -90.806 | -90.952 | 23231.48 | 600519 |
In [5]:
#需要对读取出来的数据进行相关的处理
In [6]:
#删除df中指定的一列
df.drop(labels='Unnamed: 0',axis=1,inplace=True)
In [7]:
#查看每一列的数据类型
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4911 entries, 0 to 4910
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 date 4911 non-null object
1 open 4911 non-null float64
2 close 4911 non-null float64
3 high 4911 non-null float64
4 low 4911 non-null float64
5 volume 4911 non-null float64
6 code 4911 non-null int64
dtypes: float64(5), int64(1), object(1)
memory usage: 268.7+ KB
In [8]:
#将date列转为时间序列类型
df['date'] = pd.to_datetime(df['date'])
In [9]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4911 entries, 0 to 4910
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 date 4911 non-null datetime64[ns]
1 open 4911 non-null float64
2 close 4911 non-null float64
3 high 4911 non-null float64
4 low 4911 non-null float64
5 volume 4911 non-null float64
6 code 4911 non-null int64
dtypes: datetime64[ns](1), float64(5), int64(1)
memory usage: 268.7 KB
In [10]:
#将date列作为源数据的行索引
df.set_index('date',inplace=True)
In [11]:
df.head()
Out[11]:
open | close | high | low | volume | code | |
---|---|---|---|---|---|---|
date | ||||||
2001-08-27 | -91.359 | -91.174 | -90.778 | -91.654 | 406318.00 | 600519 |
2001-08-28 | -91.274 | -90.941 | -90.916 | -91.341 | 129647.79 | 600519 |
2001-08-29 | -90.920 | -91.027 | -90.916 | -91.076 | 53252.75 | 600519 |
2001-08-30 | -91.044 | -90.899 | -90.826 | -91.094 | 48013.06 | 600519 |
2001-08-31 | -90.890 | -90.915 | -90.806 | -90.952 | 23231.48 | 600519 |
In [12]:
#输出该股票所有收盘比开盘上涨3%以上的日期
#伪代码:(收盘-开盘)/开盘 > 0.03
(df['open'] - df['close']) / df['open'] > 0.03
#在分析的过程中如果产生了boolean值则下一步马上将布尔值作为源数据的行索引
#如果布尔值作为df的行索引,则可以取出true对应的行数据,忽略false对应的行数据
df.loc[(df['open'] - df['close']) / df['open'] > 0.03] #获取了True对应的行数据(满足需求的行数据)
df.loc[(df['open'] - df['close']) / df['open'] > 0.03].index #df的行数据
Out[12]:
DatetimeIndex(['2006-05-29', '2006-06-12', '2006-10-09', '2006-10-25',
'2006-11-14', '2006-11-16', '2006-11-29', '2006-11-30',
'2006-12-11', '2006-12-14',
...
'2021-07-26', '2021-07-27', '2021-07-29', '2021-08-17',
'2021-08-26', '2021-10-18', '2021-12-29', '2022-01-13',
'2022-01-28', '2022-03-07'],
dtype='datetime64[ns]', name='date', length=680, freq=None)
In [13]:
#输出该股票所有开盘比前日收盘跌幅超过2%的日期
#伪代码:(开盘-前日收盘)/前日收盘 < -0.02
(df['open'] - df['close'].shift(1))/df['close'].shift(1) < -0.02
#将布尔值作为源数据的行索引取出True对应的行数据
df.loc[(df['open'] - df['close'].shift(1))/df['close'].shift(1) < -0.02]
df.loc[(df['open'] - df['close'].shift(1))/df['close'].shift(1) < -0.02].index
Out[13]:
DatetimeIndex(['2006-02-13', '2006-04-17', '2006-04-18', '2006-04-19',
'2006-04-20', '2006-05-25', '2006-05-30', '2006-12-27',
'2007-01-04', '2007-01-22',
...
'2020-03-13', '2020-03-23', '2020-10-26', '2021-02-26',
'2021-03-04', '2021-04-28', '2021-08-20', '2021-11-01',
'2022-03-14', '2022-03-15'],
dtype='datetime64[ns]', name='date', length=377, freq=None)
- 需求:假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖出所有股票,到今天为止,我的收益如何?
- 分析:
- 时间节点:2010-2020
- 一手股票:100支股票
- 买:
- 一个完整的年需要买入1200支股票
- 卖:
- 一个完整的年需要卖出1200支股票
- 买卖股票的单价:
- 开盘价
In [14]:
new_df = df['2010-01':'2020-02']
new_df
Out[14]:
open | close | high | low | volume | code | |
---|---|---|---|---|---|---|
date | ||||||
2010-01-04 | 35.594 | 34.047 | 35.594 | 33.573 | 44304.88 | 600519 |
2010-01-05 | 34.835 | 33.671 | 35.219 | 33.340 | 31513.18 | 600519 |
2010-01-06 | 33.333 | 31.657 | 33.716 | 31.319 | 39889.03 | 600519 |
2010-01-07 | 31.657 | 29.373 | 31.980 | 27.991 | 48825.55 | 600519 |
2010-01-08 | 29.584 | 28.081 | 29.584 | 26.654 | 36702.09 | 600519 |
... | ... | ... | ... | ... | ... | ... |
2020-02-24 | 1069.182 | 1050.862 | 1073.682 | 1049.182 | 38650.00 | 600519 |
2020-02-25 | 1041.682 | 1038.492 | 1045.772 | 1031.562 | 38385.00 | 600519 |
2020-02-26 | 1025.682 | 1037.382 | 1047.682 | 1018.682 | 43560.00 | 600519 |
2020-02-27 | 1039.682 | 1051.072 | 1058.672 | 1039.682 | 34498.00 | 600519 |
2020-02-28 | 1033.982 | 1020.682 | 1045.682 | 1013.652 | 49946.00 | 600519 |
2461 rows × 6 columns
In [15]:
new_df.head(2)
Out[15]:
open | close | high | low | volume | code | |
---|---|---|---|---|---|---|
date | ||||||
2010-01-04 | 35.594 | 34.047 | 35.594 | 33.573 | 44304.88 | 600519 |
2010-01-05 | 34.835 | 33.671 | 35.219 | 33.340 | 31513.18 | 600519 |
In [16]:
#买股票:找每个月的第一个交易日对应的行数据(捕获到开盘价)==》每月的第一行数据
#根据月份从原始数据中提取指定的数据
#每月第一个交易日对应的行数据
df_monthly = new_df.resample('M').first()#数据的重新取样
df_monthly
Out[16]:
open | close | high | low | volume | code | |
---|---|---|---|---|---|---|
date | ||||||
2010-01-31 | 35.594 | 34.047 | 35.594 | 33.573 | 44304.88 | 600519 |
2010-02-28 | 33.250 | 33.258 | 33.776 | 31.845 | 29655.94 | 600519 |
2010-03-31 | 31.424 | 31.267 | 32.176 | 31.079 | 21734.74 | 600519 |
2010-04-30 | 25.662 | 26.624 | 26.954 | 25.647 | 23980.83 | 600519 |
2010-05-31 | 2.529 | 3.017 | 3.708 | 1.702 | 23975.16 | 600519 |
... | ... | ... | ... | ... | ... | ... |
2019-10-31 | 1116.682 | 1130.782 | 1143.682 | 1115.692 | 31045.00 | 600519 |
2019-11-30 | 1144.682 | 1148.682 | 1155.632 | 1136.182 | 22811.00 | 600519 |
2019-12-31 | 1081.882 | 1096.682 | 1103.702 | 1081.882 | 30784.00 | 600519 |
2020-01-31 | 1091.682 | 1093.682 | 1108.742 | 1079.682 | 148099.00 | 600519 |
2020-02-29 | 948.682 | 967.602 | 974.362 | 943.682 | 123442.00 | 600519 |
122 rows × 6 columns
In [17]:
#买入股票花费的总金额
cost = df_monthly['open'].sum()*100
cost
Out[17]:
3245315.6
In [18]:
#卖出股票到手的钱
#特殊情况:2020年买入的股票卖不出去
new_df.resample('A').last()
#将2020年最后一行切出去
df_yearly = new_df.resample('A').last()[:-1]
df_yearly
Out[18]:
open | close | high | low | volume | code | |
---|---|---|---|---|---|---|
date | ||||||
2010-12-31 | 43.847 | 45.440 | 45.711 | 43.284 | 46084.0 | 600519 |
2011-12-31 | 68.243 | 68.739 | 70.045 | 66.011 | 29460.0 | 600519 |
2012-12-31 | 88.579 | 85.034 | 89.811 | 82.827 | 51914.0 | 600519 |
2013-12-31 | 20.074 | 23.694 | 24.463 | 18.835 | 57546.0 | 600519 |
2014-12-31 | 89.937 | 93.591 | 93.937 | 89.391 | 46269.0 | 600519 |
2015-12-31 | 143.406 | 143.376 | 144.686 | 143.006 | 19673.0 | 600519 |
2016-12-31 | 257.967 | 265.507 | 266.647 | 257.967 | 34687.0 | 600519 |
2017-12-31 | 656.144 | 635.634 | 664.644 | 629.744 | 76038.0 | 600519 |
2018-12-31 | 512.443 | 539.153 | 545.543 | 509.143 | 63678.0 | 600519 |
2019-12-31 | 1146.682 | 1146.682 | 1151.682 | 1140.192 | 22588.0 | 600519 |
In [19]:
#卖出股票到手的钱
resv = df_yearly['open'].sum()*1200
resv
Out[19]:
3632786.4000000004
In [20]:
#最后手中剩余的股票需要估量其价值计算到总收益中
#使用昨天的收盘价作为剩余股票的单价
last_monry = 200*new_df['close'][-1]
In [21]:
#计算总收益
resv+last_monry-cost
Out[21]:
591607.2000000002
需求:双均线策略制定
- 使用tushare包获取某股票的历史行情数据
In [22]:
df = pd.read_csv('./maotai.csv').drop(labels='Unnamed: 0',axis=1)
df
Out[22]:
date | open | close | high | low | volume | code | |
---|---|---|---|---|---|---|---|
0 | 2001-08-27 | -91.359 | -91.174 | -90.778 | -91.654 | 406318.00 | 600519 |
1 | 2001-08-28 | -91.274 | -90.941 | -90.916 | -91.341 | 129647.79 | 600519 |
2 | 2001-08-29 | -90.920 | -91.027 | -90.916 | -91.076 | 53252.75 | 600519 |
3 | 2001-08-30 | -91.044 | -90.899 | -90.826 | -91.094 | 48013.06 | 600519 |
4 | 2001-08-31 | -90.890 | -90.915 | -90.806 | -90.952 | 23231.48 | 600519 |
... | ... | ... | ... | ... | ... | ... | ... |
4906 | 2022-03-09 | 1764.100 | 1779.180 | 1805.000 | 1721.110 | 56434.00 | 600519 |
4907 | 2022-03-10 | 1808.000 | 1794.430 | 1821.000 | 1791.000 | 36462.00 | 600519 |
4908 | 2022-03-11 | 1766.000 | 1769.010 | 1777.000 | 1718.080 | 47727.00 | 600519 |
4909 | 2022-03-14 | 1730.000 | 1700.000 | 1750.000 | 1700.000 | 49007.00 | 600519 |
4910 | 2022-03-15 | 1650.000 | 1603.000 | 1685.000 | 1603.000 | 89056.00 | 600519 |
4911 rows × 7 columns
In [23]:
#将date列转为时间序列且将其作为源数据的行索引
df['date'] = pd.to_datetime(df['date'])
In [24]:
df.set_index('date',inplace=True)
In [25]:
df.head()
Out[25]:
open | close | high | low | volume | code | |
---|---|---|---|---|---|---|
date | ||||||
2001-08-27 | -91.359 | -91.174 | -90.778 | -91.654 | 406318.00 | 600519 |
2001-08-28 | -91.274 | -90.941 | -90.916 | -91.341 | 129647.79 | 600519 |
2001-08-29 | -90.920 | -91.027 | -90.916 | -91.076 | 53252.75 | 600519 |
2001-08-30 | -91.044 | -90.899 | -90.826 | -91.094 | 48013.06 | 600519 |
2001-08-31 | -90.890 | -90.915 | -90.806 | -90.952 | 23231.48 | 600519 |
- 计算该股票历史数据的5日均线和30日均线
- 什么是均线?
- 对于每一个交易日,都可以计算出前N天的移动平均值,然后把这些移动平均值连起来,成为一条线,就叫做N日移动平均线。移动平均线常用线有5天、10天、30天、60天、120天和240天的指标。
- 5天和10天的是短线操作的参照指标,称做日均线指标;
- 30天和60天的是中期均线指标,称做季均线指标;
- 120天和240天的是长期均线指标,称做年均线指标。
- 对于每一个交易日,都可以计算出前N天的移动平均值,然后把这些移动平均值连起来,成为一条线,就叫做N日移动平均线。移动平均线常用线有5天、10天、30天、60天、120天和240天的指标。
- 均线计算方法:MA=(C1+C2+C3+...+Cn)/N C:某日收盘价 N:移动平均周期(天数)
- 什么是均线?
In [26]:
ma5 = df['close'].rolling(5).mean()
ma30 = df['close'].rolling(30).mean()
In [27]:
ma5
Out[27]:
date
2001-08-27 NaN
2001-08-28 NaN
2001-08-29 NaN
2001-08-30 NaN
2001-08-31 -90.9912
...
2022-03-09 1763.9760
2022-03-10 1762.8620
2022-03-11 1760.5640
2022-03-14 1759.1640
2022-03-15 1729.1240
Name: close, Length: 4911, dtype: float64
In [28]:
import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(ma5[50:180])
plt.plot(ma30[50:180])
Out[28]:
[<matplotlib.lines.Line2D at 0x21df8d5fb20>]
- 分析输出所有金叉日期和死叉日期
- 股票分析技术中的金叉和死叉,可以简单解释为:
- 分析指标中的两根线,一根为短时间内的指标线,另一根为较长时间的指标线。
- 如果短时间的指标线方向拐头向上,并且穿过了较长时间的指标线,这种状态叫“金叉”;
- 如果短时间的指标线方向拐头向下,并且穿过了较长时间的指标线,这种状态叫“死叉”;
- 一般情况下,出现金叉后,操作趋向买入;死叉则趋向卖出。当然,金叉和死叉只是分析指标之一,要和其他很多指标配合使用,才能增加操作的准确性。
- 股票分析技术中的金叉和死叉,可以简单解释为:
In [29]:
ma5 = ma5[30:]
ma30 = ma30[30:]
In [30]:
s1 = ma5 < ma30
s2 = ma5 > ma30
In [31]:
df = df[30:]
In [32]:
death_ex = s1 & s2.shift(1) #判定死叉的条件
df.loc[death_ex] #死叉对应的行数据
death_date = df.loc[death_ex].index
In [33]:
golden_ex = ~(s1 | s2.shift(1))#判定金叉的条件
golden_date = df.loc[golden_ex].index #金叉的时间
- 如果我从假如我从2010年1月1日开始,初始资金为100000元,金叉尽量买入,死叉全部卖出,则到今天为止,我的炒股收益率如何?
- 分析:
- 买卖股票的单价使用开盘价
- 买卖股票的时机
- 最终手里会有剩余的股票没有卖出去
- 会有。如果最后一天为金叉,则买入股票。估量剩余股票的价值计算到总收益。
- 剩余股票的单价就是用最后一天的收盘价。
- 会有。如果最后一天为金叉,则买入股票。估量剩余股票的价值计算到总收益。
In [34]:
s1 = Series(data=1,index=golden_date) #1作为金叉的标识
s2 = Series(data=0,index=death_date) #0作为死叉的标识
s = s1.append(s2)
s = s.sort_index() #存储的是金叉和死叉对应的时间
In [35]:
s = s['2010':'2020']##存储的是金叉和死叉对应的时间
In [36]:
first_monry = 100000 #本金,不变
money = first_monry #可变的,买股票话的钱和卖股票收入的钱都从该变量中进行操作
hold = 0 #持有股票的数量(股数:100股=1手)
for i in range(0,len(s)): #i表示的s这个Series中的隐式索引
#i = 0(死叉:卖) = 1(金叉:买)
if s[i] == 1:#金叉的时间
#基于100000的本金尽可能多的去买入股票
#获取股票的单价(金叉时间对应的行数据中的开盘价)
time = s.index[i] #金叉的时间
p = df.loc[time]['open'] #股票的单价
hand_count = money // (p*100) #使用100000最多买入多少手股票
hold = hand_count * 100
money -= (hold * p) #将买股票话的钱从money中减去
else:
#将买入的股票卖出去
#找出卖出股票的单价
death_time = s.index[i]
p_death = df.loc[death_time]['open'] #卖股票的单价
money += (p_death * hold) #卖出的股票收入加入到money
hold = 0
#如何判定最后一天为金叉还是死叉
last_monry = hold * df['close'][-1] #剩余股票的价值
#总收益
money + last_monry - first_monry
Out[36]:
32376838.699999996