python可视化小程序-实际利率与黄金价格走势图
目录
二、最终结果
三、代码
1.import
2.代码
2.1 Tkinter 经典写法
2.2 creatWidget()函数与控件事件绑定
2.3 generateImage()函数:pands+matplotlib
四、完整代码
一、黄金价格与美元实际利率
在《黄金价格与实际利率的关系》的文章中,作者指出,“实际利率是唯一与黄金价格相关的指标”,但并不是直线相关。只有实际利率转为负的时候,黄金价格才会大幅上涨。
而实际利率、名义利率与通货膨胀率有该关系:实际利率=名义利率-通货膨胀率
通货膨胀率使用美国十年年平准通胀率10-Year Breakeven Inflation Rate (T10YIE):10-Year Breakeven Inflation Rate | FRED | St. Louis Fed
名义利率使用美国十年期国债收益率 Market Yield on U.S. Treasury Securities at 10-Year Constant Maturity (DGS10):https://fred.stlouisfed.org/series/DGS10
黄金价格使用MT4软件的XAUUSD日线数据
所需文件已上传至博客资源中(正在审核):https://download.csdn.net/download/zsllsz2022/35932952
二、最终结果
选择DGS10、T10YIE、Xau文件后,并设置保存位置,然后点击生成图片,会在左侧显示示意图,并在指定文件夹内生成PNG格式的图片。
三、代码
1.import
from tkinter import *from tkinter import messageboxfrom tkinter.filedialog import *import numpy as npimport matplotlib.pyplot as pltimport pandas as pdimport matplotlib.ticker as tickerimport mpl_toolkits.axisartist as AAfrom mpl_toolkits.axisartist.axislines import SubplotZeroimport pylabpylab.mpl.rcParams['font.sans-serif'] = ['SimHei'] #显示中文plt.rcParams['axes.unicode_minus']=False #用于解决不能显示负号的问题
2.代码
2.1 Tkinter 经典写法
from tkinter import *from tkinter import messageboxfrom tkinter.filedialog import *import numpy as npimport matplotlib.pyplot as pltimport pandas as pdimport matplotlib.ticker as tickerimport mpl_toolkits.axisartist as AAfrom mpl_toolkits.axisartist.axislines import SubplotZeroimport pylabpylab.mpl.rcParams['font.sans-serif'] = ['SimHei'] #显示中文plt.rcParams['axes.unicode_minus']=False #用于解决不能显示负号的问题class Application(Frame): def __init__(self,master=None): super().__init__(master) self.master = master self.pack() #使用pack布局管理器 self.config(width=1100, height=500) #加入控件后修改此参数即可知道含义 self.creatWidget() #用于控制按钮使用顺序,若某个Flag为0,表示该Button操作未完成 self.selectFileDGS10Flag = 0 self.selectFileT10YIEFlag = 0 self.selectFileXauFlag = 0 self.SavePathFlag = 0 def creatWidget(self): pass if __name__ == '__main__': root = Tk() root.title("实际利率与黄金价格走势图") #窗口名称 root.geometry("1100x500+200+50") #主窗口位置与大小/此处含义为宽度1100,高度500,+200表示距左边屏幕距离,+50表示距离上边屏幕距离 root.resizable(0,0) #不可伸缩大小,个人习惯使用固定窗口大小,然后使用pack布局设置好绝对位置 app = Application(master=root) root.mainloop() #进入事件循环
2.2 creatWidget()函数与控件事件绑定
def creatWidget(self): #text,command,bg参数与place方法里的x,y参数,见效果图即可 #或者手动修改后查看异同 #控件-图片示意图 self.imageShow = Text(self,width=130,height=35) self.imageShow.place(x=15,y=25) #控件-上传文件按钮 btnSelectFileDGS10 = Button(self,text="选择DGS10文件",command=self.selectFileDGS10,bg="blue") btnSelectFileDGS10.place(x=950,y=30) btnSelectFileT10YIE = Button(self, text="选择T10YIE文件", command=self.selectFileT10YIE, bg="blue") btnSelectFileT10YIE.place(x=950, y=80) btnSelectFileXau = Button(self, text="选择Xau文件", command=self.selectFileXau, bg="blue") btnSelectFileXau.place(x=959, y=130) #控件-设置存储位置按钮 btnSavePath = Button(self, text="设置保存位置", command=self.SavePath, bg="green") btnSavePath.place(x=959, y=180) #控件-生成图片按钮 btn = Button(self,text="生成图片", command=self.generateImage, bg="green") btn.place(x=969, y=230) def generateImage(self): #若未完成上传文件,则弹出Error窗口 #此处只有当三个Flag均为1时,才可以继续往下执行 if(self.selectFileDGS10Flag == 0 or self.selectFileT10YIEFlag == 0 or self.selectFileXauFlag == 0): messagebox.showinfo("Error","请先上传文件") return #若未设置图片存储路径,则弹出Error窗口 if(self.SavePathFlag == 0): messagebox.showinfo("Error","请先设置保存路径") return #其余功能见下文 pass #使用askopenfilename获取文件绝对路径 #使用askdirectory获取文件夹绝对路径 #当成功完成读取操作后将Flag设置为1 def selectFileDGS10(self): self.pathDGS10 = askopenfilename(title="上传文件") if len(self.pathDGS10) != 0: self.selectFileDGS10Flag = 1 def selectFileT10YIE(self): self.pathT10YIE = askopenfilename(title="上传文件") if len(self.pathT10YIE) != 0: self.selectFileT10YIEFlag = 1 def selectFileXau(self): self.pathXau = askopenfilename(title="上传文件") if len(self.pathXau) != 0: self.selectFileXauFlag = 1 def SavePath(self): self.SavePath = askdirectory(title="设置存储位置") if len(self.SavePath) != 0: self.SavePathFlag = 1
2.3 generateImage()函数:pands+matplotlib
def generateImage(self): #若未完成上传文件,则弹出Error窗口 #此处只有当三个Flag均为1时,才可以继续往下执行 if(self.selectFileDGS10Flag == 0 or self.selectFileT10YIEFlag == 0 or self.selectFileXauFlag == 0): messagebox.showinfo("Error","请先上传文件") return #若未设置图片存储路径,则弹出Error窗口 if(self.SavePathFlag == 0): messagebox.showinfo("Error","请先设置保存路径") return #pd.read_csv读取文件,文件路径即为askdirectory函数读取结果 #数据从2019年7月19日开始切片,前提使用parse_dates=True将时间解析为时间对象 #na_values将特定字符串识别成Nan #index_col设置df索引 self.dfDGS10 = pd.read_csv(self.pathDGS10, index_col="DATE", parse_dates=True, na_values=["."])["2019-7-19":] self.dfT10YIE = pd.read_csv(self.pathT10YIE, index_col="DATE", parse_dates=True, na_values=["."])["2019-7-19":] self.srAu = pd.read_csv(self.pathXau, header=None, names=["DATE", "open", "high", "low", "close", "v"], parse_dates=True)["close"]["2019-7-19":] #重新构造一个DataFrame #realRate为真实利率,即名义利率-通货膨胀率 self.realRate = pd.DataFrame({"realRate": (self.dfDGS10["DGS10"] - self.dfT10YIE["T10YIE"]), "DGS10": self.dfDGS10["DGS10"], "T10YIE": self.dfT10YIE["T10YIE"], "au": self.srAu}) #dropna-how:筛选方式-‘any’,表示该行/列只要有一个以上的空值,就删除该行/列;‘all’,表示该行/列全部都为空值,就删除该行/列。 realRate = self.realRate.dropna(how="any") fig, ax = plt.subplots(figsize=(100, 50)) plt.title("实际利率与黄金价格走势图", fontsize=140) #设置右边的坐标轴 ax2 = ax.twinx() ax2.tick_params(labelsize=100) #设置刻度大小 ax2.yaxis.set_major_locator(ticker.MultipleLocator(50))#设置黄金价格刻度间隔 ax2.set_ylabel("黄金价格/$",size=120)#设置label名称与大小 #设置坐标轴 ax.tick_params(labelsize=100) ax.xaxis.set_major_locator(ticker.MultipleLocator(100)) ax.set_ylabel("利率/%",size=120) #画图-各参数具体含义参照效果图即可 ax.plot(realRate.index, realRate["DGS10"], "-.g", label="美国十年期国债收益率/%", linewidth=10) ax.plot(realRate.index, realRate["T10YIE"], "-.b", label="10-Year Breakeven Inflation Rate/%", linewidth=10) ax.plot(realRate.index, realRate["realRate"], "-.r", label="实际利率/%", linewidth=20) #使用ax的label代替ax2的label,或可将ax2的legend加入到ax的legend中 ax.plot([], [], "-.y", label="黄金价格/$", linewidth=20) ax2.plot(realRate.index, realRate["au"], "-.y", label="黄金价格", linewidth=20) #legeng大小与位置,upper left即为左上角 ax.legend(fontsize=100,loc="upper left") #栅格grid ax.grid(linestyle=":", color="b", linewidth=5) self.imagePathPng = self.SavePath + "/result.png" plt.savefig(self.imagePathPng,dpi=10,bbox_inches='tight') #将保存到指定路径的图片重新读取并插入到Text控件中 self.photo = PhotoImage(file=self.imagePathPng) self.imageShow.image_create(1.0,image=self.photo)
四、完整代码
from tkinter import *from tkinter import messageboxfrom tkinter.filedialog import *import numpy as npimport matplotlib.pyplot as pltimport pandas as pdimport matplotlib.ticker as tickerimport mpl_toolkits.axisartist as AAfrom mpl_toolkits.axisartist.axislines import SubplotZeroimport pylabpylab.mpl.rcParams['font.sans-serif'] = ['SimHei'] #显示中文plt.rcParams['axes.unicode_minus']=False #用于解决不能显示负号的问题class Application(Frame): def __init__(self,master=None): super().__init__(master) self.master = master self.pack() #使用pack布局管理器 self.config(width=1100, height=500) #加入控件后修改此参数即可知道含义 self.creatWidget() #用于控制按钮使用顺序,若某个Flag为0,表示该Button操作未完成 self.selectFileDGS10Flag = 0 self.selectFileT10YIEFlag = 0 self.selectFileXauFlag = 0 self.SavePathFlag = 0 def creatWidget(self): #text,command,bg参数与place方法里的x,y参数,见效果图即可 #或者手动修改后查看异同 #控件-图片示意图 self.imageShow = Text(self,width=130,height=35) self.imageShow.place(x=15,y=25) #控件-上传文件按钮 btnSelectFileDGS10 = Button(self,text="选择DGS10文件",command=self.selectFileDGS10,bg="blue") btnSelectFileDGS10.place(x=950,y=30) btnSelectFileT10YIE = Button(self, text="选择T10YIE文件", command=self.selectFileT10YIE, bg="blue") btnSelectFileT10YIE.place(x=950, y=80) btnSelectFileXau = Button(self, text="选择Xau文件", command=self.selectFileXau, bg="blue") btnSelectFileXau.place(x=959, y=130) #控件-设置存储位置按钮 btnSavePath = Button(self, text="设置保存位置", command=self.SavePath, bg="green") btnSavePath.place(x=959, y=180) #控件-生成图片按钮 btn = Button(self,text="生成图片", command=self.generateImage, bg="green") btn.place(x=969, y=230) def generateImage(self): #若未完成上传文件,则弹出Error窗口 #此处只有当三个Flag均为1时,才可以继续往下执行 if(self.selectFileDGS10Flag == 0 or self.selectFileT10YIEFlag == 0 or self.selectFileXauFlag == 0): messagebox.showinfo("Error","请先上传文件") return #若未设置图片存储路径,则弹出Error窗口 if(self.SavePathFlag == 0): messagebox.showinfo("Error","请先设置保存路径") return #pd.read_csv读取文件,文件路径即为askdirectory函数读取结果 #数据从2019年7月19日开始切片,前提使用parse_dates=True将时间解析为时间对象 #na_values将特定字符串识别成Nan #index_col设置df索引 self.dfDGS10 = pd.read_csv(self.pathDGS10, index_col="DATE", parse_dates=True, na_values=["."])["2019-7-19":] self.dfT10YIE = pd.read_csv(self.pathT10YIE, index_col="DATE", parse_dates=True, na_values=["."])["2019-7-19":] self.srAu = pd.read_csv(self.pathXau, header=None, names=["DATE", "open", "high", "low", "close", "v"], parse_dates=True)["close"]["2019-7-19":] #重新构造一个DataFrame #realRate为真实利率,即名义利率-通货膨胀率 self.realRate = pd.DataFrame({"realRate": (self.dfDGS10["DGS10"] - self.dfT10YIE["T10YIE"]), "DGS10": self.dfDGS10["DGS10"], "T10YIE": self.dfT10YIE["T10YIE"], "au": self.srAu}) #dropna-how:筛选方式-‘any’,表示该行/列只要有一个以上的空值,就删除该行/列;‘all’,表示该行/列全部都为空值,就删除该行/列。 realRate = self.realRate.dropna(how="any") fig, ax = plt.subplots(figsize=(100, 50)) plt.title("实际利率与黄金价格走势图", fontsize=140) #设置右边的坐标轴 ax2 = ax.twinx() ax2.tick_params(labelsize=100) #设置刻度大小 ax2.yaxis.set_major_locator(ticker.MultipleLocator(50))#设置黄金价格刻度间隔 ax2.set_ylabel("黄金价格/$",size=120)#设置label名称与大小 #设置坐标轴 ax.tick_params(labelsize=100) ax.xaxis.set_major_locator(ticker.MultipleLocator(100)) ax.set_ylabel("利率/%",size=120) #画图-各参数具体含义参照效果图即可 ax.plot(realRate.index, realRate["DGS10"], "-.g", label="美国十年期国债收益率/%", linewidth=10) ax.plot(realRate.index, realRate["T10YIE"], "-.b", label="10-Year Breakeven Inflation Rate/%", linewidth=10) ax.plot(realRate.index, realRate["realRate"], "-.r", label="实际利率/%", linewidth=20) #使用ax的label代替ax2的label,或可将ax2的legend加入到ax的legend中 ax.plot([], [], "-.y", label="黄金价格/$", linewidth=20) ax2.plot(realRate.index, realRate["au"], "-.y", label="黄金价格", linewidth=20) #legeng大小与位置,upper left即为左上角 ax.legend(fontsize=100,loc="upper left") #栅格grid ax.grid(linestyle=":", color="b", linewidth=5) self.imagePathPng = self.SavePath + "/result.png" plt.savefig(self.imagePathPng,dpi=10,bbox_inches='tight') #将保存到指定路径的图片重新读取并插入到Text控件中 self.photo = PhotoImage(file=self.imagePathPng) self.imageShow.image_create(1.0,image=self.photo) #使用askopenfilename获取文件绝对路径 #使用askdirectory获取文件夹绝对路径 #当成功完成读取操作后将Flag设置为1 def selectFileDGS10(self): self.pathDGS10 = askopenfilename(title="上传文件") if len(self.pathDGS10) != 0: self.selectFileDGS10Flag = 1 def selectFileT10YIE(self): self.pathT10YIE = askopenfilename(title="上传文件") if len(self.pathT10YIE) != 0: self.selectFileT10YIEFlag = 1 def selectFileXau(self): self.pathXau = askopenfilename(title="上传文件") if len(self.pathXau) != 0: self.selectFileXauFlag = 1 def SavePath(self): self.SavePath = askdirectory(title="设置存储位置") if len(self.SavePath) != 0: self.SavePathFlag = 1 if __name__ == '__main__': root = Tk() root.title("实际利率与黄金价格走势图") #窗口名称 root.geometry("1100x500+200+50") #主窗口位置与大小/此处含义为宽度1100,高度500,+200表示距左边屏幕距离,+50表示距离上边屏幕距离 root.resizable(0,0) #不可伸缩大小,个人习惯使用固定窗口大小,然后使用pack布局设置好绝对位置 app = Application(master=root) root.mainloop() #进入事件循环