Skip to content

StockChartDemo 项目分析

项目信息

运行截图

文件结构

StockChartDemo/
├── DATA/                          # 股票数据目录
│   └── 日K线/                     # 日K线数据文件
│       ├── 00_加权.DAT
│       ├── 01_金融.DAT
│       ├── 02_电子.DAT
│       ├── 03_非金融.DAT
│       ├── 04_非电子.DAT
│       ├── 05_联电.DAT
│       ├── 06_台积电.DAT
│       ├── 07_华邦.DAT
│       ├── 08_明基.DAT
│       ├── 09_宏碁.DAT
│       ├── 10_华硕.DAT
│       ├── 11_友达.DAT
│       └── 12_奇美.DAT
├── Extractor_Icon.ico
├── fDemo.py                       # 主窗体代码
├── fDemo.pydfm                    # 窗体设计文件(二进制)
├── fDemo.sct                      # 设计文件(事件声明)
├── fDemo.sfm                      # 窗体结构文件
├── Project1.py                    # 项目主程序
└── Project1.xml                   # 项目配置文件

主程序文件: Project1.py

from glcl import *
from fDemo import *

def main():
    icon_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Extractor_Icon.ico")
    if not os.path.exists(icon_path):
        print('Extractor_Icon.ico is missing. Do not delete or rename this file.')
        return
    Application.Initialize()
    Application.Title = 'Project1'
    Application.MainFormOnTaskbar = True
    Application.Icon.LoadFromFile(icon_path)
    MainForm = frmDemo(Application)
    MainForm.Show()
    FreeConsole()
    Application.Run()
    MainForm.Free()

if __name__ == '__main__':
    main()

单元文件: fDemo.py

# Powered By Python Studio, The best Python GUI IDE to download from glsite.com.
import os  # 导入操作系统模块,用于文件路径操作
from glcl import *  # 导入glcl框架的所有组件

class frmDemo(Form):  # 定义主窗体类,继承自Form
    '''TStockChart Demo - Stock chart viewer application'''  # 类说明:股票图表查看器应用程序

    def __init__(self, owner):  # 构造函数,初始化窗体
        self.splitter = Splitter(self)  # 分隔条控件
        self.pnlTop = Panel(self)  # 顶部面板
        self.lblStock = Label(self)  # 股票代码标签
        self.lblStatus = Label(self)  # 状态信息标签
        self.edtStock = Edit(self)  # 股票代码输入框
        self.btnLoad = Button(self)  # "加载"按钮
        self.btnZoomIn = Button(self)  # "放大"按钮
        self.btnZoomOut = Button(self)  # "缩小"按钮
        self.btnFirst = Button(self)  # "跳转到第一条"按钮
        self.btnLeft = Button(self)  # "向左滚动"按钮
        self.btnRight = Button(self)  # "向右滚动"按钮
        self.btnLast = Button(self)  # "跳转到最后一条"按钮
        self.pnlLeft = Panel(self)  # 左侧面板
        self.grpDisplay = GroupBox(self)  # "显示选项"分组框
        self.chkMA = CheckBox(self)  # "显示均线"复选框
        self.chkVMA = CheckBox(self)  # "显示成交量均线"复选框
        self.chkDate = CheckBox(self)  # "显示日期刻度"复选框
        self.chkDot = CheckBox(self)  # "显示虚线"复选框
        self.chkHL = CheckBox(self)  # "显示高低价标签"复选框
        self.chkRSI = CheckBox(self)  # "显示RSI面板"复选框
        self.grpMA = GroupBox(self)  # "均线周期设置"分组框
        self.lblMA0 = Label(self)  # 均线0的标签
        self.lblMA1 = Label(self)  # 均线1的标签
        self.lblMA2 = Label(self)  # 均线2的标签
        self.lblMA3 = Label(self)  # 均线3的标签
        self.lblMA4 = Label(self)  # 均线4的标签
        self.lblMA5 = Label(self)  # 均线5的标签
        self.seMA0 = SpinEdit(self)  # 均线0的数值调节控件
        self.seMA1 = SpinEdit(self)  # 均线1的数值调节控件
        self.seMA2 = SpinEdit(self)  # 均线2的数值调节控件
        self.seMA3 = SpinEdit(self)  # 均线3的数值调节控件
        self.seMA4 = SpinEdit(self)  # 均线4的数值调节控件
        self.seMA5 = SpinEdit(self)  # 均线5的数值调节控件
        self.grpRSI = GroupBox(self)  # "RSI周期设置"分组框
        self.lblRSI0 = Label(self)  # RSI0的标签
        self.lblRSI1 = Label(self)  # RSI1的标签
        self.seRSI0 = SpinEdit(self)  # RSI0的数值调节控件
        self.seRSI1 = SpinEdit(self)  # RSI1的数值调节控件
        self.grpColor = GroupBox(self)  # "颜色设置"分组框
        self.btnBgColor = Button(self)  # "背景颜色"按钮
        self.btnUpColor = Button(self)  # "上涨颜色"按钮
        self.btnDnColor = Button(self)  # "下跌颜色"按钮
        self.btnEvColor = Button(self)  # "平盘颜色"按钮
        self.grpLayout = GroupBox(self)  # "布局设置"分组框
        self.lblKRatio = Label(self)  # K线比例标签
        self.lblVRatio = Label(self)  # 成交量比例标签
        self.trkKRatio = TrackBar(self)  # K线比例滑块
        self.trkVRatio = TrackBar(self)  # 成交量比例滑块
        self.grpInfo = GroupBox(self)  # "信息显示"分组框
        self.mmoInfo = Memo(self)  # 信息显示文本框
        self.pnlRight = Panel(self)  # 右侧面板
        self.grpList = GroupBox(self)  # "股票列表"分组框
        self.lstStocks = ListBox(self)  # 股票列表控件
        self.Chart = StockChart(self)  # 核心的股票图表控件
        self.ColorDlg = ColorDialog(self)  # 颜色选择对话框

        # 从.pydfm文件中加载窗体属性(位置、大小、字体等)
        self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "fDemo.pydfm"))
        # !!!!!!!!!!!!!!!!!!注意!!!!!!!!!!!!!!!!!!!!!
        # 如果需要打包为EXE,需要在配置exe中附带打包DATA目录
        # !!!!!!!!!!!!!!!!!!注意!!!!!!!!!!!!!!!!!!!!!

        # 设置事件处理程序 - 首先绑定图表相关的事件
        self.Chart.OnDataIndexChange = self.ChartDataIndexChange  # 绑定数据索引变化事件
        self.Chart.OnStockLoaded = self.ChartStockLoaded  # 绑定股票加载完成事件
        self.Chart.OnStockNotFound = self.ChartStockNotFound  # 绑定股票未找到事件

        # 绑定工具栏按钮事件
        self.btnLoad.OnClick = self.btnLoadClick  # 绑定"加载"按钮点击事件
        self.btnZoomIn.OnClick = self.btnZoomInClick  # 绑定"放大"按钮点击事件
        self.btnZoomOut.OnClick = self.btnZoomOutClick  # 绑定"缩小"按钮点击事件
        self.btnFirst.OnClick = self.btnFirstClick  # 绑定"跳转到第一条"按钮点击事件
        self.btnLast.OnClick = self.btnLastClick  # 绑定"跳转到最后一条"按钮点击事件
        self.btnLeft.OnClick = self.btnLeftClick  # 绑定"向左滚动"按钮点击事件
        self.btnRight.OnClick = self.btnRightClick  # 绑定"向右滚动"按钮点击事件

        # 绑定显示选项复选框事件
        self.chkMA.OnClick = self.chkMAClick  # 绑定"显示均线"复选框点击事件
        self.chkVMA.OnClick = self.chkVMAClick  # 绑定"显示成交量均线"复选框点击事件
        self.chkDate.OnClick = self.chkDateClick  # 绑定"显示日期刻度"复选框点击事件
        self.chkDot.OnClick = self.chkDotClick  # 绑定"显示虚线"复选框点击事件
        self.chkHL.OnClick = self.chkHLClick  # 绑定"显示高低价标签"复选框点击事件
        self.chkRSI.OnClick = self.chkRSIClick  # 绑定"显示RSI面板"复选框点击事件

        # 绑定均线周期数值调节控件事件(使用Tag属性区分不同的控件)
        self.seMA0.Tag = 0  # 设置seMA0的标识为0
        self.seMA1.Tag = 1  # 设置seMA1的标识为1
        self.seMA2.Tag = 2  # 设置seMA2的标识为2
        self.seMA3.Tag = 3  # 设置seMA3的标识为3
        self.seMA4.Tag = 4  # 设置seMA4的标识为4
        self.seMA5.Tag = 5  # 设置seMA5的标识为5
        self.seMA0.OnChange = self.seMAChange  # 绑定seMA0数值变化事件
        self.seMA1.OnChange = self.seMAChange  # 绑定seMA1数值变化事件
        self.seMA2.OnChange = self.seMAChange  # 绑定seMA2数值变化事件
        self.seMA3.OnChange = self.seMAChange  # 绑定seMA3数值变化事件
        self.seMA4.OnChange = self.seMAChange  # 绑定seMA4数值变化事件
        self.seMA5.OnChange = self.seMAChange  # 绑定seMA5数值变化事件

        # 绑定RSI周期数值调节控件事件
        self.seRSI0.Tag = 0  # 设置seRSI0的标识为0
        self.seRSI1.Tag = 1  # 设置seRSI1的标识为1
        self.seRSI0.OnChange = self.seRSIChange  # 绑定seRSI0数值变化事件
        self.seRSI1.OnChange = self.seRSIChange  # 绑定seRSI1数值变化事件

        # 绑定颜色选择按钮事件(使用Tag属性区分不同的按钮)
        self.btnBgColor.Tag = 0  # 设置"背景颜色"按钮标识为0
        self.btnUpColor.Tag = 1  # 设置"上涨颜色"按钮标识为1
        self.btnDnColor.Tag = 2  # 设置"下跌颜色"按钮标识为2
        self.btnEvColor.Tag = 3  # 设置"平盘颜色"按钮标识为3
        self.btnBgColor.OnClick = self.btnColorClick  # 绑定"背景颜色"按钮点击事件
        self.btnUpColor.OnClick = self.btnColorClick  # 绑定"上涨颜色"按钮点击事件
        self.btnDnColor.OnClick = self.btnColorClick  # 绑定"下跌颜色"按钮点击事件
        self.btnEvColor.OnClick = self.btnColorClick  # 绑定"平盘颜色"按钮点击事件

        # 绑定布局滑块事件
        self.trkKRatio.OnChange = self.trkKRatioChange  # 绑定K线比例滑块变化事件
        self.trkVRatio.OnChange = self.trkVRatioChange  # 绑定成交量比例滑块变化事件

        # 绑定股票列表选择事件
        self.lstStocks.OnClick = self.lstStocksClick  # 绑定股票列表点击事件

        # 同步控件状态与图表默认值
        self.SyncControls()  # 将图表的当前属性值同步到所有UI控件上

        # 扫描DATA文件夹获取股票列表
        self.ScanStockList()  # 扫描数据目录,将可用的股票文件添加到列表

        # 如果存在股票,则加载默认股票
        if self.lstStocks.Count > 0:  # 判断股票列表是否不为空
            self.lstStocks.ItemIndex = 0  # 选中列表中的第一项
            self.edtStock.Text = self.lstStocks.Items[0]  # 将股票代码填入输入框
            self.Chart.LoadStock(self.edtStock.Text)  # 加载默认股票数据

    # ---------------------------------------------------------------------------
    # SyncControls  -  将图表属性值同步到UI控件
    # ---------------------------------------------------------------------------
    def SyncControls(self):
        """将图表的当前显示设置同步到对应的控件上"""
        self.chkMA.Checked = self.Chart.ShowMA  # 同步"显示均线"复选框状态
        self.chkVMA.Checked = self.Chart.ShowVolumeMA  # 同步"显示成交量均线"复选框状态
        self.chkDate.Checked = self.Chart.ShowDateScale  # 同步"显示日期刻度"复选框状态
        self.chkDot.Checked = self.Chart.ShowDotLine  # 同步"显示虚线"复选框状态
        self.chkHL.Checked = self.Chart.ShowHighLowLabel  # 同步"显示高低价标签"复选框状态
        self.chkRSI.Checked = self.Chart.ShowRSI  # 同步"显示RSI面板"复选框状态

        self.seMA0.Value = int(self.Chart.GetMACycle(0))  # 同步均线0的周期值
        self.seMA1.Value = int(self.Chart.GetMACycle(1))  # 同步均线1的周期值
        self.seMA2.Value = int(self.Chart.GetMACycle(2))  # 同步均线2的周期值
        self.seMA3.Value = int(self.Chart.GetMACycle(3))  # 同步均线3的周期值
        self.seMA4.Value = int(self.Chart.GetMACycle(4))  # 同步均线4的周期值
        self.seMA5.Value = int(self.Chart.GetMACycle(5))  # 同步均线5的周期值

        self.seRSI0.Value = int(self.Chart.GetRSICycle(0))  # 同步RSI0的周期值
        self.seRSI1.Value = int(self.Chart.GetRSICycle(1))  # 同步RSI1的周期值

        self.trkKRatio.Position = int(float(self.Chart.KLineRatio) * 100)  # 同步K线比例滑块位置(转换为百分比)
        self.trkVRatio.Position = int(float(self.Chart.VolumeRatio) * 100)  # 同步成交量比例滑块位置(转换为百分比)

    # ---------------------------------------------------------------------------
    # ScanStockList  -  从 .\DATA\日K线\*.DAT 填充股票列表
    # ---------------------------------------------------------------------------
    def ScanStockList(self):
        """扫描数据文件目录,将所有.DAT文件添加到股票列表中"""
        self.lstStocks.Clear()  # 清空股票列表
        DataDir = self.Chart.DataPath  # 获取图表控件当前设置的数据路径

        import sys
        if not os.path.isdir(DataDir):  # 如果数据目录不存在
            # 尝试根据可执行文件所在位置定位数据目录
            exe_dir = os.path.dirname(os.path.abspath(__file__))
            DataDir = os.path.join(exe_dir, 'DATA', '日K线') + os.sep  # 拼接为"DATA/日K线/"路径
            self.Chart.DataPath = DataDir  # 更新图表控件的数据路径

        if os.path.isdir(DataDir):  # 如果数据目录存在
            for fname in os.listdir(DataDir):  # 遍历目录下的所有文件
                if fname.upper().endswith('.DAT'):  # 只处理扩展名为.DAT的文件(不区分大小写)
                    name = os.path.splitext(fname)[0]  # 去除扩展名,只保留文件名
                    self.lstStocks.Items.Add(name)  # 将股票名称添加到列表框中

        if self.lstStocks.Count == 0:  # 如果没有找到任何股票数据文件
            self.lstStocks.Items.Add('(no *.DAT found in ' + str(DataDir) + ')')  # 显示提示信息

    # ---------------------------------------------------------------------------
    # 工具栏按钮事件处理方法
    # ---------------------------------------------------------------------------
    def btnLoadClick(self, Sender):
        """加载按钮点击事件 - 根据输入框中的股票代码加载股票数据"""
        stock = self.edtStock.Text.strip()  # 获取输入框中的股票代码并去除前后空格
        if stock != '':  # 如果股票代码不为空
            self.Chart.LoadStock(stock)  # 调用图表控件的LoadStock方法加载数据

    def btnZoomInClick(self, Sender):
        """放大按钮点击事件 - 放大图表显示"""
        self.Chart.ZoomIn()  # 调用图表的放大方法

    def btnZoomOutClick(self, Sender):
        """缩小按钮点击事件 - 缩小图表显示"""
        self.Chart.ZoomOut()  # 调用图表的缩小方法

    def btnFirstClick(self, Sender):
        """跳转到第一条按钮点击事件 - 滚动到数据的第一条"""
        self.Chart.ScrollToFirst()  # 调用图表的滚动到第一条方法

    def btnLastClick(self, Sender):
        """跳转到最后一条按钮点击事件 - 滚动到数据的最后一条"""
        self.Chart.ScrollToLast()  # 调用图表的滚动到最后一条方法

    def btnLeftClick(self, Sender):
        """向左滚动按钮点击事件 - 向左滚动一屏"""
        self.Chart.ScrollLeft(1)  # 调用图表的向左滚动方法

    def btnRightClick(self, Sender):
        """向右滚动按钮点击事件 - 向右滚动一屏"""
        self.Chart.ScrollRight(1)  # 调用图表的向右滚动方法

    # ---------------------------------------------------------------------------
    # 显示选项复选框事件处理方法
    # ---------------------------------------------------------------------------
    def chkMAClick(self, Sender):
        """显示均线复选框点击事件 - 切换均线显示"""
        self.Chart.ShowMA = self.chkMA.Checked  # 将复选框状态设置给图表的ShowMA属性

    def chkVMAClick(self, Sender):
        """显示成交量均线复选框点击事件 - 切换成交量均线显示"""
        self.Chart.ShowVolumeMA = self.chkVMA.Checked  # 将复选框状态设置给图表的ShowVolumeMA属性

    def chkDateClick(self, Sender):
        """显示日期刻度复选框点击事件 - 切换日期刻度显示"""
        self.Chart.ShowDateScale = self.chkDate.Checked  # 将复选框状态设置给图表的ShowDateScale属性

    def chkDotClick(self, Sender):
        """显示虚线复选框点击事件 - 切换虚线显示"""
        self.Chart.ShowDotLine = self.chkDot.Checked  # 将复选框状态设置给图表的ShowDotLine属性

    def chkHLClick(self, Sender):
        """显示高低价标签复选框点击事件 - 切换高低价标签显示"""
        self.Chart.ShowHighLowLabel = self.chkHL.Checked  # 将复选框状态设置给图表的ShowHighLowLabel属性

    def chkRSIClick(self, Sender):
        """显示RSI面板复选框点击事件 - 切换RSI面板显示"""
        self.Chart.ShowRSI = self.chkRSI.Checked  # 将复选框状态设置给图表的ShowRSI属性

    # ---------------------------------------------------------------------------
    # 均线周期数值调节控件事件处理方法
    # ---------------------------------------------------------------------------
    def seMAChange(self, Sender):
        """均线周期数值变化事件 - 根据用户调整更新对应均线的周期值"""
        SE = Sender  # 获取触发事件的SpinEdit控件对象
        self.Chart.SetMACycle(SE.Tag, int(SE.Value))  # 根据Tag标识和当前值设置对应均线的周期

    # ---------------------------------------------------------------------------
    # RSI周期数值调节控件事件处理方法
    # ---------------------------------------------------------------------------
    def seRSIChange(self, Sender):
        """RSI周期数值变化事件 - 根据用户调整更新对应RSI的周期值"""
        SE = Sender  # 获取触发事件的SpinEdit控件对象
        self.Chart.SetRSICycle(SE.Tag, int(SE.Value))  # 根据Tag标识和当前值设置对应RSI的周期

    # ---------------------------------------------------------------------------
    # 颜色选择按钮事件处理方法
    # ---------------------------------------------------------------------------
    def btnColorClick(self, Sender):
        """颜色按钮点击事件 - 打开颜色选择对话框,设置图表的对应颜色"""
        Btn = Sender  # 获取触发事件的按钮对象
        tag = Btn.Tag  # 获取按钮的Tag标识
        if tag == 0:  # 如果Tag为0,表示背景颜色按钮
            self.ColorDlg.Color = self.Chart.BackColor  # 将对话框初始颜色设置为当前背景色
        elif tag == 1:  # 如果Tag为1,表示上涨颜色按钮
            self.ColorDlg.Color = self.Chart.UpColor  # 将对话框初始颜色设置为当前上涨色
        elif tag == 2:  # 如果Tag为2,表示下跌颜色按钮
            self.ColorDlg.Color = self.Chart.DownColor  # 将对话框初始颜色设置为当前下跌色
        elif tag == 3:  # 如果Tag为3,表示平盘颜色按钮
            self.ColorDlg.Color = self.Chart.EvenColor  # 将对话框初始颜色设置为当前平盘色

        if self.ColorDlg.Execute():  # 显示颜色选择对话框,如果用户点击了"确定"
            if tag == 0:  # 背景颜色按钮
                self.Chart.BackColor = self.ColorDlg.Color  # 设置图表的背景颜色
            elif tag == 1:  # 上涨颜色按钮
                self.Chart.UpColor = self.ColorDlg.Color  # 设置图表的上涨颜色
            elif tag == 2:  # 下跌颜色按钮
                self.Chart.DownColor = self.ColorDlg.Color  # 设置图表的下跌颜色
            elif tag == 3:  # 平盘颜色按钮
                self.Chart.EvenColor = self.ColorDlg.Color  # 设置图表的平盘颜色

    # ---------------------------------------------------------------------------
    # 布局滑块事件处理方法
    # ---------------------------------------------------------------------------
    def trkKRatioChange(self, Sender):
        """K线比例滑块变化事件 - 调整K线图在图表中的显示比例"""
        self.Chart.KLineRatio = float(self.trkKRatio.Position) / 100.0  # 将滑块位置值(0-100)转换为比例(0.0-1.0)
        self.lblKRatio.Caption = 'K-Line: %d%%' % self.trkKRatio.Position  # 更新显示K线比例的标签文本

    def trkVRatioChange(self, Sender):
        """成交量比例滑块变化事件 - 调整成交量图在图表中的显示比例"""
        self.Chart.VolumeRatio = float(self.trkVRatio.Position) / 100.0  # 将滑块位置值(0-100)转换为比例(0.0-1.0)
        self.lblVRatio.Caption = 'Volume: %d%%' % self.trkVRatio.Position  # 更新显示成交量比例的标签文本

    # ---------------------------------------------------------------------------
    # 股票列表事件处理方法
    # ---------------------------------------------------------------------------
    def lstStocksClick(self, Sender):
        """股票列表点击事件 - 选中股票后加载其数据到图表"""
        idx = self.lstStocks.ItemIndex  # 获取当前选中项的索引
        if idx >= 0:  # 如果选中了有效项
            Name = self.lstStocks.Items[idx]  # 获取选中的股票名称
            if Name != '' and Name[0] != '(':  # 排除提示信息(以括号开头的文本)
                self.edtStock.Text = Name  # 将股票名称填入输入框
                self.Chart.LoadStock(Name)  # 加载该股票的数据

    # ---------------------------------------------------------------------------
    # 图表事件处理方法
    # ---------------------------------------------------------------------------
    def ChartDataIndexChange(self, Sender, ADataIndex, AData):
        """图表数据索引变化事件 - 当前选中的K线数据发生变化时更新信息面板"""
        self.UpdateInfoPanel(ADataIndex, AData)  # 调用信息面板更新方法

    def ChartStockLoaded(self, Sender, AStockName, ADataCount):
        """股票加载完成事件 - 更新状态栏显示加载成功信息"""
        self.lblStatus.Caption = 'Loaded: %s  (%s bars)' % (AStockName, str(ADataCount))  # 显示股票名称和数据条数
        self.lblStatus.Font.Color = clLime  # 将状态文字颜色设置为亮绿色(表示成功)

    def ChartStockNotFound(self, Sender, AStockName):
        """股票未找到事件 - 更新状态栏显示错误信息"""
        self.lblStatus.Caption = 'NOT FOUND: ' + str(AStockName)  # 显示未找到的股票名称
        self.lblStatus.Font.Color = clRed  # 将状态文字颜色设置为红色(表示错误)
        self.mmoInfo.Lines.Clear()  # 清空信息面板
        self.mmoInfo.Lines.Add('Data file not found for: ' + str(AStockName))  # 添加未找到数据文件的提示
        self.mmoInfo.Lines.Add('Expected path: ' + str(self.Chart.DataPath) + str(AStockName) + '.DAT')  # 显示期望的数据文件路径

    # ---------------------------------------------------------------------------
    # UpdateInfoPanel  -  显示当前K线的OHLCV数据(开盘、最高、最低、收盘、成交量)
    # ---------------------------------------------------------------------------
    def UpdateInfoPanel(self, ADataIndex, AData):
        """更新信息面板 - 显示当前选中的K线数据(索引、日期、开盘价、最高价、最低价、收盘价、成交量)"""
        self.mmoInfo.Lines.BeginUpdate()  # 开始批量更新,提高性能并避免闪烁
        try:
            self.mmoInfo.Lines.Clear()  # 清空信息文本框
            self.mmoInfo.Lines.Add('Index : ' + str(ADataIndex))  # 显示当前数据索引
            if AData is not None and hasattr(AData, 'Date') and AData.Date != 0:  # 如果数据有效且日期不为0
                self.mmoInfo.Lines.Add('Date  : ' + str(AData.Date))  # 显示日期
                self.mmoInfo.Lines.Add('Open  : ' + str(AData.OP))  # 显示开盘价
                self.mmoInfo.Lines.Add('High  : ' + str(AData.HP))  # 显示最高价
                self.mmoInfo.Lines.Add('Low   : ' + str(AData.LP))  # 显示最低价
                self.mmoInfo.Lines.Add('Close : ' + str(AData.CP))  # 显示收盘价
                self.mmoInfo.Lines.Add('Volume: ' + str(AData.VOL))  # 显示成交量
                self.mmoInfo.Lines.Add('')  # 添加空行分隔
                self.mmoInfo.Lines.Add('Total bars: ' + str(self.Chart.GetDataCount()))  # 显示总数据条数
            else:  # 如果没有有效数据
                self.mmoInfo.Lines.Add('(no record)')  # 显示"无记录"提示
        finally:
            self.mmoInfo.Lines.EndUpdate()  # 确保无论是否发生异常都结束批量更新

设计文件: fDemo.sct

def btnLoadClick(Sender):
def btnZoomInClick(Sender):
def btnZoomOutClick(Sender):
def btnFirstClick(Sender):
def btnLastClick(Sender):
def btnLeftClick(Sender):
def btnRightClick(Sender):
def chkMAClick(Sender):
def chkVMAClick(Sender):
def chkDateClick(Sender):
def chkDotClick(Sender):
def chkHLClick(Sender):
def chkRSIClick(Sender):
def seMAChange(Sender):
def seRSIChange(Sender):
def btnColorClick(Sender):
def trkKRatioChange(Sender):
def trkVRatioChange(Sender):
def lstStocksClick(Sender):
def ChartDataIndexChange(Sender, ADataIndex, AData):
def ChartStockLoaded(Sender, AStockName, ADataCount):
def ChartStockNotFound(Sender, AStockName):

设计文件: fDemo.sfm

object frmDemo: TfrmDemo
  Left = 0
  Top = 0
  Caption = 'TStockChart Demo'
  ClientHeight = 814
  ClientWidth = 1180
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -12
  Font.Name = 'Tahoma'
  Font.Style = []
  Position = poDesigned
  WindowState = wsMaximized
  TextHeight = 14
  object splitter: TSplitter
    Left = 180
    Top = 36
    Width = 6
    Height = 778
    Color = clBtnFace
    ParentColor = False
  end
  object pnlTop: TPanel
    Left = 0
    Top = 0
    Width = 1180
    Height = 36
    Align = alTop
    BevelOuter = bvNone
    TabOrder = 0
    object lblStock: TLabel
      Left = 8
      Top = 10
      Width = 70
      Height = 14
      Caption = 'Stock Name:'
    end
    object lblStatus: TLabel
      Left = 548
      Top = 10
      Width = 164
      Height = 14
      Caption = 'Ready. Load a stock to begin.'
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clSilver
      Font.Height = -12
      Font.Name = 'Tahoma'
      Font.Style = []
      ParentFont = False
    end
    object edtStock: TEdit
      Left = 72
      Top = 7
      Width = 120
      Height = 22
      TabOrder = 0
    end
    object btnLoad: TButton
      Left = 198
      Top = 6
      Width = 60
      Height = 24
      Caption = 'Load'
      TabOrder = 1
    end
    object btnZoomIn: TButton
      Left = 270
      Top = 6
      Width = 36
      Height = 24
      Caption = 'Z+'
      TabOrder = 2
    end
    object btnZoomOut: TButton
      Left = 308
      Top = 6
      Width = 36
      Height = 24
      Caption = 'Z-'
      TabOrder = 3
    end
    object btnFirst: TButton
      Left = 356
      Top = 6
      Width = 50
      Height = 24
      Caption = '|<<'
      TabOrder = 4
    end
    object btnLeft: TButton
      Left = 408
      Top = 6
      Width = 36
      Height = 24
      Caption = '<'
      TabOrder = 5
    end
    object btnRight: TButton
      Left = 446
      Top = 6
      Width = 36
      Height = 24
      Caption = '>'
      TabOrder = 6
    end
    object btnLast: TButton
      Left = 484
      Top = 6
      Width = 50
      Height = 24
      Caption = '>>|'
      TabOrder = 7
    end
  end
  object pnlLeft: TPanel
    Left = 0
    Top = 36
    Width = 180
    Height = 778
    Align = alLeft
    BevelOuter = bvNone
    TabOrder = 1
    object grpDisplay: TGroupBox
      Left = 4
      Top = 4
      Width = 172
      Height = 152
      Caption = 'Display Options'
      TabOrder = 0
      object chkMA: TCheckBox
        Left = 8
        Top = 20
        Width = 150
        Height = 18
        Caption = 'Show Price MA Lines'
        Checked = True
        State = cbChecked
        TabOrder = 0
      end
      object chkVMA: TCheckBox
        Left = 8
        Top = 40
        Width = 150
        Height = 18
        Caption = 'Show Volume MA Lines'
        Checked = True
        State = cbChecked
        TabOrder = 1
      end
      object chkDate: TCheckBox
        Left = 8
        Top = 60
        Width = 150
        Height = 18
        Caption = 'Show Date Scale'
        Checked = True
        State = cbChecked
        TabOrder = 2
      end
      object chkDot: TCheckBox
        Left = 8
        Top = 80
        Width = 150
        Height = 18
        Caption = 'Show Background Dotlines'
        Checked = True
        State = cbChecked
        TabOrder = 3
      end
      object chkHL: TCheckBox
        Left = 8
        Top = 100
        Width = 150
        Height = 18
        Caption = 'Show High/Low Labels'
        Checked = True
        State = cbChecked
        TabOrder = 4
      end
      object chkRSI: TCheckBox
        Left = 8
        Top = 120
        Width = 150
        Height = 18
        Caption = 'Show RSI Panel'
        Checked = True
        State = cbChecked
        TabOrder = 5
      end
    end
    object grpMA: TGroupBox
      Left = 4
      Top = 160
      Width = 172
      Height = 200
      Caption = 'Price MA Periods'
      TabOrder = 1
      object lblMA0: TLabel
        Left = 8
        Top = 22
        Width = 28
        Height = 14
        Caption = 'MA1:'
      end
      object lblMA1: TLabel
        Left = 8
        Top = 46
        Width = 28
        Height = 14
        Caption = 'MA2:'
      end
      object lblMA2: TLabel
        Left = 8
        Top = 70
        Width = 28
        Height = 14
        Caption = 'MA3:'
      end
      object lblMA3: TLabel
        Left = 8
        Top = 94
        Width = 28
        Height = 14
        Caption = 'MA4:'
      end
      object lblMA4: TLabel
        Left = 8
        Top = 118
        Width = 28
        Height = 14
        Caption = 'MA5:'
      end
      object lblMA5: TLabel
        Left = 8
        Top = 142
        Width = 28
        Height = 14
        Caption = 'MA6:'
      end
      object seMA0: TSpinEdit
        Left = 80
        Top = 19
        Width = 60
        Height = 23
        MaxValue = 500
        MinValue = 0
        TabOrder = 0
        Value = 5
      end
      object seMA1: TSpinEdit
        Tag = 1
        Left = 80
        Top = 43
        Width = 60
        Height = 23
        MaxValue = 500
        MinValue = 0
        TabOrder = 1
        Value = 10
      end
      object seMA2: TSpinEdit
        Tag = 2
        Left = 80
        Top = 67
        Width = 60
        Height = 23
        MaxValue = 500
        MinValue = 0
        TabOrder = 2
        Value = 30
      end
      object seMA3: TSpinEdit
        Tag = 3
        Left = 80
        Top = 91
        Width = 60
        Height = 23
        MaxValue = 500
        MinValue = 0
        TabOrder = 3
        Value = 60
      end
      object seMA4: TSpinEdit
        Tag = 4
        Left = 80
        Top = 115
        Width = 60
        Height = 23
        MaxValue = 500
        MinValue = 0
        TabOrder = 4
        Value = 120
      end
      object seMA5: TSpinEdit
        Tag = 5
        Left = 80
        Top = 139
        Width = 60
        Height = 23
        MaxValue = 500
        MinValue = 0
        TabOrder = 5
        Value = 240
      end
    end
    object grpRSI: TGroupBox
      Left = 4
      Top = 364
      Width = 172
      Height = 72
      Caption = 'RSI Periods'
      TabOrder = 2
      object lblRSI0: TLabel
        Left = 8
        Top = 22
        Width = 29
        Height = 14
        Caption = 'RSI1:'
      end
      object lblRSI1: TLabel
        Left = 8
        Top = 46
        Width = 29
        Height = 14
        Caption = 'RSI2:'
      end
      object seRSI0: TSpinEdit
        Left = 80
        Top = 19
        Width = 60
        Height = 23
        MaxValue = 200
        MinValue = 2
        TabOrder = 0
        Value = 5
      end
      object seRSI1: TSpinEdit
        Tag = 1
        Left = 80
        Top = 43
        Width = 60
        Height = 23
        MaxValue = 200
        MinValue = 2
        TabOrder = 1
        Value = 10
      end
    end
    object grpColor: TGroupBox
      Left = 4
      Top = 440
      Width = 172
      Height = 121
      Caption = 'Colours'
      TabOrder = 3
      object btnBgColor: TButton
        Left = 8
        Top = 18
        Width = 152
        Height = 22
        Caption = 'Background Colour'
        TabOrder = 0
      end
      object btnUpColor: TButton
        Tag = 1
        Left = 8
        Top = 44
        Width = 152
        Height = 22
        Caption = 'Rising Bar Colour'
        TabOrder = 1
      end
      object btnDnColor: TButton
        Tag = 2
        Left = 8
        Top = 68
        Width = 152
        Height = 22
        Caption = 'Falling Bar Colour'
        TabOrder = 2
      end
      object btnEvColor: TButton
        Tag = 3
        Left = 8
        Top = 92
        Width = 152
        Height = 22
        Caption = 'Flat Bar Colour'
        TabOrder = 3
      end
    end
    object grpLayout: TGroupBox
      Left = 4
      Top = 567
      Width = 172
      Height = 92
      Caption = 'Panel Layout'
      TabOrder = 4
      object lblKRatio: TLabel
        Left = 8
        Top = 18
        Width = 67
        Height = 14
        Caption = 'K-Line: 50%'
      end
      object lblVRatio: TLabel
        Left = 8
        Top = 56
        Width = 75
        Height = 14
        Caption = 'Volume: 25%'
      end
      object trkKRatio: TTrackBar
        Left = 8
        Top = 32
        Width = 152
        Height = 22
        Max = 75
        Min = 15
        Position = 50
        TabOrder = 0
        TickStyle = tsNone
      end
      object trkVRatio: TTrackBar
        Left = 8
        Top = 70
        Width = 152
        Height = 22
        Max = 50
        Min = 10
        Position = 25
        TabOrder = 1
        TickStyle = tsNone
      end
    end
    object grpInfo: TGroupBox
      Left = 4
      Top = 665
      Width = 172
      Height = 108
      Caption = 'Current Bar Info'
      TabOrder = 5
      object mmoInfo: TMemo
        Left = 9
        Top = 17
        Width = 160
        Height = 88
        BorderStyle = bsNone
        Color = clBtnFace
        Font.Charset = DEFAULT_CHARSET
        Font.Color = clWindowText
        Font.Height = -11
        Font.Name = 'Courier New'
        Font.Style = []
        ParentFont = False
        ReadOnly = True
        ScrollBars = ssVertical
        TabOrder = 0
      end
    end
  end
  object pnlRight: TPanel
    Left = 960
    Top = 36
    Width = 220
    Height = 778
    Align = alRight
    BevelOuter = bvNone
    TabOrder = 2
    object grpList: TGroupBox
      Left = 4
      Top = 4
      Width = 212
      Height = 756
      Caption = 'Available Stocks'
      TabOrder = 0
      object lstStocks: TListBox
        Left = 4
        Top = 18
        Width = 200
        Height = 730
        ItemHeight = 14
        TabOrder = 0
      end
    end
  end
  object Chart: TStockChart
    Left = 186
    Top = 36
    Width = 774
    Height = 778
    Align = alClient
    TabOrder = 3
    TabStop = True
    DataPath = '.\DATA\日K线'
    KLineRatio = 0.500000000000000000
    VolumeRatio = 0.250000000000000000
  end
  object ColorDlg: TColorDialog
    Left = 548
    Top = 6
  end
end

其他文件

  • Extractor_Icon.ico: 应用程序图标
  • Project1.xml: 项目配置文件
  • fDemo.pydfm: 窗体设计文件(二进制格式,由窗体设计器生成)
  • DATA/日K线/: 包含13个.DAT格式的股票日K线数据文件

详细分析

功能概述

TStockChart股票图表查看器,支持加载和显示股票日K线数据。

使用的组件

  • frmDemo (TfrmDemo)
  • splitter (TSplitter)
  • pnlTop (TPanel)
  • lblStock (TLabel)
  • lblStatus (TLabel)
  • edtStock (TEdit)
  • btnLoad (TButton)
  • btnZoomIn (TButton)
  • btnZoomOut (TButton)
  • btnFirst (TButton)
  • btnLeft (TButton)
  • btnRight (TButton)
  • btnLast (TButton)
  • pnlLeft (TPanel)
  • grpDisplay (TGroupBox)
  • chkMA (TCheckBox)
  • chkVMA (TCheckBox)
  • chkDate (TCheckBox)
  • chkDot (TCheckBox)
  • chkHL (TCheckBox)
  • chkRSI (TCheckBox)
  • grpMA (TGroupBox)
  • lblMA0 (TLabel)
  • lblMA1 (TLabel)
  • lblMA2 (TLabel)
  • lblMA3 (TLabel)
  • lblMA4 (TLabel)
  • lblMA5 (TLabel)
  • seMA0 (TSpinEdit)
  • seMA1 (TSpinEdit)
  • seMA2 (TSpinEdit)
  • seMA3 (TSpinEdit)
  • seMA4 (TSpinEdit)
  • seMA5 (TSpinEdit)
  • grpRSI (TGroupBox)
  • lblRSI0 (TLabel)
  • lblRSI1 (TLabel)
  • seRSI0 (TSpinEdit)
  • seRSI1 (TSpinEdit)
  • grpColor (TGroupBox)
  • btnBgColor (TButton)
  • btnUpColor (TButton)
  • btnDnColor (TButton)
  • btnEvColor (TButton)
  • grpLayout (TGroupBox)
  • lblKRatio (TLabel)
  • lblVRatio (TLabel)
  • trkKRatio (TTrackBar)
  • trkVRatio (TTrackBar)
  • grpInfo (TGroupBox)
  • mmoInfo (TMemo)
  • pnlRight (TPanel)
  • grpList (TGroupBox)
  • lstStocks (TListBox)
  • Chart (TStockChart)
  • ColorDlg (TColorDialog)

技术特点

  • 包含56个GUI组件
  • 定义22个事件处理
  • 使用TStockChart股票图表控件
  • 支持K线显示、均线、RSI等技术指标
  • 支持缩放、滚动、颜色自定义

窗体属性

  • caption: TStockChart Demo
  • height: 814
  • width: 1180

代码分析

导入的模块: - import os - from glcl import *

定义的类: - frmDemo

定义的方法: - init - SyncControls - ScanStockList - btnLoadClick - btnZoomInClick - btnZoomOutClick - btnFirstClick - btnLastClick - btnLeftClick - btnRightClick - chkMAClick - chkVMAClick - chkDateClick - chkDotClick - chkHLClick - chkRSIClick - seMAChange - seRSIChange - btnColorClick - trkKRatioChange - trkVRatioChange - lstStocksClick - ChartDataIndexChange - ChartStockLoaded - ChartStockNotFound - UpdateInfoPanel

事件绑定: - self.Chart.OnDataIndexChange = self.ChartDataIndexChange - self.Chart.OnStockLoaded = self.ChartStockLoaded - self.Chart.OnStockNotFound = self.ChartStockNotFound - self.btnLoad.OnClick = self.btnLoadClick - self.btnZoomIn.OnClick = self.btnZoomInClick - self.btnZoomOut.OnClick = self.btnZoomOutClick - self.btnFirst.OnClick = self.btnFirstClick - self.btnLast.OnClick = self.btnLastClick - self.btnLeft.OnClick = self.btnLeftClick - self.btnRight.OnClick = self.btnRightClick - self.chkMA.OnClick = self.chkMAClick - self.chkVMA.OnClick = self.chkVMAClick - self.chkDate.OnClick = self.chkDateClick - self.chkDot.OnClick = self.chkDotClick - self.chkHL.OnClick = self.chkHLClick - self.chkRSI.OnClick = self.chkRSIClick - self.seMA0.OnChange = self.seMAChange - self.seMA1.OnChange = self.seMAChange - self.seMA2.OnChange = self.seMAChange - self.seMA3.OnChange = self.seMAChange - self.seMA4.OnChange = self.seMAChange - self.seMA5.OnChange = self.seMAChange - self.seRSI0.OnChange = self.seRSIChange - self.seRSI1.OnChange = self.seRSIChange - self.btnBgColor.OnClick = self.btnColorClick - self.btnUpColor.OnClick = self.btnColorClick - self.btnDnColor.OnClick = self.btnColorClick - self.btnEvColor.OnClick = self.btnColorClick - self.trkKRatio.OnChange = self.trkKRatioChange - self.trkVRatio.OnChange = self.trkVRatioChange - self.lstStocks.OnClick = self.lstStocksClick