python 股票量化盘后分析系统V0.42

前言:先放效果图吧
在这里插入图片描述
在这里插入图片描述
开发的过程中因为知识水平有限,且对backtrader的各种不熟悉,相关的属性跟对象操作资料较少,实在写的很吃力,看官方那个API,水平有限,实在看得头晕。
效果图的图形输出用的是mplfinance的,目前不知道怎么固定backtrader的回测图形在tkinter,所以采用了mplfinance使用backtrader的回测数据来标记买卖点。代码如下:
main.py

import tk_window
import graphic
import function
import stock_backtrader

tk_window.py

import tkinter as tk
import graphic
import function
import stock_backtrader

root = tk.Tk()  # 创建主窗口
s = graphic.Show()  # Show实例化
screenWidth = root.winfo_screenwidth()  # 获取屏幕宽的分辨率
screenHeight = root.winfo_screenheight()
x, y = int(screenWidth / 4), int(screenHeight / 4)  # 初始运行窗口屏幕坐标(x, y),设置成在左上角显示
width = int(screenWidth / 2)  # 初始化窗口是显示器分辨率的二分之一
height = int(screenHeight / 2)
root.geometry('{}x{}+{}+{}'.format(width, height, x, y))  # 窗口的大小跟初始运行位置
root.title('Wilbur量化分析软件')
# root.resizable(0, 0)  # 固定窗口宽跟高,不能调整大小,无法最大窗口化
root.iconbitmap('ZHY.ico')  # 窗口左上角图标设置,需要自己放张图标为icon格式的图片文件在项目文件目录下

# 构建上方菜单栏目框架
top_frame = tk.Frame(root, width=screenWidth, height=screenHeight, relief=tk.SUNKEN, bg='#353535', bd=5, borderwidth=4)
top_frame.pack(fill=tk.BOTH, side=tk.TOP, expand=0)

# 构建底部状态栏目框架
bottom_frame = tk.Frame(root, width=screenWidth, height=screenHeight, relief=tk.SUNKEN, bg='#353535', bd=5, borderwidth=4)
bottom_frame.pack(fill=tk.BOTH, side=tk.BOTTOM, expand=0)

# 构建左边功能栏目框架
left_frame = tk.Frame(root, width=screenWidth, height=screenHeight, relief=tk.SUNKEN, bg='#353535', bd=5, borderwidth=4)
left_frame.pack(fill=tk.BOTH, side=tk.LEFT, expand=0)

# 构建右边信息栏目框架
# right_frame = tk.Frame(root, width=screenWidth, height=screenHeight,
# relief=tk.SUNKEN, bg='#353535', bd=5, borderwidth=4)
# right_frame.pack(fill=tk.BOTH, side=tk.RIGHT, expand=0)

# 构建中间显示栏目框架
centre_frame = tk.Frame(root, width=screenWidth, height=screenHeight, relief=tk.SUNKEN, bg='#353535', bd=5, borderwidth=4)
centre_frame.pack(fill=tk.BOTH, expand=1)

# 构建各个框架的标签或按钮
top_label = tk.Label(top_frame, text='菜单栏目', bd=1)
top_label.pack()

bottom_label = tk.Label(bottom_frame, text='状态栏目', bd=1)
bottom_label.pack(side=tk.LEFT)
# 在状态栏目添加系统时钟功能
function.time_clock()

left_button1 = tk.Button(left_frame, text='全景', bd=1, command=s.stockindex_function)
left_button1.pack()
left_button2 = tk.Button(left_frame, text='查询', bd=1, command=s.stock_query_function)
left_button2.pack()
left_button3 = tk.Button(left_frame, text='股票', bd=1, command=s.show_stocklist_function)
left_button3.pack()
left_button4 = tk.Button(left_frame, text='回测', bd=1, command=stock_backtrader.run_cerebro)
left_button4.pack()

centre_label = tk.Label(centre_frame, text='显示栏目', bd=1)
centre_label.pack()

root.mainloop()

graphic.py

from __future__ import (absolute_import, division, print_function, unicode_literals)
import pandas as pd
import tushare as ts
import mplfinance as mpf
import tkinter as tk
import tkinter.tix as tix
from tkinter import ttk
import tkinter.font as tf
from tkinter.constants import *
import matplotlib.pyplot as plt
import matplotlib.dates as mdates  # 处理日期
import matplotlib as mpl  # 用于设置曲线参数
from cycler import cycler  # 用于定制线条颜色
import datetime
import tk_window
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)  # 使用后端TkAgg

mpl.use('TkAgg')
pro = ts.pro_api('数据用的是tushare,没权限自己去注册个吧')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 解决mplfinance绘制输出中文乱码
s = mpf.make_mpf_style(base_mpf_style='yahoo', rc={'font.family': 'SimHei'})
# pd.set_option()就是pycharm输出控制显示的设置
pd.set_option('expand_frame_repr', False)  # True就是可以换行显示。设置成False的时候不允许换行
pd.set_option('display.max_columns', None)  # 显示所有列
# pd.set_option('display.max_rows', None)  # 显示所有行
pd.set_option('colheader_justify', 'centre')  # 显示居中


class Show:
    def stockindex_function(self):  # 全景功能代码
        # 必须添加以下控件销毁代码,不然点击一次按钮框架长生一次,显示的画面会多一次,你可以将下面的代码删除测试看下
        for widget_graphic_main_frame in tk_window.centre_frame.winfo_children():
            widget_graphic_main_frame.destroy()
        # 在右边窗口的graphic_main_frame框架下再创建窗口
        # opaqueresize该选项的值为 False,窗格的尺寸在用户释放鼠标的时候才更新到新的位置
        stockindex_information_window = tk.PanedWindow(tk_window.centre_frame, opaqueresize=False)
        stockindex_information_window.pack(fill=BOTH, expand=1)

        # 在company_information_window窗口下设置指数信息显示功能
        stockindex_text = tk.Text(stockindex_information_window, bg='white', undo=True, wrap=tix.CHAR)
        stockindex_information_window.add(stockindex_text, width=200)

        # 首先获取今天时间
        now_time = datetime.datetime.now()
        # 转化成tushare的时间格式
        strf_time = now_time.strftime('%Y%m%d')
        # 获取上交所上一个交易日日期,PS:tushare指数的数据信息好像当天只能获取上一个交易日的数据
        pre_trade_date = pro.trade_cal(exchange='SSE', is_open='1', start_date=strf_time, fields='pretrade_date')
        pre_trade_d = pre_trade_date.at[0, 'pretrade_date']
        # print(pre_trade_d)
        shsz_index_dailybasic = pro.index_dailybasic(trade_date=pre_trade_d, fields='ts_code,trade_date, '
                                                                                    'total_mv,float_mv, total_share, '
                                                                                    'float_share, free_share, '
                                                                                    'turnover_rate, turnover_rate_f, '
                                                                                    'pe, pb')
        sh_index_daily = pro.index_daily(ts_code='000001.SH', trade_date=pre_trade_d)
        sz_index_daily = pro.index_daily(ts_code='399001.SZ', trade_date=pre_trade_d)
        cy_index_daily = pro.index_daily(ts_code='399006.SZ', trade_date=pre_trade_d)
        zx_index_daily = pro.index_daily(ts_code='399005.SZ', trade_date=pre_trade_d)
        # print(sh_index_daily)

        # 数据处理,将ts_code作为索引,方便准确调用数据,保留两位小数
        shsz_index_dailybasic.set_index('ts_code', inplace=True)
        # 数据获取
        sh_total_mv = round(shsz_index_dailybasic.at['000001.SH', 'total_mv'] / 100000000, 2)  # 元转换成亿单位
        sh_float_mv = round(shsz_index_dailybasic.at['000001.SH', 'float_mv'] / 100000000, 2)
        sh_total_share = round(shsz_index_dailybasic.at['000001.SH', 'total_share'] / 10000000000, 2)  # 股转化成亿手
        sh_float_share = round(shsz_index_dailybasic.at['000001.SH', 'float_share'] / 10000000000, 2)
        sh_free_share = round(shsz_index_dailybasic.at['000001.SH', 'free_share'] // 10000000000, 2)
        sh_turnover_rate = shsz_index_dailybasic.at['000001.SH', 'turnover_rate']
        sh_pe = shsz_index_dailybasic.at['000001.SH', 'pe']
        sh_pb = shsz_index_dailybasic.at['000001.SH', 'pb']
        sh_close = sh_index_daily.at[0, 'close']
        sh_pre_close = sh_index_daily.at[0, 'pre_close']
        sh_pct_chg = sh_index_daily.at[0, 'pct_chg']
        sh_vol = round(sh_index_daily.at[0, 'vol'] / 100000000, 2)  # 手转化成亿手
        sh_amount = round(sh_index_daily.at[0, 'amount'] / 100000, 2)  # 千元转换成亿元

        # 数据调用
        # 在文本框第一行添加股票代码,文字红色,居中显示
        stockindex_text.insert(tk.INSERT, '上证指数')
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '总市值(亿):')
        stockindex_text.insert(tk.INSERT, sh_total_mv)
        stockindex_text.tag_add('tag1', '1.0', '1.9')  # 设置选定的内容
        stockindex_text.tag_config('tag1', foreground='red', justify=CENTER)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '流通市值(亿):')
        stockindex_text.insert(tk.INSERT, sh_float_mv)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '总股本(亿手):')
        stockindex_text.insert(tk.INSERT, sh_total_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '流通股本(亿手):')
        stockindex_text.insert(tk.INSERT, sh_float_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '自由流通股本(亿手):')
        stockindex_text.insert(tk.INSERT, sh_free_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '换手率:')
        stockindex_text.insert(tk.INSERT, sh_turnover_rate)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '市盈率:')
        stockindex_text.insert(tk.INSERT, sh_pe)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '市净率:')
        stockindex_text.insert(tk.INSERT, sh_pb)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '收盘点位:')
        stockindex_text.insert(tk.INSERT, sh_close)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '昨日收盘点:')
        stockindex_text.insert(tk.INSERT, sh_pre_close)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '涨跌幅(%):')
        stockindex_text.insert(tk.INSERT, sh_pct_chg)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '成交量(亿手):')
        stockindex_text.insert(tk.INSERT, sh_vol)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '成交额(亿):')
        stockindex_text.insert(tk.INSERT, sh_amount)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.tag_add('content1', '2.0', 'end')  # 设置选定的内容
        stockindex_text.tag_config('content1', foreground='blue')

        sz_total_mv = round(shsz_index_dailybasic.at['399001.SZ', 'total_mv'] / 100000000, 2)  # 转换成亿单位
        sz_float_mv = round(shsz_index_dailybasic.at['399001.SZ', 'float_mv'] / 100000000, 2)
        sz_total_share = round(shsz_index_dailybasic.at['399001.SZ', 'total_share'] / 10000000000, 2)  # 转化成亿手
        sz_float_share = round(shsz_index_dailybasic.at['399001.SZ', 'float_share'] / 10000000000, 2)
        sz_free_share = round(shsz_index_dailybasic.at['399001.SZ', 'free_share'] // 10000000000, 2)
        sz_turnover_rate = shsz_index_dailybasic.at['399001.SZ', 'turnover_rate']
        sz_pe = shsz_index_dailybasic.at['399001.SZ', 'pe']
        sz_pb = shsz_index_dailybasic.at['399001.SZ', 'pb']
        sz_close = sz_index_daily.at[0, 'close']
        sz_pre_close = sz_index_daily.at[0, 'pre_close']
        sz_pct_chg = sz_index_daily.at[0, 'pct_chg']
        sz_vol = round(sz_index_daily.at[0, 'vol'] / 100000000, 2)  # 手转化成亿手
        sz_amount = round(sz_index_daily.at[0, 'amount'] / 100000, 2)  # 千元转换成亿元

        stockindex_text.insert(tk.INSERT, '深证指数')
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '总市值(亿):')
        stockindex_text.insert(tk.INSERT, sz_total_mv)
        stockindex_text.tag_add('tag2', '15.0', '15.9')  # 设置选定的内容,
        stockindex_text.tag_config('tag2', foreground='red', justify=CENTER)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '流通市值(亿):')
        stockindex_text.insert(tk.INSERT, sz_float_mv)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '总股本(亿手):')
        stockindex_text.insert(tk.INSERT, sz_total_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '流通股本(亿手):')
        stockindex_text.insert(tk.INSERT, sz_float_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '自由流通股本(亿手):')
        stockindex_text.insert(tk.INSERT, sz_free_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '换手率:')
        stockindex_text.insert(tk.INSERT, sz_turnover_rate)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '市盈率:')
        stockindex_text.insert(tk.INSERT, sz_pe)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '市净率:')
        stockindex_text.insert(tk.INSERT, sz_pb)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '收盘点位:')
        stockindex_text.insert(tk.INSERT, sz_close)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '昨日收盘点:')
        stockindex_text.insert(tk.INSERT, sz_pre_close)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '涨跌幅(%):')
        stockindex_text.insert(tk.INSERT, sz_pct_chg)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '成交量(亿手):')
        stockindex_text.insert(tk.INSERT, sz_vol)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '成交额(亿):')
        stockindex_text.insert(tk.INSERT, sz_amount)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.tag_add('content2', '16.0', 'end')  # 设置选定的内容
        stockindex_text.tag_config('content2', foreground='DarkViolet')

        cy_total_mv = round(shsz_index_dailybasic.at['399006.SZ', 'total_mv'] / 100000000, 2)  # 转换成亿单位
        cy_float_mv = round(shsz_index_dailybasic.at['399006.SZ', 'float_mv'] / 100000000, 2)
        cy_total_share = round(shsz_index_dailybasic.at['399006.SZ', 'total_share'] / 10000000000, 2)  # 转化成亿手
        cy_float_share = round(shsz_index_dailybasic.at['399006.SZ', 'float_share'] / 10000000000, 2)
        cy_free_share = round(shsz_index_dailybasic.at['399006.SZ', 'free_share'] // 10000000000, 2)
        cy_turnover_rate = shsz_index_dailybasic.at['399006.SZ', 'turnover_rate']
        cy_pe = shsz_index_dailybasic.at['399006.SZ', 'pe']
        cy_pb = shsz_index_dailybasic.at['399006.SZ', 'pb']
        cy_close = sh_index_daily.at[0, 'close']
        cy_pre_close = cy_index_daily.at[0, 'pre_close']
        cy_pct_chg = cy_index_daily.at[0, 'pct_chg']
        cy_vol = round(cy_index_daily.at[0, 'vol'] / 100000000, 2)  # 手转化成亿手
        cy_amount = round(cy_index_daily.at[0, 'amount'] / 100000, 2)  # 千元转换成亿元

        stockindex_text.insert(tk.INSERT, '创业板指数')
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '总市值(亿):')
        stockindex_text.insert(tk.INSERT, cy_total_mv)
        stockindex_text.tag_add('tag3', '29.0', '29.9')  # 设置选定的内容,
        stockindex_text.tag_config('tag3', foreground='red', justify=CENTER)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '流通市值(亿):')
        stockindex_text.insert(tk.INSERT, cy_float_mv)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '总股本(亿手):')
        stockindex_text.insert(tk.INSERT, cy_total_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '流通股本(亿手):')
        stockindex_text.insert(tk.INSERT, cy_float_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '自由流通股本(亿手):')
        stockindex_text.insert(tk.INSERT, cy_free_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '换手率:')
        stockindex_text.insert(tk.INSERT, cy_turnover_rate)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '市盈率:')
        stockindex_text.insert(tk.INSERT, cy_pe)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '市净率:')
        stockindex_text.insert(tk.INSERT, cy_pb)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '收盘点位:')
        stockindex_text.insert(tk.INSERT, cy_close)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '昨日收盘点:')
        stockindex_text.insert(tk.INSERT, cy_pre_close)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '涨跌幅(%):')
        stockindex_text.insert(tk.INSERT, cy_pct_chg)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '成交量(亿手):')
        stockindex_text.insert(tk.INSERT, cy_vol)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '成交额(亿):')
        stockindex_text.insert(tk.INSERT, cy_amount)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.tag_add('content3', '30.0', 'end')  # 设置选定的内容
        stockindex_text.tag_config('content3', foreground='DarkCyan')

        zx_total_mv = round(shsz_index_dailybasic.at['399005.SZ', 'total_mv'] / 100000000, 2)  # 转换成亿单位
        zx_float_mv = round(shsz_index_dailybasic.at['399005.SZ', 'float_mv'] / 100000000, 2)
        zx_total_share = round(shsz_index_dailybasic.at['399005.SZ', 'total_share'] / 10000000000, 2)  # 转化成亿手
        zx_float_share = round(shsz_index_dailybasic.at['399005.SZ', 'float_share'] / 10000000000, 2)
        zx_free_share = round(shsz_index_dailybasic.at['399005.SZ', 'free_share'] // 10000000000, 2)
        zx_turnover_rate = shsz_index_dailybasic.at['399005.SZ', 'turnover_rate']
        zx_pe = shsz_index_dailybasic.at['399005.SZ', 'pe']
        zx_pb = shsz_index_dailybasic.at['399005.SZ', 'pb']
        zx_close = zx_index_daily.at[0, 'close']
        zx_pre_close = zx_index_daily.at[0, 'pre_close']
        zx_pct_chg = zx_index_daily.at[0, 'pct_chg']
        zx_vol = round(zx_index_daily.at[0, 'vol'] / 100000000, 2)  # 手转化成亿手
        zx_amount = round(zx_index_daily.at[0, 'amount'] / 100000, 2)  # 千元转换成亿元

        stockindex_text.insert(tk.INSERT, '中小板指数')
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '总市值(亿):')
        stockindex_text.insert(tk.INSERT, zx_total_mv)
        stockindex_text.tag_add('tag4', '43.0', '43.9')  # 设置选定的内容,
        stockindex_text.tag_config('tag4', foreground='red', justify=CENTER)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '流通市值(亿):')
        stockindex_text.insert(tk.INSERT, zx_float_mv)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '总股本(亿手):')
        stockindex_text.insert(tk.INSERT, zx_total_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '流通股本(亿手):')
        stockindex_text.insert(tk.INSERT, zx_float_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '自由流通股本(亿手):')
        stockindex_text.insert(tk.INSERT, zx_free_share)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '换手率:')
        stockindex_text.insert(tk.INSERT, zx_turnover_rate)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '市盈率:')
        stockindex_text.insert(tk.INSERT, zx_pe)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '市净率:')
        stockindex_text.insert(tk.INSERT, zx_pb)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '收盘点位:')
        stockindex_text.insert(tk.INSERT, zx_close)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '昨日收盘点:')
        stockindex_text.insert(tk.INSERT, zx_pre_close)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '涨跌幅(%):')
        stockindex_text.insert(tk.INSERT, zx_pct_chg)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '成交量(亿手):')
        stockindex_text.insert(tk.INSERT, zx_vol)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '成交额(亿):')
        stockindex_text.insert(tk.INSERT, zx_amount)
        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.tag_add('content4', '44.0', 'end')  # 设置选定的内容
        stockindex_text.tag_config('content4', foreground='Sienna')

        stockindex_text.insert(tk.INSERT, '\n')
        stockindex_text.insert(tk.INSERT, '数据交易日期:')
        stockindex_text.insert(tk.INSERT, pre_trade_d)
        stockindex_text.tag_add('content5', '58.0', 'end')  # 设置选定的内容
        stockindex_text.tag_config('content5', foreground='Crimson')

        stockindex_window = tk.PanedWindow(orient='vertical', opaqueresize=False)
        stockindex_information_window.add(stockindex_window)
        # 创建显示上证指数的框架跟窗口
        stockindex_sh_frame = tk.Frame(stockindex_window, width=tk_window.screenWidth, height=tk_window.screenHeight,
                                       relief=tk.SUNKEN, bg='#353535', bd=5, borderwidth=4)
        stockindex_sh_frame.pack(fill=BOTH)
        stockindex_window.add(stockindex_sh_frame, height=tk_window.screenHeight / 2)
        # 创建显示深证指数的框架跟窗口
        stockindex_sz_frame = tk.Frame(stockindex_window, width=tk_window.screenWidth, height=tk_window.screenHeight,
                                       relief=tk.SUNKEN, bg='#353535', bd=5, borderwidth=4)
        stockindex_sz_frame.pack(fill=BOTH)
        stockindex_window.add(stockindex_sz_frame)

        for widget_stockindex_sh_frame in stockindex_sh_frame.winfo_children():
            widget_stockindex_sh_frame.destroy()
        for widget_stockindex_sz_frame in stockindex_sz_frame.winfo_children():
            widget_stockindex_sz_frame.destroy()
        for widget_stockindex_text in stockindex_text.winfo_children():
            widget_stockindex_text.destroy()
        # 上证指数
        index_data_sh = pro.index_daily(ts_code='000001.SH', start_date=20100101)
        # 日数据处理
        # :取所有行数据,后面取date列,open列等数据
        index_data_sh = index_data_sh.loc[:, ['trade_date', 'open', 'close', 'high', 'low', 'vol']]
        index_data_sh = index_data_sh.rename(columns={'trade_date': 'Date', 'open': 'Open', 'close': 'Close',
                                                      'high': 'High', 'low': 'Low', 'vol': 'Volume'})  # 更换列名,为后面函数变量做准备
        index_data_sh.set_index('Date', inplace=True)  # 设置date列为索引,覆盖原来索引,这个时候索引还是 object 类型,就是字符串类型。
        # 将object类型转化成 DateIndex 类型,pd.DatetimeIndex 是把某一列进行转换,同时把该列的数据设置为索引 index。
        index_data_sh.index = pd.DatetimeIndex(index_data_sh.index)
        index_data_sh = index_data_sh.sort_index(ascending=True)  # 将时间顺序升序,符合时间序列
        # print(index_data_sh)

        # 设置marketcolors,up:设置K线线柱颜色,up意为收盘价大于等于开盘价,down:与up相反,这样设置与国内K线颜色标准相符
        # edge:K线线柱边缘颜色(i代表继承自up和down的颜色),wick:灯芯(上下影线)颜色,volume:成交量直方图的颜色,inherit:是否继承,选填
        sh_mc = mpf.make_marketcolors(up='red', down='green', edge='i', wick='i', volume='in', inherit=True)
        # 设置图形风格,gridaxis:设置网格线位置,gridstyle:设置网格线线型,y_on_right:设置y轴位置是否在右
        sh_s = mpf.make_mpf_style(gridaxis='both', gridstyle='-.', y_on_right=False, marketcolors=sh_mc)
        # 设置线宽
        mpl.rcParams['lines.linewidth'] = .5
        # 设置均线颜色,这里可以设置6条均线的颜色
        mpl.rcParams['axes.prop_cycle'] = cycler(
            color=['dodgerblue', 'deeppink', 'navy', 'teal', 'maroon', 'darkorange'])

        index_sh_fig, axlist = mpf.plot(index_data_sh, type='candle', mav=(5, 10, 20), volume=True, tight_layout=False,
                                        show_nontrading=False, returnfig=True, style=sh_s)

        canvas_index_sh = FigureCanvasTkAgg(index_sh_fig, master=stockindex_sh_frame)  # 设置tkinter绘制区
        canvas_index_sh.draw()
        toolbar_index_sh = NavigationToolbar2Tk(canvas_index_sh, stockindex_sh_frame)
        toolbar_index_sh.update()  # 显示图形导航工具条
        canvas_index_sh._tkcanvas.pack(fill=BOTH, expand=1)

        # 深圳指数
        index_data_sz = pro.index_daily(ts_code='399001.SZ', start_date=20100101)
        # 日数据处理
        # :取所有行数据,后面取date列,open列等数据
        index_data_sz = index_data_sz.loc[:, ['trade_date', 'open', 'close', 'high', 'low', 'vol']]
        index_data_sz = index_data_sz.rename(columns={'trade_date': 'Date', 'open': 'Open', 'close': 'Close',
                                                      'high': 'High', 'low': 'Low', 'vol': 'Volume'})  # 更换列名,为后面函数变量做准备
        index_data_sz.set_index('Date', inplace=True)  # 设置date列为索引,覆盖原来索引,这个时候索引还是 object 类型,就是字符串类型。
        # 将object类型转化成 DateIndex 类型,pd.DatetimeIndex 是把某一列进行转换,同时把该列的数据设置为索引 index。
        index_data_sz.index = pd.DatetimeIndex(index_data_sh.index)
        index_data_sz = index_data_sz.sort_index(ascending=True)  # 将时间顺序升序,符合时间序列
        # print(index_data_sz)

        index_sz_fig, axlist = mpf.plot(index_data_sz, type='candle', mav=(5, 10, 20), volume=True, tight_layout=False,
                                        show_nontrading=False, returnfig=True)
        canvas_index_sz = FigureCanvasTkAgg(index_sz_fig, master=stockindex_sz_frame)  # 设置tkinter绘制区
        canvas_index_sz.draw()
        toolbar_index_sz = NavigationToolbar2Tk(canvas_index_sz, stockindex_sz_frame)
        toolbar_index_sz.update()  # 显示图形导航工具条
        canvas_index_sz._tkcanvas.pack(fill=BOTH, expand=1)

    def stock_query_function(self):  # 查询功能代码
        # 必须添加以下控件销毁代码,不然点击一次按钮框架长生一次,显示的画面会多一次,你可以将下面的代码删除测试看下
        for widget_graphic_main_frame in tk_window.centre_frame.winfo_children():
            widget_graphic_main_frame.destroy()
        # 在主框架下创建股票代码输入子框架
        code_frame = tk.Frame(tk_window.centre_frame, borderwidth=1, bg='#353535')
        code_frame.pack()
        # 创建标签‘股票代码’
        stock_label = tk.Label(code_frame, text='股票代码', bd=1)
        stock_label.pack(side=LEFT)
        # 创建股票代码输入框
        input_code_var = tk.StringVar()
        code_widget = tk.Entry(code_frame, textvariable=input_code_var, borderwidth=1, justify=CENTER)
        # input_code_get = input_code_var.set(input_code_var.get())  # 获取输入的新值
        code_widget.pack(side=LEFT, padx=4)

        # 在主框架下创建股票日期输入框子框架
        input_date_frame = tk.Frame(tk_window.centre_frame, borderwidth=1, bg='#353535')
        input_date_frame.pack()
        # 创建标签‘开始日期’
        date_start_label = tk.Label(input_date_frame, text='开始日期', bd=1)
        date_start_label.pack(side=LEFT)
        # 创建开始日期代码输入框
        input_startdate_var = tk.StringVar()
        startdate_widget = tk.Entry(input_date_frame, textvariable=input_startdate_var, borderwidth=1, justify=CENTER)
        input_startdate_get = input_startdate_var.set(input_startdate_var.get())  # 获取输入的新值
        startdate_widget.pack(side=LEFT, padx=4)
        # 创建标签‘结束日期’
        date_end_label = tk.Label(input_date_frame, text='结束日期', bd=1)
        date_end_label.pack(side=LEFT)
        # 创建结束日期代码输入框
        input_enddate_var = tk.StringVar()
        enddate_widget = tk.Entry(input_date_frame, textvariable=input_enddate_var, borderwidth=1, justify=CENTER)
        input_enddate_get = input_enddate_var.set(input_enddate_var.get())  # 获取输入的新值
        enddate_widget.pack(side=LEFT, padx=4)

        # 创建Notebook标签选项卡
        tabControl = ttk.Notebook(tk_window.centre_frame)
        # 增加新选项卡日K线图
        stock_graphics_daily = tk.Frame(tk_window.centre_frame, borderwidth=1, bg='#353535', relief=tk.RAISED)
        # stock_graphics_daily.pack(expand=1, fill=tk.BOTH, anchor=tk.CENTER)
        stock_graphics_daily_basic = tk.Frame(tk_window.centre_frame, borderwidth=1, bg='#353535',
                                              relief=tk.RAISED)  # 增加新选项卡基本面指标
        stock_graphics_week = tk.Frame(tk_window.centre_frame, borderwidth=1, bg='#353535', relief=tk.RAISED)
        stock_graphics_month = tk.Frame(tk_window.centre_frame, borderwidth=1, bg='#353535', relief=tk.RAISED)
        company_information = tk.Frame(tk_window.centre_frame, borderwidth=1, bg='#353535', relief=tk.RAISED)

        tabControl.add(stock_graphics_daily, text='日K线图')  # 把新选项卡日K线框架增加到Notebook
        tabControl.add(stock_graphics_daily_basic, text='基本面指标')
        tabControl.add(stock_graphics_week, text='周K线图')
        tabControl.add(stock_graphics_month, text='月K线图')
        tabControl.add(company_information, text='公司信息')
        tabControl.pack(expand=1, fill="both")  # 设置选项卡布局
        tabControl.select(stock_graphics_daily)  # 默认选定日K线图开始

        def go():  # 图形输出渲染
            # 以下函数作用是省略输入代码后缀.sz .sh
            def code_name_transform(get_stockcode):  # 输入的数字股票代码转换成字符串股票代码
                str_stockcode = str(get_stockcode)
                str_stockcode = str_stockcode.strip()  # 删除前后空格字符
                if 6 > len(str_stockcode) > 0:
                    str_stockcode = str_stockcode.zfill(6) + '.SZ'  # zfill()函数返回指定长度的字符串,原字符串右对齐,前面填充0
                if len(str_stockcode) == 6:
                    if str_stockcode[0:1] == '0':
                        str_stockcode = str_stockcode + '.SZ'
                    if str_stockcode[0:1] == '3':
                        str_stockcode = str_stockcode + '.SZ'
                    if str_stockcode[0:1] == '6':
                        str_stockcode = str_stockcode + '.SH'
                return str_stockcode

            # 清除stock_graphics_daily框架中的控件内容,winfo_children()返回的项是一个小部件列表,
            # 以下代码作用是为每次点击查询按钮时更新图表内容,如果没有以下代码句,则每次点击查询会再生成一个图表
            for widget_daily in stock_graphics_daily.winfo_children():
                widget_daily.destroy()
            for widget_daily_basic in stock_graphics_daily_basic.winfo_children():
                widget_daily_basic.destroy()
            for widget_week in stock_graphics_week.winfo_children():
                widget_week.destroy()
            for widget_month in stock_graphics_month.winfo_children():
                widget_month.destroy()
            for widget_company_information in company_information.winfo_children():
                widget_company_information.destroy()

            # 获取用户输入信息
            stock_name = input_code_var.get()
            code_name = code_name_transform(stock_name)
            start_date = input_startdate_var.get()
            end_date = input_enddate_var.get()

            # 获取股票数据
            stock_data = pro.daily(ts_code=code_name, start_date=start_date, end_date=end_date)
            stock_daily_basic = pro.daily_basic(ts_code=code_name, start_date=start_date, end_date=end_date,
                                                fields='close,trade_date,turnover_rate,volume_ratio,pe,pb')
            stock_week_data = pro.weekly(ts_code=code_name, start_date=start_date, end_date=end_date)
            stock_month_data = pro.monthly(ts_code=code_name, start_date=start_date, end_date=end_date)
            stock_name_change = pro.namechange(ts_code=code_name, fields='ts_code,name')
            stock_information = pro.stock_company(ts_code=code_name, fields='introduction,main_business,business_scope')

            # 日数据处理
            data = stock_data.loc[:, ['trade_date', 'open', 'close', 'high', 'low', 'vol']]  # :取所有行数据,后面取date列,open列等数据
            data = data.rename(
                columns={'trade_date': 'Date', 'open': 'Open', 'close': 'Close', 'high': 'High', 'low': 'Low',
                         'vol': 'Volume'})  # 更换列名,为后面函数变量做准备
            data.set_index('Date', inplace=True)  # 设置date列为索引,覆盖原来索引,这个时候索引还是 object 类型,就是字符串类型。
            # 将object类型转化成 DateIndex 类型,pd.DatetimeIndex 是把某一列进行转换,同时把该列的数据设置为索引 index。
            data.index = pd.DatetimeIndex(data.index)
            data = data.sort_index(ascending=True)  # 将时间顺序升序,符合时间序列

            # 基本面指标数据处理
            stock_daily_basic.set_index('trade_date', inplace=True)  # 设置date列为索引,覆盖原来索引,这个时候索引还是 object 类型,就是字符串类型。
            # 将object类型转化成 DateIndex 类型,pd.DatetimeIndex 是把某一列进行转换,同时把该列的数据设置为索引 index。
            stock_daily_basic.index = pd.DatetimeIndex(stock_daily_basic.index)
            stock_daily_basic = stock_daily_basic.sort_index(ascending=True)  # 将时间顺序升序,符合时间序列
            print(stock_daily_basic)

            # 周数据处理
            week_data = stock_week_data.loc[:, ['trade_date', 'open', 'close', 'high', 'low', 'vol']]
            week_data = week_data.rename(
                columns={'trade_date': 'Date', 'open': 'Open', 'close': 'Close', 'high': 'High',
                         'low': 'Low', 'vol': 'Volume'})  # 更换列名,为后面函数变量做准备
            week_data.set_index('Date', inplace=True)  # 设置date列为索引,覆盖原来索引,这个时候索引还是 object 类型,就是字符串类型。
            # 将object类型转化成 DateIndex 类型,pd.DatetimeIndex 是把某一列进行转换,同时把该列的数据设置为索引 index。
            week_data.index = pd.DatetimeIndex(week_data.index)
            week_data = week_data.sort_index(ascending=True)  # 将时间顺序升序,符合时间序列

            # 月数据处理
            month_data = stock_month_data.loc[:, ['trade_date', 'open', 'close', 'high', 'low', 'vol']]
            month_data = month_data.rename(
                columns={'trade_date': 'Date', 'open': 'Open', 'close': 'Close', 'high': 'High',
                         'low': 'Low', 'vol': 'Volume'})  # 更换列名,为后面函数变量做准备
            month_data.set_index('Date', inplace=True)  # 设置date列为索引,覆盖原来索引,这个时候索引还是 object 类型,就是字符串类型。
            # 将object类型转化成 DateIndex 类型,pd.DatetimeIndex 是把某一列进行转换,同时把该列的数据设置为索引 index。
            month_data.index = pd.DatetimeIndex(month_data.index)
            month_data = month_data.sort_index(ascending=True)  # 将时间顺序升序,符合时间序列

            # 公司信息处理
            stock_company_code = stock_name_change.at[0, 'ts_code']
            stock_company_name = stock_name_change.at[0, 'name']
            stock_introduction = stock_information.at[0, 'introduction']
            stock_main_business = stock_information.at[0, 'main_business']
            stock_business_scope = stock_information.at[0, 'business_scope']

            # K线图图形输出
            daily_fig, axlist = mpf.plot(data, type='candle', mav=(5, 10, 20), volume=True,
                                         show_nontrading=False, returnfig=True)
            # 基本面指标图形输出
            # 注意必须按照选项卡的排列顺序渲染图形输出,假如你把matplotlib的图形放到最后,则会出现图像错位现象,不信你可以把以下的代码放到month_fig后试下
            plt_stock_daily_basic = plt.figure(facecolor='white')
            plt.suptitle('Daily Basic Indicator', size=10)

            fig_close = plt.subplot2grid((3, 2), (0, 0), colspan=2)  # 创建网格子绘图,按行切分成3份,列切分成2分,位置(0,0),横向占用2列
            fig_close.set_title('Close Price')
            plt.xticks(stock_daily_basic.index, rotation=45)  # 设置x轴时间显示方向,放在这跟放在最后显示效果不一样
            fig_close.plot(stock_daily_basic.index, stock_daily_basic['close'])
            plt.xlabel('Trade Day')
            plt.ylabel('Close')
            plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))  # 设置X轴主刻度显示的格式
            plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=1))  # 设置X轴主刻度的间距

            fig_turnover_rate = plt.subplot2grid((3, 2), (1, 0))  # 创建网格子绘图,按行切分成3份,列切分成2分,位置(1,0)
            fig_turnover_rate.set_title('Turnover Rate')
            plt.xticks(stock_daily_basic.index, rotation=45)  # 设置x轴时间显示方向,放在这跟放在最后显示效果不一样
            fig_turnover_rate.bar(stock_daily_basic.index, stock_daily_basic['turnover_rate'], facecolor='red')
            plt.xlabel('Trade Day')
            plt.ylabel('Turnover Rate')
            plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))  # 设置X轴主刻度显示的格式
            plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=2))  # 设置X轴主刻度的间距

            fig_volume_ratio = plt.subplot2grid((3, 2), (2, 0))  # 创建网格子绘图,按行切分成3份,列切分成2分,位置(1,2)
            fig_volume_ratio.set_title('Volume Ratio')
            plt.xticks(stock_daily_basic.index, rotation=45)  # 设置x轴时间显示方向,放在这跟放在最后显示效果不一样
            fig_volume_ratio.bar(stock_daily_basic.index, stock_daily_basic['volume_ratio'])
            plt.xlabel('Trade Day')
            plt.ylabel('Volume Ratio')
            plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m'))  # 设置X轴主刻度显示的格式
            plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=2))  # 设置X轴主刻度的间距

            fig_pe = plt.subplot2grid((3, 2), (1, 1))  # 创建网格子绘图,按行切分成3份,列切分成2分,位置在第3行,第1列
            fig_pe.set_title('PE')
            plt.xticks(stock_daily_basic.index, rotation=45)  # 设置x轴时间显示方向,放在这跟放在最后显示效果不一样
            fig_pe.plot(stock_daily_basic.index, stock_daily_basic['pe'])
            plt.xlabel('Trade Day')
            plt.ylabel('PE')
            plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m'))  # 设置X轴主刻度显示的格式
            plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=2))  # 设置X轴主刻度的间距

            fig_pb = plt.subplot2grid((3, 2), (2, 1))  # 创建网格子绘图,按行切分成3份,列切分成2分,位置在第3行,第2列
            fig_pb.set_title('PB')
            plt.xticks(stock_daily_basic.index, rotation=45)  # 设置x轴时间显示方向,放在这跟放在最后显示效果不一样
            fig_pb.plot(stock_daily_basic.index, stock_daily_basic['pb'])
            plt.xlabel('Trade Day')
            plt.ylabel('PB')
            plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%m'))  # 设置X轴主刻度显示的格式
            plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=2))  # 设置X轴主刻度的间距
            plt_stock_daily_basic.tight_layout(h_pad=-2, w_pad=0)  # 解决子图图形重叠问题

            # 周K线图形输出
            week_fig, axlist = mpf.plot(week_data, type='candle', mav=(5, 10, 20), volume=True,
                                        show_nontrading=False, returnfig=True)
            # 月k线图形输出
            month_fig, axlist = mpf.plot(month_data, type='candle', mav=(5, 10, 20), volume=True,
                                         show_nontrading=False, returnfig=True)

            # 将获得的图形渲染到画布上
            # 日K线图形渲染到tkinter画布上
            canvas_daily = FigureCanvasTkAgg(daily_fig, master=stock_graphics_daily)  # 设置tkinter绘制区
            canvas_daily.draw()
            toolbar_daily = NavigationToolbar2Tk(canvas_daily, stock_graphics_daily)
            toolbar_daily.update()  # 显示图形导航工具条
            canvas_daily._tkcanvas.pack(side=BOTTOM, fill=BOTH, expand=1)
            # 基本面指标图形渲染到tkinter画布上
            canvas_stock_daily_basic = FigureCanvasTkAgg(plt_stock_daily_basic, master=stock_graphics_daily_basic)
            canvas_stock_daily_basic.draw()
            toolbar_stock_daily_basic = NavigationToolbar2Tk(canvas_stock_daily_basic, stock_graphics_daily_basic)
            toolbar_stock_daily_basic.update()  # 显示图形导航工具条
            canvas_stock_daily_basic._tkcanvas.pack(side=BOTTOM, fill=BOTH, expand=1)
            plt.close()
            # 周K线图形渲染到tkinter画布上
            canvas_week = FigureCanvasTkAgg(week_fig, master=stock_graphics_week)  # 设置tkinter绘制区
            canvas_week.draw()
            toolbar_week = NavigationToolbar2Tk(canvas_week, stock_graphics_week)
            toolbar_week.update()  # 显示图形导航工具条
            canvas_week._tkcanvas.pack(side=BOTTOM, fill=BOTH, expand=1)
            # 月K线图形渲染到tkinter画布上
            canvas_month = FigureCanvasTkAgg(month_fig, master=stock_graphics_month)  # 设置tkinter绘制区
            canvas_month.draw()
            toolbar_month = NavigationToolbar2Tk(canvas_month, stock_graphics_month)
            toolbar_month.update()  # 显示图形导航工具条
            canvas_month._tkcanvas.pack(side=BOTTOM, fill=BOTH, expand=1)

            # 在company_information框架下设置文字选项卡功能内容
            company_text = tk.Text(company_information, bg='white', undo=True, wrap=tix.CHAR)
            # 在文本框第一行添加股票代码,文字红色,居中显示
            company_text.insert(tk.INSERT, stock_company_code)
            company_text.tag_add('tag1', '1.0', '1.9')  # 设置选定的内容,
            company_text.tag_config('tag1', foreground='red', justify=CENTER)
            company_text.insert(tk.INSERT, '\n')

            company_text.insert(tk.INSERT, stock_company_name)
            company_text.tag_add('tag2', '2.0', '2.9')
            company_text.tag_config('tag2', foreground='red', justify=CENTER)
            company_text.insert(tk.INSERT, '\n')

            company_text.insert(tk.INSERT, '    ')
            company_text.insert(tk.INSERT, '公司简介:')
            company_text.tag_add('tag3', '3.3', '3.9')
            company_text.tag_config('tag3', foreground='red', font=tf.Font(family='SimHei', size=12))
            company_text.insert(tk.INSERT, stock_introduction)
            company_text.tag_add('tag4', '3.9', 'end')
            company_text.tag_config('tag4', foreground='black', spacing1=20, spacing2=10,
                                    font=tf.Font(family='SimHei', size=12))
            company_text.insert(tk.INSERT, '\n')

            company_text.insert(tk.INSERT, '    ')
            company_text.insert(tk.INSERT, '主要业务及产品:')
            company_text.tag_add('tag5', '4.4', '4.12')
            company_text.tag_config('tag5', foreground='blue')
            company_text.insert(tk.INSERT, stock_main_business)
            company_text.tag_add('tag6', '4.12', 'end')
            company_text.tag_config('tag6', spacing1=20, spacing2=10,
                                    font=tf.Font(family='SimHei', size=12))
            company_text.insert(tk.INSERT, '\n')

            company_text.insert(tk.INSERT, '    ')
            company_text.insert(tk.INSERT, '经营范围:')
            company_text.tag_add('tag7', '5.4', '5.9')
            company_text.tag_config('tag7', foreground='#cc6600')
            company_text.insert(tk.INSERT, stock_business_scope)
            company_text.tag_add('tag8', '5.9', 'end')
            company_text.tag_config('tag8', spacing1=20, spacing2=10,
                                    font=tf.Font(family='SimHei', size=12))
            company_text.insert(tk.INSERT, '\n')

            company_text.pack(fill=BOTH, expand=1)

        # 在主框架下创建查询按钮子框架
        search_frame = tk.Frame(tk_window.centre_frame, borderwidth=1, bg='#353535', relief=tix.SUNKEN)
        search_frame.pack(before=tabControl)  # 必须加上before,否则控件则会出现在底部,除非tabControl设置了bottom布局属性
        # 创建查询按钮并设置功能
        stock_find = tk.Button(search_frame, text='查询', width=5, height=1, command=go)
        stock_find.pack()

    def show_stocklist_function(self):  # 股票功能代码
        for widget_graphic_main_frame in tk_window.centre_frame.winfo_children():
            widget_graphic_main_frame.destroy()

        # 首先获取今天时间
        now_time = datetime.datetime.now()
        # 转化成tushare的时间格式
        strf_time = now_time.strftime('%Y%m%d')
        # 获取上交所上一个交易日日期,PS:tushare指数的数据信息好像当天只能获取上一个交易日的数据
        pre_trade_date = pro.trade_cal(exchange='SSE', is_open='1', start_date=strf_time, fields='pretrade_date')
        pre_trade_d = pre_trade_date.at[0, 'pretrade_date']
        # print(pre_trade_d)

        df_basic = pro.stock_basic(exchange='', list_status='L')  # 再获取所有股票的基本信息
        df_daily = pro.daily(trade_date=pre_trade_d)  # 先获得所有股票的行情数据,成交额单位是千元,成交量是手
        df_daily_basic = pro.daily_basic(ts_code='', trade_date=pre_trade_d,
                                         fields='ts_code, turnover_rate, turnover_rate_f,'
                                                ' volume_ratio, pe, pe_ttm, pb, ps, ps_ttm,'
                                                ' total_share, float_share,'
                                                ' free_share, total_mv, circ_mv ')  # 获取每日指标,单位是万股,万元
        df_first = pd.merge(left=df_basic, right=df_daily, on='ts_code',
                            how='outer')  # on='ts_code'以ts_code为索引,合并数据,how='outer',取并集
        df_all = pd.merge(left=df_first, right=df_daily_basic, on='ts_code', how='outer')
        # 数据清洗,删除symbol列数据,跟ts_code数据重复
        df_all = df_all.drop('symbol', axis=1)
        df_all = df_all[df_all['trade_date'].notna()]  # 删除当天不交易的股票
        df_all = df_all[df_all['list_date'].notna()]  # 删除退市或将要退市的股票
        for w in ['name', 'area', 'industry', 'market']:  # 在'name', 'area', 'industry', 'market'列内循环填充NaN值
            df_all[w].fillna('退市股', inplace=True)
        # print(type(df_all.at[1, 'pb']))

        # df_all['amount'] = df_all['amount'] / 100000  # 千转亿
        # df_all['circ_mv'] = df_all['circ_mv'] / 10000  # 万转亿
        # df_all['total_mv'] = df_all['total_mv'] / 10000  # 万转亿

        # 对获取的股票数据列名称进行重命名以方便阅读
        df_all = df_all.rename(columns={'ts_code': '股票代码', 'name': '股票名称', 'area': '所在地域', 'industry': '行业',
                                        'market': '市场类型', 'list_date': '上市日期', 'trade_date': '交易日期',
                                        'open': '开盘价', 'high': '最高价', 'low': '最低价', 'close': '收盘价',
                                        'pre_close': '昨日价', 'change': '涨跌额', 'pct_chg': '涨跌幅',
                                        'vol': '成交量(手)', 'amount': '成交额(千元)', 'turnover_rate': '换手率(%)',
                                        'turnover_rate_f': '流通换手率', 'volume_ratio': '量比', 'pe': '市盈率',
                                        'pe_ttm': '滚动市盈率', 'pb': '市净率', 'ps': '市销率', 'ps_ttm': '滚动市销率',
                                        'total_share': '总股本(万股)', 'float_share': '流通股本 (万股)',
                                        'free_share': '自由流通股本(万股)', 'total_mv': '总市值 (万元)',
                                        'circ_mv': '流通市值(万元)'})
        # 亏损的为空值
        # 先设置表的列名有哪些
        area = ('股票代码', '股票名称', '所在地域', '行业', '市场类型', '上市日期', '交易日期', '开盘价', '最高价', '最低价',
                '收盘价', '昨日价', '涨跌额', '涨跌幅', '成交量(手)', '成交额(千元)', '换手率(%)', '流通换手率', '量比',
                '市盈率', '滚动市盈率', '市净率', '市销率', '滚动市销率', '总股本(万股)',
                '流通股本 (万股)', '自由流通股本(万股)', '总市值 (万元)', '流通市值(万元)')

        stock_treeview = ttk.Treeview(tk_window.centre_frame, columns=area, show='headings')
        # 在treeview布局钱先布局横竖滚动条,不然会出现布局问题,你可以试着将滚动条代码放在最后试下
        VScroll1 = ttk.Scrollbar(tk_window.centre_frame, orient='vertical', command=stock_treeview.yview)
        stock_treeview.configure(yscrollcommand=VScroll1.set)
        VScroll1.pack(side=RIGHT, fill=Y)

        HScroll1 = ttk.Scrollbar(tk_window.centre_frame, orient='horizontal', command=stock_treeview.xview)
        stock_treeview.configure(xscrollcommand=HScroll1.set)
        HScroll1.pack(side=BOTTOM, fill=X)

        for i in range(len(area)):  # 命名列表名
            stock_treeview.column(area[i], width=70, anchor='center')
            stock_treeview.heading(area[i], text=area[i])
        stock_treeview.pack(fill=BOTH, expand=1)

        j = 0
        for i in range(len(df_all.index)):  # 导入插入股票数据
            # 插入的值数组格式用.tolist()转化成list格式,否则显示会多出‘跟[这种字符串
            stock_treeview.insert('', 'end', values=df_all.values[i].tolist())
            # print(df_all.values[i].tolist())
            j += 1
            print('已经插入到第%s个股票了,请耐心等待' % j)

        def stock_treeview_sort(tv, col, reverse):  # Treeview、列名、排列方式
            try:
                # tv.set指定item,如果不设定column和value,则返回他们的字典,如果设定了column,则返回该column的value,如果value也设定了,则作相应更改。
                # get_children()函数,其返回的是treeview中的记录号
                # 参照网上的treeview排序方法函数,由于股票的价格排序数据类型是浮点数字,在排序钱将价格类型有str转换成float,否则排序会不正确
                stockdata_list = [(float(tv.set(k, col)), k) for k in tv.get_children('')]
            except Exception:
                stockdata_list = [(tv.set(k, col), k) for k in tv.get_children('')]
                # print(tv.get_children(''))
                # print(stockdata_list)
            stockdata_list.sort(reverse=reverse)  # 排序方式
            # rearrange items in sorted positions
            # 根据排序后索引移动,enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标
            for index, (val, k) in enumerate(stockdata_list):
                tv.move(k, '', index)
                # print(k)
            tv.heading(col, command=lambda col=col: stock_treeview_sort(tv, col, not reverse))  # 重写标题,使之成为再点倒序的标题

        for col in area:
            stock_treeview.column(col, width=70, anchor='center')
            stock_treeview.heading(col, text=col,
                                   command=lambda col=col: stock_treeview_sort(stock_treeview, col, False))

        # 创建选中股票显示K线图形功能函数
        def stock_k_show():
            for item in stock_treeview.selection():
                item_text = stock_treeview.item(item, "values")
                print(item_text[0])  # 输出所选行的第一列的值
                stock_kline_window = tk.Toplevel()
                stock_kline_window.geometry('{}x{}'.format(800, 600))

                code_name = item_text[0]
                start_date = '20150101'
                end_date = pre_trade_d
                stock_data = pro.daily(ts_code=code_name, start_date=start_date, end_date=end_date)
                print(stock_data)
                # :取所有行数据,后面取date列,open列等数据
                data = stock_data.loc[:, ['trade_date', 'open', 'close', 'high', 'low', 'vol']]
                data = data.rename(columns={'trade_date': 'Date', 'open': 'Open', 'close': 'Close', 'high': 'High',
                                            'low': 'Low', 'vol': 'Volume'})  # 更换列名,为后面函数变量做准备
                data.set_index('Date', inplace=True)  # 设置date列为索引,覆盖原来索引,这个时候索引还是 object 类型,就是字符串类型。
                # 将object类型转化成 DateIndex 类型,pd.DatetimeIndex 是把某一列进行转换,同时把该列的数据设置为索引 index。
                data.index = pd.DatetimeIndex(data.index)
                data = data.sort_index(ascending=True)  # 将时间顺序升序,符合时间序列

                fig, axlist = mpf.plot(data, title=item_text[1], type='candle', mav=(5, 10, 20), volume=True,
                                       show_nontrading=False, returnfig=True, style=s)

                canvas = FigureCanvasTkAgg(fig, master=stock_kline_window)  # 设置tkinter绘制区
                canvas.draw()
                toolbar = NavigationToolbar2Tk(canvas, stock_kline_window)
                toolbar.update()  # 显示图形导航工具条
                canvas._tkcanvas.pack(side=BOTTOM, fill=BOTH, expand=1)

        # 创建弹出菜单,为后面功能开发做准备
        stocklist_menu = tk.Menu(tk_window.centre_frame, tearoff=False)  # tearoff=True显示分割线

        def pop(event):
            stocklist_menu.post(event.x_root, event.y_root)

        stock_treeview.bind('<Button-3>', pop)

        stocklist_menu.add_command(label='K线图', command=stock_k_show)

stock_backtrader.py

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import datetime
import pandas as pd
import backtrader as bt
import tushare as ts
import tk_window
import tkinter as tk
from tkinter import ttk
import matplotlib.pyplot as plt
import mplfinance as mpf
import matplotlib as mpl  # 用于设置曲线参数
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)  # 使用后端TkAgg

# pd.set_option()就是pycharm输出控制显示的设置
pd.set_option('expand_frame_repr', False)  # True就是可以换行显示。设置成False的时候不允许换行
pd.set_option('display.max_columns', None)  # 显示所有列
# pd.set_option('display.max_rows', None)  # 显示所有行
pd.set_option('colheader_justify', 'centre')  # 显示居中

mpl.use('TkAgg')
ts.set_token('数据用的是tushare,没权限自己去注册个吧')


class my_strategy(bt.Strategy):
    # 设置简单均线周期,以备后面调用
    params = (
        ('maperiod21', 21),
        ('maperiod55', 55),)

    def log(self, txt, dt=None):
        # 日记记录输出
        dt = dt or self.datas[0].datetime.date(0)
        print('%s, %s' % (dt.isoformat(), txt))

    def __init__(self):
        # 初始化数据参数
        # 设置当前收盘价为dataclose
        self.dataclose = self.datas[0].close

        self.order = None
        self.buyprice = None
        self.buycomm = None

        # 添加简单均线, subplot=False是否单独子图显示
        self.sma21 = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.maperiod21, plotname='mysma')
        self.sma55 = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.maperiod55, subplot=False)

    def next(self):
        # self.log('Close, %.2f' % self.dataclose[0])  # 输出打印收盘价
        # self.log('持仓 %.2f' % self.position.size)  # 输出持仓
        # 检查是否有订单发送当中,如果有则不再发送第二个订单
        if self.order:
            return

        # 检查是否已经有仓位
        if not self.position:
            # 如果没有则可以执行一下策略了
            if self.sma21[0] > self.sma55[0] and self.sma21[-1] < self.sma55[-1]:
                # 记录输出买入价格
                # self.log('买入信号产生的价格: %.2f' % self.dataclose[0])
                # 跟踪已经创建好的订单避免重复第二次交易
                self.order = self.buy()

        else:
            if self.sma21[0] < self.sma55[0] and self.sma21[-1] > self.sma55[-1]:
                # self.log('卖入信号产生的价格: %.2f' % self.dataclose[0])
                self.order = self.sell()

    # 记录交易执行情况,输出打印
    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            # 如果有订单提交或者已经接受的订单,返回退出
            return
        # 主要是检查有没有成交的订单,如果有则日志记录输出价格,金额,手续费。注意,如果资金不足是不会成交订单的
        if order.status in [order.Completed]:
            if order.isbuy():
                # self.log(
                #     '实际买入价格: %.2f, 市值: %.2f, 手续费 %.2f' %
                #     (order.executed.price,
                #      order.executed.value,
                #      order.executed.comm))

                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
            # else:  # Sell
            # self.log('实际卖出价格: %.2f, 市值: %.2f, 手续费 %.2f' %
            #          (order.executed.price,
            #           order.executed.value,
            #           order.executed.comm))
            # len(self)是指获取截至当前数据一共有多少根bar
            # 以下代码就是指当交易发生时立刻记录下了当天有多少根bar
            # 如果要表示当成交后过了5天卖,则可以这样写 if len(self) >= (self.bar_executed + 5):
            self.bar_executed = len(self)

        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')

        self.order = None

    # 记录交易收益情况
    # def notify_trade(self, trade):
    #     if not trade.isclosed:  # 如果交易还没有关闭,则退出不输出显示盈利跟手续费
    #         return
    #     self.log('策略收益 %.2f, 成本 %.2f' %
    #              (trade.pnl, trade.pnlcomm))

    def stop(self):
        # 策略停止输出结果
        total_funds = self.broker.getvalue()
    # print('MA均线: %2d日,总资金: %.2f' % (self.params.maperiod21, total_funds))


def run_cerebro():  # 策略回测
    for widget_backtrader_window in tk_window.centre_frame.winfo_children():
        widget_backtrader_window.destroy()
    backtrader_window = tk.PanedWindow(tk_window.centre_frame, opaqueresize=False)
    backtrader_window.pack(fill=tk.BOTH, expand=1)
    # 创建左边frame框架,主要放回测策略文件代码
    backtrader_left_frame = tk.Frame(backtrader_window, relief=tk.SUNKEN, bg='#353535', bd=5, borderwidth=4)
    backtrader_left_frame.pack(fill=tk.BOTH, expand=1)
    top_label = tk.Label(backtrader_left_frame, text='回测策略文件', bd=1)
    top_label.pack()
    backtrader_window.add(backtrader_left_frame)

    # 创建右边图形输出框架,主要放回测分析显示跟用户输入的股票代码跟日期
    backtrader_plot_window = tk.PanedWindow(orient='vertical', opaqueresize=False)
    backtrader_window.add(backtrader_plot_window)

    backtrader_plot_window_top = tk.PanedWindow(opaqueresize=False)
    backtrader_plot_window.add(backtrader_plot_window_top)

    backtrader_top_frame = tk.Frame(backtrader_plot_window_top, width=tk_window.screenWidth,
                                    height=tk_window.screenHeight,
                                    relief=tk.SUNKEN, bg='#353535', bd=5, borderwidth=4)
    backtrader_top_frame.pack(fill=tk.BOTH)

    # 在主框架下创建股票代码输入子框架
    code_frame = tk.Frame(backtrader_top_frame, borderwidth=1, bg='#353535')
    code_frame.pack()
    # 创建标签‘股票代码’
    stock_label = tk.Label(code_frame, text='股票代码', bd=1)
    stock_label.pack(side=tk.LEFT)
    # 创建股票代码输入框
    input_code_var = tk.StringVar()
    code_widget = tk.Entry(code_frame, textvariable=input_code_var, borderwidth=1, justify=tk.CENTER)
    # input_code_get = input_code_var.set(input_code_var.get())  # 获取输入的新值
    code_widget.pack(side=tk.LEFT, padx=4)

    # 在主框架下创建股票日期输入框子框架
    input_date_frame = tk.Frame(backtrader_top_frame, borderwidth=1, bg='#353535')
    input_date_frame.pack()
    # 创建标签‘开始日期’
    date_start_label = tk.Label(input_date_frame, text='开始日期', bd=1)
    date_start_label.pack(side=tk.LEFT)
    # 创建开始日期代码输入框
    input_startdate_var = tk.StringVar()
    startdate_widget = tk.Entry(input_date_frame, textvariable=input_startdate_var, borderwidth=1, justify=tk.CENTER)
    input_startdate_get = input_startdate_var.set(input_startdate_var.get())  # 获取输入的新值
    startdate_widget.pack(side=tk.LEFT, padx=4)
    # 创建标签‘结束日期’
    date_end_label = tk.Label(input_date_frame, text='结束日期', bd=1)
    date_end_label.pack(side=tk.LEFT)
    # 创建结束日期代码输入框
    input_enddate_var = tk.StringVar()
    enddate_widget = tk.Entry(input_date_frame, textvariable=input_enddate_var, borderwidth=1, justify=tk.CENTER)
    input_enddate_get = input_enddate_var.set(input_enddate_var.get())  # 获取输入的新值
    enddate_widget.pack(side=tk.LEFT, padx=4)
    # 先把部件布局好了再backtrader_top_frame用.add()添加到backtrader_plot_window
    backtrader_plot_window_top.add(backtrader_top_frame, height=tk_window.screenHeight / 10)

    backtrader_plot_window_bottom = tk.PanedWindow(opaqueresize=False)
    backtrader_plot_window.add(backtrader_plot_window_bottom)
    # 创建底部窗口框架,用来放图形输出
    backtrader_bottom_frame = tk.Frame(backtrader_plot_window_bottom, width=tk_window.screenWidth,
                                       height=tk_window.screenHeight, relief=tk.SUNKEN, bg='#353535', bd=5,
                                       borderwidth=4)
    backtrader_bottom_frame.pack(fill=tk.BOTH)

    backtrader_plot_window_bottom.add(backtrader_bottom_frame)

    def backtrader_go():  # 图形输出渲染
        # 在backtrader_bottom_frame的原有基础上再创建一个框架,目的方便在更新股票股票回测时防止图形重叠
        for widget_backtrader_bottom_frame in backtrader_bottom_frame.winfo_children():
            widget_backtrader_bottom_frame.destroy()
        # 创建左右两个frame框架方便管理布局大小跟刷新,framed大小跟控件的长高有关
        backtrader_bottomleft_frame = tk.Frame(backtrader_bottom_frame, bg='#353535', bd=5, borderwidth=4)
        backtrader_bottomleft_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
        backtrader_bottomright_frame = tk.Frame(backtrader_bottom_frame, bg='#353535', bd=5, borderwidth=4)
        backtrader_bottomright_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=0)

        # 以下函数作用是省略输入代码后缀.sz .sh
        def code_name_transform(get_stockcode):  # 输入的数字股票代码转换成字符串股票代码
            str_stockcode = str(get_stockcode)
            str_stockcode = str_stockcode.strip()  # 删除前后空格字符
            if 6 > len(str_stockcode) > 0:
                str_stockcode = str_stockcode.zfill(6) + '.SZ'  # zfill()函数返回指定长度的字符串,原字符串右对齐,前面填充0
            if len(str_stockcode) == 6:
                if str_stockcode[0:1] == '0':
                    str_stockcode = str_stockcode + '.SZ'
                if str_stockcode[0:1] == '3':
                    str_stockcode = str_stockcode + '.SZ'
                if str_stockcode[0:1] == '6':
                    str_stockcode = str_stockcode + '.SH'
            return str_stockcode

        # 交互数据的获取跟处理
        stock_name = input_code_var.get()
        code_name = code_name_transform(stock_name)
        start_date = input_startdate_var.get()
        end_date = input_enddate_var.get()

        # adj='qfq'向前复权,freq='D 数据频度:日K线
        df = ts.pro_bar(ts_code=code_name, start_date=start_date, end_date=end_date, adj='qfq', freq='D')
        df['trade_date'] = pd.to_datetime(df['trade_date'])
        # df = df.drop(['change', 'pre_close', 'pct_chg', 'amount'], axis=1)

        # 设置用于backtrader的数据
        df_back = df.rename(columns={'vol': 'volume'})
        df_back.set_index('trade_date', inplace=True)  # 设置索引覆盖原来的数据
        df_back = df_back.sort_index(ascending=True)  # 将时间顺序升序,符合时间序列
        df_back['openinterest'] = 0
        # 喂养数据到backtrader当中去
        back_start_time = datetime.datetime.strptime(start_date, "%Y%m%d")  # str转换成时间格式2015-01-01 00:00:00
        back_end_time = datetime.datetime.strptime(end_date, '%Y%m%d')
        # print(back_start_time)
        data_back = bt.feeds.PandasData(dataname=df_back,
                                        fromdate=back_start_time,
                                        todate=back_end_time)

        # 设置用于mpf图形的数据
        data_mpf = df.loc[:, ['trade_date', 'open', 'close', 'high', 'low', 'vol']]  # :取所有行数据,后面取date列,open列等数据
        data_mpf = data_mpf.rename(
            columns={'trade_date': 'Date', 'open': 'Open', 'close': 'Close', 'high': 'High', 'low': 'Low',
                     'vol': 'Volume'})  # 更换列名,为后面函数变量做准备
        data_mpf.set_index('Date', inplace=True)  # 设置date列为索引,覆盖原来索引,这个时候索引还是 object 类型,就是字符串类型。
        # 将object类型转化成 DateIndex 类型,pd.DatetimeIndex 是把某一列进行转换,同时把该列的数据设置为索引 index。
        data_mpf.index = pd.DatetimeIndex(data_mpf.index)
        data_mpf = data_mpf.sort_index(ascending=True)  # 将时间顺序升序,符合时间序列
        # print(data_mpf)

        # 创建策略容器
        cerebro = bt.Cerebro()
        # 添加自定义的策略my_strategy
        cerebro.addstrategy(my_strategy)
        # 添加数据
        cerebro.adddata(data_back)
        # 设置资金
        startcash = 100000
        cerebro.broker.setcash(startcash)
        # 设置每笔交易交易的股票数量
        cerebro.addsizer(bt.sizers.FixedSize, stake=100)
        # 设置手续费
        cerebro.broker.setcommission(commission=0.0005)
        # 输出初始资金
        d1 = back_start_time.strftime('%Y%m%d')
        d2 = back_end_time.strftime('%Y%m%d')

        cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='SharpeRatio')
        cerebro.addanalyzer(bt.analyzers.DrawDown, _name='DW')
        cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='TradeAnalyzer')
        cerebro.addanalyzer(bt.analyzers.Transactions, _name='Transactions')

        # 运行策略
        # stdstats=False不显示回测的统计结果
        result = cerebro.run(stdstats=True, optreturn=False)
        backtrader_analysis = result[0]
        # print(backtrader_analysis.analyzers.SharpeRatio.get_analysis())
        # print(backtrader_analysis.analyzers.DW.get_analysis())
        # print(backtrader_analysis.analyzers.TradeAnalyzer.get_analysis())
        # 在下面的占位符后面不能有空格,否则空格后面的输入信息是输不进treeview的单元格
        startcash_value = '初始资金:%.2f' % startcash
        endcash_value = '期末资金:%.2f' % cerebro.broker.getvalue()
        completed_net = '已完成盈亏:%.2f' % backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['pnl']['net']['total']
        float_profit = '浮动盈亏:%.2f' % (cerebro.broker.getvalue() - startcash -
                                      backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['pnl']['net']['total'])
        completed_commission = '手续费用:%.2f' % (
                    backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['pnl']['gross']['total'] -
                    backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['pnl']['net']['total'])
        start_backtrade_date = '回测开始时间:%s' % d1
        end_backtrade_date = '回测结束时间:%s' % d2
        sharpeRatio_value = '夏普比例:%.2f' % backtrader_analysis.analyzers.SharpeRatio.get_analysis()['sharperatio']
        drawdown_value = '最大回撤:%.2f' % backtrader_analysis.analyzers.DW.get_analysis()['max']['drawdown']
        moneydown_value = '最大资金回撤:%.2f' % backtrader_analysis.analyzers.DW.get_analysis()['max']['moneydown']
        max_drawdown_lastday = '最大回撤持续天数:%d' % backtrader_analysis.analyzers.DW.get_analysis()['max']['len']
        total_value = '交易次数:%d' % backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['total']['total']
        uncompleted_trade = '未完成交易数量:%d' % backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['total']['open']
        completed_trade = '已完成交易数量:%d' % backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['total']['closed']
        win_value = '盈利次数:%d' % backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['won']['total']
        lost_value = '亏损次数:%d' % backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['lost']['total']
        win_rate = '胜率:%.2f' % (backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['won']['total'] /
                                backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['total']['total'])
        lost_rate = '败率:%.2f' % (backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['lost']['total'] /
                                 backtrader_analysis.analyzers.TradeAnalyzer.get_analysis()['total']['total'])

        analysis_log = []  # 设置空列表用来接收回测记录
        history_trade_buy_date_list = []  # 设置空列表用来接收买点标记的时间日期,下面的空列表都是为标记做准备
        history_trade_sell_date_list = []
        history_trade_buy_vol_list = []
        history_trade_sell_vol_list = []
        history_trade_buy_price_list = []
        history_trade_sell_price_list = []
        trade_signal_buy = pd.DataFrame(columns=['Date', 'buy_price', 'buy_vol'])   # 创建买点dataframe
        trade_signal_sell = pd.DataFrame(columns=['Date', 'sell_price', 'sell_vol'])
        analysis_log.extend([startcash_value, endcash_value, float_profit, completed_net, completed_commission,
                             start_backtrade_date, end_backtrade_date, sharpeRatio_value, drawdown_value,
                             moneydown_value, max_drawdown_lastday, total_value, uncompleted_trade, completed_trade,
                             win_value, lost_value, win_rate, lost_rate])
        for key, value in backtrader_analysis.analyzers.Transactions.get_analysis().items():
            trade_log = '日期:%s,价格:%.2f,数量:%d,市值:%.2f' % (key.strftime('%Y-%m-%d'), value[0][1], value[0][0],
                                                         value[0][4])
            analysis_log.extend([trade_log])

            history_trade_date = key.strftime('%Y-%m-%d')
            history_trade_price = value[0][1]
            history_trade_vol = value[0][0]

            if history_trade_vol > 0:
                history_trade_buy_date_list.append(history_trade_date)
                history_trade_buy_price_list.append(history_trade_price)
                history_trade_buy_vol_list.append(history_trade_vol)
            elif history_trade_vol < 0:
                history_trade_sell_date_list.append(history_trade_date)
                history_trade_sell_price_list.append(history_trade_price)
                history_trade_sell_vol_list.append(history_trade_vol)

        trade_signal_buy['Date'] = history_trade_buy_date_list
        trade_signal_buy['buy_price'] = history_trade_buy_price_list
        trade_signal_buy['buy_vol'] = history_trade_buy_vol_list
        trade_signal_buy.set_index('Date', inplace=True)
        trade_signal_buy.index = pd.DatetimeIndex(trade_signal_buy.index)

        trade_signal_sell['Date'] = history_trade_sell_date_list
        trade_signal_sell['sell_price'] = history_trade_sell_price_list
        trade_signal_sell['sell_vol'] = history_trade_sell_vol_list
        trade_signal_sell.set_index('Date', inplace=True)
        trade_signal_sell.index = pd.DatetimeIndex(trade_signal_sell.index)
        # 合并前面的买卖数据dataframe,为绘图做准备
        trade_all = pd.merge(left=data_mpf, right=trade_signal_buy, left_index=True, right_index=True, how='outer')
        trade_all = pd.merge(left=trade_all, right=trade_signal_sell, left_index=True, right_index=True, how='outer')
        # print(trade_all)

        # grid = False不显示分割线
        # cerebro.plot(style='candlestick', grid=False, iplot=False)
        colors_set = mpf.make_marketcolors(up='red', down='green', edge='i', wick='i', volume='in', inherit=True)
        # 设置图形风格,gridaxis:设置网格线位置,gridstyle:设置网格线线型,y_on_right:设置y轴位置是否在右
        mpf_style = mpf.make_mpf_style(gridaxis='horizontal', gridstyle='-.', y_on_right=False, facecolor='white',
                                       figcolor='white', marketcolors=colors_set)
        # 添加买卖点附图
        add_plot = [mpf.make_addplot(trade_all['buy_price'], scatter=True, markersize=130, marker='^', color='r'),
                    mpf.make_addplot(trade_all['sell_price'], scatter=True, markersize=130, marker='v', color='g')]

        daily_fig, axlist = mpf.plot(data_mpf, type='candle', mav=(21, 55), volume=True, show_nontrading=False,
                                     style=mpf_style, addplot=add_plot, returnfig=True)

        canvas_stock_daily_basic = FigureCanvasTkAgg(daily_fig, master=backtrader_bottomleft_frame)
        canvas_stock_daily_basic.draw()
        toolbar_stock_daily_basic = NavigationToolbar2Tk(canvas_stock_daily_basic, backtrader_bottomleft_frame)
        toolbar_stock_daily_basic.update()  # 显示图形导航工具条
        canvas_stock_daily_basic._tkcanvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)

        backtrader_treeview = ttk.Treeview(backtrader_bottomright_frame, columns=['1'], show='headings')
        # 在treeview布局钱先布局横竖滚动条,不然会出现布局问题,你可以试着将滚动条代码放在最后试下
        VScroll1 = ttk.Scrollbar(backtrader_bottomright_frame, orient='vertical', command=backtrader_treeview.yview)
        backtrader_treeview.configure(yscrollcommand=VScroll1.set)
        VScroll1.pack(side=tk.RIGHT, fill=tk.Y)

        backtrader_treeview.column('1', width=int(tk_window.screenWidth / 4), anchor='w')
        backtrader_treeview.heading('1', text='回测记录')
        backtrader_treeview.pack(side=tk.LEFT, fill=tk.BOTH, expand=0)
        for i in range(len(analysis_log)):  # 写入回测记录
            backtrader_treeview.insert('', 'end', values=analysis_log[i])

    # 在主框架下创建回测按钮子框架
    search_frame = tk.Frame(backtrader_top_frame, borderwidth=1, bg='#353535', relief=tk.SUNKEN)
    search_frame.pack()
    # 创建查询按钮并设置功能
    stock_find = tk.Button(search_frame, text='回测', width=5, height=1, command=backtrader_go)
    stock_find.pack()

function.py

import tkinter as tk
import time
import tk_window


def time_clock():
    tk_clock_var = tk.StringVar()
    tk_clock = tk.Label(tk_window.bottom_frame, textvariable=tk_clock_var, bg='#353535', fg='white')
    tk_clock.pack(side=tk.RIGHT)

    def tk_clock_trickit():
        tk_clock_var.set(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
        tk_window.bottom_frame.update()
        tk_clock.after(0, tk_clock_trickit)

    tk_clock.after(0, tk_clock_trickit)

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wilburzzz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值