持仓股票价格监控系统V28 - 洛阳翼展电脑


持仓股票价格监控系统V28

2026-2-7 乱云飞

#SingleInstance Force
#Persistent
#NoEnv
SetWorkingDir %A_ScriptDir%

;---------------------------------------
;	持仓股票价格监控系统
;	http://80c.cc/wwwylg
;	date:2026/1/9
;---------------------------------------

; 全局变量
股票列表 := []
更新时间 := 60000	; 60秒更新一次
每股市值基数 := 100	; 假设每只股票持有100股
最大显示行数 := 20	; 每页显示20行
当前页数 := 1		; 当前页码

; 初始化GUI
创建表格界面()

; 加载保存的股票代码
Gosub, 加载股票列表

; 设置定时器
SetTimer, 模拟点击按钮, %更新时间%
return

模拟点击按钮:
    ControlClick, Button5, 持仓股票价格监控系统
return

创建表格界面() {
    global
    
    ; 创建主窗口
    Gui, Main:New, +Resize +MaximizeBox
    Gui, Main:Font, s12, Microsoft YaHei
    Gui, Main:Color, FFFFFF
    
    ; 操作按钮区域
    按钮Y := 10
    按钮W := 80
    按钮H := 28
    按钮间距 := 15

    Gui, Main:Font, s10
    当前X := 10

    Gui, Main:Add, Button, x%当前X% y%按钮Y% w%按钮W% h%按钮H% g添加股票, 添加股票
    当前X += 按钮W + 按钮间距

    Gui, Main:Add, Button, x%当前X% y%按钮Y% w%按钮W% h%按钮H% g删除股票, 删除股票
    当前X += 按钮W + 按钮间距

    Gui, Main:Add, Button, x%当前X% y%按钮Y% w%按钮W% h%按钮H% g修改基数, 修改基数
    当前X += 按钮W + 按钮间距

    Gui, Main:Add, Button, x%当前X% y%按钮Y% w%按钮W% h%按钮H% g导出数据, 导出CSV
    当前X += 按钮W + 按钮间距

    Gui, Main:Add, Button, x%当前X% y%按钮Y% w%按钮W% h%按钮H% g手动更新, 手动更新
    当前X += 按钮W + 按钮间距

    ; 翻页按钮
    当前X += 30
    翻页按钮W := 70
    翻页按钮间距 := 15

    Gui, Main:Add, Button, x%当前X% y%按钮Y% w%翻页按钮W% h%按钮H% g上一页, 上一页
    当前X += 翻页按钮W + 翻页按钮间距

    Gui, Main:Add, Button, x%当前X% y%按钮Y% w%翻页按钮W% h%按钮H% g下一页, 下一页
    
    ; 分隔线
    Gui, Main:Add, Text, x10 y42 w710 0x10
    
    ; 股票列表标题行
    标题Y := 55
    
    ; 列宽定义
    local 序号宽度值 := 50
    local 名称宽度值 := 180
    local 代码宽度值 := 100
    local 价格宽度值 := 100
    local 持有股数宽度值 := 80  ; 新增:持有股数列宽度
    local 市值宽度值 := 100
    local 涨跌幅宽度值 := 100
    
    ; 计算每列的起始x坐标
    local 序号起始X值 := 15
    local 名称起始X值 := 序号起始X值 + 序号宽度值
    local 代码起始X值 := 名称起始X值 + 名称宽度值
    local 价格起始X值 := 代码起始X值 + 代码宽度值
    local 持有股数起始X值 := 价格起始X值 + 价格宽度值  ; 新增:持有股数列起始位置
    local 市值起始X值 := 持有股数起始X值 + 持有股数宽度值  ; 调整:市值列起始位置
    local 涨跌幅起始X值 := 市值起始X值 + 市值宽度值  ; 调整:涨跌幅列起始位置
    
    Gui, Main:Font, s12 
    Gui, Main:Add, Text, x%序号起始X值% y%标题Y% w%序号宽度值% Center c333333, 序号
    Gui, Main:Add, Text, x%名称起始X值% y%标题Y% w%名称宽度值% Center c333333, 股票名称
    Gui, Main:Add, Text, x%代码起始X值% y%标题Y% w%代码宽度值% Center c333333, 股票代码
    Gui, Main:Add, Text, x%价格起始X值% y%标题Y% w%价格宽度值% Center c333333, 当前价格
    Gui, Main:Add, Text, x%持有股数起始X值% y%标题Y% w%持有股数宽度值% Center c333333, 持有股数  ; 新增:持有股数列标题
    Gui, Main:Add, Text, x%市值起始X值% y%标题Y% w%市值宽度值% Center c333333, 市值(元)
    Gui, Main:Add, Text, x%涨跌幅起始X值% y%标题Y% w%涨跌幅宽度值% Center c333333, 涨跌幅
    
    ; 股票数据行区域
    local 行高值 := 25
    local 起始Y值 := 标题Y + 25
    
    ; 创建20行数据区域
    Loop, %最大显示行数% {
        行号 := A_Index
        y位置值 := 起始Y值 + (行号-1) * 行高值
        
        Gui, Main:Add, Text, x%序号起始X值% y%y位置值% w%序号宽度值% Center v序号%行号%, --
        Gui, Main:Add, Text, x%名称起始X值% y%y位置值% w%名称宽度值% Center v名称%行号%, --
        Gui, Main:Add, Text, x%代码起始X值% y%y位置值% w%代码宽度值% Center v代码%行号%, --
        Gui, Main:Add, Text, x%价格起始X值% y%y位置值% w%价格宽度值% Center v价格%行号%, 0.00
        Gui, Main:Add, Text, x%持有股数起始X值% y%y位置值% w%持有股数宽度值% Center v股数%行号%, 100  ; 新增:持有股数列
        Gui, Main:Add, Text, x%市值起始X值% y%y位置值% w%市值宽度值% Center v市值%行号%, 0.00
        Gui, Main:Add, Text, x%涨跌幅起始X值% y%y位置值% w%涨跌幅宽度值% Center v涨跌%行号%, 0.00`%
    }
    
    ; 显示信息
    local 表格高度值 := 行高值 * 最大显示行数
    local 信息Y值 := 起始Y值 + 表格高度值 + 10
    
    ; 状态栏
    Gui, Main:Add, StatusBar
    
    ; 初始状态栏文本
    更新状态栏()
    
    ; 调整窗口宽度,以适应新增列
    local 窗口宽度值 := 涨跌幅起始X值 + 涨跌幅宽度值 + 20
    local 窗口高度值 := 信息Y值 + 30
    Gui, Main:Show, w%窗口宽度值% h%窗口高度值%, 持仓股票价格监控系统(洛阳牛魔王)
}

; 翻页功能
上一页:
    global 当前页数, 股票列表, 最大显示行数
    总页数 := Ceil(股票列表.Length() / 最大显示行数)
    if (当前页数 > 1) {
        当前页数 -= 1
    } else {
        当前页数 := 总页数
    }
    Gosub, 更新显示行
return

下一页:
    global 当前页数, 股票列表, 最大显示行数
    总页数 := Ceil(股票列表.Length() / 最大显示行数)
    if (当前页数 < 总页数) {
        当前页数 += 1
    } else {
        当前页数 := 1
    }
    Gosub, 更新显示行
return

更新显示行:
    global 股票列表, 当前页数, 最大显示行数, 每股市值基数
    
    总股票数 := 股票列表.Length()
    总页数 := Ceil(总股票数 / 最大显示行数)
    
    if (总页数 = 0) {
        当前页数 := 1
        总页数 := 1
    } else if (当前页数 > 总页数) {
        当前页数 := 总页数
    } else if (当前页数 < 1) {
        当前页数 := 1
    }
    
    开始位置 := (当前页数 - 1) * 最大显示行数 + 1
    
    ; 更新所有可见行的显示
    Loop, %最大显示行数% {
        显示行号 := A_Index
        实际索引 := 开始位置 + 显示行号 - 1
        
        if (实际索引 <= 总股票数) {
            股票 := 股票列表[实际索引]
            
            if (股票.名称 && 股票.价格 > 0) {
                价格显示 := Round(股票.价格, 2)
                市值显示 := Round(股票.价格 * 每股市值基数, 2)
                
                涨跌幅 := 0
                if (股票.昨收价 > 0 && 股票.昨收价 != "") {
                    涨跌幅 := ((股票.价格 - 股票.昨收价) / 股票.昨收价) * 100
                }
                
                涨跌文本 := Round(涨跌幅, 2) . "`%"
                
                GuiControl, Main:, 序号%显示行号%, %实际索引%
                GuiControl, Main:, 名称%显示行号%, % 股票.名称
                GuiControl, Main:, 代码%显示行号%, % 股票.代码
                GuiControl, Main:, 价格%显示行号%, % 价格显示
                GuiControl, Main:, 股数%显示行号%, %每股市值基数%  ; 新增:更新持有股数
                GuiControl, Main:, 市值%显示行号%, % 市值显示
                GuiControl, Main:, 涨跌%显示行号%, % 涨跌文本
                
                ; 设置颜色
                if (股票.昨收价 > 0) {
                    if (股票.价格 > 股票.昨收价) {
                        GuiControl, Main:+cRed, 价格%显示行号%
                        GuiControl, Main:+cRed, 涨跌%显示行号%
                    } else if (股票.价格 < 股票.昨收价) {
                        GuiControl, Main:+cGreen, 价格%显示行号%
                        GuiControl, Main:+cGreen, 涨跌%显示行号%
                    } else {
                        GuiControl, Main:+cBlack, 价格%显示行号%
                        GuiControl, Main:+cBlack, 涨跌%显示行号%
                    }
                }
            } else {
                GuiControl, Main:, 序号%显示行号%, %实际索引%
                GuiControl, Main:, 名称%显示行号%, 加载中...
                GuiControl, Main:, 代码%显示行号%, % 股票.代码
                GuiControl, Main:, 价格%显示行号%, 0.00
                GuiControl, Main:, 股数%显示行号%, %每股市值基数%  ; 新增:更新持有股数
                GuiControl, Main:, 市值%显示行号%, 0.00
                GuiControl, Main:, 涨跌%显示行号%, 0.00`%
                
                GuiControl, Main:+cBlack, 价格%显示行号%
                GuiControl, Main:+cBlack, 涨跌%显示行号%
            }
            
            ; 显示这一行
            GuiControl, Main:Show, 序号%显示行号%
            GuiControl, Main:Show, 名称%显示行号%
            GuiControl, Main:Show, 代码%显示行号%
            GuiControl, Main:Show, 价格%显示行号%
            GuiControl, Main:Show, 股数%显示行号%  ; 新增:显示持有股数列
            GuiControl, Main:Show, 市值%显示行号%
            GuiControl, Main:Show, 涨跌%显示行号%
        } else {
            ; 隐藏多余的行
            GuiControl, Main:Hide, 序号%显示行号%
            GuiControl, Main:Hide, 名称%显示行号%
            GuiControl, Main:Hide, 代码%显示行号%
            GuiControl, Main:Hide, 价格%显示行号%
            GuiControl, Main:Hide, 股数%显示行号%  ; 新增:隐藏持有股数列
            GuiControl, Main:Hide, 市值%显示行号%
            GuiControl, Main:Hide, 涨跌%显示行号%
        }
    }
    
    ; 更新状态栏统计信息
    更新状态栏()
return

加载股票列表:
    global 股票列表
    
    if FileExist("1.txt") {
        FileRead, 内容, 1.txt
        if (内容) {
            行数组 := StrSplit(内容, "`n", "`r")
            Loop, % 行数组.Length() {
                代码 := Trim(行数组[A_Index])
                if (代码 != "" && SubStr(代码, 1, 1) != "#") {
                    股票信息 := Object()
                    股票信息.代码 := 标准化股票代码(代码)
                    股票信息.名称 := ""
                    股票信息.价格 := 0
                    股票信息.昨收价 := 0
                    股票信息.市值 := 0
                    股票列表.Push(股票信息)
                }
            }
        }
    }
    
    Gosub, 更新所有股票数据
return

更新所有股票数据:
    global 股票列表, 每股市值基数
    
    ; 在状态栏显示更新状态
    SB_SetText("正在更新股票数据...", 1)
    
    For 索引, 股票 in 股票列表 {
        股票代码 := 股票.代码
        股票信息 := 获取股票实时信息(股票代码)
        
        if (股票信息 && 股票信息.名称 && 股票信息.价格 > 0) {
            股票.名称 := 股票信息.名称
            股票.价格 := 股票信息.价格
            股票.昨收价 := 股票信息.昨收价
            股票.市值 := 股票.价格 * 每股市值基数
        }
    }
    
    Gosub, 更新显示行
    
    ; 更新状态栏
    更新状态栏()
return

获取股票实时信息(股票代码) {
    股票信息 := Object()
    
    腾讯代码 := 转换到腾讯格式(股票代码)
    if (腾讯代码 = "") {
        return false
    }
    
    url := "http://qt.gtimg.cn/q=" . 腾讯代码
    
    try {
        whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
        whr.Open("GET", url, false)
        whr.SetRequestHeader("User-Agent", "Mozilla/5.0")
        whr.SetRequestHeader("Accept", "*/*")
        whr.Send()
        
        if (whr.Status = 200) {
            response := whr.ResponseText
            response := Trim(response)
            
            if RegExMatch(response, "v_[^=]+=""([^""]+)""", 数据匹配) {
                数据内容 := 数据匹配1
                字段数组 := StrSplit(数据内容, "~")
                
                if (字段数组.Length() >= 5) {
                    股票信息.名称 := 字段数组[2]
                    股票信息.价格 := 字段数组[4]
                    股票信息.昨收价 := 字段数组[5]
                    
                    if (股票信息.名称 && 股票信息.名称 != "" && 股票信息.价格 > 0) {
                        return 股票信息
                    }
                }
            }
        }
    } catch {
        股票信息 := 备用接口获取(股票代码)
        if (股票信息) {
            return 股票信息
        }
    }
    
    return false
}

备用接口获取(股票代码) {
    股票信息 := Object()
    
    url := "https://hq.sinajs.cn/list=" . 股票代码
    
    try {
        whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
        whr.Open("GET", url, false)
        whr.SetRequestHeader("User-Agent", "Mozilla/5.0")
        whr.SetRequestHeader("Referer", "https://finance.sina.com.cn")
        whr.Send()
        
        if (whr.Status = 200) {
            response := whr.ResponseText
            
            if RegExMatch(response, "hq_str_[^=]+=""([^""]+)""", 数据匹配) {
                数据内容 := 数据匹配1
                字段数组 := StrSplit(数据内容, ",")
                
                if (字段数组.Length() > 3) {
                    股票信息.名称 := 字段数组[1]
                    股票信息.昨收价 := 字段数组[3]
                    股票信息.价格 := 字段数组[4]
                    
                    if (股票信息.名称 && 股票信息.价格 > 0) {
                        return 股票信息
                    }
                }
            }
        }
    } catch {
    }
    
    return false
}

转换到腾讯格式(股票代码) {
    代码 := Trim(股票代码)
    
    if (SubStr(代码, 1, 2) = "sh") {
        return "sh" . SubStr(代码, 3)
    } else if (SubStr(代码, 1, 2) = "sz") {
        return "sz" . SubStr(代码, 3)
    }
    
    if (RegExMatch(代码, "^[0-9]{6}$")) {
        首两位 := SubStr(代码, 1, 2)
        
        ; 沪市基金
        if (首两位 = "50" || 首两位 = "51" || 首两位 = "52" 
            || 首两位 = "56" || 首两位 = "58" || 首两位 = "59") {
            return "sh" . 代码
        }
        ; 深市基金
        else if (首两位 = "15" || 首两位 = "16" || 首两位 = "18") {
            return "sz" . 代码
        }
        
        ; 普通股票代码
        if (首两位 = "60" || 首两位 = "68" || 首两位 = "90") {
            return "sh" . 代码
        } else if (首两位 = "00" || 首两位 = "30" || 首两位 = "20" || 首两位 = "39") {
            return "sz" . 代码
        } else {
            return "sz" . 代码
        }
    }
    
    return 代码
}

标准化股票代码(代码) {
    代码 := Trim(代码)
    
    if (SubStr(代码, 1, 2) = "sh" || SubStr(代码, 1, 2) = "sz") {
        return 代码
    }
    
    if (RegExMatch(代码, "^[0-9]{6}$")) {
        首两位 := SubStr(代码, 1, 2)
        
        ; 沪市基金
        if (首两位 = "50" || 首两位 = "51" || 首两位 = "52" 
            || 首两位 = "56" || 首两位 = "58" || 首两位 = "59") {
            return "sh" . 代码
        }
        ; 深市基金
        else if (首两位 = "15" || 首两位 = "16" || 首两位 = "18") {
            return "sz" . 代码
        }
        
        ; 普通股票代码
        if (首两位 = "60" || 首两位 = "68" || 首两位 = "90") {
            return "sh" . 代码
        } else if (首两位 = "00" || 首两位 = "30" || 首两位 = "20" || 首两位 = "39") {
            return "sz" . 代码
        } else {
            return "sz" . 代码
        }
    } else if (RegExMatch(代码, "i)^(sh|sz)[0-9]+$")) {
        return 代码
    }
    
    return 代码
}

添加股票:
    InputBox, 新代码, 添加股票/基金, 请输入股票/基金代码:`n`n示例:`n? A股:600519 或 sz000001 或 002202`n? 基金:561800 或 sh561800 (稀有金属ETF), , 450, 250
    
    if (新代码 != "" && !ErrorLevel) {
        新代码 := Trim(新代码)
        标准代码 := 标准化股票代码(新代码)
        
        if (标准代码 = "") {
            MsgBox, 48, 错误, 代码格式不正确!
            return
        }
        
        存在 := false
        For _, 股票 in 股票列表 {
            if (股票.代码 = 标准代码) {
                存在 := true
                break
            }
        }
        
        if (!存在) {
            股票信息 := 获取股票实时信息(标准代码)
            if (股票信息 && 股票信息.名称 && 股票信息.价格 > 0) {
                新股票 := Object()
                新股票.代码 := 标准代码
                新股票.名称 := 股票信息.名称
                新股票.价格 := 股票信息.价格
                新股票.昨收价 := 股票信息.昨收价
                新股票.市值 := 0
                
                股票列表.Push(新股票)
                保存股票列表()
                Gosub, 更新所有股票数据
                
                消息 := "? 添加成功!`n`n"
                消息 .= "代码:" . 标准代码 . "`n"
                消息 .= "名称:" . 股票信息.名称 . "`n"
                消息 .= "当前价格:" . 股票信息.价格 . "元"
                MsgBox, 64, 添加成功, %消息%
            } else {
                MsgBox, 48, 错误, 无法获取该代码的信息!
            }
        } else {
            MsgBox, 48, 提示, 该代码已存在!
        }
    }
return

删除股票:
    if (股票列表.Length() = 0) {
        MsgBox, 64, 提示, 列表为空!
        return
    }
    
    选择列表 := ""
    For 索引, 股票 in 股票列表 {
        选择列表 .= 索引 . ". " . 股票.名称 . " (" . 股票.代码 . ")`n"
    }
    
    InputBox, 选择序号, 删除项目, 请选择要删除的序号:`n`n%选择列表%, , 500, 350
    
    if (选择序号 != "" && !ErrorLevel) {
        if (选择序号 >= 1 && 选择序号 <= 股票列表.Length()) {
            删除代码 := 股票列表[选择序号].代码
            删除名称 := 股票列表[选择序号].名称
            
            MsgBox, 52, 确认删除, 确定要删除这个项目吗?`n`n名称:%删除名称%`n代码:%删除代码%
            IfMsgBox Yes
            {
                股票列表.RemoveAt(选择序号)
                保存股票列表()
                Gosub, 更新所有股票数据
                
                MsgBox, 64, 删除成功, 已删除项目:`n`n名称:%删除名称%`n代码:%删除代码%
            }
        } else {
            MsgBox, 48, 错误, 序号无效!
        }
    }
return

修改基数:
    InputBox, 新基数, 修改每股市值基数, 当前基数:%每股市值基数%`n请输入新的每股市值基数:, , 300, 150
    
    if (新基数 != "" && !ErrorLevel) {
        if (新基数 > 0) {
            每股市值基数 := 新基数
            更新状态栏()
            Gosub, 更新所有股票数据
            ;;;MsgBox, 64, 修改成功, 市值基数已更新!`n`n新基数:%新基数%
        } else {
            MsgBox, 48, 错误, 请输入有效的正数!
        }
    }
return

导出数据:
    if (股票列表.Length() = 0) {
        MsgBox, 64, 提示, 没有数据可以导出!
        return
    }
    
    文件名 := "股票数据_" . A_Year . A_Mon . A_Day . "_" . A_Hour . A_Min . ".csv"
    
    csv内容 := "序号,名称,代码,当前价格,持有股数,市值,更新时间`n"  ; 修改:添加持有股数列
    
    总市值 := 0
    For 索引, 股票 in 股票列表 {
        市值 := 股票.价格 * 每股市值基数
        总市值 += 市值
        
        csv内容 .= 索引 . ","
        csv内容 .= 股票.名称 . ","
        csv内容 .= 股票.代码 . ","
        csv内容 .= Round(股票.价格, 2) . ","
        csv内容 .= 每股市值基数 . ","  ; 新增:导出持有股数
        csv内容 .= Round(市值, 2) . ","
        csv内容 .= A_Now . "`n"
    }
    
    csv内容 .= "总计,,,,," . Round(总市值, 2) . ","  ; 调整:对应列数
    csv内容 .= 股票列表.Length() . "只股票"
    
    FileDelete, %文件名%
    FileAppend, %csv内容%, %文件名%
    
    消息 := "? 数据导出成功!`n`n"
    消息 .= "文件名:" . 文件名 . "`n"
    消息 .= "包含股票:" . 股票列表.Length() . "只`n"
    消息 .= "总市值:" . Round(总市值, 2) . "元"
    MsgBox, 64, 导出成功, %消息%
return

手动更新:
    Gosub, 更新所有股票数据
    ;;;;MsgBox, 64, 手动更新, ? 股票数据已手动更新!
return

保存股票列表() {
    global 股票列表
    
    文件内容 := ""
    For _, 股票 in 股票列表 {
        文件内容 .= 股票.代码 . "`n"
    }
    
    FileDelete, 1.txt
    FileAppend, %文件内容%, 1.txt
}

更新状态栏() {
    global 股票列表, 每股市值基数
    
    总股票数显示 := 0
    总市值显示 := 0
    
    For 索引, 股票 in 股票列表 {
        if (股票.价格 > 0) {
            总股票数显示++
            总市值显示 += 股票.价格 * 每股市值基数
        }
    }
    
    FormatTime, 当前日期时间, , yyyy-MM-dd HH:mm:ss
    
    状态栏文本 := "股票数:" . 总股票数显示 . " | 总市值:" . Round(总市值显示, 2) . "元 | 更新时间:" . 当前日期时间
    SB_SetText(状态栏文本, 1)
}

MainGuiSize:
    if (A_EventInfo = 1) {
        return
    }
    
    ; 调整控件宽度以适应窗口大小变化
    SB_SetParts(A_GuiWidth)
return

MainGuiClose:
    ExitApp
return


#IfWinActive, 持仓股票价格监控系统
F5::Gosub, 模拟点击按钮
Left::Gosub, 上一页
Right::Gosub, 下一页
#IfWinActive
本文链接:http://80c.cc/ez/860.html
0

发表评论:

VirtualCamera:在录像机中虚拟一个通道显示电脑桌面、视频文件、USB摄像头~
预ICP备10086-001号 © 翼展网/80C.CC 技术支持/洛阳翼展科技
TEL / 13213610060 QQ / 345794501
Powered by emlog