GUI与面向对象3

该系列为南京大学课程《用Python玩转数据》学习笔记,主要以思维导图的记录

7.8 综合应用

综合应用

财经数据GUI项目

my_finance.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# -*- coding: utf-8 -*-
# author:zhengk
import json
import re
import requests


def retrieve_dji_list():
try:
url = 'http://money.cnn.com/data/dow30/'
res = requests.get(url)
except ConnectionError as e:
print(e)
pattern = re.compile(
'class="wsod_symbol">(.*?)<\/a>.*?<span.*?>(.*?)<\/span>.*?\n.*?class="wsod_stream">(.*?)<\/span>')
dji_list_raw = re.findall(pattern, res.text)
dji_list = []
for item in dji_list_raw:
dji_list.append({
'code': item[0],
'name': item[1],
'price': float(item[2])
})
return dji_list


def retrieve_quotes_historical(stock_code, start = '', end = ''):
quotes = []
url = 'https://finance.yahoo.com/quote/%s/history?p=%s' % (stock_code, stock_code)
try:
r = requests.get(url)
except ConnectionError as err:
print(err)
m = re.findall('"HistoricalPriceStore":{"prices":(.*?),"isPending"', r.text)
if m:
quotes = json.loads(m[0])
quotes = quotes[::-1]
return [item for item in quotes if not 'type' in item]

dji_wxPython.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# -*- coding: utf-8 -*-
# author:zhengk

import datetime as dt
import my_finance as finance
import matplotlib.pyplot as plt
import pandas as pd
import _thread as thread
import wx

ID_EVENT_REFRESH = 9999


class StockFrame(wx.Frame):

option_list = {
'open': True,
'close': True,
'high': False,
'low': False,
'volume': False
}

def __init__(self, title):
wx.Frame.__init__(self, None, title=title, size=(430,600))

self.CreateStatusBar()
# 菜单栏
menuBar = wx.MenuBar()
filemenu = wx.Menu()
menuBar.Append(filemenu, '文件')
# 刷新按钮
menuRefresh = filemenu.Append(ID_EVENT_REFRESH, '刷新', '刷新价格')
self.Bind(wx.EVT_MENU, self.on_refresh, menuRefresh)
# 退出按钮
menuQuit = filemenu.Append(wx.ID_EXIT, '退出', '退出程序')
self.Bind(wx.EVT_MENU, self.on_quit, menuQuit)

self.SetMenuBar(menuBar)

panel = wx.Panel(self)

# 选项栏
codeSizer = wx.BoxSizer(wx.HORIZONTAL)
# 标签
labelText = wx.StaticText(panel, label='股票代码')
codeSizer.Add(labelText, 0, wx.ALIGN_BOTTOM)
# 输入框
codeText = wx.TextCtrl(panel, value='BA', style=wx.TE_PROCESS_ENTER)
self.Bind(wx.EVT_TEXT_ENTER, self.on_text_submit, codeText)
codeSizer.Add(codeText)

# 多选栏
optionSizer = wx.BoxSizer(wx.HORIZONTAL)
for key, value in self.option_list.items():
checkBox = wx.CheckBox(panel, label=key)
checkBox.SetValue(value)
self.Bind(wx.EVT_CHECKBOX, self.on_checked)
optionSizer.Add(checkBox)

# 列表栏
self.list = wx.ListCtrl(panel, wx.NewId(), style=wx.LC_REPORT)
# 插入列表标题
self.create_handler()

pos = self.list.InsertItem(0, '--')
self.list.SetItem(pos, 1, 'loading...')
self.list.SetItem(pos, 2, '--')
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_double_click, self.list)

# 底部按钮栏
ctrlSizer = wx.BoxSizer(wx.HORIZONTAL)
# 空隙
ctrlSizer.Add((10, 10))
# 退出按钮
buttonQuit = wx.Button(panel, -1, '退出')
self.Bind(wx.EVT_BUTTON, self.on_quit, buttonQuit)
ctrlSizer.Add(buttonQuit, 1)
# 刷新按钮
buttonRefresh = wx.Button(panel, -1, '刷新')
self.Bind(wx.EVT_BUTTON, self.on_refresh, buttonRefresh)
ctrlSizer.Add(buttonRefresh, 1, wx.LEFT|wx.BOTTOM)

# 全局sizer
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(codeSizer, 0, wx.ALL, 5)
sizer.Add(optionSizer, 0, wx.ALL, 5)
sizer.Add(self.list, -1, wx.ALL | wx.EXPAND, 5)
sizer.Add(ctrlSizer, 0, wx.ALIGN_BOTTOM)

panel.SetSizerAndFit(sizer)
self.Center()

self.on_refresh(None)

def create_handler(self):
self.list.InsertColumn(0, '代码')
self.list.InsertColumn(1, '名称')
self.list.InsertColumn(2, '成交量')

def set_data(self, data):
self.list.ClearAll()
self.create_handler()
pos = 0
for row in data:
pos = self.list.InsertItem(pos+1, row['code'])
self.list.SetItem(pos, 1, row['name'])
self.list.SetColumnWidth(1, -1)
self.list.SetItem(pos, 2, str(row['price']))
if pos % 2 == 0:
self.list.SetItemBackgroundColour(pos, (134, 255, 249))

def plot_data(self, code):
quotes = finance.retrieve_quotes_historical(code)
fields = ['date', 'open', 'close', 'high', 'low', 'volume']
dates = []
for i in range(0, len(quotes)):
x = dt.datetime.utcfromtimestamp(int(quotes[i]['date']))
y = dt.datetime.strftime(x, '%Y-%m-%d')
dates.append(y)
quotesdf = pd.DataFrame(quotes, index=dates, columns=fields)

fields_to_drop = ['date']
for key, value in self.option_list.items():
if not value:
fields_to_drop.append(key)
quotesdf = quotesdf.drop(fields_to_drop, axis=1)
quotesdf.plot()
plt.show()

def on_double_click(self, event):
self.plot_data(event.GetText())

def on_text_submit(self, event):
self.plot_data(event.GetString())

def on_checked(self, event):
checkBox = event.GetEventObject()
text = checkBox.GetLabel().lower()
self.option_list[text] = checkBox.GetValue()

def on_quit(self, event):
self.Close()
self.Destroy()

def on_refresh(self, event):
thread.start_new_thread(self.retrieve_quotes, ())

def retrieve_quotes(self):
data = finance.retrieve_dji_list()
if data:
self.set_data(data)
else:
wx.MessageBox('下载失败!', '报错信息', wx.OK|wx.ICON_INFORMATION)


if __name__ == '__main__':
app = wx.App(False)
top = StockFrame('Dow Jones Industrial Average (^DJI)')
top.Show(True)
app.MainLoop()