最近在學習 Python 的使用者介面(GUI)設計 , 先從最基本的 tkinter 下手 , 接下來就是把之前學的 panda , matplotlib 及 K線圖呈現到 Python 的使用者介面中 .
我的目標是一邊學習 Python 程式設計 , 順便打造我的 [台指期即時自動當沖交易系統 第三代] , 首先設計一個視窗主程式單獨放在一隻 Python 程式中 , 其他的功能各自獨立放在個別的 Python 程式中 , 最後再將這些個別的功能集中透過這個視窗主程式來使用及呈現 .
視窗主程式程式碼如下 :
# 匯入使用者介面(GUI)套件
import tkinter as tk
from tkinter import *
# 匯入 AFDTS3 類別及函式
import AFDTS as a, Ticks2K5 as t
# ----------------------------------------------------------------------------
class MainPage(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
self.frames["AFDTS"] = a.AFDTS(parent=container, controller=self)
self.frames["AFDTS"].grid(row=0, column=0, sticky="nsew")
self.frames["TicksToK5"] = t.TicksToK5(parent=container,
controller=self)
self.frames["TicksToK5"].grid(row=0, column=0, sticky="nsew")
self.show_frame("AFDTS")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
# ----------------------------------------------------------------------------
if __name__ == '__main__':
# 創建根視窗
afdts3 = MainPage()
afdts3.iconbitmap('afdts.ico')
afdts3.geometry('1024x768')
afdts3.title('台指期自動當沖交易系統 (第三代)')
# 主選單
mmenu = Menu(afdts3, font=('標楷體'))
# 創建主選單內容
smenu = Menu(mmenu, tearoff=0)
smenu.add_command(label="台指期即時自動當沖交易系統",
command=lambda:afdts3.show_frame("AFDTS"))
smenu.add_separator()
smenu.add_command(label="關閉程式", command=afdts3.quit)
mmenu.add_cascade(label="交易", menu=smenu)
smenu = Menu(mmenu, tearoff=0)
smenu.add_command(label="用原始資料畫K線圖",
command=lambda:afdts3.show_frame("TicksToK5"))
mmenu.add_cascade(label="工具", menu=smenu)
afdts3['menu'] = mmenu
afdts3.mainloop()
# ----------------------------------------------------------------------------
執行結果如下 :
TicksToK5 類別的程式碼如下 :
# 匯入使用者介面(GUI)套件
import tkinter as tk
import tkinter.filedialog as fd
from tkinter import messagebox,colorchooser,font,Button,Frame,Label,Entry
# 匯入資料處理套件
import pandas as pd
import xlrd
# 匯入畫K線圖套件
import mpl_finance as mpf
from mpl_finance import candlestick_ochl
# 匯入畫圖套件
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
from matplotlib import dates as mdates
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk
from matplotlib.gridspec import GridSpec
# 讓 matplotlib 可以顯示中文
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']
plt.rcParams['axes.unicode_minus'] = False
# ----------------------------------------------------------------------------
# 用原始資料畫K線圖 的 類別及函式
class TicksToK5(Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.parent = parent
self.controller = controller
self.createWidgets()
def createWidgets(self):
self.source_file = tk.StringVar()
self.up_fm = Frame(self, height=68)
self.up_fm.pack(padx=10, pady=10, fill=tk.X)
self.lb_title = Label(self.up_fm, text="用原始資料畫K線圖",
font=('標楷體', 20))
self.lb_title.place(rely=0.2, relx=0.5, anchor='center')
self.btn_select_file = Button(self.up_fm,
text="選取原始資料檔",
font=('標楷體', 12),
command=lambda:self.chooseFile())
self.btn_select_file.place(rely=0.8, relx=0.3, anchor='e')
self.ent_file = Entry(self.up_fm, textvariable=self.source_file,
width=50, font=('標楷體', 12))
self.ent_file.place(rely=0.8, relx=0.5, anchor='center')
self.btn_draw_k_line = Button(self.up_fm,
text="畫K線圖",
font=('標楷體', 12),
command=lambda:self.DrawKLine())
self.btn_draw_k_line.place(rely=0.8, relx=0.7, anchor='w')
def chooseFile(self):
f_name = fd.askopenfilename()
self.source_file.set(f_name)
def DrawKLine(self):
# 從 Excel 讀入 ticks row data
fileName = self.source_file.get()
product = fileName[-17:-14]
title = fileName[-13:-5]
date_title = title[:4] + '/' + title[4:6] + '/' + title[6:]
if product == 'MXF' :
date_title = '小型台指期 - ' + date_title
else :
date_title = '台指期 - ' + date_title
book = xlrd.open_workbook(fileName)
sheet = book.sheet_by_index(0)
# 先開好一個空的 DataFrame
ticks = pd.DataFrame(columns=['date', 'open', 'close', 'high', 'low',
'volume', 'time'])
for row in range(sheet.nrows):
timesecond = sheet.cell_value(row,1)
price = sheet.cell_value(row,2) / 100
volume = sheet.cell_value(row,3)
newRow = [[timesecond, price, price, price, price,
volume, timesecond]]
ticks = ticks.append(pd.DataFrame(newRow, columns=['date', 'open',
'close', 'high',
'low', 'volume',
'time'
]), ignore_index=True)
ticks['date'] = pd.to_datetime(ticks['date'], unit='s')
ticks['time'] = pd.to_timedelta(ticks['time'], unit='s')
ticks.index = ticks['date']
k5 = pd.DataFrame(columns=['date', 'open', 'close', 'high', 'low',
'volume', 'time'])
k5 = ticks.resample('5T', closed='left', label='left').apply({
'open':'first', 'close':'last', 'high':'max',
'low':'min', 'volume':'sum', 'time':'first'})
k5.reset_index(inplace=True)
# ------------------------------------------------------------------
# 銷毀前一個 Frame
try:
self.down_fm.destroy()
self.down_fm.pack_forget()
except :
print('self.down_fm does not exist !')
# 開一個新的 Frame
self.down_fm = Frame(self, height=700)
self.down_fm.pack(padx=10, pady=10, fill=tk.X)
# ----------------------------------------------------------------------
k5['date'] = k5['date'].apply(mdates.date2num)
# 用 plt.Figure() , 不是 plt.figure()
fig = plt.Figure(figsize=(15,8))
# 用 GridSpec 設定 fig 為 3列 * 1行
gs = GridSpec(3, 1, figure=fig)
# ax 會佔用上兩列的空間
ax = fig.add_subplot(gs.new_subplotspec((0, 0), rowspan=2))
candlestick_ochl(ax, k5.values, width=0.001, colorup='#ff1717',
colordown='#53c156', alpha=1.0)
ax.set_title(date_title)
ax.set_ylabel('指數')
ax.set_xticks(k5['date'])
ax.set_xticklabels(k5['time'], rotation=30, ha='right',
fontsize='small')
ax.grid(True)
# ax2 會佔用最下面那列的空間
ax2 = fig.add_subplot(gs[-1, :])
mpf.volume_overlay(ax2, k5['open'], k5['close'],
k5['volume'], width=0.3,
colorup='#ff1717', colordown='#53c156', alpha=1.0)
ax2.set_ylabel('成交量')
ax2.set_xticks(range(0, len(k5['date'])))
ax2.set_xticklabels(k5['time'], rotation=30, ha='right',
fontsize='small')
ax2.set_xlabel('時間')
ax2.grid(True)
fig.subplots_adjust(bottom=0.2)
fig.subplots_adjust(hspace=0.4)
# 在 tkinter 的 Frame 中畫K線圖
canvas = FigureCanvasTkAgg(fig, self.down_fm)
canvas.get_tk_widget().pack()
canvas.draw()
# 顯示K線圖的 Tool Bar
toolbar = NavigationToolbar2Tk(canvas, self.down_fm)
toolbar.update()
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
執行結果如下 :
沒有留言:
張貼留言