一.数据准备:本地化股票数据
1.1为什么要创建股票数据库
-
数据费用->按数据量收费,每日更新增量数据
-
获取速度->本地直接获取>远程访问服务器
1.2如何创建,更新股票数据库 -
存储方式->股票代码.csv,MySql,MangoDB等数据库
-
实现思路: 1.获取股票列表
2.依次存储股票数据
3.每天以增量形式更新数据
每天以增量形式更新数据
-> -
如何追加数据:df.to_csv(mode=‘a’)
-
重复获取了怎么办:df.drop_duplicates
-
缺少数据怎么办:startdate=最后一个日期
import time
import pandas as pd
import os
#全局变量:
data_root='D:/python project/pythonProject/data/'
#000002.XSHE 万 科A 000001.XSHE 平安银行
from jqdatasdk import *
auth('15608617235','Xwt688698') #账号是申请时所填写的手机号;密码为聚宽官网登录密码
pd.set_option('display.max_rows',1000000)
pd.set_option('display.max_columns',10000)
import datetime
def init_db():
"""
初始化股票数据库
:return:
"""
#1.获取所有股票代码
stocks=get_stock_list()
#2.存储到csv文件中
for code in stocks:
df=get_single_stock_Price(code,'daily')
export_data(df,code,'price')
print(code)
print(df.head())
def get_stock_list():
"""
获取所有A股股票列表
:return: stock_list
"""
stocks_list= list(get_all_securities(['stock']).index)
return stocks_list
def get_single_stock_Price(code,time_freq,start_date=None,end_date=None):
"""
获取当个股票行情数据
:param code:
:param time_freq:
:param start_date:
:param end_date:
:return:
"""
#如果start_date=None,默认从上市日期开始
if start_date is None:
start_date=get_security_info(code).start_date
if end_date is None:
end_date=datetime.datetime.today()
#获取行情数据
data = get_price(code,start_date=start_date, end_date=end_date, frequency=time_freq, panel=False)
return data
def export_data(data,filename,type,mode=None):
"""
导出股票相关数据
:param data:
:param type:股票数据类型,可以是:price,finance
:param filename:
:param mode:a代表追加,none代表默认写入
:return:
"""
file_root=data_root+type+'/'+filename+'.csv'
data.index.names=['date']
if mode=='a':
data.to_csv(file_root,mode=mode,header=False)
#删除重复值
data=pd.read_csv(file_root)#读取数据
data=data.drop_duplicates(subset=['date'])#以日期列为准
data.to_csv(file_root)#重新写入
else:
data.to_csv(file_root)#判断一下file是否存在>存在:追加/不存在:保持
print('已成功存储至:',file_root)
def get_csv_data(code,type):
file_root=data_root+type+'/'+code+'.csv'
return pd.read_csv(file_root)
def transfer_price_freq(data,time_freq):
"""
将数据转换为指定周期:周期开盘价(周期第一天),收盘价(周期最后一天),最高价(周期内),最低价(周期内)
:param data:
:param time_freq:
:return:
"""
#获取周K(当周的):开盘价(当周第一天),收盘价(当周最后一天),最高价(当周),最低价(当周)
df_trans=pd.DataFrame()
df_trans['open']=data['open'].resample(time_freq).first()
df_trans['close']=data['close'].resample(time_freq).last()
df_trans['high']=data['high'].resample(time_freq).max()
df_trans['low']=data['low'].resample(time_freq).min()
return df_trans
def get_signle_finance(code,date,statDate):
"""
获取单个股票财务指标
:param code:
:param date:
:param statDate:
:return:
"""
data = get_fundamentals(query(indicator).filter(indicator.code==code), date=date,statDate=statDate) # 获取财务指标数据
return data
def get_single_valuation(code,date,statDate):
"""
获取单个股票估值指标
:param code:
:param date:
:param statDate:
:return:
"""
data = get_fundamentals(query(valuation).filter(valuation.code==code), date=date,statDate=statDate) # 获取财务指标数据
return data
def calculate_change_pct(data):
"""
涨跌幅=(当期收盘价-前期收盘价)/前期收盘价
:param data:dataframe,带有收盘价
:return:datafram,带有涨跌幅
"""
data['close_pct']=(data['close']-data['close'].shift(1))/data['close'].shift(1)
return data
def update_daily_price(stock_code,type):
# 3.1是否存在文件:不存在-重新获取,存在->3.2
file_root=data_root+type+'/'+stock_code+'.csv'
if os.path.exists(file_root):#如果存在对应文件
# 3.2获取增量数据(code.startdate=对应股票csv中最新日期。enddate=今天)
startdate=pd.read_csv(file_root,usecols=['date'])['date'].iloc[-1]
df=get_single_stock_Price(stock_code,'daily',startdate,datetime.datetime.today())
# 3.3追加到已有文件中
export_data(df,stock_code,'price','a')
else:
#重新获取该股票行情数据
df=get_single_stock_Price(stock_code,'daily')
export_data(df,stock_code,'price')
import data.stock as st
import pandas as pd
#调用一只股票的行情数据
# code='000002.XSHG'
# data=st.get_single_stock_Price(code=code,time_freq='daily',start_date='2021-01-01',end_date='2021-02-01')
# # # 存入csv
# st.export_data(data=data,filename=code,type='price')
#从csv中获取数据
# data=st.get_csv_data(code=code,type='price')
# print(data)
#1.获取所有股票代码
# stocks=st.get_stock_list()
#2.存储到csv文件中
# for code in stocks:
# df=st.get_single_stock_Price(code,'daily')
# st.export_data(df)
#1+2.
st.init_db()
#3.每日更新数据
#3.1是否存在文件:不存在-重新获取,存在->3.2
#3.2获取增量数据(code.startdate=对应股票csv中最新日期。enddate=今天)
#3.3追加到已有文件中
# for code in stocks:
# st.update_daily_price(code,'price')
二.数据准备:从本地读取数据
import time
import pandas as pd
import os
#全局变量:
data_root='D:/python project/pythonProject/data/'
#000002.XSHE 万 科A 000001.XSHE 平安银行
from jqdatasdk import *
auth('15608617235','Xwt688698') #账号是申请时所填写的手机号;密码为聚宽官网登录密码
pd.set_option('display.max_rows',1000000)
pd.set_option('display.max_columns',10000)
import datetime
def init_db():
"""
初始化股票数据库
:return:
"""
#1.获取所有股票代码
stocks=get_stock_list()
#2.存储到csv文件中
for code in stocks:
df=get_single_stock_Price(code,'daily')
export_data(df,code,'price')
print(code)
print(df.head())
def get_stock_list():
"""
获取所有A股股票列表
:return: stock_list
"""
stocks_list= list(get_all_securities(['stock']).index)
return stocks_list
def get_single_stock_Price(code,time_freq,start_date=None,end_date=None):
"""
获取当个股票行情数据
:param code:
:param time_freq:
:param start_date:
:param end_date:
:return:
"""
#如果start_date=None,默认从上市日期开始
if start_date is None:
start_date=get_security_info(code).start_date
if end_date is None:
end_date=datetime.datetime.today()
#获取行情数据
data = get_price(code,start_date=start_date, end_date=end_date, frequency=time_freq, panel=False)
return data
def export_data(data,filename,type,mode=None):
"""
导出股票相关数据
:param data:
:param type:股票数据类型,可以是:price,finance
:param filename:
:param mode:a代表追加,none代表默认写入
:return:
"""
file_root=data_root+type+'/'+filename+'.csv'
data.index.names=['date']
if mode=='a':
data.to_csv(file_root,mode=mode,header=False)
#删除重复值
data=pd.read_csv(file_root)#读取数据
data=data.drop_duplicates(subset=['date'])#以日期列为准
data.to_csv(file_root)#重新写入
else:
data.to_csv(file_root)#判断一下file是否存在>存在:追加/不存在:保持
print('已成功存储至:',file_root)
def get_csv_price(code,start_date,end_date):
#使用update直接更新
update_daily_price(code)
#读取数据
file_root=data_root+'price/'+code+'.csv'
data=pd.read_csv(file_root,index_col='date')
#根据日期筛选股票数据
return data[(data.index>=start_date) & (data.index<end_date)]
def transfer_price_freq(data,time_freq):
"""
将数据转换为指定周期:周期开盘价(周期第一天),收盘价(周期最后一天),最高价(周期内),最低价(周期内)
:param data:
:param time_freq:
:return:
"""
#获取周K(当周的):开盘价(当周第一天),收盘价(当周最后一天),最高价(当周),最低价(当周)
df_trans=pd.DataFrame()
df_trans['open']=data['open'].resample(time_freq).first()
df_trans['close']=data['close'].resample(time_freq).last()
df_trans['high']=data['high'].resample(time_freq).max()
df_trans['low']=data['low'].resample(time_freq).min()
return df_trans
def get_signle_finance(code,date,statDate):
"""
获取单个股票财务指标
:param code:
:param date:
:param statDate:
:return:
"""
data = get_fundamentals(query(indicator).filter(indicator.code==code), date=date,statDate=statDate) # 获取财务指标数据
return data
def get_single_valuation(code,date,statDate):
"""
获取单个股票估值指标
:param code:
:param date:
:param statDate:
:return:
"""
data = get_fundamentals(query(valuation).filter(valuation.code==code), date=date,statDate=statDate) # 获取财务指标数据
return data
def calculate_change_pct(data):
"""
涨跌幅=(当期收盘价-前期收盘价)/前期收盘价
:param data:dataframe,带有收盘价
:return:datafram,带有涨跌幅
"""
data['close_pct']=(data['close']-data['close'].shift(1))/data['close'].shift(1)
return data
def update_daily_price(stock_code,type='price'):
# 3.1是否存在文件:不存在-重新获取,存在->3.2
file_root=data_root+type+'/'+stock_code+'.csv'
if os.path.exists(file_root):#如果存在对应文件
# 3.2获取增量数据(code.startdate=对应股票csv中最新日期。enddate=今天)
startdate=pd.read_csv(file_root,usecols=['date'])['date'].iloc[-1]
df=get_single_stock_Price(stock_code,'daily',startdate,datetime.datetime.today())
# 3.3追加到已有文件中
export_data(df,stock_code,'price','a')
else:
#重新获取该股票行情数据
df=get_single_stock_Price(stock_code,'daily')
export_data(df,stock_code,'price')
print("股票数据已经更新成功:",stock_code)
import data.stock as st
#本地读取数据
data=st.get_csv_price('000001.XSHE','2020-01-01','2020-02-01')
print(data)
exit()
#获取平安银行的行情数据(日K)
data=st.get_single_stock_Price('000001.XSHE','daily','2020-01-01','2020-02-01')
# print(data)
#计算涨跌幅,验证准确性
#data=st.calculate_change_pct(data)
# print(data)#多了一列close_pct
#获取周K
data=st.transfer_price_freq(data,'W')
print(data)
#计算涨跌幅,验证准确性
data=st.calculate_change_pct(data)
print(data)
三.双均线策略
3.1什么是双均线策略
均线->美国投资专家Joseph E.Granville
1962年提出,利用股价和均线择时
->代表过去N日股价平均走势
3.2策略实现思路
1)获取标的行情
2)计算技术指标
3)生成交易信号
4)计算收益率
5)寻找最优参数
6)与市场基准比较
7)策略评估
四.双均线策略:生成交易信号
import numpy as np
import pandas as pd
import strategy.base as strat
import data.stock as st
import pandas as pd
def ma_stratey(data,short_window=5,long_window=20):
"""
双均线策略
:param data:dataframe,投资标的行情数据(必须包含收盘价)
:param short_window:短期n期移动平均线,默认5
:param long_window:长期n日移动平均线,默认20
:return:
"""
data=pd.DataFrame(data)
#计算技术指标:ma短期,ma长期
data['short_ma']=data['close'].rolling(window=short_window).mean()
data['long_ma']=data['close'].rolling(window=long_window).mean()
#生成信号:金叉买入,死叉卖出
data['buy_signal']=np.where(data['short_ma']>data['long_ma'],1,0)
data['sell_signal'] = np.where(data['short_ma'] < data['long_ma'], -1, 0)
#过滤信号:st.compose_signal
data=strat.compose_signal(data)
#数据预览
# print(data[['close','short_ma','long_ma','buy_signal','sell_signal','signal']])
#删除多余的columns
data.drop(labels=['buy_signal','sell_signal'],axis=1)
return data
if __name__=='__main__':
df=st.get_single_stock_Price('000001.XSHE','daily','2021-11-05','2022-01-04')
df=ma_stratey(df)
#筛选有信号点
df=df[df['signal']!=0]
#数据预览
print("开仓次数:",int(len(df) / 2))
print(df[['close','short_ma','long_ma','signal']])
五.双均线策略:计算信号收益率
import numpy as np
import pandas as pd
import strategy.base as strat
import data.stock as st
import pandas as pd
import matplotlib.pyplot as plt
def ma_stratey(data,short_window=5,long_window=20):
"""
双均线策略
:param data:dataframe,投资标的行情数据(必须包含收盘价)
:param short_window:短期n期移动平均线,默认5
:param long_window:长期n日移动平均线,默认20
:return:
"""
data=pd.DataFrame(data)
#计算技术指标:ma短期,ma长期
data['short_ma']=data['close'].rolling(window=short_window).mean()
data['long_ma']=data['close'].rolling(window=long_window).mean()
#生成信号:金叉买入,死叉卖出
data['buy_signal']=np.where(data['short_ma']>data['long_ma'],1,0)
data['sell_signal'] = np.where(data['short_ma'] < data['long_ma'], -1, 0)
#过滤信号:st.compose_signal
data=strat.compose_signal(data)
#计算单次收益率
data=strat.calculate_prof_pct(data)
#计算累计收益
data=strat.calculate_cum_prof(data)
#数据预览
#print(data[['close','short_ma','long_ma','buy_signal','sell_signal','signal']])
#删除多余的columns
data.drop(labels=['buy_signal','sell_signal'],axis=1)
return data
if __name__=='__main__':
#股票列表
stocks=['000001.XSHE','000858.XSHE','002594.XSHE']
#存放累计收益率
cum_profits=pd.DataFrame()
#循环获取数据
for code in stocks:
df=st.get_single_stock_Price(code,'daily','2016-01-01','2021-01-01')
df=ma_stratey(df)#调用双均线策略
cum_profits[code] = df['cum_profit'].reset_index(drop=True) # 存储累计收益率
#折线图
df['cum_profit'].plot(label=code)
#筛选有信号点
# df=df[df['signal']!=0]
# #数据预览
print("开仓次数:", int(len(df)))
# print(df[['close','signal','profit_pct','cum_profit']])
#预览
print(cum_profits)
#可视化
# cum_profits.plot()
plt.title('Comparison of Ma Strategy Pofits')
plt.show()
六.什么是假设检验
双均线策略->基于不同周期平均价格的突破性策略
如何验证策略的可靠性:
- 评估指标->胜率,年化收益,最大回撤,夏普
- 假设检验->收益>0是否为大概率事件
- 先提出一个假设,通过多次实验,计算不同结果出现的频率,来决定是否接受或者拒绝这个假设,从而验证这个现象是否随机(偶然)
假设检验:t-test
H0:样本均值=理论均值->每次收益率的均值=0
H1:样本均值>理论均值->每次收益率>0
七.双均线策略:利用p值检验可靠性
import numpy as np
import pandas as pd
import strategy.base as strat
import data.stock as st
import pandas as pd
import matplotlib.pyplot as plt
def ma_stratey(data,short_window=5,long_window=20):
"""
双均线策略
:param data:dataframe,投资标的行情数据(必须包含收盘价)
:param short_window:短期n期移动平均线,默认5
:param long_window:长期n日移动平均线,默认20
:return:
"""
print("=======当前周期参数对:",short_window,long_window)
data=pd.DataFrame(data)
#计算技术指标:ma短期,ma长期
data['short_ma']=data['close'].rolling(window=short_window).mean()
data['long_ma']=data['close'].rolling(window=long_window).mean()
#生成信号:金叉买入,死叉卖出
data['buy_signal']=np.where(data['short_ma']>data['long_ma'],1,0)
data['sell_signal'] = np.where(data['short_ma'] < data['long_ma'], -1, 0)
#过滤信号:st.compose_signal
data=strat.compose_signal(data)
#计算单次收益率
data=strat.calculate_prof_pct(data)
#计算累计收益
data=strat.calculate_cum_prof(data)
# 删除多余的columns
data.drop(labels=['buy_signal', 'sell_signal'], axis=1)
#数据预览
print(data[['close','short_ma','long_ma','cum_profit','signal']])
return data
if __name__=='__main__':
#股票列表
stocks=['000001.XSHE','000858.XSHE','002594.XSHE']
#存放累计收益率
cum_profits=pd.DataFrame()
#循环获取数据
for code in stocks:
df=st.get_single_stock_Price(code,'daily','2016-01-01','2021-01-01')
df=ma_stratey(df)#调用双均线策略
cum_profits[code] = df['cum_profit'].reset_index(drop=True) # 存储累计收益率
#折线图
df['cum_profit'].plot(label=code)
#筛选有信号点
# df=df[df['signal']!=0]
# #数据预览
print("开仓次数:", int(len(df)))
# print(df[['close','signal','profit_pct','cum_profit']])
#预览
print(cum_profits)
#可视化
# cum_profits.plot()
plt.title('Comparison of Ma Strategy Pofits')
plt.show()
八.双均线策略:寻找最优参数
import pandas as pd
import strategy.ma_strategy as ma
import data.stock as st
#参数1:股票池
#stocks=['000001.XSHE']
data=st.get_csv_price('000001.XSHE','2016-01-01','2021-01-01')
#参数2:周期参数
params=[5,10,20,60,120,250]
#存放参数与收益
res=[]
#匹配,并计算不同的周期参数对:5-10,2-20...120-250
for short in params:
for long in params:
if long > short:
data_res=ma.ma_strategy(data=data,short_window=short,long_window=long)
#获取周期参数,及其对应累计收益率
cum_profit=data_res['cum_profit'].iloc[-1]#获取累计收益率最终数据
res.append([short,long,cum_profit])#将参数放入结果里面
#将结果列表转换为df,并找到最优参数
res=pd.DataFrame(res,columns=['short_win','long_win','cum_win'])
#排序
res=res.sort_values(by='cum_profit',ascending=False)#按收益倒序排序
print(res)