一个简单粗糙的python写的显示股票k线和买卖点的小工具。
用了新浪的源,主要是学习python的编程。
本软件仅供学习交流,任何问题与本人无关,特此声明。侵删。
用到的知识点:
1、requests模块获取http网页信息
2、matplotlib画图,包括mpl_finance画k线,pyplot画界面,widgets添加小工具
代码:
1、
import requests
import os
import re
import datetime
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import matplotlib
from matplotlib.widgets import Button
from matplotlib.widgets import TextBox
from matplotlib.widgets import RadioButtons
import pandas as pd
from matplotlib.dates import MONDAY, DateFormatter, DayLocator, WeekdayLocator
from mpl_finance import candlestick_ohlc
导入用到的模块
2、
#import zh font
zhfont = matplotlib.font_manager.FontProperties(fname='./fonts/msyh.ttf')
#global var
get_str=''
stock_code=''
data_path='./data/'
fig, ax = plt.subplots()
zhfont是导入自定义的字体文件,matplot不支持中文,导入后可以指定字体属性来显示中文。其他的是全局变量,在后边的函数中会用到。get_str保存从文本框得到的字符串,stock_code保存股票代码字符串,data_path保存数据文件夹的路径,fig和ax是subplots的返回值。
3、
def get_stock_name(stock_code):
if stock_code=='':
return
url='http://hq.sinajs.cn/list={}'.format(stock_code)
req = requests.request('GET',url)
str1=req.text.split('="',1)[1]
if len(str1)<5:
print('get stock details failed')
return
str1=str1.split(',')[0]
print ('get stock name:'+str1)
return str1
此函数获取股票的名称,requests会返回类似下图的信息,=“后第一个,前是股票名称,提取出来返回。如果没有对应的名称,引号内为空,所以通过判断第一次分割后第二个字符串的长度可以确定是否返回成功。
4、
def get_stock_data(stock_code,scale=240,datalen=30,mode='w',header=True):
dic={}
if stock_code=='':
return False
url='http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol={}&scale={}&datalen={}'.format(stock_code,scale,datalen)
print (url)
req = requests.request('GET',url)
if req.text == 'null':
print('get stock data failed')
return False
strlist=req.text.replace('[{','')
strlist=strlist.replace('}]','')
strlist=strlist.split('},{')
for strl in strlist:
str1=strl.split(',')
for s in str1:
t=s.split(':',1)
if t[0] in dic:
dic[t[0]].append(t[1].replace('"',''))
else:
dic[t[0]]=[t[1].replace('"','')]
df = pd.DataFrame(dic)
#print (df)
df.to_csv(data_path+'{}.csv'.format(stock_code),mode=mode,index=False,header=header)
print ('write data to file')
return True
此函数获取指定股票、指定条数、指定间隔的信息,返回如下信息,这些信息都是字符串,需要做进一步处理,先去掉首尾的[{和}],再按照},{分割,子串再按照,分割,最后按照:分割将结果存在字典中。
通过pd.DataFrame()函数将字典转换为2维数组,调用to_csv()写入到csv格式的文件中。
5、
def write_buy_sell_to_file(string):
if string =='':
return
dic={'day':'','buy':'','sell':''}
str1=re.split(',| ',string)
for stri in str1:
if stri=='':
continue
if stri[0]=='d':
dic['day']=stri.replace('d','')
elif stri[0]=='b':
dic['buy']=stri.replace('b','')
elif stri[0]=='s':
dic['sell']=stri.replace('s','')
else:
print ('input error')
return
if dic['day']=='':
dic['day']=datetime.datetime.now().strftime('%Y-%m-%d')
print (dic)
df = pd.DataFrame(dic,index=[0])
if os.path.exists(data_path+'{}-bs.csv'.format(stock_code)):
df.to_csv(data_path+'{}-bs.csv'.format(stock_code),mode='a',index=False,header=False)
else:
df.to_csv(data_path+'{}-bs.csv'.format(stock_code),mode='w',index=False)
此函数用来记录买卖点到另一个csv文件中,三个item分别是日期day、买入价buy和卖出价sell。在输入时需要加标识符d、b、s表明是什么数据,同时用空格或者逗号分割,日期的格式是xxxx-xx-xx(年-月-日)。写入文件时判断文件是否已经存在,如果存在就追加,不存在就新建。
6、
def get_data_and_display(stock_code,startdate=(datetime.date.today()-datetime.timedelta(1)).strftime('%Y-%m-%d'),datalen=60):
global ax
if stock_code=='':
return
if not os.path.exists(data_path+'{}.csv'.format(stock_code)):
print ('not exists')
if not get_stock_data(stock_code,datalen=60):
return
# plot_day_summary(ax, quotes, ticksize=3)
print ('read scv {}'.format(stock_code))
ax.cla()
ax.set_title(get_stock_name(stock_code),fontproperties=zhfont)
ax.xaxis.set_major_locator(mondays)
ax.xaxis.set_minor_locator(alldays)
ax.xaxis.set_major_formatter(weekFormatter)
ax.xaxis_date()
ax.autoscale_view()
if os.path.exists(data_path+'{}-bs.csv'.format(stock_code)):
bs = pd.read_csv(data_path+'{}-bs.csv'.format(stock_code),index_col=0,parse_dates=True,infer_datetime_format=True)
ax.plot(mdates.date2num(bs.index.to_pydatetime()),bs['buy'],'mo')
ax.plot(mdates.date2num(bs.index.to_pydatetime()),bs['sell'],'c^')
if os.path.exists(data_path+'{}.csv'.format(stock_code)):
print ('get csv data')
quotes = pd.read_csv(data_path+'{}.csv'.format(stock_code),index_col=0,parse_dates=True,infer_datetime_format=True)
cutlen=len(quotes)
print('{} {}'.format(quotes.last_valid_index(),startdate))
quotes = quotes[quotes.index <= startdate]
cutlen-=len(quotes)
if (quotes.last_valid_index().strftime('%Y-%m-%d')<startdate or len(quotes)<datalen):
get_stock_data(stock_code,datalen=datalen+cutlen)
quotes = pd.read_csv(data_path+'{}.csv'.format(stock_code),index_col=0,parse_dates=True,infer_datetime_format=True)
quotes = quotes[quotes.index <= startdate]
#print (quotes.at_time('2019-06-20'))
quotes = quotes.tail(datalen)
print(quotes)
ax.plot(mdates.date2num(quotes.index.to_pydatetime()),quotes['ma_price5'],'k-')
ax.plot(mdates.date2num(quotes.index.to_pydatetime()),quotes['ma_price10'],'m-')
ax.plot(mdates.date2num(quotes.index.to_pydatetime()),quotes['ma_price30'],'b-')
candlestick_ohlc(ax, zip(mdates.date2num(quotes.index.to_pydatetime()),
quotes['open'], quotes['high'],
quotes['low'], quotes['close']),
width=0.6,colorup='r', colordown='g')
else:
raise
该函数获取数据并显示k线图。首选判断文件是否存在,不存在说明是第一次显示这个股票,需要获取数据。之后清除显示准备新的数据,先读取买卖信息,显示买卖点。再读取股票数据信息,需要判断读取到的信息是不是最新的,数据长度够不够。如果从一个旧的时间点读取很可能数据不够,需要从新拉取数据。得到最终需要的数据后显示5日线、10日线和30日线,最后显示k线。
7、
#button
def bdspl_handle(event):
global stock_code
lens=60
date1=(datetime.date.today()-datetime.timedelta(1)).strftime('%Y-%m-%d')
str1=re.split(',| ',get_str)
for stri in str1:
if stri[0:2]=='sh' or stri[0:2]=='sz':
stock_code=stri
get_data_and_display(stock_code)
elif stri[0:3]=='len':
lens=int(stri[3:])
elif stri[0:4]=='date':
date1=stri[4:]
else:
print ('input error')
return
get_data_and_display(stock_code,date1,lens)
显示按钮回调函数
8、
def b_s_handle(event):
print ('buy-sell')
write_buy_sell_to_file(get_str)
get_data_and_display(stock_code)
从文本框获取信息并写入到文件中然后显示。
9、
###text###
def submit(text):
global get_str
get_str=text
获取文本框信息
10、
if __name__=='__main__':
if not os.path.exists(data_path):
os.makedirs(data_path)
if not os.path.exists('setup.txt'):
os.mknod('setup.txt')
f=open('setup.txt','r')
stock_code=f.readline().strip('\n')
f.close()
axdspl = plt.axes([0.81, 0.05, 0.1, 0.075])
bdspl = Button(axdspl, 'stock')
bdspl.on_clicked(bdspl_handle)
axb_s = plt.axes([0.7, 0.05, 0.1, 0.075])
bb_s = Button(axb_s, 'buy-sell')
bb_s.on_clicked(b_s_handle)
axbox = plt.axes([0.1, 0.05, 0.2, 0.075])
text_box = TextBox(axbox, 'input', initial='')
text_box.on_submit(submit)
mondays = WeekdayLocator(MONDAY) # major ticks on the mondays
alldays = DayLocator() # minor ticks on the days
weekFormatter = DateFormatter('%b %d') # e.g., Jan 12
dayFormatter = DateFormatter('%d') # e.g., 12
# select desired range of dates
#quotes = quotes[(quotes.index >= date1) & (quotes.index <= date2)]
fig.subplots_adjust(bottom=0.2)
#fig.subplots_adjust(left=0.2)
#display the one last software close
get_data_and_display(stock_code)
plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')
plt.show()
print ('save setup')
f=open('setup.txt','w')
print (stock_code)
f.write(stock_code)
f.close()
main函数,先读取配置文件,此处只是保存了上次关闭软件前显示的股票代码。创建按钮和文本框,显示图表,显示是block的。关闭软件后将当前股票代码写入文件中。